eio-net: add an adversarial/chaos wrapper for flows, datagrams, and nets
Protocol adapters (requests, h2, quic, ssh, ttrpc, tls, tcpcl, websocket) must survive a hostile or degraded network -- dribbled and coalesced reads, short and torn writes, a mid-stream reset, dropped or duplicated or reordered datagrams, a refused or slow connect, a keep-alive server that drops after N accepts. That fault-injecting socket belongs in one shared library, not duplicated per adapter, so it lives here beside eio-net.mem and reuses its in-memory transport.
Eio_net_chaos.{Flow,Datagram,Net} each wrap a base Eio resource and inject faults from an inspectable schedule -- either an exact per-call script or a seeded generator whose sequence is a pure function of the seed, so a fuzz run replays byte for byte and composes with Eio_mock.Backend's deadlock detector as a liveness oracle. Stalls yield cooperatively rather than block; a scripted EOF/reset surfaces as End_of_file or an Eio.Io error carrying a dedicated backend code.
eio-net.mem gains pipe, handing out a bare connected flow pair so the chaos layer (and any test) can wrap both ends without a listen/connect handshake.
eio: move the tree to 1.5
eio 1.5 made path syntax a property of the backend, for Windows: a new
`Eio.Fs.Pi.PATH` (`split`, `join`) is included in `Eio.Fs.Pi.DIR`, so
every custom directory provider in the tree stopped compiling on "the
value split is required but not provided". The nine of them now
`include Eio_utils.Posix_path`, from eio's own public `eio.utils`
sub-library and exactly what its eio_posix backend does. `PATH` carries
no type parameter, so a wrapper cannot delegate to whatever it wraps; it
has to state a syntax, and stating the one eio itself states beats nine
hand-rolled copies.
`Eio.Net.Pi.NETWORK.connect` gained `bind_to` and `options`, the
pre-connect socket-option feature. The two real proxies -- eio-net's
chaos layer and mirage's net_device -- forward them. The in-memory
network and the pure nox-tcp stack refuse them loudly instead: neither
has anything to bind to or set an option on, and quietly swallowing an
option a caller asked for is the silent-stub failure this tree rules out.
The test and fuzz fakes, whose behaviour is fixed by construction,
ignore them.
1.5 also retires code written around a bug it fixes. `Ctx.mkdirs` in
monopam walked a path top-down and created each component itself, for
the reason its comment stated: `Eio.Path.mkdirs` checks that the parent
exists before creating, and the parent of a single-component path
relative to a filesystem capability is the empty path -- the filesystem
itself, which no `stat` answered for. So it failed on the one shape that
matters, a directory directly under the work dir. eio_posix now rewrites
an empty relative path to "." on its way to `openat`/`fstatat`, and
eio_linux answered all along through `statx` with `AT_EMPTY_PATH`, so
the three call sites take `Eio.Path.mkdirs ~exists_ok:true` -- what every
other call in that package already used. Two hand-built empty paths
become `Eio.Path.of_dir`, which 1.5 adds for exactly this and which
eio's own backends switched to.
`(eio (>= 1.5))` goes on the sixteen packages whose own sources use one
of the changed signatures, `Sockopt.settings`, or that empty-path
behaviour; a package that merely consumes `Eio.Path` or `Eio.Net` is
left alone. Eight need 1.5 only in test or fuzz code and take the plain
dependency rather than a with-test duplicate, because `opam install
--with-test` genuinely fails against 1.4 there. monopam's is a behaviour
floor rather than a signature one -- `mkdirs` is byte-identical in 1.4
and 1.5 -- so nothing there would fail to compile against the older eio;
it would fail at runtime, on the first fresh checkout directory, which
is worse.
`ocaml-oci`'s `mkdirs` guard stays as it is: eio_linux still hands an
empty relative path to `mkdirat`, and the ENOENT that comes back is not
the `Already_exists` that `~exists_ok:true` swallows. Its comment
already says so.
eio-net: add an adversarial/chaos wrapper for flows, datagrams, and nets
Protocol adapters (requests, h2, quic, ssh, ttrpc, tls, tcpcl, websocket) must survive a hostile or degraded network -- dribbled and coalesced reads, short and torn writes, a mid-stream reset, dropped or duplicated or reordered datagrams, a refused or slow connect, a keep-alive server that drops after N accepts. That fault-injecting socket belongs in one shared library, not duplicated per adapter, so it lives here beside eio-net.mem and reuses its in-memory transport.
Eio_net_chaos.{Flow,Datagram,Net} each wrap a base Eio resource and inject faults from an inspectable schedule -- either an exact per-call script or a seeded generator whose sequence is a pure function of the seed, so a fuzz run replays byte for byte and composes with Eio_mock.Backend's deadlock detector as a liveness oracle. Stalls yield cooperatively rather than block; a scripted EOF/reset surfaces as End_of_file or an Eio.Io error carrying a dedicated backend code.
eio-net.mem gains pipe, handing out a bare connected flow pair so the chaos layer (and any test) can wrap both ends without a listen/connect handshake.