TCPSocket's SSL_CTX*-taking constructor - the one every accepted
TCPSession actually goes through (TCPSession(EPoll&, TCPServer*, ...)
passes server->ctx into it) - never initialized the `tlsInfo` member,
and TCPSocket.h gave it no default either. Every session's `tlsInfo`
was uninitialized garbage.
receiveData()/sendData() key their TLS-vs-plain dispatch on
`if(tlsInfo)`. Since that garbage value is non-zero often enough on a
real stack, sessions on a plain, non-TLS server were intermittently
routed through TLS::receiveData()/sendData() (SSL_read()/SSL_write())
against an also-uninitialized SSL*, segfaulting inside libssl. Confirmed
via dmesg: repeated "general protection fault ... in libssl.so.3",
signal 11, non-deterministic timing consistent with depending on
whatever garbage happened to be on the stack for a given session.
Fixed by dispatching on `ctx` instead of `tlsInfo`. `ctx` (TLS.h) now
defaults to NULL (previously also uninitialized) and is the value that
actually gets set for real in TLS::createContext() and correctly
inherited by every session via TLS(SSL_CTX*) - unlike `tlsInfo`, which
is only ever set on the listening TCPServer's own constructor and never
propagated to sessions at all. For the previously-working TLS-enabled
case this is a no-op: ctx and tlsInfo were always both set (or both
unset) together on the listening server, so the observable behavior
there is unchanged - only the previously-undefined session-level
behavior is fixed.
Verified live: restarted the APIServer test instance (a plain, non-TLS
TCPServer - the exact configuration that was crashing), ran 100
sequential requests with no failures, and confirmed no new libssl
segfaults in dmesg since the fix (three separate pre-fix crash
incidents are all still visible in the dmesg history for comparison).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous commit picked up CRLF line endings from a Windows-side
working copy used during development. Converting to plain LF to match
the rest of this Linux-native repo - content unchanged, this is purely
a line-ending normalization (932 insertions/932 deletions, 1:1).
TCPSocket inherits from both Socket and TLS, both declaring receiveData()
as unrelated sibling methods - only Socket::receiveData was virtual, so
TLS::receiveData (SSL_read) was never reached regardless of TLS config,
and even when reached its result was never forwarded to onDataReceived
(that call was commented out). Added an explicit TCPSocket::receiveData
override dispatching to TLS::receiveData or Socket::receiveData based on
tlsInfo, and completed TLS::receiveData to actually return/forward the
decrypted bytes.
Write path did not exist at all. Added Socket::sendData() as a new
virtual hook mirroring receiveData, routed Socket::writeSocket() through
it instead of a raw ::write(), added TLS::sendData() (SSL_write, same
error-handling style as the existing TLS methods), and TCPSocket::sendData()
dispatching the same way the read side does.
Also fixed: a queued write in writeSocket() was being popped off the fifo
as if sent even when shutDown was true and nothing was actually written;
removed a dead empty if(tlsInfo){} stub in onDataReceived, no longer
needed now dispatch happens one level up; replaced leftover debug
std::cout lines with proper Log() calls matching the rest of the file.
Verified via full local compile: all 20 .cpp files build clean, link
into libServerCore.a, and nm confirms the new/fixed symbols are correctly
defined in the right object files.