• src/xpdev/multisock.c

    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/908bb2320b285cb91ad80c82
    Modified Files:
    src/xpdev/multisock.c
    Log Message:
    Fix missing socket fd argument in HAPROXY error log format string

    The lprintf call had format "%04d * HAPROXY Unable to parse %s
    address [%s]" with three specifiers but only two variadic arguments.
    The socket fd (ret) was missing, causing undefined behavior Ä %04d
    reads garbage from the stack and the string arguments shift.

    Co-Authored-By: Claude Opus 4.6 <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 7 15:55:33 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/0db85afb4cff6c0b9efbd74c
    Modified Files:
    src/xpdev/multisock.c
    Log Message:
    Set close-on-exec on listen sockets on POSIX (issue #1174)

    A fork()ed child inherits every open descriptor, and external() closes
    nothing but stdio and its pipes before execvp(), so every external program inherits each server's listening sockets. An external that outlives a server recycle then keeps those ports bound, and the rebind fails:

    mail !ERROR 98 binding SMTP Transfer Agent socket to port 25: Address
    already in use

    This is not merely a failed rebind, which would be self-announcing. The parent's own listen sockets are still open, so the kernel keeps completing handshakes into a backlog that no longer has an accept() behind it: clients connect and then wait forever for a protocol banner. It presents as a hung server.

    Mark the sockets close-on-exec where they are created, mirroring what the Windows half of xpms_add() has done since 6816ce611 (carries-19-baby, 2026-06-24). Doing it at creation, rather than closing descriptors in the child, is what covers
    externals already running when a recycle happens: their copies were made
    long before, and nothing done at recycle time can reach them.

    fcntl() rather than SOCK_CLOEXEC: macOS has no SOCK_CLOEXEC, and passing it
    to socket() on a kernel that predates support fails the call outright and
    would take the listener with it. That leaves a window between socket() and fcntl() in which a concurrent exec still inherits the descriptor, which is worth accepting for sockets created during server start-up and recycle.

    Accepted client sockets are left alone. They do not pin a listening port,
    and on POSIX the passthru listener a socket door talks over is created by open_socket() in main.cpp, not here, so it is unaffected either way.

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

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