// POSIX socket module (macOS only) // sockaddr_in layout, errno symbol, and constants are platform-specific; // per-OS selection is PLAN-HTTPZ C3. libc :: #library "c"; // POSIX socket API socket :: (domain: i32, kind: i32, protocol: i32) -> i32 extern libc; setsockopt :: (fd: i32, level: i32, optname: i32, optval: *i32, optlen: u32) -> i32 extern libc; bind :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 extern libc; listen :: (fd: i32, backlog: i32) -> i32 extern libc; accept :: (fd: i32, addr: *SockAddr, addrlen: *u32) -> i32 extern libc; connect :: (fd: i32, addr: *SockAddr, addrlen: u32) -> i32 extern libc; read :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; write :: (fd: i32, buf: [*]u8, count: usize) -> isize extern libc; close :: (fd: i32) -> i32 extern libc; shutdown :: (fd: i32, how: i32) -> i32 extern libc; socketpair :: (domain: i32, kind: i32, protocol: i32, fds: *i32) -> i32 extern libc; fcntl :: (fd: i32, cmd: i32, ..args: []i32) -> i32 extern libc; // Constants (macOS) AF_UNIX :i32: 1; AF_INET :i32: 2; SOCK_STREAM :i32: 1; SOL_SOCKET :i32: 0xFFFF; SO_REUSEADDR :i32: 0x4; SHUT_RD :i32: 0; SHUT_WR :i32: 1; SHUT_RDWR :i32: 2; // macOS sockaddr_in (16 bytes, has sin_len field) SockAddr :: struct { sin_len: u8; sin_family: u8; sin_port: u16; sin_addr: u32 = 0; sin_zero: u64 = 0; } htons :: (port: i64) -> u16 { cast(u16) (((port & 0xFF) << 8) | ((port >> 8) & 0xFF)) } // ── nonblocking I/O (PLAN-HTTPZ S2) ────────────────────────────────── // Typed wrappers over the readiness-loop syscall patterns: callers see // WouldBlock / Closed / Fault, never a raw -1/errno pair. EINTR is // retried internally — a readiness loop has nothing useful to do with // an interrupted syscall except issue it again. // errno resolves to a real function under the C macro: `__error` on // darwin, `__errno_location` on linux (C3 selects per-OS). errno_slot :: () -> *i32 extern libc "__error"; // fcntl file-status flags + errno values (macOS). F_GETFL :i32: 3; F_SETFL :i32: 4; O_NONBLOCK :i32: 4; EINTR :i32: 4; EPIPE :i32: 32; EAGAIN :i32: 35; // == EWOULDBLOCK on darwin (and linux's 11 == its EWOULDBLOCK) EINPROGRESS :i32: 36; ECONNABORTED :i32: 53; ECONNRESET :i32: 54; errno :: () -> i32 { return errno_slot().*; } is_wouldblock :: (e: i32) -> bool { return e == EAGAIN; } // Put `fd` in nonblocking mode (reads/writes/accepts return EAGAIN // instead of parking the thread). False when fcntl refuses. set_nonblocking :: (fd: i32) -> bool { flags := fcntl(fd, F_GETFL); if flags < 0 { return false; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK) >= 0; } // Failure classes for the _nb wrappers. // WouldBlock — no data/space/pending connection right now; wait for // readiness and retry. // Closed — the peer is gone: EOF on read, EPIPE/ECONNRESET on // write, ECONNRESET on read. // Fault — any other errno (caller treats the fd as broken). SockErr :: error { WouldBlock, Closed, Fault, } // Accept one pending connection on a nonblocking listener. A connection // that died between queueing and accept (ECONNABORTED) is skipped, not // surfaced — the listener is fine. accept_nb :: (fd: i32) -> (i32, !SockErr) { while true { c := accept(fd, null, null); if c >= 0 { return c; } e := errno(); if e == EINTR or e == ECONNABORTED { continue; } if is_wouldblock(e) { raise error.WouldBlock; } raise error.Fault; } raise error.Fault; } // Read up to `cap` bytes. Returns the byte count (> 0); an orderly EOF // or a peer reset is Closed. read_nb :: (fd: i32, buf: [*]u8, cap: usize) -> (i64, !SockErr) { while true { n := read(fd, buf, cap); if n > 0 { return xx n; } if n == 0 { raise error.Closed; } e := errno(); if e == EINTR { continue; } if is_wouldblock(e) { raise error.WouldBlock; } if e == ECONNRESET { raise error.Closed; } raise error.Fault; } raise error.Fault; } // Write up to `len` bytes, returning how many the kernel took (possibly // fewer — the caller continues from there on the next writability). write_nb :: (fd: i32, buf: [*]u8, len: usize) -> (i64, !SockErr) { while true { n := write(fd, buf, len); if n >= 0 { return xx n; } e := errno(); if e == EINTR { continue; } if is_wouldblock(e) { raise error.WouldBlock; } if e == EPIPE or e == ECONNRESET { raise error.Closed; } raise error.Fault; } raise error.Fault; }