• src/sbbs3/zmodem.c

    From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Fri Sep 26 14:17:14 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/1af0752917c8a7c0d331582d
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Handle rx'd hex headers terminated with "\x8D\x8A" (i.e. "\r\n" with parity)

    Although this sequence doesn't really make sense since there's an odd number
    of set bits in 0x0D and an even number of set bits in 0x0A, setting the
    parity flag in each byte is just wrong, this is how Tera Term 5.5.0 terminates its transmitted ZMODEM hex headers:

    ZShHdr() from Tera Term's zmodem.c:

    zv->PktOut[zv->PktOutCount] = 0x8D;
    zv->PktOutCount++;
    zv->PktOut[zv->PktOutCount] = 0x8A;
    zv->PktOutCount++;

    Although this code does appear "inspired" by Chuck's rz/sz source, they failed to duplicate this logic from Chuck's zshhdr() from zm.c (with added comments):

    s[len++]=015; // 0x0D
    s[len++]=0212; // 0x0A

    Chuck's zrhhdr() function handled this CR parity-oddity on the receive size (using octal constants as he did):

    switch ( c = READLINE_PF(1)) {
    case 0215: // 0x8D
    /* **** FALL THRU TO **** */
    case 015: // 0x0D
    /* Throw away possible cr/lf */
    READLINE_PF(1);
    break;
    }

    ... so we'll do so too for bug-compatibility with Chuck Forsberg (RIP) and
    T. Teranishi.

    This resolves issue #595

    Incremented version of this file to 2.1

    ---
    þ 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 Tue Dec 2 15:29:39 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/ab995dd1db4530b0f3bd90ab
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Fix parity inversion in comments

    Even parity means that the high bit is *set* (when necessary) to insure an
    even number of set bits in every sent byte. Odd parity is the opposite.
    I had this backwards in my comments.

    ---
    þ 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 Fri Mar 6 21:58:36 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/02f0ebb9bd66b1c1ad3873b5
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Add some more log messages to zmodem_get_zfin()

    to try to root cause 'OO' transmission issue (observed with Chuck Forsberg's rz).

    ---
    þ 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 Fri Mar 6 22:30:03 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a3b7cff7fa45e4e5fb7a185f
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Call zmodem_flush() after sending the 'OO' after a ZFIN

    Chuck's rz (readline) waits indefinitely for these two O's.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¨@VERT to Git commit to main/sbbs/master on Sun Mar 15 16:01:53 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/87b7d946c0ab40a5a20343ee
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Remove vestigial int32_t casts truncating file sizes in zmodem_recv_files()

    Three comparisons between l and bytes cast bytes to int32_t, silently truncating file sizes > 2GB. Both variables are int64_t Ä the casts
    were left over from the 887147a69c "64-bitify" conversion where
    long/ulong became int32_t/uint32_t before being later widened to
    int64_t.

    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

    ---
    þ 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 Sun Mar 15 16:24:40 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/c787342dc9ae4fd3005d224e
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Fix API violation in zmodem_recv_bin32_header()

    Introduced in commit 83b672364, Claude caught this:

    zmodem_recv_bin32_header() returns TRUE on error (zmodem.c:1200)
    When zmodem_rx() returns an error (c < 0) during CRC-32 header reception, the function returns TRUE (success) instead of FALSE. The subsequent CRC check will almost certainly catch this, but the function's contract is violated.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/master on Thu Jul 23 21:55:30 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a816b8cb21e49f495d818c4d
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Optimize ZMODEM transmit byte classification

    Replace the data-dependent switch in zmodem_tx() with a lookup table
    and session mask. This preserves the existing escaping behavior while
    reducing the per-byte CPU cost of ZMODEM uploads.

    Validate every byte and escape-mode combination against the previous classifier, and verify a real transfer byte-for-byte with lrz.

    Refs #1195

    Co-authored-by: OpenAI Codex <noreply@openai.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 Thu Jul 23 23:03:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/e15a36f6908c70ae351a15fc
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    zmodem: bump zmodem_ver to 2.3

    Reflects the 2 GiB windowed-transfer fix (widening the transmit-window /
    ACK file positions from signed int32_t to uint32_t; GitLab #1196), the one functional change to zmodem.c this cycle.

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

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/master on Thu Jul 23 23:32:44 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/06282ad2f21eec8f375a9bf3
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Inline the common ZMODEM transmit path

    Hoist the active escape mask out of the per-byte ZMODEM data loops
    and defer the conditional-CR last_sent check until a CR is actually encountered.

    Split error reporting and non-normal escaping into noinline cold
    helpers. This allows the compiler to inline the class-table lookup and
    raw send callback directly into the data loops while leaving uncommon
    work out of the hot path.

    Six interleaved 1 GiB uploads to lrz improved average throughput from
    44.251 MiB/s to 50.651 MiB/s, a 14.46 percent increase.

    Verify classification against the previous implementation for every
    byte, escape-mode combination, and preceding byte. Inspect the release
    output for inlining and run the SyncTERM test suite.

    Refs #1195

    Co-authored-by: OpenAI Codex <noreply@openai.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 Fri Jul 24 00:10:51 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a84e414a9ae4b712e2d55c54
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    Merge branch 'master' of gitlab.synchro.net:main/sbbs

    ---
    þ 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 Fri Aug 21 21:15:30 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/36c17d6b1e4c14b79b0c3ccd
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    zmodem: stop stalling a second before the data of every file sent

    zmodem_handle_zrpos() purged the receive buffer with a 1-second timeout.
    That purge sits on the sender's normal path (every file's first ZRPOS is
    just the routine answer to ZFILE), and with nothing to discard, the purge
    can only conclude the buffer is empty by letting the read time out. Each
    file transferred therefore cost a flat second of silence between its
    ZRPOS and its ZDATA, whatever the line speed.

    Pass the purge timeout in: 0 for that initial ZRPOS, where anything worth discarding has already arrived, and 1 for the mid-transfer ZRPOS that
    follows an error, where waiting briefly for the rest of the receiver's retransmit request is the point.

    Sending four files over a pipe took 4.01 seconds before and 0.006 after,
    to sexyz and to lrzsz's rz alike.

    The purge dates to 76d678710e (sheets-20-lone, 2020-11-28).

    Reported by Uwe Ohse, who found it comparing sexyz against lrzsz and
    zmtx/zmrx over a simulated 115200 bps line: 5.9 KB/s where the others
    managed 10.2 KB/s.

    Co-Authored-By: Claude Opus 5 (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 Fri Aug 21 22:09:19 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a8843ffb8b199017665b83fd
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    zmodem: don't retransmit the ZFILE at a receiver's opening ZRINIT

    A ZMODEM receiver announces itself with a ZRINIT unprompted, and the
    sender then sends a ZRQINIT of its own before the first file, drawing a
    second ZRINIT. That second one arrives after the ZFILE has already gone
    out, and the loop waiting for the ZFILE's answer accepted only ZACK, so a ZRINIT counted as a failed attempt and the whole ZFILE frame was sent
    again. The receiver answered both copies, leaving a second ZRPOS on the back-channel that the sender then read mid-stream and treated as a
    retransmit request, restarting the file from the beginning and taking two rounds of error recovery to settle. Sending four files to lrzsz cost a
    round trip, a duplicate frame and an error in the receiver's log every
    session; under load the stale ZRPOS cost seconds.

    Absorb one such ZRINIT per ZFILE attempt and keep waiting for the real
    answer instead, which is what lrzsz's sender does in the same spot. A
    second ZRINIT still retransmits, so a receiver that genuinely missed the
    ZFILE recovers as before.

    The stale ZRPOS was previously consumed by the 1-second receive-buffer
    purge removed in 36c17d6b1e (2026-08-21), which is why the cost was only
    the wasted round trip until now. Verified with the sender and receiver
    pinned to one CPU, which reproduced the restart in 2 runs of 3 before the change and 0 of 12 after; a 256 MiB send to lrzsz stays at 204 MB/s, and
    error recovery under injected bit-flips still completes byte-identical.

    Visible in a protocol dump sent by Uwe Ohse, who reported the purge stall.

    Co-Authored-By: Claude Opus 5 (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 Sun Aug 23 02:30:27 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/09ea8a69012ea2688447f28b
    Modified Files:
    src/sbbs3/zmodem.c
    Log Message:
    zmodem: report the receiver's file position instead of always zero

    Nearly every message in zmodem.c is prefixed with the current file offset,
    but zm->current_file_pos was assigned in exactly one place,
    zmodem_send_from(), so on the receiving side it kept the zero that zmodem_init() memset it to. A download therefore ended with
    "0 Finishing Session (Sending ZFIN)" printed directly beneath
    "8192 Received: ZEOF" -- the latter reads a local position from ftello(),
    which is why only some of the numbers looked wrong.

    Assign current_file_pos from that same ftello(), at the start of the file
    and after each received subpacket, so the two cannot disagree. With a
    download stalled after 236504064 bytes, the receiver's timeout message now names that offset rather than 0.

    Drop the prefix from the ZFIN message: it ends a session rather than a
    file, and has no offset to report in either direction. On the sending side
    it had been printing the last file's final position.

    zmodem_ver 2.5 -> 2.6.

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

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