• src/ssh/design-channel-io-api.md

    From Deucе@1:103/705 to Git commit to main/sbbs/master on Sat Mar 28 16:46:56 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d5a9dd33ac68c0f3fd88906d
    Modified Files:
    src/ssh/design-channel-io-api.md
    Log Message:
    Revise channel I/O design: two models, deferred window, linear accumulation

    Replace unified read/write proposal with two distinct I/O models:
    - Stream API (dssh_channel_read/write) for session channels (shell/exec)
    - Zero-copy callback for subsystem channels (sftp, etc.)

    Key design decisions:
    - Max packet size per-session (set once, used in all channel opens)
    - Max window size per-channel (deferred to channel request/accept)
    - Channel accept as finalization point (server callback, client function)
    - Linear accumulation buffer for subsystem callbacks (no ring, no wrap)
    - Flow control via natural window exhaustion during accumulation

    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Deucе@1:103/705 to Git commit to main/sbbs/master on Sun Mar 29 10:21:44 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/4150f7036a5e39b78802cb29
    Modified Files:
    src/ssh/design-channel-io-api.md
    Log Message:
    Channel I/O design: ZC/stream split, locking, events, params builder

    Squash of design iteration commits into one coherent update.

    - dssh_chan_ prefix; zero-copy API uses dssh_chan_zc_
    - Stream API (open/read/write/poll) built on ZC internals
    - ZC API (zc_open/zc_getbuf/zc_send/zc_cancel): zero-copy TX
    (app writes directly into tx_packet) and RX (callback gets
    pointer into rx_packet). Zero mallocs, zero copies both directions.
    - All functions except open take dssh_channel only (channel carries
    session). No mismatched sess/ch pairs.
    - Stream parameter (0=stdout, 1=stderr) replaces _ext variants
    - Channel type as enum in params struct, not separate open functions
    - Params builder: init/set_*/free, all strings copied in. Type,
    max_window, pty (orthogonal to type), modes, env all in struct.
    Zero terminal modes by default (library can't know terminal state).
    Consumed at open time, library keeps no references.
    - Events separate from data (signalfd model). poll(DSSH_POLL_EVENT)
    + read_event(), or event callback with full event struct.
    Poll freezes positions; one event per cycle; uncollected discarded.
    - dssh_chan_close(ch, int64_t exit_code): negative = no exit-status.
    Preserves full uint32 wire range.
    - dssh_chan_shutwr(ch): half-close (EOF), shutdown(SHUT_WR) semantics
    - TX locking: zc_getbuf acquires tx_mtx, zc_send releases. App must
    not block between them. tx_mac_scratch eliminated via 4-byte seq
    prefix in tx_packet.
    - RX locking: ZC callback runs with no library mutex. remote_window
    and state flags are atomic.
    - RX callback cannot TX (deadlock: rekey needs demux thread).
    Enforced via _Thread_local bool in_zc_rx.
    - Callback protection: cb_mtx per channel. Session-level defaults
    copied to channel at creation time (no open-time race).
    - Stream built on ZC: internal zc_cb copies to ring buffer; public
    ZC functions validate, internal versions skip checks.
    - No void returns for fallible functions; infallible ops (free) void.

    Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)