• src/sbbs3/sexyz.c

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, February 20, 2025 20:29:35
    https://gitlab.synchro.net/main/sbbs/-/commit/c5b1b4b5c65f56b4bc3da536
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Bug fix for multi-file zmodem-send using wildcards

    If the first specified file in the list had a wildcard pattern, multiple ZRQINIT (request init) frames would be sent (one for each file matching
    the first list item file pattern).

    This was just found via code review, not in the wild.

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Friday, September 26, 2025 14:17:14
    https://gitlab.synchro.net/main/sbbs/-/commit/6bc626bedf028105f520ad56
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Increment version to 3.1

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Friday, September 26, 2025 18:16:24
    https://gitlab.synchro.net/main/sbbs/-/commit/70a445decf8a4c69f1ac0c65
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Sanitize the stdio-path of sendbuf()

    Fix what appear to be bugs in the mix-up of the global 'sock', the 's' argument, and FILENO_STDIN versus FILENO_STDOUT.

    This seemed to work anyway since stdout was blocking (would never return EAGAIN/EWOULDBLOCK).

    Just wanted to clean this up before pollifying (related to issue #445).

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Friday, September 26, 2025 19:38:47
    https://gitlab.synchro.net/main/sbbs/-/commit/fa6202f2a587411b40d3a94d
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Implement poll (rather than select) support when PREFER_POLL defined

    Attempt to fix issue #445

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/master on Friday, October 24, 2025 22:27:59
    https://gitlab.synchro.net/main/sbbs/-/commit/929fc7cde612b44a7dbb9489
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Fix error on systems where poll() is preferred (ie: *nix)

    Broken in fa6202f2a58, after poll() indicates there is data to
    read, recv_buffer() would return a timeout rather than set the
    timeout to zero and retry the recv().

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Thursday, January 08, 2026 03:55:52
    https://gitlab.synchro.net/main/sbbs/-/commit/231233096fde3a7595afcf69
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Remove glob() usage

    If we really need to expand wildcards in specified transmit path/filenames
    (do we?), there's better ways to do it.

    Increment version to 3.2

    Fix issue #1044

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/1672d1f70b2d5f2f14c794c4
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    sexyz: batch ZMODEM output into the ring buffer to fix send throughput

    The transmit path fed the output ring buffer one byte at a time via send_byte(), so the protocol thread and the draining output_thread
    ping-ponged over tiny amounts: a 32 MB send made ~2.3 million futex calls
    and ~409 K writes averaging ~84 bytes. lrzsz and SyncTERM, which buffer
    their output, ran several times faster over the same protocol.

    Accumulate escaped output in a per-session buffer and push it into the
    ring one subpacket-sized span at a time (on the zmodem flush callback, or
    when the buffer fills). The output_thread and its asynchronous socket
    draining are kept intact: that asynchrony is what lets the protocol thread service ZRPOS on the back-channel during error recovery, so removing the
    thread (measured) stalled lossy transfers.

    Results, sending to lrz over a localhost socket:
    - 32 MB send: ~2.3 M -> ~12 K futex calls, ~409 K -> ~4 K writes (~8 KB ea)
    - 256 MB steady-state send: ~11 -> ~66 MB/s
    - error-recovery time under injected bit errors: unchanged (~50 s)
    - receiver throughput: unchanged (~130 MB/s)

    The remaining gap to lrzsz (~204 MB/s) is zmodem.c's per-byte send_byte-callback overhead, addressed separately.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thursday, July 23, 2026 23:03:46
    https://gitlab.synchro.net/main/sbbs/-/commit/da546fbe1bd20ff1754e49b6
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Revert "sexyz: batch ZMODEM output into the ring buffer to fix send throughput"

    This reverts commit 4e671c75640ccf8248ea9b3822df2d0a08f4f6c9.

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Friday, July 24, 2026 23:28:15
    https://gitlab.synchro.net/main/sbbs/-/commit/34af5f34b57436e1430bdf80
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    sexyz: buffer the ZMODEM streaming send path (#1195)

    The send bottleneck was never the two output threads or the ring -- it
    was feeding the ring one byte at a time. send_byte() took the ring mutex
    twice per byte while output_thread hot-looped on it, so a 256 MB send
    cost 44 CPU-seconds and 1.46 million voluntary context switches and
    topped out near 11 MB/s on localhost.

    Accumulate bytes into a 4 KB buffer and hand whole spans to the ring
    instead. The two-thread architecture, flow control and error handling
    are all unchanged; the producer just stops trickling. A 256 MB send now
    runs at ~115 MB/s using 0.85 CPU-seconds and 64 K context switches -- the
    same throughput a single-threaded rewrite would give, for a fraction of
    the change and none of the risk.

    Buffering only applies to full ZMODEM streaming. A transmit window or segmented mode (-w, -s) depends on the receiver's acks flowing back as
    data is sent; bursty buffered output would fill the window before any ack returns and stall the transfer, so those modes fall through to the
    original byte-at-a-time path and are byte-for-byte unchanged.

    A fast streaming sender also fills the socket's auto-tuned, possibly multi-megabyte send buffer, so a single line error would cost a ZRPOS retransmission of everything in flight and break error recovery. Bound SO_SNDBUF to the ring size to cap the in-flight backlog (streaming only --
    a window already bounds it, and a socket buffer smaller than the window
    would fight it). This is applied outside the stdio guard so it takes
    effect for a piped socket as well, and [sockopts] can override it for a
    high bandwidth-delay link.

    Verified against lrz over the bench harness: 256 MB streaming MATCH at
    ~115 MB/s; the 3x error-injection gate passes 5/5; windowed (-w8192
    through -w65536), segmented (-s) and the receive path are unchanged from before; an 8 MB transfer over a 25 ms link matches the byte-at-a-time
    sender (both link-bound). No zmodem.c change, so SyncTERM is untouched
    (and it already has a buffered send path of its own).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Monday, August 24, 2026 20:32:03
    https://gitlab.synchro.net/main/sbbs/-/commit/b0455509ae102252c4b5f605
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    sexyz: supply the bulk receive callback

    recv_byte() already hands out bytes from a 64 KB inbuf, so a span fetch is
    the same loop without the per-byte call: copy while the engine's table says
    the byte is plain, stop before the one that is not. A 256 MiB localhost receive goes from 113.4 to 280.3 MB/s and from 2.36 to 0.67 CPU-seconds,
    which is level with zmtx/zmrx 2.02 and above lrz's 208.7 at 1.28.

    The span path stays disabled in telnet mode, where the IAC state machine in recv_byte() has to inspect every byte. It is off by default anyway for a
    stdio session, which is how the BBS invokes sexyz for rlogin, SSH and raw connections.

    Version to 3.6 for the zmodem.c 2.7 receive work; the startup banner prints only sexyz's own revision, so it has to move to keep a build identifiable without "sexyz v".

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net