https://gitlab.synchro.net/main/sbbs/-/commit/65fdf2d1c97cff5a11c77490
Modified Files:
src/syncterm/rlogin.c
Log Message:
SyncTERM: gate rlogin OOB consume on recv()==0 + exceptfds
The previous SIOCATMARK gate doesn't survive Win32: per dotnet/runtime
issue #24310 and Microsoft's own docs, Winsock's SIOCATMARK has
inverted polarity (returns 1 for "no OOB pending", 0 for "OOB pending")
and doesn't track stream position at all — it only answers "is there
urgent data still queued." In SO_OOBINLINE=on mode it's pinned to
TRUE outright. That's the wrong question for an at-mark gate.
What does work, on POSIX at least, is the documented pseudo-EOF.
With SO_OOBINLINE off, "a read never reads across the urgent mark":
when the inline read pointer reaches tp->urg_seq with the urgent byte
still queued, recv() returns 0 even though the connection is alive
(see Linux tcp(7), `tcp_recvmsg` in the kernel). Combined with
exceptfds having fired (the oob_pending latch), recv()==0 is exactly
the at-mark signal we need.
So the input thread now:
- Latches oob_pending on the first exceptfds notification (and
drops exceptfds from the select set so we don't spin).
- Reads inline normally; recv() > 0 just buffers as before.
- On recv()==0 with oob_pending, treats it as the urgent-mark
pseudo-EOF, pulls the byte via recv(MSG_OOB), and dispatches.
Mode-switch bytes (0x10 / 0x20) still apply correctly to data
following the urgent ptr because we've drained pre-mark inline
in the old mode first.
- On recv()<=0 with no oob_pending, treats it as a real peer-close
and breaks out as before.
Win32 may not reproduce the recv()==0 pseudo-EOF — Microsoft's docs
say boundaries are preserved ("three reads to get past OOB") but
don't pin down what the boundary read actually returns, and there's
no authoritative empirical reference for it. If Windows simply
blocks/EAGAINs at the boundary instead, this gate just never fires
there: the OOB byte sits unread in its mailbox and the 0x80
window-size handshake still doesn't fire. That's a regression we
can't fix without empirical Windows testing, but it's strictly
better than the prior SIOCATMARK gate, which falsely declared
at-mark on every iteration and kept calling recv(MSG_OOB) on an
empty queue.
Co-Authored-By: Claude Opus 4.7 (1M context) <
noreply@anthropic.com>
---
■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net