{"name":"std/net.nu","source":"// stdlib/std/net.nu — TCP sockets (HTTP server foundation)\n//\n// Wraps the runtime bridge in stdlib/runtime.c (§18). Blocking sockets\n// at this layer; concurrency (thread-per-connection or epoll) is\n// layered on top in the HTTP server.\n//\n// API (this revision):\n//\n//   ( tcp_listen          s host i port )                   → ! TcpListener NetErr\n//   ( tcp_listen_with_backlog s host i port i backlog )     → ! TcpListener NetErr\n//   ( tcp_accept          TcpListener l )                   → ! TcpConn NetErr\n//   ( tcp_connect         s host i port )                   → ! TcpConn NetErr\n//   ( tcp_connect_timeout s host i port i ms )              → ! TcpConn NetErr\n//   ( tcp_connect_tls_timeout s host i port s sni i verify s alpn ( Vec u ) sess i ms )\n//                                                           → ! TcpConn NetErr\n//   ( tcp_read_chunk      TcpConn c i max )                 → ! ( Vec u ) NetErr\n//   ( tcp_write_all       TcpConn c ( Vec u ) bytes )       → ! v NetErr\n//   ( tcp_write_all2      TcpConn c ( Vec u ) head ( Vec u ) body ) → ! v NetErr\n//   ( tcp_write_str       TcpConn c s text )                → ! v NetErr\n//   ( tcp_sendfile        TcpConn c PFile f i off i len )   → ! i NetErr  sendfile(2) where it can\n//   ( tcp_tls_ktls        TcpConn c )                       → i    kTLS handover, see std/tls.nu\n//   ( tcp_close_listener  TcpListener l )                   → v    early close (optional)\n//   ( tcp_close_conn      TcpConn c )                       → v    early close (optional)\n//   ( tcp_conn_adopt      i raw )                           → TcpConn  owns the runtime socket\n//   ( tcp_conn_view       i raw )                           → TcpConn  never closes it\n//   ( tcp_peer_addr       TcpConn c )                       → s    BORROWED view\n//   ( tcp_local_addr      TcpListener l )                   → String OWNED\n//   ( tcp_set_timeout     TcpConn c i ms )                  → v\n//   ( net_err_name        NetErr e )                        → s    diagnostic\n//\n// Memory model:\n//\n//   * TcpListener and TcpConn are handles over a counted block holding\n//     the runtime's NurlTcp pointer (the runtime owns the FD + a\n//     sideband err_kind): every copy is the same socket, and its last\n//     owner closes it — nothing to close by hand. `tcp_close_*` closes\n//     it early, for every copy. A conn made with `tcp_conn_view` is a\n//     view of a socket something else closes, and closes nothing.\n//   * `tcp_read_chunk` returns an OWNED Vec[u]. Caller frees with\n//     `( vec_free [u] v )`. EOF is reported as the NetClosed variant\n//     so empty payloads (max <= 0) don't get conflated with a clean\n//     peer shutdown.\n//   * `tcp_write_all` and `tcp_write_str` BORROW their input — the\n//     caller still owns the Vec[u] / `s` after the call returns.\n//   * `tcp_peer_addr` returns a BORROWED view (\"ip:port\") whose\n//     lifetime is tied to the TcpConn. Copy with `string_from` if\n//     a long-lived String is needed.\n//   * Error arms never carry a handle: the runtime frees its half on\n//     dispatch, so the NURL caller has nothing to release on Err.\n//\n// Errors — `NetErr` tags must mirror the runtime constants in\n// stdlib/runtime.c §18 (NURL_NET_ERR_*):\n//\n//   NetBind         1   bind / listen failed (bad host, perm, …)\n//   NetAddrInUse    2   EADDRINUSE on bind\n//   NetAccept       3   accept(2) failed\n//   NetRead         4   recv(2) failed (non-timeout)\n//   NetWrite        5   send(2) failed (non-timeout, non-closed)\n//   NetClosed       6   peer reset / clean EOF on read\n//   NetTimeout      7   EAGAIN/EWOULDBLOCK after SO_*TIMEO\n//   NetOther        8   anything else / unsupported target (WASI); also\n//                       the TLS-listener features the pure server lacks\n//                       (tcp_tls_add_sni / tcp_tls_reload /\n//                       tcp_tls_require_client_cert)\n//   NetTlsCtxInit   9   not produced by the pure TLS stack — kept so the\n//                       tags still mirror the runtime; only its inert\n//                       nurl_tcp_*_tls* stubs set it, and no .nu calls them\n//   NetTlsCertLoad  10  TLS listener: cert PEM unreadable or has no\n//                       parsable CERTIFICATE block (_load_tls_ident)\n//   NetTlsKeyLoad   11  TLS listener: key PEM is not an EC P-256, RSA or\n//                       ML-DSA PKCS#8 key, or tcp_listen_tls_dual's second\n//                       identity is not ML-DSA\n//   NetTlsHandshake 12  pure TLS handshake failed — server side on accept\n//                       (tls_server.nu) or client side in tcp_connect_tls*\n//                       / tcp_starttls (tls.nu). A TCP connect that fails\n//                       under tcp_connect_tls* reports its own error\n//                       (NetTimeout, NetOther, …), not this\n//\n// Platform notes:\n//\n//   * POSIX backend is plain BSD sockets — `socket`/`bind`/`listen`/\n//     `accept`/`recv`/`send`. `MSG_NOSIGNAL` is set on send to avoid\n//     SIGPIPE, so a peer-closed connection surfaces as NetClosed\n//     instead of killing the process.\n//   * Win32 backend uses Winsock2 (`-lws2_32`); the runtime calls\n//     WSAStartup lazily on the first listen.\n//   * wasm32-wasi targets compile but every call returns NetOther.\n//\n// MVP scope — explicitly left for later phases:\n//   - IPv6 (`AF_INET6`) — Phase 1.x extension.\n//\n// TLS is not among them: it is pure NURL — stdlib/std/tls.nu (client) and\n// stdlib/std/tls_server.nu (TLS 1.3 server), run over these plain sockets\n// by tcp_connect_tls* / tcp_starttls / tcp_listen_tls* below.\n\n$ `stdlib/core/string.nu`\n$ `stdlib/core/vec.nu`\n$ `stdlib/std/bytes.nu`\n$ `stdlib/std/fs.nu`\n$ `stdlib/std/pfile.nu`\n$ `stdlib/std/tls.nu`\n$ `stdlib/std/tls_server.nu`\n$ `stdlib/std/pkey.nu`\n$ `stdlib/std/arc.nu`\n$ `stdlib/std/thread.nu`\n\n: | NetErr {\n    NetBind\n    NetAddrInUse\n    NetAccept\n    NetRead\n    NetWrite\n    NetClosed\n    NetTimeout\n    NetOther\n    NetTlsCtxInit\n    NetTlsCertLoad\n    NetTlsKeyLoad\n    NetTlsHandshake\n}\n\n// Listener and connection are intentionally distinct types — the\n// compiler refuses to mix them at call sites, which catches the\n// classic \"passed listener to read\" mistake at type-check time.\n// A TLS listener carries its identity — the loaded certificate_list\n// (CertificateEntry blobs, leaf first) and the leaf's private key,\n// prepared for signing when the listener is made (std/tls_server.nu\n// TlsIdent) — so each accept runs the pure handshake (is_tls = 1) with\n// nothing derived from the key on the way. `pq` is an OPTIONAL second\n// identity — an ML-DSA chain and key served beside the classical one to\n// clients that list its scheme (`tcp_listen_tls_dual`). `alpn` is the\n// TLS listener's ALPN preference list in wire form ([len:1][name]\n// entries, server order — see tls_alpn_pack), empty when the listener\n// does not negotiate ALPN. The listener is a plain value every accepting\n// worker copies, so the material lives in a table of the module's\n// (g_tls_lcreds below) and `creds` names its slot (0 on a plaintext\n// listener); `keytype` is the identity's (tls_ident_keytype).\n: TlsCreds {\n    ( Arc TlsIdent ) id\n    ? ( Arc TlsIdent ) pq\n    ( Vec u ) alpn\n}\n\n// The listener's state: the runtime socket handle, and for a TLS\n// listener its key type and credentials slot. None of it changes once\n// made: an early tcp_close_listener stops the runtime socket (closing its\n// fd) and empties the slot, and the last owner releases the handle.\n: TcpListenerImpl { i raw i is_tls i keytype i creds }\n\n% Drop TcpListenerImpl {\n    @ drop TcpListenerImpl l → v {\n        ( nurl_tcp_close . l raw )\n        ? != . l creds 0 { ( __tls_lcreds_close . l creds ) } {}\n    }\n}\n\n// A listener is a handle: every copy (each accepting worker's) is the\n// same socket, and the last owner closes it — nothing to close by hand.\n: TcpListener { ( Shared TcpListenerImpl ) ctl }\n\n// Its drop closes something the outside world sees (stdlib/core/marker.nu).\n% Resource TcpListener {}\n\n// Its copies are made to be used by several threads at once — workers\n// accepting on one socket, another thread closing it to stop them. That\n// is an assertion, not a proof (stdlib/core/marker.nu). What backs it:\n// the fields never change after tcp_listen; the runtime socket's accept\n// counts itself in before it reads the fd, and its stop\n// (tcp_close_listener / tcp_shutdown_listener, idempotent) closes the fd\n// only once no accept is in progress (nurl__tcp_listener_stop,\n// stdlib/runtime_ffi.c); the TLS material's slot is read and emptied\n// under its lock.\n% Sync TcpListener {}\n\n@ TcpListener_share TcpListener h → TcpListener { ^ @ TcpListener { ( shared_clone [TcpListenerImpl] . h ctl ) } }\n\n@ TcpListener_drop sink TcpListener h → v {}\n\n@ __tli TcpListener l → *TcpListenerImpl { ^ ( shared_ptr [TcpListenerImpl] . l ctl ) }\n\n@ __tcp_listener_make i raw i is_tls i keytype i creds → TcpListener {\n    ^ @ TcpListener { ( shared_new [TcpListenerImpl] @ TcpListenerImpl { raw is_tls keytype creds } ) }\n}\n\n// The runtime handle behind a listener.\n@ tcp_listener_raw TcpListener l → i { ^ . ( __tli l ) raw }\n\n// Every TLS listener's material, by slot (a listener's `creds` is its\n// slot + 1). A handshake takes a share of its own under the lock, and\n// tcp_close_listener empties the slot: the material goes with the last\n// share, so a handshake still running when the listener closes keeps\n// what it reads. The table and its lock are made by the first TLS\n// listen, while the process is still single-threaded (as the ticket key\n// is), and every other use follows one.\n: TlsSlot { ? ( Arc TlsCreds ) creds }\n\n: ~ ( Vec TlsSlot ) g_tls_lcreds 0\n: ~ Mutex g_tls_lcreds_mu 0\n: ~ b g_tls_lcreds_made F\n\n@ __tls_lcreds_add sink ( Arc TlsCreds ) c → i {\n    ? ! g_tls_lcreds_made {\n        = g_tls_lcreds ( vec_new [TlsSlot] )\n        = g_tls_lcreds_mu ( mutex_new )\n        = g_tls_lcreds_made T\n    } {}\n    ( mutex_lock g_tls_lcreds_mu )\n    ( vec_push [TlsSlot] g_tls_lcreds @ TlsSlot { @ ?( Arc TlsCreds ) { T c } } )\n    : i slot ( vec_len [TlsSlot] g_tls_lcreds )\n    ( mutex_unlock g_tls_lcreds_mu )\n    ^ slot\n}\n\n@ __tls_lcreds_get i slot → ?( Arc TlsCreds ) {\n    ( mutex_lock g_tls_lcreds_mu )\n    : TlsSlot e ( vec_at [TlsSlot] g_tls_lcreds - slot 1 )\n    : ?( Arc TlsCreds ) out ?? . e creds {\n        T a → @ ?( Arc TlsCreds ) { T ( arc_clone [TlsCreds] a ) }\n        F → @ ?( Arc TlsCreds ) { F }\n    }\n    ( mutex_unlock g_tls_lcreds_mu )\n    ^ out\n}\n\n@ __tls_lcreds_close i slot → v {\n    ( mutex_lock g_tls_lcreds_mu )\n    ( vec_put [TlsSlot] g_tls_lcreds - slot 1 @ TlsSlot { @ ?( Arc TlsCreds ) { F } } )\n    ( mutex_unlock g_tls_lcreds_mu )\n}\n// kind: 0 = plaintext (raw is the runtime socket handle), 1 = pure TLS\n// client, 2 = pure TLS server. For kinds 1/2 `tlsh` is one owner of the\n// TlsConn as a word (`_tls_word`; tcp_close_conn gives it back) and\n// reads/writes dispatch to the pure stack.\n: TcpConnImpl { i raw i kind i tlsh b owns }\n\n% Drop TcpConnImpl {\n    @ drop TcpConnImpl c → v {\n        ? . c owns { ( __tcp_conn_close_parts . c raw . c kind . c tlsh ) } {}\n    }\n}\n\n// A connection is a handle: every copy is the same connection, and the\n// last owner closes it — nothing to close by hand (tcp_close_conn closes\n// it early). A view (tcp_conn_view) of a socket something else owns\n// never closes it.\n: TcpConn { ( Shared TcpConnImpl ) ctl }\n\n// Its drop closes something the outside world sees (stdlib/core/marker.nu).\n% Resource TcpConn {}\n\n@ TcpConn_share TcpConn h → TcpConn { ^ @ TcpConn { ( shared_clone [TcpConnImpl] . h ctl ) } }\n\n@ TcpConn_drop sink TcpConn h → v {}\n\n@ __tci TcpConn c → *TcpConnImpl { ^ ( shared_ptr [TcpConnImpl] . c ctl ) }\n\n@ __tcp_conn_make i raw i kind i tlsh b owns → TcpConn {\n    ^ @ TcpConn { ( shared_new [TcpConnImpl] @ TcpConnImpl { raw kind tlsh owns } ) }\n}\n\n// A connection on runtime socket handle `raw`, which the TcpConn now owns:\n// its last owner (or tcp_close_conn) closes it.\n@ tcp_conn_adopt i raw → TcpConn { ^ ( __tcp_conn_make raw 0 0 T ) }\n\n// A TcpConn over a socket something else owns and closes (a protocol\n// client that keeps the runtime handle in its own record): reads and\n// writes go to it, and neither its drop nor tcp_close_conn closes it.\n@ tcp_conn_view i raw → TcpConn { ^ ( __tcp_conn_make raw 0 0 F ) }\n\n// The runtime handle field of a connection (0 for a TLS conn, whose\n// socket lives in its TlsConn, and once it is closed).\n@ tcp_conn_raw TcpConn c → i { ^ . ( __tci c ) raw }\n\n// Hand the socket over (to the TLS layer): its runtime handle, which this\n// conn — and every copy of it — no longer closes.\n@ __tcp_conn_release TcpConn c → i {\n    : *TcpConnImpl p ( __tci c )\n    = . p owns F\n    ^ . p raw\n}\n\n// The server side of a TLS handshake over an accepted plaintext conn, with\n// a certificate chain and key in memory (tls_accept): the TlsConn takes\n// the socket over, and `c` — every copy of it — no longer closes it. On a\n// failed handshake the TLS layer has closed the socket.\n@ tls_accept_conn TcpConn c ( Vec u ) cert_chain ( Vec u ) priv → !TlsConn TlsErr {\n    ^ ( tls_accept ( __tcp_conn_release c ) cert_chain priv )\n}\n\n// Render a NetErr variant name as a raw `s` for log lines.\n@ net_err_name NetErr e → s {\n    ^ ?? e {\n        NetBind → `NetBind`\n        NetAddrInUse → `NetAddrInUse`\n        NetAccept → `NetAccept`\n        NetRead → `NetRead`\n        NetWrite → `NetWrite`\n        NetClosed → `NetClosed`\n        NetTimeout → `NetTimeout`\n        NetOther → `NetOther`\n        NetTlsCtxInit → `NetTlsCtxInit`\n        NetTlsCertLoad → `NetTlsCertLoad`\n        NetTlsKeyLoad → `NetTlsKeyLoad`\n        NetTlsHandshake → `NetTlsHandshake`\n    }\n}\n\n// True iff a NetErr is a recv/send TIMEOUT (SO_*TIMEO fired) rather than a\n// hard failure — the caller can retry the same operation. A partial-frame\n// reader uses this to distinguish \"the rest is still coming\" from \"the peer\n// is gone\".\n@ net_is_timeout NetErr e → b { ^ ?? e { NetTimeout → T _ → F } }\n\n// Internal: classify the runtime err_kind into a NetErr variant.\n// `deflt` is the variant to return for any unmapped err_kind (kept\n// caller-controlled because read/write/listen each have a different\n// \"natural\" fallback).\n@ _net_err_of i ek → NetErr {\n    ? == ek 1 { ^ # NetErr NetBind } {}\n    ? == ek 2 { ^ # NetErr NetAddrInUse } {}\n    ? == ek 3 { ^ # NetErr NetAccept } {}\n    ? == ek 4 { ^ # NetErr NetRead } {}\n    ? == ek 5 { ^ # NetErr NetWrite } {}\n    ? == ek 6 { ^ # NetErr NetClosed } {}\n    ? == ek 7 { ^ # NetErr NetTimeout } {}\n    ? == ek 9 { ^ # NetErr NetTlsCtxInit } {}\n    ? == ek 10 { ^ # NetErr NetTlsCertLoad } {}\n    ? == ek 11 { ^ # NetErr NetTlsKeyLoad } {}\n    ? == ek 12 { ^ # NetErr NetTlsHandshake } {}\n    ^ # NetErr NetOther\n}\n\n// ── Listener lifecycle ─────────────────────────────────────────────\n\n// Bind on host:port and start listening with the given backlog.\n//\n// `port` 0 means \"let the kernel pick a free ephemeral port\" — the way\n// to bind without racing another process for a fixed number. Read back\n// what it picked with `tcp_local_addr`.\n@ tcp_listen_with_backlog s host i port i backlog → !TcpListener NetErr {\n    ^ ( tcp_listen_with host port @ TcpListenOpts { backlog F } )\n}\n\n// Listener options:\n//   backlog     the accept queue's length (the kernel caps it at its own\n//               maximum — net.core.somaxconn on Linux); <= 0 → 16.\n//   reuse_port  SO_REUSEPORT: several listeners may bind the same address\n//               (each must ask, the first included), and the kernel spreads\n//               incoming connections across them — one listener, and one\n//               accept loop, per worker. Linux and the BSDs; ignored where\n//               the platform has no such option.\n: TcpListenOpts { i backlog b reuse_port }\n\n// The accept-queue length every listener gets unless it asks otherwise:\n// 4096, the kernel's own default ceiling (Linux's somaxconn since 5.4;\n// the kernel clamps it to the configured one). 128 — the old default,\n// and the pre-5.4 somaxconn — overflows under a burst of connections: the\n// kernel drops the SYNs it has no room for, and each dropped client waits\n// out a 1 s retransmission. A long queue costs nothing until it is used.\n@ tcp_listen_default_backlog → i { ^ 4096 }\n\n@ tcp_listen_opts_default → TcpListenOpts { ^ @ TcpListenOpts { ( tcp_listen_default_backlog ) F } }\n\nunsafe & `c` @ nurl_tcp_listen_opts s host i port i backlog i flags → i\n\n// Bind on host:port and listen with `o` (TcpListenOpts).\n@ tcp_listen_with s host i port TcpListenOpts o → !TcpListener NetErr {\n    : i raw ( nurl_tcp_listen_opts host port . o backlog ? . o reuse_port 1 0 )\n    ? == raw 0 { ^ @ !TcpListener NetErr { F # NetErr NetOther } } {}\n    : i ek ( nurl_tcp_err_kind raw )\n    ? != ek 0 {\n        ( nurl_tcp_close raw )\n        ^ @ !TcpListener NetErr { F ( _net_err_of ek ) }\n    } {}\n    ^ @ !TcpListener NetErr { T ( __tcp_listener_make raw 0 0 0 ) }\n}\n\n// Convenience: tcp_listen_with and the default options\n// (tcp_listen_default_backlog, no SO_REUSEPORT).\n@ tcp_listen s host i port → !TcpListener NetErr {\n    ^ ( tcp_listen_with host port ( tcp_listen_opts_default ) )\n}\n\n// TLS listener — loads the PEM cert chain + private key files (EC P-256,\n// RSA or ML-DSA key), then binds and starts listening exactly like\n// tcp_listen. On accept the per-conn pure TLS 1.3 server handshake\n// (tls_server.nu) runs transparently; the returned TcpConn is\n// polymorphic — `tcp_read_chunk` / `tcp_write_all` dispatch to the pure\n// record layer, so HttpServer (and any other code that consumed\n// TcpConn) gets HTTPS without changes. Cert and key are loaded once at\n// listener creation. ALPN is negotiated when the listener was made with\n// tcp_listen_tls_with_alpn; SNI cert selection, client-cert auth and\n// live cert reload are not implemented in the pure stack\n// (tcp_tls_add_sni / tcp_tls_reload / tcp_tls_require_client_cert\n// return NetOther).\n// Frame every `-----BEGIN CERTIFICATE-----` block in `pem` as a TLS 1.3\n// CertificateEntry (tls_cert_entry) and concatenate them, leaf first —\n// the certificate_list the server sends. Supports a single leaf or a\n// full chain (fullchain.pem: leaf + intermediates). Returns an empty Vec\n// if no cert block parses.\n@ __net_cert_chain String pem → ( Vec u ) {\n    : ( Vec u ) list ( vec_new [u] )\n    : i total ( string_len pem )\n    : ~ i pos 0\n    : ~ i guard 0\n    ~ & < pos total < guard 64 {\n        = guard + guard 1\n        : String suf ( string_substr pem pos - total pos )\n        : i rel ( nurl_str_find ( string_data suf ) `-----BEGIN CERTIFICATE-----` )\n        ? < rel 0 { = pos total } {\n            : i bi + pos rel\n            : String suf2 ( string_substr pem bi - total bi )\n            : i erel ( nurl_str_find ( string_data suf2 ) `-----END CERTIFICATE-----` )\n            ? < erel 0 { = pos total } {\n                : i blen + erel 25  // through the END marker (25 chars)\n                : String block ( string_substr pem bi blen )\n                ?? ( pem_to_der ( string_data block ) ) {\n                    T der → {\n                        : ( Vec u ) e ( tls_cert_entry der )\n                        ( bytes_extend_bytes list e )\n                    }\n                    F _ → {}\n                }\n                = pos + bi blen\n            }\n        }\n    }\n    ^ list\n}\n\n// Load cert chain + private key from PEM files into a server identity:\n// the framed certificate_list and the key, prepared for signing\n// (tls_ident_ec / tls_ident_rsa / tls_ident_mldsa). Fails with\n// NetTlsCertLoad / NetTlsKeyLoad. The key form is auto-detected: the EC,\n// RSA and ML-DSA PKCS#8 parsers each cleanly reject the others'\n// encodings.\n@ _load_tls_ident s cert_path s key_path → !( Arc TlsIdent ) NetErr {\n    : String certpem ?? ( read_file cert_path ) { T p → p F _ → ( string_new ) }\n    : ( Vec u ) chain ( __net_cert_chain certpem )\n    ? == ( vec_len [u] chain ) 0 { ^ @ !( Arc TlsIdent ) NetErr { F ( _net_err_of 10 ) } } {}\n    : String keypem ?? ( read_file key_path ) { T p → p F _ → ( string_new ) }\n    // EC first; on failure try RSA (the parsers reject foreign encodings).\n    ?? ( ec_p256_priv_from_pem ( string_data keypem ) ) {\n        T sc → { ^ @ !( Arc TlsIdent ) NetErr { T ( tls_ident_ec chain sc ) } }\n        F _ → {}\n    }\n    ?? ( rsa_priv_from_pem ( string_data keypem ) ) {\n        T k → {\n            // CRT form when the key carries its factors (std/pkey.nu)\n            ?? ( rsa_priv_sign_key k ) {\n                T sk → { ^ @ !( Arc TlsIdent ) NetErr { T ( tls_ident_rsa chain sk ) } }\n                F → { ^ @ !( Arc TlsIdent ) NetErr { F ( _net_err_of 11 ) } }\n            }\n        }\n        F _ → {}\n    }\n    ?? ( mldsa_priv_from_pem ( string_data keypem ) ) {\n        T mk → { ^ @ !( Arc TlsIdent ) NetErr { T ( tls_ident_mldsa chain ( mldsa_level_of_sk_len ( vec_len [u] . mk sk ) ) . mk sk ) } }\n        F _ → {}\n    }\n    ^ @ !( Arc TlsIdent ) NetErr { F ( _net_err_of 11 ) }\n}\n\n@ tcp_listen_tls_with_backlog s host i port i backlog s cert_path s key_path → !TcpListener NetErr {\n    ^ ( __tcp_listen_tls_impl host port backlog cert_path key_path `` `` `` )\n}\n\n// Shared body of the TLS listener constructors. `alpn_protocols` is a\n// space-separated server preference list (\"h2 http/1.1\") or \"\" for no\n// ALPN; it is packed to wire form once here and parked on the listener\n// like the cert and key. `pq_cert_path` / `pq_key_path` name an optional\n// ML-DSA chain + key to serve beside the classical pair (\"\" for none).\n@ __tcp_listen_tls_impl s host i port i backlog s cert_path s key_path s alpn_protocols s pq_cert_path s pq_key_path → !TcpListener NetErr {\n    : ( Arc TlsIdent ) id ?? ( _load_tls_ident cert_path key_path ) {\n        T x → x\n        F e → { ^ @ !TcpListener NetErr { F e } }\n    }\n    // The second identity: it has to BE an ML-DSA key — a classical key\n    // here would be a configuration mistake, and is refused as a key\n    // load error rather than silently served as a second ECDSA cert.\n    : ~ ? ( Arc TlsIdent ) pq @ ?( Arc TlsIdent ) { F }\n    ? > ( nurl_str_len pq_cert_path ) 0 {\n        : ( Arc TlsIdent ) p2 ?? ( _load_tls_ident pq_cert_path pq_key_path ) {\n            T x → x\n            F e → { ^ @ !TcpListener NetErr { F e } }\n        }\n        ? != ( tls_ident_keytype p2 ) 2 {\n            ^ @ !TcpListener NetErr { F ( _net_err_of 11 ) }\n        } {}\n        = pq @ ?( Arc TlsIdent ) { T p2 }\n    } {}\n    : i raw ( nurl_tcp_listen host port backlog )\n    ? == raw 0 {\n        ^ @ !TcpListener NetErr { F # NetErr NetOther }\n    } {}\n    : i ek ( nurl_tcp_err_kind raw )\n    ? != ek 0 {\n        ( nurl_tcp_close raw )\n        ^ @ !TcpListener NetErr { F ( _net_err_of ek ) }\n    } {}\n    // The session-ticket key is drawn here, while the process is still\n    // single-threaded, so every worker that later accepts on this\n    // listener seals and opens tickets under the same key.\n    ( _tls_ticket_key_ensure )\n    // The identities move into the listener's shared credentials.\n    : i keytype ( tls_ident_keytype id )\n    : ( Vec u ) alpn ( tls_alpn_pack alpn_protocols )\n    : ( Arc TlsCreds ) creds ( arc_new [TlsCreds] @ TlsCreds { id pq alpn } )\n    ^ @ !TcpListener NetErr { T ( __tcp_listener_make raw 1 keytype ( __tls_lcreds_add creds ) ) }\n}\n\n@ tcp_listen_tls s host i port s cert_path s key_path → !TcpListener NetErr {\n    ^ ( tcp_listen_tls_with_backlog host port ( tcp_listen_default_backlog ) cert_path key_path )\n}\n\n// TLS listener with ALPN (RFC 7301). `alpn_protocols` is a space-separated\n// preference list, most-preferred first — \"h2 http/1.1\" is what an\n// HTTP/2-capable HTTPS server advertises. Per accepted connection the\n// handshake picks the first protocol in THIS order that the client also\n// offered and announces it in EncryptedExtensions; read it back with\n// tcp_alpn_protocol. A client that offers ALPN with nothing in common is\n// refused with a fatal no_application_protocol alert (§3.2); a client\n// that sends no ALPN negotiates nothing and gets \"\" — the caller decides\n// what that means (HTTP servers treat it as HTTP/1.1).\n@ tcp_listen_tls_with_alpn s host i port i backlog s cert_path s key_path s alpn_protocols → !TcpListener NetErr {\n    ^ ( __tcp_listen_tls_impl host port backlog cert_path key_path alpn_protocols `` `` )\n}\n\n// A TLS listener with TWO identities: the classical `cert_path` /\n// `key_path` (EC P-256 or RSA) and a post-quantum `pq_cert_path` /\n// `pq_key_path` (an ML-DSA-44/65/87 leaf, PKCS#8 key). Each accepted\n// connection is shown the one its ClientHello can verify: the ML-DSA\n// leaf when the client's signature_algorithms lists its scheme\n// (RFC 8446 §4.4.2.2), the classical leaf otherwise — so a server can\n// deploy an ML-DSA certificate for the clients that understand it\n// without turning away a single client that does not. With the\n// X25519MLKEM768 group the handshake already prefers, such a\n// connection has no classical asymmetric operation left in it.\n// `tcp_is_post_quantum` reports the group; `tcp_tls_sig_scheme` the\n// scheme the server signed with.\n//\n// The PQ key file must hold an ML-DSA key — a classical key there is\n// refused with NetTlsKeyLoad, since serving it as a second ECDSA\n// identity would silently not be what was asked for.\n@ tcp_listen_tls_dual s host i port i backlog s cert_path s key_path s pq_cert_path s pq_key_path s alpn_protocols → !TcpListener NetErr {\n    ^ ( __tcp_listen_tls_impl host port backlog cert_path key_path alpn_protocols pq_cert_path pq_key_path )\n}\n\n// Read the negotiated ALPN protocol off a TLS conn — a client conn (kind\n// 1), a STARTTLS upgrade, or a conn accepted by a tcp_listen_tls_with_alpn\n// listener (kind 2). Returns \"\" for plaintext conns or when no ALPN was\n// negotiated.\n@ tcp_alpn_protocol TcpConn c → String {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ ( string_new ) } {}\n    ^ ( tls_alpn_selected # TlsConn tp )\n}\n\n// True iff this conn negotiated exactly `proto` over ALPN. F for a\n// plaintext conn or when nothing was negotiated. No allocation — this is\n// the per-connection protocol dispatch in the HTTP server.\n@ tcp_alpn_is TcpConn c s proto → b {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ F } {}\n    ^ ( tls_alpn_is # TlsConn tp proto )\n}\n\n// The key-exchange group this connection negotiated, as its IANA\n// number — 4588 X25519MLKEM768, 29 x25519, 23 secp256r1 — or 0 for a\n// plaintext conn or one that has not got that far.\n//\n// Worth asking rather than assuming, on either side. A peer that has\n// not deployed ML-KEM falls back to a classical group silently, and\n// nothing else about the connection looks different; a server that\n// wants to log, require or report post-quantum key exchange has no\n// other way to find out.\n@ tcp_tls_group TcpConn c → i {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ 0 } {}\n    ^ ( tls_group # TlsConn tp )\n}\n\n// kTLS on this TLS connection (std/tls.nu tls_ktls): hand its record\n// protection to the kernel where it can go and report what the kernel\n// now protects — 1 the write side, 2 the read side, 3 both, 0 neither\n// (or not a TLS connection).\n@ tcp_tls_ktls TcpConn c → i {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ 0 } {}\n    ^ ( tls_ktls # TlsConn tp )\n}\n\n// T when this TLS connection was established from a session ticket\n// (RFC 8446 §4.6.1) rather than a full handshake — on the server, one\n// of its own tickets; on a client, the exported session it offered.\n// F for plaintext connections.\n@ tcp_tls_resumed TcpConn c → b {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ F } {}\n    ^ ( tls_is_resumed # TlsConn tp )\n}\n\n// T when this connection's key exchange has a post-quantum component,\n// so its forward secrecy survives an adversary recording it today and\n// factoring later.\n@ tcp_is_post_quantum TcpConn c → b {\n    ^ == ( tcp_tls_group c ) 4588\n}\n\n// The SignatureScheme the CertificateVerify of this TLS connection was\n// signed with — on an accepted connection, which of the listener's\n// identities this client was shown: ecdsa_secp256r1_sha256 0x0403 (1027),\n// rsa_pss_rsae_sha256 0x0804 (2052), mldsa44/65/87 0x0904–0x0906\n// (2308–2310). 0 for plaintext and for resumed handshakes (no certificate).\n@ tcp_tls_sig_scheme TcpConn c → i {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ 0 } {}\n    ^ ( tls_cv_scheme # TlsConn tp )\n}\n\n& `c` @ nurl_tcp_connect_ms s host i port i ms → i\n\n& `c` @ nurl_monotonic_ns → i\n\n// The runtime half of every client connect: a connected runtime handle,\n// or the transport's own NetErr (the failed handle already closed).\n//\n// Context-aware like the reads: on a fiber, neither the name lookup nor\n// the TCP handshake holds the worker — a name resolves on a runtime\n// resolver thread and the handshake waits on the netpoller, while the\n// other fibers on that worker keep running. A numeric address never\n// reaches a resolver. Every address the name resolves to is tried in\n// order until one connects. Off a fiber the call blocks the thread, as\n// it always has. `ms` > 0 bounds the whole call — lookup and handshake\n// — and reports NetTimeout once it passes; 0 waits as long as the\n// resolver and the kernel do (an unanswered SYN: minutes).\n@ __tcp_connect_raw s host i port i ms → !i NetErr {\n    : i raw ( nurl_tcp_connect_ms host port ? > ms 0 ms 0 )\n    ? == raw 0 { ^ @ !i NetErr { F # NetErr NetOther } } {}\n    : i ek ( nurl_tcp_err_kind raw )\n    ? != ek 0 {\n        ( nurl_tcp_close raw )\n        ^ @ !i NetErr { F ( _net_err_of ek ) }\n    } {}\n    ^ @ !i NetErr { T raw }\n}\n\n// Open a plain (unencrypted) TCP client connection. Returns a\n// polymorphic TcpConn (kind 0) usable with the same tcp_read/tcp_write\n// family as accepted connections. For an encrypted connection use\n// tcp_connect_tls below. No deadline of its own: see\n// tcp_connect_timeout.\n@ tcp_connect s host i port → !TcpConn NetErr {\n    ^ ( tcp_connect_timeout host port 0 )\n}\n\n// tcp_connect, giving up after `ms` milliseconds with NetTimeout. The\n// budget covers the name lookup and the TCP handshake together, and is\n// honoured on a fiber (a netpoller deadline — the worker keeps running\n// other fibers meanwhile) and off one (poll(2)) alike. ms <= 0 = no\n// deadline. For TLS with one deadline over both handshakes, see\n// tcp_connect_tls_timeout.\n@ tcp_connect_timeout s host i port i ms → !TcpConn NetErr {\n    ?? ( __tcp_connect_raw host port ms ) {\n        F e → ^ @ !TcpConn NetErr { F e }\n        T raw → ^ @ !TcpConn NetErr { T ( tcp_conn_adopt raw ) }\n    }\n}\n\n// Open a verified (or, with verify = 0, encrypted-only) pure-TLS client\n// connection. Returns a polymorphic TcpConn (kind 1) whose reads/writes\n// dispatch to the pure client stack.\n@ tcp_connect_tls s host i port s server_name i verify → !TcpConn NetErr {\n    : i raw ?? ( __tcp_connect_raw host port 0 ) { F e → ^ @ !TcpConn NetErr { F e } T r → r }\n    : !TlsConn TlsErr r ? != verify 0 ( tls_attach_verify raw server_name ) ( tls_attach raw server_name )\n    ?? r {\n        F _ → ^ @ !TcpConn NetErr { F # NetErr NetTlsHandshake }\n        T tc → ^ @ !TcpConn NetErr { T ( __tcp_conn_make 0 1 ( _tls_word tc ) T ) }\n    }\n}\n\n// As tcp_connect_tls, but offers ALPN protocols — one (\"h2\") or a\n// preference list (\"h2 http/1.1\", most preferred first, RFC 7301). After\n// connecting, the negotiated protocol is read with tcp_alpn_protocol —\n// empty if the server declined ALPN. With verify the chain is validated\n// AND the ALPN handshake runs; on TLS 1.2 servers the pure stack does\n// not parse ALPN, so callers requiring h2 should check.\n@ tcp_connect_tls_alpn s host i port s server_name i verify s alpn → !TcpConn NetErr {\n    : i raw ?? ( __tcp_connect_raw host port 0 ) { F e → ^ @ !TcpConn NetErr { F e } T r → r }\n    : !TlsConn TlsErr r ? != verify 0 ( tls_attach_alpn_verify raw server_name alpn ) ( tls_attach_alpn raw server_name alpn )\n    ?? r {\n        F _ → ^ @ !TcpConn NetErr { F # NetErr NetTlsHandshake }\n        T tc → ^ @ !TcpConn NetErr { T ( __tcp_conn_make 0 1 ( _tls_word tc ) T ) }\n    }\n}\n\n// tcp_connect_tls_alpn with a resumption offer as well: `sess` is what\n// tcp_tls_session_export returned from an earlier connection to the same\n// server (empty = full handshake). ALPN, resumption and verification in\n// one call — what an HTTP client that pools connections needs, since the\n// one-knob variants each leave one of the three out.\n@ tcp_connect_tls_full s host i port s server_name i verify s alpn ( Vec u ) sess → !TcpConn NetErr {\n    ^ ( tcp_connect_tls_timeout host port server_name verify alpn sess 0 )\n}\n\n// tcp_connect_tls_full with ONE deadline, `ms` milliseconds, over the\n// whole connect: name lookup, TCP handshake and TLS handshake. Running\n// out reports NetTimeout, at whichever step it happens; ms <= 0 = no\n// deadline (each handshake read then waits up to 20 s, as in\n// tcp_connect_tls*). For the one-knob forms pass `` alpn and an empty\n// session: verify 1 `` ( vec_new [u] ) is tcp_connect_tls with a\n// deadline. On a fiber every wait parks; off one it is poll(2) and the\n// socket timeouts.\n@ tcp_connect_tls_timeout s host i port s server_name i verify s alpn ( Vec u ) sess i ms → !TcpConn NetErr {\n    : i deadline ? > ms 0 + ( nurl_monotonic_ns ) * ms 1000000 0\n    : i raw ?? ( __tcp_connect_raw host port ms ) { F e → ^ @ !TcpConn NetErr { F e } T r → r }\n    : !TlsConn TlsErr r ( tls_attach_full_until raw server_name alpn sess verify deadline )\n    ?? r {\n        F _ → {\n            ? & > deadline 0 >= ( nurl_monotonic_ns ) deadline {\n                ^ @ !TcpConn NetErr { F # NetErr NetTimeout }\n            } {}\n            ^ @ !TcpConn NetErr { F # NetErr NetTlsHandshake }\n        }\n        T tc → ^ @ !TcpConn NetErr { T ( __tcp_conn_make 0 1 ( _tls_word tc ) T ) }\n    }\n}\n\n// Wrap a TLS connection the caller established itself (tls_attach_full /\n// tls_connect_full — say, to read the ALPN pick before deciding which\n// protocol stack to hand the socket to) as a client TcpConn (kind 1).\n// The TcpConn holds an owner of it from here: tcp_close_conn closes it.\n@ tcp_conn_from_tls TlsConn tc → TcpConn {\n    ^ ( __tcp_conn_make 0 1 ( _tls_word tc ) T )\n}\n\n// The resumption session of a TLS client conn (tls_session_export): offer\n// it to tcp_connect_tls_full on the next connection to the same server.\n// Empty for plaintext conns and when the server issued no ticket.\n@ tcp_tls_session_export TcpConn c → ( Vec u ) {\n    : i tp ( __conn_tlsptr c )\n    ? == tp 0 { ^ ( vec_new [u] ) } {}\n    ^ ( tls_session_export # TlsConn tp )\n}\n\n// Register a per-hostname cert/key pair on a TLS listener for Server\n// Name Indication (RFC 6066 §3). NOT YET SUPPORTED on the pure-NURL TLS\n// server (tls_server.nu serves a single default cert) — returns NetOther\n// so callers can detect the gap rather than silently serving the wrong\n// cert. (The old OpenSSL-backed multi-cert SNI path was removed with\n// libssl.) TODO: per-SNI cert selection in tls_accept.\n@ tcp_tls_add_sni TcpListener l s hostname s cert_path s key_path → !v NetErr {\n    ^ @ !v NetErr { F # NetErr NetOther }\n}\n\n// Reload the cert/key on a live TLS listener. NOT YET SUPPORTED on the\n// pure-NURL TLS server — returns NetOther. (Was OpenSSL SSL_CTX hot-swap;\n// removed with libssl.) TODO: atomic cert reload for the pure listener.\n@ tcp_tls_reload TcpListener l s hostname s cert_path s key_path → !v NetErr {\n    ^ @ !v NetErr { F # NetErr NetOther }\n}\n\n// Require/request client-cert (mTLS) authentication. NOT YET SUPPORTED on\n// the pure-NURL TLS server — returns NetOther DELIBERATELY: silently\n// returning Ok would let a caller believe mTLS is enforced when it is not\n// (a security footgun). (Was OpenSSL client-cert verification; removed\n// with libssl.) TODO: client-cert request + verify in tls_accept.\n@ tcp_tls_require_client_cert TcpListener l s ca_bundle_path b strict → !v NetErr {\n    ^ @ !v NetErr { F # NetErr NetOther }\n}\n\n// Peer certificate subject. Always \"\" on the pure TLS stack: it verifies\n// the chain during the handshake but does not expose the subject string,\n// and the pure server never requests a client cert, so there is no mTLS\n// identity to read. (Was the OpenSSL one-line DN, e.g.\n// \"/CN=client.example.com/O=Acme/C=US\"; removed with libssl.)\n@ tcp_peer_cert_subject TcpConn c → String {\n    ^ ( string_new )\n}\n\n// Close the listener now rather than with its last owner, from any\n// thread. Every copy sees it closed: an accept in progress returns\n// NetAccept, and so does every later one. The runtime handle stays\n// named until the last owner: a worker that retained it\n// (tcp_listener_retain) still releases it.\n@ tcp_close_listener TcpListener l → v {\n    : *TcpListenerImpl p ( __tli l )\n    ( nurl_tcp_shutdown . p raw )\n    ? != . p creds 0 { ( __tls_lcreds_close . p creds ) } {}\n}\n\n// Stop the listener's socket — every accept in progress returns NetAccept,\n// and so does every later one — and leave its TLS material in place.\n// `server_run_pool`'s shutdown thread stops its workers so; the last\n// owner releases the rest.\n@ tcp_shutdown_listener TcpListener l → v {\n    : s rp # s . ( __tli l ) raw\n    : i raw # i rp\n    ( nurl_tcp_shutdown raw )\n}\n\n// ── Connection acceptance ──────────────────────────────────────────\n\n// ── STARTTLS registry ──────────────────────────────────────────────\n//\n// An in-place TLS upgrade (tcp_starttls) attaches a TlsConn to an\n// ALREADY-connected fd (SMTP STARTTLS, etc). A TcpConn is passed BY\n// VALUE, so the upgraded `tlsh`/`kind` can't be written back into the\n// caller's copy. Because the fd is the stable identity across the\n// upgrade, the fd→TlsConn mapping lives here instead and is consulted\n// by the read/write/close dispatch. The whole thing is gated on\n// g_st_n: a process that never calls tcp_starttls does ZERO lookups.\n//\n// Storage is an owned `( Vec i )` of (fd, ptr) pairs, two words each.\n: ~ ( Vec i ) g_st 0\n: ~ b g_st_made F\n: ~ i g_st_n 0\n\n@ __starttls_register i fd i ptr → v {\n    ? ! g_st_made { = g_st ( vec_new [i] ) = g_st_made T } {}\n    ( vec_push [i] g_st fd )\n    ( vec_push [i] g_st ptr )\n    = g_st_n + g_st_n 1\n}\n\n@ __starttls_lookup i fd → i {\n    ? == g_st_n 0 { ^ 0 } {}\n    : *i b ( vec_data [i] g_st )\n    : ~ i k 0\n    ~ < k g_st_n {\n        ? == . b * k 2 fd { ^ . b + * k 2 1 } {}\n        = k + k 1\n    }\n    ^ 0\n}\n\n@ __starttls_unregister i fd → v {\n    ? == g_st_n 0 { ^ } {}\n    : *i b ( vec_data [i] g_st )\n    : ~ i k 0\n    : ~ i found 0\n    ~ & == found 0 < k g_st_n {\n        ? == . b * k 2 fd {\n            : i last - g_st_n 1\n            = . b * k 2 . b * last 2\n            = . b + * k 2 1 . b + * last 2 1\n            : b _t ( vec_truncate [i] g_st * last 2 )\n            = g_st_n last\n            = found 1\n        } {}\n        = k + k 1\n    }\n}\n\n// Resolve a TcpConn's TlsConn (as its word), or 0 if the conn is plaintext.\n// kinds 1/2 carry it inline in `tlsh`; a STARTTLS-upgraded kind-0 conn\n// is found via the fd registry.\n@ __conn_tlsptr TcpConn c → i {\n    ? != . ( __tci c ) tlsh 0 { ^ . ( __tci c ) tlsh } {}\n    ? == . ( __tci c ) kind 0 { ^ ( __starttls_lookup . ( __tci c ) raw ) } {}\n    ^ 0\n}\n\n// The fd backing a TcpConn — the runtime handle for plaintext, or the\n// pure TLS conn's socket fd for TLS (kinds 1/2 or STARTTLS-upgraded).\n@ __conn_fd TcpConn c → i {\n    : i tp ( __conn_tlsptr c )\n    ? != tp 0 { ^ ( tls_socket # TlsConn tp ) } {}\n    ^ . ( __tci c ) raw\n}\n\n// The runtime socket handle behind ANY TcpConn — plaintext, pure-TLS\n// client or server, STARTTLS-upgraded — for readiness polling with\n// nurl_reactor_wait_read / nurl_tcp_get_fd. A TLS conn keeps its handle\n// inside the TlsConn and has raw = 0; reading `. c raw` directly, as the\n// HTTP/2 client did, polls handle 0 — which on the hosted runtime is a\n// null handle (never readable, so the probe merely fell through to the\n// blocking read) and on the pure in-process stack is somebody else's\n// socket, reported readable while the caller's own had nothing.\n@ tcp_conn_fd TcpConn c → i { ^ ( __conn_fd c ) }\n\n// Run the server-side pure-TLS handshake over a freshly accepted raw\n// conn handle, using the listener's parked cert/key material. Consumes\n// `craw` (the TlsConn owns the socket on success; closed on failure).\n@ __tls_accept_handshake TcpListener l i craw → !TcpConn NetErr {\n    // A share of its own for the handshake's whole run.\n    ?? ( __tls_lcreds_get . ( __tli l ) creds ) {\n        T a → { ^ ( __tls_accept_with l ( arc_ptr [TlsCreds] a ) craw ) }\n        F → {\n            ( nurl_tcp_close craw )\n            ^ @ !TcpConn NetErr { F # NetErr NetTlsHandshake }\n        }\n    }\n}\n\n@ __tls_accept_with TcpListener l * TlsCreds c i craw → !TcpConn NetErr {\n    // With a second identity parked on the listener the handshake\n    // chooses between the two per ClientHello (tls_accept_ident_dual).\n    : !TlsConn TlsErr r ?? . c pq {\n        T pq → ( tls_accept_ident_dual craw . c id pq . c alpn )\n        F → ( tls_accept_ident craw . c id . c alpn )\n    }\n    ?? r {\n        F _ → ^ @ !TcpConn NetErr { F # NetErr NetTlsHandshake }\n        T tc → ^ @ !TcpConn NetErr { T ( __tcp_conn_make 0 2 ( _tls_word tc ) T ) }\n    }\n}\n\n// Accept ONLY the transport (TCP) connection — even on a TLS listener,\n// no handshake runs here. Context-aware: on a fiber the wait parks on\n// the reactor. This is the building block a fiber-per-connection\n// server wants: accept cheaply on the accept fiber, then let each\n// CONNECTION's fiber run `tcp_conn_complete_tls`, so handshakes\n// proceed concurrently instead of serialising on the accept loop.\n@ tcp_accept_transport TcpListener l → !TcpConn NetErr {\n    : i fcur ( nurl_fiber_current )\n    ? != fcur 0 { ^ ( tcp_accept_async l ) } {}\n    : i lraw . ( __tli l ) raw\n    : i craw ( nurl_tcp_accept lraw )\n    ? == craw 0 { ^ @ !TcpConn NetErr { F # NetErr NetOther } } {}\n    : i ek ( nurl_tcp_err_kind craw )\n    ? != ek 0 {\n        ( nurl_tcp_close craw )\n        ^ @ !TcpConn NetErr { F ( _net_err_of ek ) }\n    } {}\n    : TcpConn c ( tcp_conn_adopt craw )\n    ^ @ !TcpConn NetErr { T c }\n}\n\n// Complete a TLS listener's server handshake over a transport conn from\n// `tcp_accept_transport`. Consumes `c` — on success the returned conn\n// supersedes it (the TlsConn owns the socket); on Err the socket is\n// already closed by the TLS layer. A plaintext listener returns `c`\n// unchanged. The handshake's record I/O is context-aware, so on a fiber\n// a slow client parks this fiber instead of blocking the worker.\n@ tcp_conn_complete_tls TcpListener l TcpConn c → !TcpConn NetErr {\n    ? == . ( __tli l ) is_tls 0 { ^ @ !TcpConn NetErr { T c } } {}\n    ^ ( __tls_accept_handshake l ( __tcp_conn_release c ) )\n}\n\n@ tcp_accept TcpListener l → !TcpConn NetErr {\n    // Context-aware: on a fiber, the transport accept parks on the\n    // reactor so the worker pthread stays free while we wait. For a\n    // TLS listener the handshake then runs right here in the calling\n    // context (fiber-aware record I/O parks; a plain thread blocks).\n    : !TcpConn NetErr acc ( tcp_accept_transport l )\n    ? == . ( __tli l ) is_tls 0 { ^ acc } {}\n    ?? acc {\n        T rawc → ^ ( __tls_accept_handshake l ( __tcp_conn_release rawc ) )\n        F e → ^ @ !TcpConn NetErr { F e }\n    }\n}\n\n// Close `raw` / its TLS connection (kind, tlsh as in TcpConnImpl).\n@ __tcp_conn_close_parts i raw i kind i tlsh → v {\n    : i tp ? != tlsh 0 tlsh ? == kind 0 ( __starttls_lookup raw ) 0\n    ? != tp 0 {\n        ( __starttls_unregister raw )\n        // kind 2 = pure-NURL TLS server conn: its close_notify must be\n        // encrypted under the server write keys (tls_server_close);\n        // tls_close's alert uses the client direction.\n        ? == kind 2 { ( tls_server_close # TlsConn tp ) } { ( tls_close # TlsConn tp ) }\n        // …and the conn's owner of it goes back: the last one frees it.\n        ( _tls_word_release tp )\n    } { ( nurl_tcp_close raw ) }\n}\n\n// Close the connection now rather than with its last owner. Every copy\n// sees it closed; a view closes nothing.\n@ tcp_close_conn TcpConn c → v {\n    : *TcpConnImpl p ( __tci c )\n    ? . p owns { ( __tcp_conn_close_parts . p raw . p kind . p tlsh ) } {}\n    = . p owns F\n    = . p raw 0\n    = . p kind 0\n    = . p tlsh 0\n}\n\n// In-place STARTTLS upgrade: run a pure TLS 1.3 handshake over an\n// already-connected plaintext TcpConn's fd, registering the resulting\n// TlsConn against that fd so subsequent read/write/close on the SAME\n// (by-value) conn transparently go through TLS. `server_name` drives\n// SNI + (when verify) certificate validation. Used by SMTP STARTTLS,\n// IMAP/POP STLS, etc. The conn keeps its identity — no new TcpConn is\n// returned, so callers holding the conn by value see the upgrade.\n@ tcp_starttls TcpConn c s server_name b verify → !v NetErr {\n    : i tp ( __conn_tlsptr c )\n    ? != tp 0 { ^ @ !v NetErr { T 0 } } {}\n    : i fd . ( __tci c ) raw\n    : !TlsConn TlsErr r ? verify ( tls_attach_verify fd server_name ) ( tls_attach fd server_name )\n    ?? r {\n        F _ → {\n            // A failed handshake (or a certificate refused) closed the\n            // socket with the TLS state that took it over: the conn\n            // holds a closed handle now, which its drop must not close\n            // a second time (a use-after-free of the runtime's record).\n            : *TcpConnImpl p ( __tci c )\n            = . p owns F\n            = . p raw 0\n            ^ @ !v NetErr { F # NetErr NetTlsHandshake }\n        }\n        T tc → {\n            ( __starttls_register fd ( _tls_word tc ) )\n            ^ @ !v NetErr { T 0 }\n        }\n    }\n}\n\n@ tcp_peer_addr TcpConn c → s {\n    ^ ( nurl_tcp_peer_addr ( __conn_fd c ) )\n}\n\nunsafe & `c` @ nurl_tcp_local_addr i handle → sink s\n\n// OWNED String \"ip:port\" of the address a listener is actually bound to,\n// read fresh from getsockname. This is the counterpart of listening on\n// port 0: the kernel picks the port, and this is how the process that\n// asked for it finds out. Caller frees with `string_free`.\n//\n// Note the ownership difference from `tcp_peer_addr`, which hands back a\n// BORROWED view cached on the handle: there is no cached local address,\n// so this one is computed and owned. Same shape as `udp_local_addr`.\n@ tcp_local_addr TcpListener l → String {\n    ^ ( string_adopt ( nurl_tcp_local_addr . ( __tli l ) raw ) )\n}\n\n@ tcp_set_timeout TcpConn c i ms → v {\n    ( nurl_tcp_set_timeout ( __conn_fd c ) ms )\n}\n\nunsafe & `c` @ nurl_tcp_set_send_buffer i handle i bytes → i\n\n// Request the native TCP send-buffer size in bytes (1..2147483647).\n// The operating system may adjust this value. TLS uses the same underlying\n// socket; providers without native buffer tuning return NetOther.\n@ tcp_set_send_buffer TcpConn c i bytes → !v NetErr {\n    : i error ( nurl_tcp_set_send_buffer ( __conn_fd c ) bytes )\n    ? != error 0 { ^ @ !v NetErr { F ( _net_err_of error ) } } {}\n    ^ @ !v NetErr { T 0 }\n}\n\nunsafe & `c` @ nurl_tcp_conn_shutdown i handle i both → v\n\n// Shut the connection down — from any thread — without closing it: its\n// read side (a read blocked on it, on a thread or a fiber, returns EOF;\n// writes still go out), or with `both` its write side too (a blocked\n// write fails). The connection is still closed as usual by its owner.\n// The HTTP server's graceful drain ends idle keep-alive connections this\n// way. Windows always shuts both sides; a provider with no way to shut a\n// socket does nothing.\n@ tcp_conn_shutdown TcpConn c b both → v {\n    ( nurl_tcp_conn_shutdown ( __conn_fd c ) ? both 1 0 )\n}\n\n// Absolute monotonic nanoseconds; zero clears the write bound. Unlike\n// the idle timeout this survives partial writes and every TLS record.\n@ tcp_set_write_deadline TcpConn c i ns → v {\n    ( nurl_tcp_set_write_deadline ( __conn_fd c ) ns )\n}\n\n@ tcp_write_deadline TcpConn c → i {\n    ^ ( nurl_tcp_write_deadline ( __conn_fd c ) )\n}\n\n// ── Reading ────────────────────────────────────────────────────────\n\n// Issue ONE recv(2). The returned Vec[u] holds 0..max bytes. EOF is\n// surfaced as `Err(NetClosed)` so empty Ok-vectors are never confused\n// Pure-TLS read dispatch (kind 1 = client, kind 2 = server). Clean EOF\n// (tls_read returns []) is surfaced as NetClosed to match the plain path.\n@ __tls_read_net TcpConn c i max → !( Vec u ) NetErr {\n    : TlsConn tc # TlsConn ( __conn_tlsptr c )\n    : !( Vec u ) TlsErr r ? == . ( __tci c ) kind 2 ( tls_server_read tc max ) ( tls_read tc max )\n    ?? r {\n        F e → {\n            : NetErr ne ?? e { TlsClosed → # NetErr NetClosed _ → # NetErr NetRead }\n            ^ @ !( Vec u ) NetErr { F ne }\n        }\n        T v → {\n            ? == ( vec_len [u] v ) 0 {\n                ^ @ !( Vec u ) NetErr { F # NetErr NetClosed }\n            } {}\n            ^ @ !( Vec u ) NetErr { T v }\n        }\n    }\n}\n\n@ __tls_write_net TcpConn c ( Vec u ) bytes → !v NetErr {\n    : TlsConn tc # TlsConn ( __conn_tlsptr c )\n    : !v TlsErr r ? == . ( __tci c ) kind 2 ( tls_server_write tc bytes ) ( tls_write tc bytes )\n    ?? r { T _ → ^ @ !v NetErr { T 0 } F _ → ^ @ !v NetErr { F ? == ( nurl_tcp_err_kind ( __conn_fd c ) ) 7 # NetErr NetTimeout # NetErr NetWrite } }\n}\n\n// Two-buffer TLS write: the record layer seals `head`‖`body` into\n// records straight from the two buffers (see tls_server_write2), so the\n// plaintext is never joined into one buffer first.\n@ __tls_write_net2 TcpConn c ( Vec u ) head ( Vec u ) body → !v NetErr {\n    : TlsConn tc # TlsConn ( __conn_tlsptr c )\n    : !v TlsErr r ? == . ( __tci c ) kind 2 ( tls_server_write2 tc head body ) ( tls_write2 tc head body )\n    ?? r { T _ → ^ @ !v NetErr { T 0 } F _ → ^ @ !v NetErr { F ? == ( nurl_tcp_err_kind ( __conn_fd c ) ) 7 # NetErr NetTimeout # NetErr NetWrite } }\n}\n\n// with a clean peer shutdown. Caller frees the Vec on the Ok path.\n@ tcp_read_chunk TcpConn c i max → !( Vec u ) NetErr {\n    ? != ( __conn_tlsptr c ) 0 { ^ ( __tls_read_net c max ) } {}\n    // Context-aware dispatch — see tcp_accept's note.\n    : i fcur ( nurl_fiber_current )\n    ? != fcur 0 { ^ ( tcp_read_chunk_async c max ) } {}\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    ? <= max 0 {\n        : ( Vec u ) v ( vec_new [u] )\n        ^ @ !( Vec u ) NetErr { T v }\n    } {}\n    : ( Vec u ) v ( vec_with_cap [u] max )\n    : *u p ( vec_data [u] v )\n    : s pbuf # s p\n    : i n ( nurl_tcp_read raw pbuf max )\n    ? < n 0 {\n        : i ek ( nurl_tcp_err_kind raw )\n        ^ @ !( Vec u ) NetErr { F ( _net_err_of ek ) }\n    } {}\n    ? == n 0 {\n        ^ @ !( Vec u ) NetErr { F # NetErr NetClosed }\n    } {}\n    ( vec_set_len [u] v n )\n    ^ @ !( Vec u ) NetErr { T v }\n}\n\n// ONE recv(2), appended IN PLACE: up to `max` bytes land directly in\n// `buf`'s spare capacity (reserved here, grown at most once). This is\n// tcp_read_chunk minus its per-call throwaway Vec — on the HTTP keep-\n// alive hot path that per-read allocate + copy-into-carry + free pair\n// is pure overhead, since every caller immediately appends the chunk\n// to a connection-level buffer anyway. Context-aware like the rest of\n// the family: TLS conns route through the record layer, fibers park on\n// the reactor for EAGAIN, plain threads block.\n//\n// Ok(n) = n > 0 bytes appended. EOF is Err(NetClosed), a fiber-side\n// deadline overrun Err(NetTimeout) — identical to tcp_read_chunk.\n@ tcp_read_into TcpConn c ( Vec u ) buf i max → !i NetErr {\n    ? <= max 0 { ^ @ !i NetErr { T 0 } } {}\n    ? != ( __conn_tlsptr c ) 0 {\n        // TLS: records are opened in place in the connection's record\n        // buffer and the plaintext copied once, straight into `buf`.\n        : TlsConn tc # TlsConn ( __conn_tlsptr c )\n        : !i TlsErr r ? == . ( __tci c ) kind 2 ( tls_server_read_into tc buf max ) ( tls_read_into tc buf max )\n        ?? r {\n            T n → {\n                ? == n 0 { ^ @ !i NetErr { F # NetErr NetClosed } } {}\n                ^ @ !i NetErr { T n }\n            }\n            F e → {\n                : NetErr ne ?? e { TlsClosed → # NetErr NetClosed _ → # NetErr NetRead }\n                ^ @ !i NetErr { F ne }\n            }\n        }\n    } {}\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    ( vec_reserve [u] buf max )\n    : i len ( vec_len [u] buf )\n    : *u p ( vec_data [u] buf )\n    : s pbuf # s + # i p len\n    : i fcur ( nurl_fiber_current )\n    ? == fcur 0 {\n        : i n ( nurl_tcp_read raw pbuf max )\n        ? > n 0 {\n            : b _ok ( vec_set_len [u] buf + len n )\n            ^ @ !i NetErr { T n }\n        } {}\n        ? == n 0 { ^ @ !i NetErr { F # NetErr NetClosed } } {}\n        ^ @ !i NetErr { F ( _net_err_of ( nurl_tcp_err_kind raw ) ) }\n    } {}\n    // Fiber path: mirrors tcp_read_chunk_async (EAGAIN → park with the\n    // socket's OWN deadline; see that function's timeout note).\n    ( nurl_tcp_set_nonblock raw 1 )\n    : i fd ( nurl_tcp_get_fd raw )\n    ~ T {\n        : i n ( nurl_tcp_read raw pbuf max )\n        ? > n 0 {\n            : b _ok ( vec_set_len [u] buf + len n )\n            ^ @ !i NetErr { T n }\n        } {}\n        ? == n 0 { ^ @ !i NetErr { F # NetErr NetClosed } } {}\n        : i ek ( nurl_tcp_err_kind raw )\n        ? == ek 7 {\n            : i rc ( nurl_reactor_wait_read fd ( __wait_ms raw ) )\n            ? <= rc 0 { ^ @ !i NetErr { F # NetErr NetTimeout } } {}\n        } {\n            ^ @ !i NetErr { F ( _net_err_of ek ) }\n        }\n    }\n    ^ @ !i NetErr { F # NetErr NetOther }\n}\n\n// Queue-ready I/O: encoding and socket progress are separate. Prepared\n// TLS records must leave in FIFO order and be retried by byte offset.\n@ tcp_prepare_write TcpConn c ( Vec u ) bytes → !( Vec u ) NetErr {\n    : i tls ( __conn_tlsptr c )\n    ? == tls 0 { ^ @ !( Vec u ) NetErr { T ( bytes_slice bytes 0 ( vec_len [u] bytes ) ) } } {}\n    : TlsConn state # TlsConn tls\n    : !( Vec u ) TlsErr result ? == . ( __tci c ) kind 2\n    ( tls_server_prepare_write state bytes ) ( tls_prepare_write state bytes )\n    ?? result {\n        T wire → ^ @ !( Vec u ) NetErr { T wire }\n        F _ → ^ @ !( Vec u ) NetErr { F NetClosed }\n    }\n}\n\n// Pair form for a queued writer: `head`‖`body` goes straight onto the end\n// of `out` — appended as-is on plaintext, sealed into ≤16 KB records on\n// TLS — so a frame header and its payload never meet in a scratch buffer.\n@ tcp_prepare_write2_to TcpConn c ( Vec u ) out ( Vec u ) head ( Vec u ) body → !v NetErr {\n    : i tls ( __conn_tlsptr c )\n    ? == tls 0 {\n        ( vec_extend [u] out head )\n        ( vec_extend [u] out body )\n        ^ @ !v NetErr { T 0 }\n    } {}\n    : TlsConn state # TlsConn tls\n    : !v TlsErr result ? == . ( __tci c ) kind 2\n    ( tls_server_prepare_write2_to state out head body ) ( tls_prepare_write2_to state out head body )\n    ?? result {\n        T _ → ^ @ !v NetErr { T 0 }\n        F _ → ^ @ !v NetErr { F NetClosed }\n    }\n}\n\n// Append source-generated TLS control records to the caller's existing\n// ciphertext FIFO; returns the byte count (0 = none pending, and nothing\n// is touched — plaintext connections cost a handle check). No socket I/O.\n@ tcp_prepare_control_to TcpConn c ( Vec u ) out → i {\n    : i tls ( __conn_tlsptr c )\n    ? == tls 0 { ^ 0 } {}\n    : ~ * TlsConnImpl state ( _tls_ptr # TlsConn tls )\n    ? != . state closed 0 { ^ 0 } {}\n    ? & == . state update_pending 0 == . state fatal_alert 0 { ^ 0 } {}\n    : i before ( vec_len [u] out )\n    ( _tls_control_to . state 0 out ? == . ( __tci c ) kind 2 0 1 )\n    ^ - ( vec_len [u] out ) before\n}\n\n// Same, into a fresh Vec. Empty output means none pending.\n@ tcp_prepare_control TcpConn c → !( Vec u ) NetErr {\n    : ( Vec u ) wire ( vec_new [u] )\n    : i appended ( tcp_prepare_control_to c wire )\n    ^ @ !( Vec u ) NetErr { T wire }\n}\n\n@ __tcp_write_failed TcpConn c → v {\n    : i tls ( __conn_tlsptr c )\n    ? != tls 0 { : *TlsConnImpl state ( _tls_ptr # TlsConn tls ) = . state closed 1 } {}\n}\n\n// Positive byte count, zero would-block, or a typed terminal error. No\n// blocking-mode or read-timeout changes, and no encryption on retries.\n@ tcp_try_write_wire TcpConn c ( Vec u ) wire i offset → !i NetErr {\n    : i size ( vec_len [u] wire )\n    ? | < offset 0 > offset size { ^ @ !i NetErr { F NetOther } } {}\n    ? == offset size { ^ @ !i NetErr { T 0 } } {}\n    : i raw ( __conn_fd c )\n    : i wrote ( nurl_tcp_write_nowait raw # s + # i ( vec_data [u] wire ) offset - size offset )\n    ? > wrote 0 { ^ @ !i NetErr { T wrote } } {}\n    : i error ( nurl_tcp_err_kind raw )\n    ? & == error 7 != ( nurl_tcp_write_wait_ms raw ) 0 { ^ @ !i NetErr { T 0 } } {}\n    ( __tcp_write_failed c )\n    ^ @ !i NetErr { F ? == wrote 0 # NetErr NetWrite ( _net_err_of error ) }\n}\n\n// Append immediately available plaintext, retaining incomplete TLS records.\n// Zero means would-block; EOF is NetClosed. Control records may be consumed\n// without producing plaintext, and never force a blocking read for the next.\n@ tcp_try_read_into TcpConn c ( Vec u ) bytes i max → !i NetErr {\n    ? <= max 0 { ^ @ !i NetErr { T 0 } } {}\n    : i raw ( __conn_fd c )\n    : i tls ( __conn_tlsptr c )\n    ? != tls 0 {\n        : TlsConn conn # TlsConn tls\n        : *TlsConnImpl state ( _tls_ptr conn )\n        : i previous . state read_nowait\n        = . state read_nowait 1\n        : !i TlsErr result ? == . ( __tci c ) kind 2 ( tls_server_read_into conn bytes max ) ( tls_read_into conn bytes max )\n        = . state read_nowait previous\n        ?? result {\n            T count → {\n                ? == count 0 { ^ @ !i NetErr { F NetClosed } } {}\n                ^ @ !i NetErr { T count }\n            }\n            F error → {\n                ?? error {\n                    TlsRead → { ? | != . state update_pending 0 == ( nurl_tcp_err_kind raw ) 7 { ^ @ !i NetErr { T 0 } } {} }\n                    TlsProtocol → { ? != . state fatal_alert 0 { ^ @ !i NetErr { T 0 } } {} }\n                    TlsClosed → { ^ @ !i NetErr { F NetClosed } }\n                    _ → {}\n                }\n                ^ @ !i NetErr { F NetRead }\n            }\n        }\n    } {}\n    ( vec_reserve [u] bytes max )\n    : i length ( vec_len [u] bytes )\n    : i got ( nurl_tcp_read_nowait raw # s + # i ( vec_data [u] bytes ) length max )\n    ? > got 0 {\n        : b sized ( vec_set_len [u] bytes + length got )\n        ^ @ !i NetErr { T got }\n    } {}\n    ? == got 0 { ^ @ !i NetErr { F NetClosed } } {}\n    : i error ( nurl_tcp_err_kind raw )\n    ? == error 7 { ^ @ !i NetErr { T 0 } } {}\n    ^ @ !i NetErr { F ( _net_err_of error ) }\n}\n\n@ __tcp_buffered_read TcpConn c → b {\n    : i tls ( __conn_tlsptr c )\n    ? == tls 0 { ^ F } {}\n    : *TlsConnImpl state ( _tls_ptr # TlsConn tls )\n    ? | != . state closed 0 | != . state fatal_alert 0 > ( vec_len [u] . state appbuf ) 0 { ^ T } {}\n    : i size ( vec_len [u] . state rxbuf )\n    ? < size 5 { ^ F } {}\n    : *u data ( vec_data [u] . state rxbuf )\n    ^ >= size + 5 | << # i . data 3 8 # i . data 4\n}\n\n@ tcp_wait_io TcpConn c b readable b writable i timeout_ms → i {\n    ? & readable ( __tcp_buffered_read c ) { ^ 1 } {}\n    : i events + ? readable 1 0 ? writable 2 0\n    ? == events 0 { ^ -1 } {}\n    : i raw ( __conn_fd c )\n    : ~ i wait timeout_ms\n    ? writable {\n        : i remaining ( nurl_tcp_write_wait_ms raw )\n        ? == remaining 0 { ^ 0 } {}\n        ? & >= remaining 0 | < wait 0 < remaining wait { = wait remaining } {}\n    } {}\n    ? != ( nurl_fiber_current ) 0 {\n        ^ ( nurl_reactor_wait_io ( nurl_tcp_get_fd raw ) events wait )\n    } {}\n    ^ ( nurl_tcp_wait_io raw events wait )\n}\n\n// Readiness permits a try-read; a TLS peer may have sent a partial record.\n@ tcp_read_ready TcpConn c → b { ^ > ( tcp_wait_io c T F 0 ) 0 }\n\n// ── Writing ────────────────────────────────────────────────────────\n\n// Two-segment send: `b1[0..n1)` then `b2[0..n2)` through ONE\n// sendmsg(2)/WSASend, returning the count written across both (short\n// counts allowed; -1 = nothing written, err_kind set). With one segment\n// empty it is exactly nurl_tcp_write. Declared here rather than in the\n// compiler preamble, like the other stdlib-only runtime entry points.\nunsafe & `c` @ nurl_tcp_write2 i conn *u b1 i n1 *u b2 i n2 → i\n\n& `c` @ nurl_tcp_sendfile i conn i fd i off i n → i\n\n// The one blocking send loop behind tcp_write_all, tcp_write_str and\n// tcp_write_all2: writes the logical concatenation `p1[0..n1)‖p2[0..n2)`\n// to the raw handle, re-pointing the pair at the unsent remainder after\n// every short count. A single buffer is the pair with `n2 == 0`.\n//\n// write(2) on a blocking socket is NOT all-or-nothing: it returns as soon\n// as it has copied SOME bytes into the send buffer, and with SO_SNDTIMEO\n// set (tcp_set_timeout) it returns a short count when the timer fires with\n// the peer's window full. Writing once and reporting success left the rest\n// of the buffer unsent, and — because the frame header had already\n// announced the full length — DESYNCED the stream: the peer's next\n// read_exact spliced the tail of one frame onto the head of the next and\n// handed up a frame of the right length with the wrong bytes. Loopback\n// hides it (the receiver drains as fast as the sender fills, so one write\n// takes everything); a real network path with an autotuned 64 KiB initial\n// send buffer does not, past a few hundred KiB. Loop until it is all gone,\n// exactly as the async twin below does.\n@ __tcp_write_pair_sync i raw s p1 i n1 s p2 i n2 → !v NetErr {\n    : i total + n1 n2\n    ? <= total 0 { ^ @ !v NetErr { T 0 } } {}\n    : ~ i sent 0\n    ~ < sent total {\n        : ~ s a p1\n        : ~ i an - n1 sent\n        : ~ i bn n2\n        ? < sent n1 { = a # s + # i p1 sent } {\n            = a # s + # i p2 - sent n1\n            = an - total sent\n            = bn 0\n        }\n        : i wn ( nurl_tcp_write2 raw a an p2 bn )\n        ? > wn 0 { = sent + sent wn } {\n            : i ek ( nurl_tcp_err_kind raw )\n            ^ @ !v NetErr { F ? == wn 0 # NetErr NetWrite ( _net_err_of ek ) }\n        }\n    }\n    ^ @ !v NetErr { T 0 }\n}\n\n@ tcp_write_all TcpConn c ( Vec u ) bytes → !v NetErr {\n    ? != ( __conn_tlsptr c ) 0 { ^ ( __tls_write_net c bytes ) } {}\n    // Context-aware dispatch — see tcp_accept's note.\n    : i fcur ( nurl_fiber_current )\n    ? != fcur 0 { ^ ( tcp_write_all_async c bytes ) } {}\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    : *u p ( vec_data [u] bytes )\n    ^ ( __tcp_write_pair_sync raw # s p ( vec_len [u] bytes ) # s 0 0 )\n}\n\n// `len` bytes of `f` from offset `off` to the connection. On a plain\n// TCP connection, and on a TLS one whose write side the kernel seals\n// (kTLS, tls_ktls), the kernel copies them straight from the page cache\n// (sendfile(2)) — the bytes never enter this process, and under kTLS\n// the records are sealed on the way out. A TLS connection sealing its\n// own records, or a platform without sendfile, reads the file in 64 KB\n// slices into one buffer and writes them through tcp_write_all. Ok(the\n// bytes sent: `len`, fewer when the file ends first).\n@ tcp_sendfile TcpConn c PFile f i off i len → !i NetErr {\n    ? <= len 0 { ^ @ !i NetErr { T 0 } } {}\n    : i tls ( __conn_tlsptr c )\n    : b kernel ? == tls 0 T ( tls_ktls_tx_ready # TlsConn tls )\n    : ~ i sent 0\n    ? kernel {\n        // The socket's runtime handle: a TLS connection's own (__conn_fd),\n        // not TcpConnImpl.raw, which only a plaintext connection fills.\n        : i raw ( __conn_fd c )\n        : i fd ( _pfile_fd f )\n        : b on_fiber != ( nurl_fiber_current ) 0\n        ? on_fiber { ( nurl_tcp_set_nonblock raw 1 ) } {}\n        ~ < sent len {\n            : i n ( nurl_tcp_sendfile raw fd + off sent - len sent )\n            ? > n 0 { = sent + sent n } {\n                ? == n 0 { ^ @ !i NetErr { T sent } } {}\n                ? == n -2 { break } {}\n                : i error ( nurl_tcp_err_kind raw )\n                ? | != error 7 ! on_fiber { ^ @ !i NetErr { F ( _net_err_of error ) } } {}\n                : i remaining ( nurl_tcp_write_wait_ms raw )\n                ? == remaining 0 { ^ @ !i NetErr { F NetTimeout } } {}\n                ? <= ( nurl_reactor_wait_write ( nurl_tcp_get_fd raw ) remaining ) 0 { ^ @ !i NetErr { F NetTimeout } } {}\n            }\n        }\n        ? >= sent len { ^ @ !i NetErr { T sent } } {}\n    } {}\n    // Read-and-write: one 64 KB buffer reused for every slice.\n    : ( Vec u ) buf ( vec_with_cap [u] 65536 )\n    ~ < sent len {\n        : i want ? < - len sent 65536 - len sent 65536\n        ( vec_clear [u] buf )\n        ?? ( pfile_read_vec_into f buf + off sent want ) {\n            T got → {\n                ? == got 0 { ^ @ !i NetErr { T sent } } {}\n                ?? ( tcp_write_all c buf ) { T _ → {} F e → { ^ @ !i NetErr { F e } } }\n                = sent + sent got\n            }\n            F _ → { ^ @ !i NetErr { F NetRead } }\n        }\n    }\n    ^ @ !i NetErr { T sent }\n}\n\n// Write `head` then `body` as ONE logical message. On the plaintext\n// path both segments leave in a single sendmsg(2), so a caller that\n// keeps a message head and its payload in separate buffers (the HTTP\n// server: serialised head in the connection's wire buffer, body still\n// in the response) pays neither the concat copy nor a second syscall.\n// On TLS the record layer seals the pair straight from the two buffers.\n// Both inputs are BORROWED, as for tcp_write_all.\n@ tcp_write_all2 TcpConn c ( Vec u ) head ( Vec u ) body → !v NetErr {\n    ? != ( __conn_tlsptr c ) 0 { ^ ( __tls_write_net2 c head body ) } {}\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    : *u hp ( vec_data [u] head )\n    : i hn ( vec_len [u] head )\n    : *u bp ( vec_data [u] body )\n    : i bn ( vec_len [u] body )\n    : i fcur ( nurl_fiber_current )\n    ? != fcur 0 { ^ ( __tcp_write_pair_async raw # s hp hn # s bp bn ) } {}\n    ^ ( __tcp_write_pair_sync raw # s hp hn # s bp bn )\n}\n\n// Convenience: write a NUL-terminated `s` (the typical HTTP header /\n// status-line case). The bytes [0..len) are sent — the trailing NUL is\n// NOT transmitted.\n@ tcp_write_str TcpConn c s text → !v NetErr {\n    ? != ( __conn_tlsptr c ) 0 {\n        : ( Vec u ) b ( bytes_from_str text )\n        : !v NetErr r ( __tls_write_net c b )\n        ^ r\n    } {}\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    // Same short-write rule as tcp_write_all — see __tcp_write_pair_sync.\n    // Status lines and headers are small enough that one write almost\n    // always takes them, which is exactly why a partial one here would be\n    // a rare, load-dependent corruption rather than an outright failure.\n    ^ ( __tcp_write_pair_sync raw text ( nurl_str_len text ) # s 0 0 )\n}\n\n// ── Phase 6 — fiber-aware async TCP wrappers ───────────────────────\n//\n// These mirror the sync API one-to-one. Inside a fiber, an EAGAIN /\n// EWOULDBLOCK from the underlying socket is converted into a park on\n// the reactor; the worker pthread is NOT blocked. From outside a\n// fiber (e.g. main thread with no scheduler attached), the reactor\n// returns -1 immediately and the async wrapper falls back to the\n// blocking variant transparently.\n//\n// First call on a (listener / conn) handle flips its fd to\n// O_NONBLOCK via `nurl_tcp_set_nonblock` — subsequent sync calls on\n// the SAME handle will start surfacing NetTimeout on no-data; mixing\n// sync + async on one handle is not supported.\n\n$ `stdlib/std/async_ffi.nu`\n\n// nurl_tcp_get_fd / nurl_tcp_timeout_ms / nurl_tcp_set_nonblock are\n// declared in async_ffi.nu (imported above) so the pure TLS stack can\n// use them too without an import cycle.\n\nunsafe & `c` @ nurl_tcp_ref i handle → v\n\nunsafe & `c` @ nurl_tcp_unref i handle → v\n\n// Take/drop an extra reference on a listener handle so it survives a\n// concurrent `tcp_close_listener` (e.g. `server_stop` fired from another\n// thread). `server_run_async` retains the listener for the life of its\n// accept fiber and releases it once the fiber has exited — without this,\n// closing the listener mid-accept frees the struct out from under the\n// parked fiber (use-after-free). Each retain MUST be paired with one\n// release.\n@ tcp_listener_retain TcpListener l → v {\n    : s rp # s . ( __tli l ) raw\n    ( nurl_tcp_ref # i rp )\n}\n\n@ tcp_listener_release TcpListener l → v {\n    : s rp # s . ( __tli l ) raw\n    ( nurl_tcp_unref # i rp )\n}\n\n// Set non-blocking mode (idempotent). Used internally by the async\n// wrappers on first call. Exposed in case callers want to manage the\n// mode explicitly (e.g. a custom proactor loop).\n@ tcp_set_nonblock_listener TcpListener l i on → v {\n    : s rp # s . ( __tli l ) raw\n    : i raw # i rp\n    ( nurl_tcp_set_nonblock raw on )\n}\n\n@ tcp_set_nonblock_conn TcpConn c i on → v {\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    ( nurl_tcp_set_nonblock raw on )\n}\n\n// The deadline to hand the reactor for this socket: what the caller set\n// with `tcp_set_timeout`, or −1 (\"no deadline\") when they set none. The\n// reactor spells \"for ever\" as −1 and 0 would mean \"do not wait at all\",\n// so the translation lives here rather than at four call sites.\n@ __wait_ms i raw → i {\n    : i ms ( nurl_tcp_timeout_ms raw )\n    ^ ? > ms 0 ms - 0 1\n}\n\n// Non-blocking accept. Loops: try accept; if NetTimeout (EAGAIN),\n// wait_readable on listener fd, retry. On non-fiber callers,\n// wait_readable returns -1 immediately and we fall back to the\n// existing sync `tcp_accept` (which blocks on the kernel).\n@ tcp_accept_async TcpListener l → !TcpConn NetErr {\n    : s lrp # s . ( __tli l ) raw\n    : i lraw # i lrp\n    ( nurl_tcp_set_nonblock lraw 1 )\n    : i fd ( nurl_tcp_get_fd lraw )\n    ~ T {\n        : i craw ( nurl_tcp_accept lraw )\n        ? == craw 0 { ^ @ !TcpConn NetErr { F # NetErr NetOther } } {}\n        : i ek ( nurl_tcp_err_kind craw )\n        ? == ek 0 {\n            ^ @ !TcpConn NetErr { T ( tcp_conn_adopt craw ) }\n        } {\n            ( nurl_tcp_close craw )\n            ? == ek 7 {  // NetTimeout / EAGAIN\n                // ACCEPT KEEPS WAITING. `tcp_set_timeout` is about a\n                // CONNECTION's reads and writes; a listener has no such\n                // deadline, and a server loop reads \"the accept ended\"\n                // as \"we were stopped\" — report a timeout there and\n                // every clean shutdown becomes an error. The accept wait\n                // runs this fiber as soon as the listener is ready, ahead\n                // of everything queued: accepting is how the connections\n                // waiting in the kernel enter the service order, so it\n                // does not wait its turn behind work that became runnable\n                // after they arrived (Admission, stdlib/runtime_ffi.c).\n                : i rc ( nurl_reactor_wait_accept fd - 0 1 )\n                // wait_readable returns -1 outside a fiber; in that\n                // case the sync accept already blocked, so EAGAIN\n                // shouldn't recur — bail to NetAccept.\n                ? < rc 0 { ^ @ !TcpConn NetErr { F # NetErr NetAccept } } {}\n            } {\n                ^ @ !TcpConn NetErr { F ( _net_err_of ek ) }\n            }\n        }\n    }\n    ^ @ !TcpConn NetErr { F # NetErr NetOther }\n}\n\n// Non-blocking single recv. Same shape as tcp_read_chunk; loops on\n// EAGAIN via the reactor.\n@ tcp_read_chunk_async TcpConn c i max → !( Vec u ) NetErr {\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    ( nurl_tcp_set_nonblock raw 1 )\n    : i fd ( nurl_tcp_get_fd raw )\n    ? <= max 0 {\n        : ( Vec u ) v0 ( vec_new [u] )\n        ^ @ !( Vec u ) NetErr { T v0 }\n    } {}\n    : ( Vec u ) v ( vec_with_cap [u] max )\n    : *u p ( vec_data [u] v )\n    : s pbuf # s p\n    ~ T {\n        : i n ( nurl_tcp_read raw pbuf max )\n        ? > n 0 {\n            ( vec_set_len [u] v n )\n            ^ @ !( Vec u ) NetErr { T v }\n        } {}\n        ? == n 0 {\n            ^ @ !( Vec u ) NetErr { F # NetErr NetClosed }\n        } {}\n        : i ek ( nurl_tcp_err_kind raw )\n        ? == ek 7 {\n            // The socket's OWN deadline, not \"for ever\". A blocking read\n            // gets it from SO_RCVTIMEO; a parked fiber has to be told,\n            // and a hard-coded −1 here silently discarded every\n            // `tcp_set_timeout` the caller had made. It cost a\n            // distributed node its startup: a relay read that should\n            // have given up after 150 ms waited for a message that was\n            // never going to come, and only on a runtime where threads\n            // ARE fibers — which is why no hosted test saw it.\n            : i rc ( nurl_reactor_wait_read fd ( __wait_ms raw ) )\n            ? < rc 0 {\n                ^ @ !( Vec u ) NetErr { F # NetErr NetTimeout }\n            } {}\n            ? == rc 0 {\n                ^ @ !( Vec u ) NetErr { F # NetErr NetTimeout }\n            } {}\n        } {\n            ^ @ !( Vec u ) NetErr { F ( _net_err_of ek ) }\n        }\n    }\n    ^ @ !( Vec u ) NetErr { F # NetErr NetOther }\n}\n\n// Non-blocking write-all. Loops issuing send(2) until the full Vec\n// is delivered, parking on wait_writable when the kernel returns\n// EAGAIN.\n@ tcp_write_all_async TcpConn c ( Vec u ) bytes → !v NetErr {\n    : s rp # s . ( __tci c ) raw\n    : i raw # i rp\n    : *u p ( vec_data [u] bytes )\n    ^ ( __tcp_write_pair_async raw # s p ( vec_len [u] bytes ) # s 0 0 )\n}\n\n// The non-blocking twin of __tcp_write_pair_sync: same pair-of-segments\n// contract, parking the fiber on the reactor instead of blocking in the\n// kernel when the socket would block.\n@ __tcp_write_pair_async i raw s p1 i n1 s p2 i n2 → !v NetErr {\n    ( nurl_tcp_set_nonblock raw 1 )\n    : i fd ( nurl_tcp_get_fd raw )\n    : i total + n1 n2\n    ? <= total 0 { ^ @ !v NetErr { T 0 } } {}\n    : ~ i sent 0\n    // A timeout ends this write even after partial progress. The caller\n    // must retire the connection rather than reuse a truncated frame.\n    ~ < sent total {\n        : ~ s a p1\n        : ~ i an - n1 sent\n        : ~ i bn n2\n        ? < sent n1 { = a # s + # i p1 sent } {\n            = a # s + # i p2 - sent n1\n            = an - total sent\n            = bn 0\n        }\n        : i n ( nurl_tcp_write2 raw a an p2 bn )\n        ? > n 0 {\n            = sent + sent n\n        } {\n            : i error ( nurl_tcp_err_kind raw )\n            ? & < n 0 != error 7 { ^ @ !v NetErr { F ( _net_err_of error ) } } {}\n            : i remaining ( nurl_tcp_write_wait_ms raw )\n            ? == remaining 0 { ^ @ !v NetErr { F NetTimeout } } {}\n            : i ready ( nurl_reactor_wait_write fd remaining )\n            ? <= ready 0 { ^ @ !v NetErr { F NetTimeout } } {}\n        }\n    }\n    ^ @ !v NetErr { T 0 }\n}\n","bytes":75633}