Add a stale/never-active session reaper and raise the listen backlog

TCPServer accepted a connection and never revisited it again once it
stopped generating epoll events - a connection that completes the TCP
handshake and then goes permanently silent (an incomplete TLS
handshake, a port scanner/prober) sat in sessions forever, one
TCPSession + one fd each. sweepStaleSessions() now drops any session
that has gone 30+ seconds without a single byte of real data ever
passing through onDataReceived(), run each time a new connection
arrives rather than needing a dedicated timer. hasReceivedData latches
permanently true on a sessions first real byte, so an ordinary
connected-but-briefly-idle client is never at risk.

Also raised listen()s backlog from 20 to 128, so a burst of connection
attempts has more headroom before the kernel starts dropping SYNs.

Verified live on zephora.barant.com: a silent connection held open was
reaped within the grace window while a real concurrent connection was
left untouched, with the service remaining healthy throughout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Matt ArantandClaude Sonnet 5 committed 2026-10-06 17:54:20 +00:00
1 parent d058322cc6
commit 6483729de3
4 files changed
+103 -1

No files matched your search

+25
View File
@@ -149,6 +149,31 @@ namespace core {
void connectionRequest() override;
///
/// Drops any session that completed a TCP accept() but has never
/// had a single byte of real data pass through onDataReceived() -
/// covers both a TLS handshake that never finishes and a plain
/// connection that never sends anything - once it's been open
/// longer than a short grace period. Nothing else in this class
/// ever revisits an already-accepted session once it stops
/// generating epoll events (Thread::run()'s dispatch loop only
/// acts on a session when a real event for it arrives), so a
/// connection that completes the handshake and then goes
/// permanently silent - exactly what a port scan/prober looks
/// like from here, as opposed to a normal scan that just connects
/// and immediately closes again, which the existing read-hangup
/// path already cleans up fine - would otherwise sit in `sessions`
/// forever, one TCPSession + one fd each. Called from
/// connectionRequest() (see its own call site) so the sweep keeps
/// pace with however fast new connections are actually arriving,
/// without needing a dedicated timer/thread of its own; a
/// legitimate, already-talking client is never at risk, since
/// hasReceivedData latches true permanently on its first real byte
/// and is never consulted again after that.
///
void sweepStaleSessions();
///
/// The listening socket itself is never a TLS peer - accepting a
/// connection on it surfaces as a plain read() failing with ENOTCONN