feat(tcp): a failed send or receive says which errno it failed with

Send() and the receives threw a bare std::runtime_error with the
strerror text, so a caller that reports the cause the way Python does -
"the connection broke ([Errno 104] Connection reset by peer)", which a
language model reads in Crafter.Review's SQL helper output - could not
tell the code. They throw SocketErrorException now, as a failed connect
already does: kind System, the errno, and the same message, still a
std::runtime_error. A receive timeout stays SocketTimeoutException and
a closed peer SocketClosedException.

ShouldReportIoErrors: a peer that resets the connection (SO_LINGER 0)
fails the next receive with ECONNRESET and a send into it with EPIPE
or ECONNRESET.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 07:06:24 +01:00
commit 16da0a1979
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
5 changed files with 124 additions and 7 deletions

View file

@ -176,6 +176,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
cfg.AddTest("ShouldRecieveTCP").Dependencies({ &cfg });
cfg.AddTest("ShouldConnectDualStack").Dependencies({ &cfg });
cfg.AddTest("ShouldReportConnectErrors").Dependencies({ &cfg });
cfg.AddTest("ShouldReportIoErrors").Dependencies({ &cfg });
cfg.AddTest("ShouldBindLoopbackEphemeral").Dependencies({ &cfg });
cfg.AddTest("ShouldTimeoutSilentHTTP1").Dependencies({ &cfg });
cfg.AddTest("ShouldFollowRedirectsHTTP1").Dependencies({ &cfg });