diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-14 14:10:28 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-14 14:20:25 -0300 |
| commit | 5f24c4a2284a0af84fb9d116f7a39f6a58e42ae9 (patch) | |
| tree | 8679763439492361fe99ea01f5190e5204fa590c /docs/design.md | |
| download | cloud9-5f24c4a2284a0af84fb9d116f7a39f6a58e42ae9.tar.gz cloud9-5f24c4a2284a0af84fb9d116f7a39f6a58e42ae9.zip | |
Implement base 9P2000 sessions, shared transports, and conformance probes
Diffstat (limited to 'docs/design.md')
| -rw-r--r-- | docs/design.md | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..ed9a66e --- /dev/null +++ b/docs/design.md @@ -0,0 +1,73 @@ +# API and ownership + +The public entry point is `src/root.zig`. `Msg` covers every base request and +response, excluding the reserved, nonexistent Terror. Decode returns borrowed +strings/data. Encode checks complete output size before writing; input payloads +may already occupy their exact final position in the output frame, but arbitrary +input/output overlap is not supported. Stat uses the protocol's inner length; +Rstat and Twstat add and validate the outer length separately. + +`Client` supports 16 ordinary outstanding requests and one additional flush. +Replies can arrive out of order. Tags remain reserved while flushes are pending, +even when the original request has already completed. Multiple flushes and +flushing a flush are accounted for. A completed result's slices remain valid +until the next `take()` or `hangup()`. `push()` only appends and never compacts. +Submit copies request payloads into the output buffer. An iounit returned by an +open/create is per fid; the caller must apply it when selecting atomic I/O sizes. +`maxRead()` and `maxWrite()` describe frame limits, not that per-fid guarantee. +Renegotiation requires an empty client request window. + +`Server` supports 64 ordinary outstanding requests and one additional flush. +Receive errors terminate the connection. A full request table produces NoTags; +output backpressure instead returns null without consuming the next request. +`receive()` yields at most one frame. `release()` ends its borrow and advances +input. A backend retaining any request data must copy it before release. +A successful reply copies output and frees the request tag. An output-capacity +error leaves that tag pending so the backend can drain and retry. + +The server validates transaction structure, not filesystem policy. Backends +own fid maps, authentication state, file handles, access modes, complete directory +records, atomic wstat, and cancellations. They must retire canceled work before +reusing its tag; a tag alone cannot distinguish a stale backend completion from a +new request. A version event requires backend cancellation and fid cleanup before +`negotiate()`. A partially sent response drains before a new version is accepted. +An Rflush promises no later reply to oldtag. Replying Rerror to a flush is refused. + +Caller-provided input/output buffers must be disjoint and remain stable for the +session. No protocol API takes an allocator. Server and client request tables are +fixed-size. Copies and work per frame are bounded by buffer size and fixed table +capacities; transports and application backends can have their own allocations. + +# Transports + +`transport.readFrame` and `writeFrame` adapt `std.Io.Reader` and `std.Io.Writer`. +The writer remains buffered until its owner flushes it. Reader errors leave the +stream unsuitable for further frame processing; close the connection. + +`transport.connect` and `listen` use `std.Io.net` for TCP and Unix streams. The +POSIX `connectFd`, `listenFd`, `acceptFd`, `read`, `write`, and `wait` APIs fit +caller-owned poll loops. They configure nonblocking descriptors and close-on-exec; +read/write return null for retry, and read returns zero for EOF. `wait` takes an +absolute monotonic deadline. The application closes descriptors, limits its +connections, selects addresses and deadlines, and manages Unix path permissions +and removal. No mounting or namespace policy is performed. + +`Quic(OpenSSL, alpn)` is an optional OpenSSL 3.6+ adapter with a single ordered +bidirectional stream per connection. It preserves the previous Pardes transport: +ephemeral self-signed certificates, no peer authentication. Applications needing +identity verification must provide that policy before using it across a trust +boundary. OpenSSL allocations and handshake costs are outside the allocation-free +protocol core. Accepted connections must close before their shared listener. + +# Pardes integration + +Pardes consumes the sibling package through build.zig.zon. Its `src/9p.zig` now +adapts filesystem requests and retains editor/GPIO capacities and permissions. +`src/9p_io.zig` retains mounting, discovery, the editor's event-loop scheduling, +connection limits, and error presentation. Protocol bytes, session validation, +and TCP/Unix/QUIC transport implementation come from cloud9. Pardes selects the +existing `pardes-9p` ALPN for compatibility. + +The separate `05-zig-p4` firmware build adds cloud9 to the GPIO application's +module map. UART hardware access remains in the board firmware. No hardware was +flashed by this change. |
