• src/sbbs3/main.cpp

    From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sun Feb 9 00:09:24 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/64352121b6727a90eee5e848
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Don't attempt to remove inbound QWK packet if doesn't exist (renamed?)

    Address error report by Greg Meckel (THEICECA)
    evnt QNET !ERROR 2 (No such file or directory) (EinError 2) in main.cpp line 3195 (event_thread) removing "C:\sbbs\data\VERT.qwk" access=0

    ... this could happen after a bad QWK packet was detected and renamed.
    --- SBBSecho 3.23-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on ChromeOS)@1:103/705 to Git commit to main/sbbs/master on Sun Mar 23 18:11:52 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/6a0971f6e79ec18c2ed611dc
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    filelength() can return -1 on error, deal

    Just caught during code review
    --- SBBSecho 3.24-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on ChromeOS)@1:103/705 to Git commit to main/sbbs/master on Sun Mar 23 18:11:54 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/0ac5ed5728c53d93eb347c23
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Set node "interrupt" flag to try to gracefully disconnect user blocking event

    When a timed event is configured to run "exclusively", all nodes need to not be in in-use. As it was, after waiting 60 minutes for the online user(s) to
    notice they'd run out of time and disconnect, we'd just (rather ungracefully) close the sockets used by such node(s) connections. This results in same logged errors about trying to send to bad socket descriptors and provides no feedback to the user about why they were disconnected.

    Since we have the node interrupt flag (which hopefully, all scripts are checking via node_sync) - use that to try to more gracefully terminate the user's session/connection after 30 minutes of waiting for the user to disconnect.

    If after 60 minutes of waiting, the node is still in-use, we still do the socket disconnection method.
    --- SBBSecho 3.24-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Deucе@1:103/705 to Git commit to main/sbbs/master on Thu Apr 10 14:57:08 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/aea882a8e4552b64c03c521d
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Initialize Terminal in global sbbs when answering

    Should fix issue where extra pauses occur on connection.
    --- SBBSecho 3.24-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Deucе@1:103/705 to Git commit to main/sbbs/master on Thu Apr 10 14:58:16 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/f218ad1fec992a71f590120e
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Fix typo (thrad->thread)
    --- SBBSecho 3.24-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Wed Jul 2 16:07:06 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/3073a9a3503a3961912a54c2
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Add and improve log messages (warnings, errors) in input_thread()

    ... mainly to help understand (still a mystery) how the first check of
    the inbuf free space could pass (there's at least one byte available), but
    the second check (after recv()) fail and the "INPUT BUFFER FULL" message gets logged - that doesn't seem possible unless there's some other thread stuffing chars into the inbuf (and that shouldn't be happening with the exception of node spying).

    While investigating this mystery, I saw there missing node numbers and other helpful data (e.g. the number of bytes received to that point) from some of
    the log messages. And in some SSH error conditions, nothing would be logged though the input_thread's loop would terminate (break), so added some log messages for "Operation complete" and "Timeout" which had explicit handlers with no log output.

    Increase the received byte counter from 32 to 64-bits.

    Stop using the 'rd' varible for multiple purposes, improving readability.
    --- SBBSecho 3.28-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on ChromeOS)@1:103/705 to Git commit to main/sbbs/master on Sat Aug 30 21:23:54 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/3a2790c7d3e538cd27404feb
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Immediately abort the event_thread() if started with server terminated

    Resolve this crash that happens when aborting startup while trying to bind
    TCP ports:

    Thread 11 "sbbs/events" received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 0x7ffff1dfc6c0 (LWP 13543)]
    js::gc::Chunk::init (this=0x7fffeb600000, rt=0x7fffe0019120) at jsgc.cpp:293 293 arena->header()->next = arena + 1;
    (gdb) bt

    Not root-caused, just worked-around/avoided. Most likely there's a js cleanup happening (e.g. destroying the JS runtime) the same time that js_init() is executing from the event_thread(), so just avoid this by not calling js_init() while already set to terminate the server.
    --- SBBSecho 3.29-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sun Sep 28 01:57:30 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/b7d3db6c3e57e75f3ee36569
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Revert write_raw() back to direct, unprocessed, output

    deon (ALTERANT) reported an issue with his Viewdata terminal support after upgrading from v3.19 to the latest code in git. He's using JS write_raw() to send viewdata sequences to the remote terminal.

    I'm not sure why Deuce changed write_raw() from calling putcom(), but let's try reverting back to using putcom() to see if that resolves the reported issue
    and whatever objection Deuce may have.
    --- SBBSecho 3.29-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Wed Dec 31 01:48:10 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/70480dcee4378c21be0ca536
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Add some passthru thread debug log messages

    To hopefully help identify the cause of issue #1038

    The theory being that the client socket was disconnected while running an external program (sexyz in this case) and this check at the end of external() (the *nix version) might have a race condition with the passthru thread terminating due to disconnection as well:
    if (!(mode & EX_STDIN)) {
    if (passthru_thread_running)
    passthru_socket_activate(false);
    else
    pthread_mutex_unlock(&input_thread_mutex);
    }
    in which case it would try to unlock the input_thread_mutex that it did not own. I'm not clear why that would cause the pthread_mutex_destroy() call to fail (on input_thread_mutex) but maybe it does.
    --- SBBSecho 3.34-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Thu Jan 1 22:32:06 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/7e7db957384647c44958d0cb
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    When upgrading a legacy time.dab to new time.ini format, ignore unreadables

    It's possible the configuration was upgraded (e.g. by update.js) before any timed events have run, so the time.dab could be short. Just zero-initialize (and don't log any errors) if there's trouble reading a legacy timestamp from time.dab or qnet.dab.
    --- SBBSecho 3.34-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sun Jan 11 03:40:04 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/f21adb001964358bc95c1e28
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Defeat the extra lines goings to the events.log file

    Example:
    2026-01-06 23:59:59 BBS Events New Day - Prev: Wed Jan 07 2026 12:00 am
    != New Day - Prev: Wed Jan 07 2026 12:00 am

    In theory this cold happen while a user was logging on, hence the use of llprintf()->logline(), but we don't want that redundant noise in the
    events.log file so we have to play a dance with 'online' value.
    --- SBBSecho 3.34-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Tue Jan 20 21:00:06 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/7e8760ce6ef8c60051202ef0
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Don't backup empty user bases or mail bases

    Address "it seems silly to have five backup empty mail files too" comment
    in issue #993.
    --- SBBSecho 3.35-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Tue Jan 20 22:53:22 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/674c4facfbfcd5855915ade5
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Fix (new) bug caught by GCC printf verifier
    --- SBBSecho 3.35-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Wed Jan 21 00:39:42 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/b9e11d2fd2a13154b382f5a0
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Fix accidental recursion in sbbs_t::backup()

    Bug introduced in commit 39e1c58ad631baea289349eb02
    --- SBBSecho 3.35-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Tue Jan 27 11:30:04 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/372404c4f6491a962cbd9471
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Don't try to validate the userbase if it doesn't exist

    Fix for new installs as reported by Storm on IRC (thank you)
    --- SBBSecho 3.35-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Fri Feb 13 00:34:20 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/a401004cd4401616a2a2312f
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Remove debug log line inadvertently left in
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sat Mar 7 19:47:06 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/8b6210dcaf2e3b49ed16f110
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Destroy the nodefile_mutex in sbbs_t destructor

    This could've been a small memory leak

    Also using [F]CLOSE_OPEN_FILE function-like macros to simplify code
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sun Mar 8 01:36:50 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/819d26b6c593606c3e2e2497
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Simplify/correct the node status fixup upon client connect

    - when we treat a non-WFC node status the same as WFC because the node_socket
    is invalid, don't call lprintf(LOG_CRIT, ...) with the node logged. That's
    ultimately going to call errormsg() which is going to try to increment the
    node's critical error counter and fail or deadlock because the node's
    record is already locked. Log the error after we call putnodedat() and the
    node record has been unlocked.
    - The "status is WFC" while the node_socket is valid check would always fail
    because we already checked the node_socket validity at the top of the loop
    so just remove this check/error message as dead code
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sun Mar 8 01:52:44 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/80137a5129d974935681c478
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Log the corrected node status value (error caught be GCC printf-validation)
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sun Mar 8 03:41:52 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/5c099d90d119dd447133160b
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Replace break accidentally removed in previous commit

    Would mark all nodes as at the prompt up new connection (big whoops)
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Mon Mar 9 17:01:48 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/783473d285db5e03b445a9fb
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Correct node status stuck in "logout" status too (abnormal condition)

    "LOGOUT" is another node status where the socket should be valid

    Since my Debian 13 (and Samba) upgrade, I've been getting a lot of node.dab
    and mail base corruption. Some of these conditions can be auto-corrected and this is one of them.

    Removed some obsolete comments about old crash reports.
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Wed Mar 11 02:35:18 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/43328cad606fde38aec86eea
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Fix potential socket leak upon server termination

    caught/reported by Claude via Deuce
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Wed Mar 11 15:36:28 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/6e49cb9c959c7e1710a1ac09
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Coverity complained about this unnecessary invalidation of client_socket here

    CID 644869
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Mon Mar 16 22:50:16 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/b598dcbb541ca8ddf8a083d8
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Insure all alert() output begins in the first (left-most) column
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sat May 2 18:58:14 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/ff1aae498b3464b1f2fd050a
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    sbbs3 terminal server: drop unsent goodbye output before close_socket

    In the four listener exit paths that queue output via the listener
    pseudo-sbbs (CLIENT BLOCKED for ip.can / host.can, "no nodes
    available", node init failure), call sbbs->rioctl(IOFB) right after flush_output() and before close_socket(). Without this, any
    text/badip.msg / badhost.msg / nonodes.txt residue that didn't make
    it out within the flush timeout sits in the ring buffer; when the
    output thread next wakes it tries to send the leftover on the
    now-closed FD, and the failed send logs a noisy warning (e.g.
    "!ERROR 22 (...)" or "!ERROR 58 (...)" sending on socket).

    This is the same idiom as the existing rioctl(IOFB) at the start of
    the per-connection setup (main.cpp:5795) — purge stale buffer state
    before changing socket lifecycle.

    It does not eliminate the race entirely: data already pulled from
    the ring buffer into the output thread's linear buffer is still sent
    (or attempted), since rioctl operates on the ring buffer only. The
    remaining noise is handled separately by demoting the typical
    post-shutdown send errors (ESHUTDOWN, EINVAL) to LOG_NOTICE.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Tue May 5 15:55:24 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/88889e94e52406ca3ff0b721
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    node_thread: avoid throttle-loop hang on loginAttempts() failure (CID 645970)

    loginAttempts() returns long and is documented to return a negative
    value on failure, but the result was stored in a uint. On -1 the value
    became UINT_MAX, passed the (> 1) check, and the throttle loop would
    run ~4 billion mswait() iterations. Match the signed return type and
    update the matching format specifier and loop counter.
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Wed May 6 19:41:52 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/ded9a017f3b2199433125aad
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    sbbs_t::lputs: guard event-thread log-level check against null startup (CID 543171)

    sbbs_t::lputs() consults startup->event_log_level when is_event_thread
    is set, but the surrounding callers (e.g. sbbs_t::js_create_user_objects) already treat startup as potentially-null. If any caller reaches an errprintf/lprintf path with startup == nullptr while is_event_thread is
    true, the deref would crash. Add the null check that the call sites
    already assume.

    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Wed May 6 22:36:56 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/d6d35429bd173a0284d8fc5a
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    main: cast cryptSetAttribute SSH_CHANNEL_ACTIVE deactivation to void (CID 487166)

    In crypt_pop_channel_data the inner cryptSetAttribute that flips the
    selected channel inactive is best-effort (we're tearing down anyway).
    Make the discarded return explicit.

    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Sun May 17 19:37:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/6fb53e92e2ffbe510d6c44a1
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    sbbs: reuse ip_can / ip_silent_can .fname instead of rebuilding the path

    The trashCan instances are already initialized at startup with the full
    path in .fname; just pick the one matching filter_silent. Matches the
    existing log at main.cpp:5850 which already uses ip_can.fname directly.

    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Mon Jul 6 00:00:16 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/39112546f2b835451e37289b
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Fix client-socket errors misreported as spy-socket errors on *nix (#1184)

    input_thread() identified which socket a failed/completed recv() belonged
    to by re-comparing 'sock' against the atomic sbbs->client_socket after the fact. Since sbbs_t::hangup() (and other cross-thread teardown) closes the client socket and stores INVALID_SOCKET to wake this thread, the identity re-check could fail for a socket that WAS the client socket, misrouting an ordinary disconnect into the *nix else-branch that assumes any non-client socket is the node's local spy socket. Result: routine (usually SSH)
    session teardowns were logged to error.log as, e.g.:

    Node 11 !ERROR 9 (Bad file descriptor) on local spy socket 179 receive

    where fd 179 was actually the node's passthru/client socket, never a spy connection -- sending the sysop hunting for spy-socket problems that don't exist. Observed four times since Jan-2025 on Vertrauen's Linux host,
    always coinciding with 'disconnecting client' teardown.

    Remember which socket was selected at poll time (new 'spy_sock' bool) and branch on that instead, at all four re-comparison sites: the SSH receive
    path, the receive-error handler, the EOF/'disconnected' check, and the skip-telnet-interpretation check. A post-hangup wake-up now routes to the client branch, which exits quietly via the existing !online check (hangup clears 'online' before closing the socket).

    Validated against a live scratch terminal server: client disconnect, spy connect/mirror/disconnect (clean 'Closing local spy socket' notice), and server-terminated-mid-session teardown -- no misattributed spy-socket
    errors logged. Closes issue #1184.

    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Mon Jul 6 00:00:16 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/8101584ded3352342328fcb6
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Terminal server: shutdown(), don't close(), node sockets at terminate/recycle

    At server termination/recycle, the terminal server thread force-
    disconnected active nodes by calling close_socket() on each node's client socket. But that descriptor is owned by the node thread: sbbs_t::hangup() closes it again during the node's own teardown (after its 1-second output- flush mswait), producing a double-close. On *nix that logged the (benign
    but alarming) shutdown-time noise:

    !ERROR 9 closing socket 11

    one second after 'Closing node N socket 11'; on Windows the same double-
    close was silent only because close_socket() exempts ENOTSOCK. Worse than
    the noise: between the two closes the fd number could be reused (a new
    inbound connection during recycle, an opened file) and hangup() would then close an unrelated descriptor out from under its new owner.

    Shut the socket down (SHUT_RDWR) instead of closing it: that wakes every blocked reader -- and unlike close(), propagates EOF through dup'd
    descriptors held by external programs -- while the fd number stays
    allocated until the owning node thread performs the one real close in
    hangup(). node_socket[] is still marked INVALID_SOCKET here, preserving
    the input_thread 'shutdown locally' signal that terminates JS execution promptly.

    Same fd-lifetime family as 39112546f2 (tables-20-ideas) / issue #1184. Validated against a live scratch terminal server: SIGTERM with an active
    client session now yields a clean 'Shutting down node 1 socket 11' ->
    'Node 1 disconnected' -> node-thread-terminated sequence with no EBADF
    errors logged.

    Co-Authored-By: Claude Fable 5 <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 Thu Jul 16 14:26:08 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/2154c2b9295e07c6cb38f551
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    sbbs: drain buffered SSH plaintext before polling

    Cryptlib can consume all pending encrypted socket input while
    returning only one SSH channel packet from cryptPopData(). The input
    thread then waited for the raw socket to become readable before
    calling it again, leaving plaintext buffered inside Cryptlib. Large unidirectional transfers could stop near EOF until reverse traffic
    woke the socket path, causing ZMODEM timeouts and retransmission.

    After each successful SSH pop, bypass the raw-socket poll and keep
    popping through the existing input path until Cryptlib returns zero
    bytes or an error. Normal polling resumes once its buffered plaintext
    has been drained.

    Co-Authored-By: OpenAI Codex <noreply@openai.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sun Jul 19 15:25:24 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/7853fb5c959aa15a946c9434
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Terminal server: flag nodes to re-read config on recycle signal

    When a recycle was signaled (ctrl/recycle semaphore, MQTT recycle topic, SIGHUP/systemctl reload, or a console recycle command), the terminal
    server only acted on it once every node was idle: the recycle detection
    was gated on node_threads_running == 0. Until then, new connections
    kept attaching with the old configuration, so on a busy board that never
    fully drains, hand-edited config changes could effectively never reach
    new logins.

    Detect the recycle request every iteration now, and when one is seen,
    set the NODE_RRUN flag on this instance's nodes (first_node..last_node)
    so each node re-reads its per-node configuration on its next connection
    -- the same mechanism SCFG's refresh_cfg() already uses. The full
    server recycle (which re-reads the master config and reinitializes the listening sockets) still waits until all nodes are idle, so this only
    adds immediate per-connection config propagation without changing when
    the server-level reinitialization happens.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Tue Jul 21 21:53:26 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/473e880ec144eb322ad4b5ec
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Terminal server: transmit the final output before hanging up

    sbbs_t::hangup() gave the output ring buffer a blind mswait(1000) and then
    tore the connection down, never confirming that the pending output had
    actually been sent. Over SSH the last output was lost every time -- most visibly the echoed command key of a fast log-off (/O), which produces no
    other output at all, so the user saw their keystroke simply vanish.

    Wait for the output to be transmitted instead, using WaitForOutbufDrained() (added in 9cf170c024, squad-4-memo, for issue #1157). WaitForOutbufEmpty() alone would not do: outbuf.empty_event fires when output_thread moves the
    ring buffer into its linear buffer, before the send, and the ssh_session_destroy() a few lines below then discards those still- untransmitted bytes. On telnet the equivalent window ends in sendsocket(), whose kernel buffer survives until close() -- hence the SSH-only symptom.

    The wait is performed while still online, so that flush_output()'s online short-circuit would not apply and input_thread keeps draining the receive
    queue meanwhile. It also turns the unconditional one-second sleep into a one-second ceiling, so an ordinary hang-up now completes as soon as the
    output has drained.

    Verified with three different SSH clients.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Tue Jul 21 23:33:58 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/454cc802610dcfa661db6178
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Terminal server: apply the 8KB SSH send clamp that was never wired up

    757e389522 (deputy-13-floating) limited cryptPushData() sends to 8KB in
    both the web and terminal servers, after the same limit fixed a problem
    in js_socket.c. The web server half took effect; the terminal server
    half never did. output_thread() computed sendbytes and clamped it, then
    called cryptPushData() with buftop - bufbot anyway, so the variable has
    been dead ever since. Because the clamp expression reads sendbytes, no compiler warns about it.

    Pass sendbytes to the push, as websrvr.cpp and sftp.cpp both already do.
    Where getsockopt(TCP_MAXSEG) succeeds this changes nothing -- mss then
    caps a linear-buffer read well below 8KB -- but where TCP_MAXSEG is
    unavailable mss stays IO_THREAD_BUF_SIZE (20000) and pushes of up to
    ~20KB were bypassing the intended limit.

    Hoist sendbytes to cover the whole send, so that it means "bytes offered
    to the transport this iteration" for the sendsocket() path as well, and
    key the short-send warning off it. Otherwise a clamped push would be
    reported as a short send every time. The error paths that discard the
    linear buffer ("pretend we sent it all") reset sendbytes to the full
    remainder first, preserving their existing behavior of dropping it in
    one go rather than in 8KB steps.

    No functional change on this host, where TCP_MAXSEG is available.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Thu Jul 23 23:03:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/bd9a08274766f7097074dad9
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    main: suppress output_thread INTEGER_OVERFLOW false positive (CID 651667)

    Coverity flagged the linear-buffer sends in output_thread() as passing a possibly-underflowed size to sendsocket(): sendbytes (buftop - bufbot) to
    the client-socket send, and i to the spy-socket send. Neither can wrap.
    The refill guard at the loop top keeps 0 <= bufbot < buftop wherever the subtraction runs, so sendbytes >= 1; and every error path resets i to a non-negative sendbytes before bufbot += i, so i is never negative where it feeds the spy send. The checker simply can't prove bufbot <= buftop across iterations.

    Annotate both sites with coverity[INTEGER_OVERFLOW:SUPPRESS] and the
    one-line invariant, matching the existing precedent in atcodes.cpp. No behavioral change.

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