• src/sbbs3/main.cpp

    From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Mon Jan 20 20:37:00 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/3bf096b52465792776df3787
    Modified Files:
    src/sbbs3/main.cpp
    Log Message:
    Make JS global alert() and deny() methods inline with jsexec versions

    alert() doesn't throw exception on null/undefined, just no arg

    deny() throws exception on no args or null/undefined arg
    --- SBBSecho 3.23-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 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)