The Serve::Reset case closed with linger 0 as soon as the server's handshake returned, while the client could still be reading the last flight; on Linux the RST discards unread data, so sceSslConnect reported the closed socket instead of 0. The server now reads one byte the client writes after its sceSslConnect and resets after it.
sceSslConnect verifies the server's chain under MBEDTLS_SSL_VERIFY_OPTIONAL and returns the first failure the connection's verify options select, with the SSL_ERROR_* codes KytyPS5 lists. The initial options are all five checks, so a connection whose title never sets them fails closed: with no CA loaded it returns SSL_ERROR_UNKNOWN_CA instead of throwing. The result is final for the connection: a failure sends close_notify, later sceSslConnect calls return the same code, and sceSslRead and sceSslWrite throw. A verify callback runs once after the handshake, outside the session lock, with the connection id, that code, handles to a copy of the peer chain that the context's certificate readers accept, the chain length and the user argument; a negative return fails the connect with SSL_ERROR_APPLICATION_VERIFICATION_CALLBACK_CHECK. The ALPN list set with sceSslSetAlpn is split on commas and offered, sceSslGetAlpnSelected returns the protocol the server chose, and the minimum version floors the handshake at TLS 1.2. A socket that would block returns SSL_ERROR_WANT_POLLIN or WANT_POLLOUT from connect, read and write and the next sceSslConnect resumes the handshake; the BIO maps a reset to MBEDTLS_ERR_NET_CONN_RESET, which returns SSL_ERROR_SOCKET_CLOSED, and tells a blocking socket's expired receive timeout, which returns SSL_ERROR_READ_TIMEOUT, apart from a non-blocking would-block. sceSslClose sends close_notify once and marks the connection closed. The debt entry records the default options and the situation-to-code choices as unverified and drops the title IDs.
Each client thread handshakes, writes, reads the reply and the end of
the stream, so session setup and record allocations from several
threads contend for the same context pool. The pool memory must return
to its loaded size afterwards.
Initialize the pool's mutex explicitly, which -Wextra asks for.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoU3ZF76A6uR8sCA7NMLch
sceSslConnect performs the client handshake on the host socket that the
guest number maps to in the libkernel or libSceNet socket table, and
sceSslRead and sceSslWrite carry application data. Session state comes
from the context's memory pool, and the server is verified against the
CAs loaded with sceSslLoadCert; a loaded client certificate is sent when
the server asks for one.
libkernel exports KernelLookupSocketNative_nid_no_patch, which checks
its own socket table before the one libSceNet registers. Pools take a
lock so connections can allocate outside the library lock.
TLS 1.3 is compiled out. A missing CA, a verify callback, would-block
sockets and every failure whose console code is unknown throw, as
recorded in the libSceSsl debt entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoU3ZF76A6uR8sCA7NMLch