• src/sbbs3/js_socket.cpp

    From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Sunday, October 25, 2026 13:37:51
    https://gitlab.synchro.net/main/sbbs/-/commit/6a90215fb1d8b41969c854f6
    Modified Files:
    src/sbbs3/js_socket.cpp
    Log Message:
    js: restore the socket's blocking mode after an asynchronous connect

    The connect thread restored the caller's nonblocking setting by passing
    the address of the one-byte bool in its argument block to ioctlsocket()
    as a ulong. The read took in the padding and the port field behind it,
    so the value was nonzero for any nonzero port and the socket was always
    left nonblocking, whatever mode the script had set. A Socket.connect()
    with a callback on a blocking socket therefore returned a nonblocking
    one: send() of more than the kernel would buffer failed with EWOULDBLOCK instead of waiting.

    Copy the flag into a ulong first. Dates from 1928973941 (2021-04-02).

    Co-Authored-By: Claude Fable 5.1 <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 Sunday, October 25, 2026 16:13:09
    https://gitlab.synchro.net/main/sbbs/-/commit/dd03edda573f914bc975282e
    Modified Files:
    src/sbbs3/js_socket.cpp
    Log Message:
    js: route every FIONBIO ioctl through one helper

    Five sites passed the address of private_t's BOOL nonblocking field to ioctlsocket() through a (ulong*) cast. That is correct only while the
    field stays four bytes wide; the connect-thread copy of the same field
    was converted to bool in 118984e9af (2024-01-19) and broke exactly this
    way, fixed in 6a90215fb1 (2026-10-25).

    Add set_socket_nonblocking(), which copies the flag into a local and
    passes that, so the pointer type is compiler-checked and the field's
    width no longer matters. The local is u_long on Windows and int
    elsewhere, the width each platform's FIONBIO consumer actually reads.
    The ulong locals used until now are 8 bytes on LP64 and only worked on little-endian targets.

    Use the helper for all nine FIONBIO calls in the file, dropping three single-use locals. The TLS session setup also set TCP_NODELAY via a
    ulong; use an int there, as elsewhere since 77d90bedea (2026-05-05).

    Co-Authored-By: Claude Fable 5.1 <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, November 05, 2026 18:23:16
    https://gitlab.synchro.net/main/sbbs/-/commit/bd00cf5e2a27ffefdc428180
    Modified Files:
    src/sbbs3/js_socket.cpp
    Log Message:
    Address Coverity CID 661670

    js_socket_finish_connect(): stop collecting the asynchronous connect
    result if recv() reports more than was requested, which bounds
    sizeof result - received for the analyzer. recv() never returns more
    than the length it is given, so behavior is unchanged; a short result
    still reports ECONNABORTED. The function was added in 55431cba50
    (ever-6-ears, 2026-11-04).

    Same change as made to finduserstr_ex() for CID 661303 in 90e345693a (hired-20-raid, 2026-10-29).

    Co-Authored-By: Claude Fable 5.1 <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, November 05, 2026 18:23:16
    https://gitlab.synchro.net/main/sbbs/-/commit/814800d565783450d5495c6d
    Modified Files:
    src/sbbs3/js_socket.cpp
    Log Message:
    js: don't leave a freed private on a socket whose constructor failed

    The Socket, ConnectedSocket and ListeningSocket constructors each free
    their private data and return failure when js_DefineSocketOptionsArray()
    fails, but by then JS_SetPrivate() has attached that data to the new
    object. The object's finalizer later ran do_js_close() on the freed
    memory and freed it a second time.

    Clear the object's private pointer before freeing, so the finalizer
    finds nothing to do.

    The path needs an allocation failure to reach, so there is no test in
    the suite. Checked by forcing js_DefineSocketOptionsArray() to fail in a scratch build: before, each constructor's failure ended in a double free
    or segfault at the next garbage collection; after, each throws and the collection is clean.

    Co-Authored-By: Claude Fable 5.1 <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 Wednesday, November 11, 2026 21:04:16
    https://gitlab.synchro.net/main/sbbs/-/commit/93eb019585c9d4389322f2fe
    Modified Files:
    src/sbbs3/js_socket.cpp
    Log Message:
    js: don't freeze closing a non-blocking TLS socket

    Ending a cryptlib TLS session sends a close alert with a write timeout of
    at least 5 seconds, then waits for the peer to acknowledge it. On a non-blocking socket (e.g. an ircd client or server link) that stalled the
    whole event loop for 5 seconds per close, and longer when the peer's
    receive window was full. Now a non-blocking socket sends the alert only
    when it can go at once, behind no partly-written record (which the peer
    would see as a corrupt record), and shuts down the read side so cryptlib doesn't wait for the reply. A receive error shuts down both directions
    first. The errno is preserved across the session teardown.

    do_CryptFlush() kept the unflushed count after a permanent error, so a
    socket whose peer had reset kept polling as writable with pending output
    (about 96,000 wasted retries in a test). Only a timeout leaves anything
    that can still be sent, so the count is now cleared for any other error.
    This follows 38c93be5ba (logical-13-face, 2026-11-11).

    js_socket_recv() reported a failed pop with the return value (-1) instead
    of the cryptlib status, logging "Bad argument, parameter 1" for every
    receive error since 472692f792c (bullet-14-flesh, 2018-03-15). A normal
    peer disconnect is now logged at debug level as other read errors are.

    Tested on GCC/Linux only, against a TLS peer that stalls, resets, sends
    a corrupt record, or leaves a full window at close.

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

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