network: UnixListener and UnixStream in std/network (step 2 of #119) #546
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Second step of #119 (Unix domain sockets for
std/network, FIRST-PARTY.md gap 21): a program can listen on and connect to a Unix stream socket by path, with the same shape as the TCP types. The runtime side landed in step 1 (#428, PR #430, commit5dd2b9a4): the nativesnetworkListenUnixandnetworkConnectUnix, the sandbox refusal, and the notes indocs/design/NETWORK.md("Unix domain sockets, as built (step 1)").Design
Decided in #119 (body and comment
decided by the loop);docs/design/NETWORK.mdsection 10 for the sandbox. New filestd/network/src/unix.trb, exported fromstd/network/src/lib.trb(public use UnixListener, UnixStream, UnixSource, UnixSink from "./unix"). Stream sockets only. Methods, no settings object, a path is aString(nostd/pathdependency). Mirror the TCP types instd/network/src/tcp.trb:public shared type UnixListener with Close:static fn listen(path: String, backlog: Int = 128): Result<UnixListener, NetworkError>,fn path(): String,fn accept(): Task<Result<UnixStream, NetworkError>>,fn stop()andvar fn close()likeTcpListener. Closing the handle removes the socket file the runtime bound (done by the native, nothing to do instd/). Noacceptor()in this step (a Unix server on every core is a later addition, filed when needed).public shared type UnixStream with Close:static fn connect(path: String): Task<Result<UnixStream, NetworkError>>,fn receive(maximum: Int = 65536): Task<Result<Bytes?, NetworkError>>,fn send(bytes: Bytes): Task<Result<Void, NetworkError>>,fn shutdown(): Result<Void, NetworkError>,fn source(chunk: Int = 65536): UnixSource,fn sink(): UnixSink,var fn close().UnixSourceis aSource<Bytes, NetworkError>,UnixSinkaSink<Bytes, NetworkError>(end()is a half close), asTcpSourceandTcpSink.localAddress/peerAddress(an accepted stream has no peer path; the options of a TCP stream areinvalid argumenton a Unix one).NetworkError; no new kind.NetworkError.of(code).about("listening on {path}")as TCP does.native fndeclarations inunix.trb(networkListenUnix(path: String, backlog: Int): Int,networkConnectUnix(path: String): Task<Int>), matching the manifest entries of step 1 (runtime/include/torb_network.h).accept,receive,takeReceived,sendandshutdownuse the existing natives on the new handles: they are madepublic native fnintcp.trbthe waynetworkClosealready is (imported byunix.trb, not exported by the package), or declared again inunix.trbif the compiler allows it and it is smaller; the implementer picks, it is internal.TORB_SANDBOX_REFUSED, step 1); nothing instd/changes for it. Aunix:pattern is step 3 of #119, not this one.Acceptance criteria
UnixListener,UnixStream,UnixSourceandUnixSinkexist instd/network/src/unix.trbwith doc comments and are exported fromstd/network.std/network/tests(a newunix.test.trb) over a socket file in a directory made withFile.createTemporaryDirectory(removed at the end): a listener bound to a path accepts aUnixStream.connectto it; bytes go both ways (send/receive, and throughsource()/sink());shutdown()gives the peerNonefromreceive(end of stream) while the other direction still works;connectto a path nobody bound fails withisUnreachable()(the refused case, a file that exists with nobody listening, is asserted only if it needs no more than a plain file at the path);listenon a path that exists fails withisAddressInUse();path()answers the path given; after the listener closed the file is gone (File.existsfalse); a path longer thansun_pathfails with an invalid-argumentNetworkError. Run natively and in the VM (the existingstd/networktest setup, likeoptions.test.trb: the scenarios run at the top of the file where the file's own task can wait).docs/standard-library/network.mddocuments the four types;docs/design/NETWORK.mdsection 4 and the slice table say Unix sockets are done (step 2) and what stays later (datagrams, abstract names, peer credentials, descriptor passing, theunix:grant);docs/design/FIRST-PARTY.mdgap 21 marked done with the date and a pointer tostd/network/src/unix.trband the tests (the "Unix sockets" mention undertorb/postgresstays that package's); the generatedskills/regenerated (docs change,docs skill docs skills).sh tools/gates.sh a);bifCLAUDE.mdasks for it for the touched paths. Windows and macOS code of step 1 was not run by CI; this step adds no per-system code, so no new claim about them.Seed
Touches the seed: no further seed change. This is the second commit of the two-commit rule of CLAUDE.md ("Seed and breaking changes"): the natives were taught in step 1 (#430,
5dd2b9a4, 2026-10-23), and the published seeds (releaseseeds; newest142293fd98fc, built from a commit after it, andc4a8443532aaof 2026-10-24) contain them, sostd/networkcan use them and the compiler (which importsstd/networkincompiler/src/debugger/adapter.trb) still bootstraps in CI. No new native, no syntax change, no new driver flag, no std name looked up by string by the compiler. A seed refresh stays the merge gate's and Torben's.Size
One PR, one commit:
feat(network): UnixListener and UnixStream. About 2 to 3 h: ~250 lines ofstd/(a mirror of the TCP types without the options, address and acceptor), one test file, three doc edits and the regenerated skills.Dependencies
Step 1 (#428, PR #430) landed. Independent of #120 step 2 (#473, PR #477,
TcpStreamoptions instd/network/src/tcp.trb): both edittcp.trb/lib.trb/network.md/NETWORK.md, so whichever lands second rebases. Nothing else.Source
#119 (epic, design),
docs/design/NETWORK.mdsections 4 and 10,docs/design/FIRST-PARTY.mdgap 21.[loop:torbscript] claim implement by session:loop-torbscript-20261028 until 2026-10-28T20:27:50Z
[loop:torbscript] implement: PR #548 opened (
feat(network): UnixListener and UnixStream, one commit):std/network/src/unix.trb, exports,unix.test.trb(12 tests pass in the VM locally on the nightly toolchain), docs and regenerated skills; format and docs checks clean locally, tier A runs in CI. Worker usage: one Sonnet 5.5 sub-agent session, tokens not metered here. next: waiting (CI on PR and merge gate)