Skip to content

fix(iocp)!: map remote RST to connection_reset, not cond::canceled (#…#319

Merged
mvandeberg merged 1 commit into
cppalliance:developfrom
mvandeberg:pr/304-normalize-errors
Jul 17, 2026
Merged

fix(iocp)!: map remote RST to connection_reset, not cond::canceled (#…#319
mvandeberg merged 1 commit into
cppalliance:developfrom
mvandeberg:pr/304-normalize-errors

Conversation

@mvandeberg

Copy link
Copy Markdown
Contributor

…304)

IOCP delivers ERROR_NETNAME_DELETED both when a local closesocket() cancels a pending overlapped op and when the peer hard-closes with a RST. detail::make_err mapped it unconditionally to capy::error::canceled, so a remote reset on Windows surfaced as cond::canceled -- conflating remote termination with deliberate local cancellation. POSIX already mapped RST to errc::connection_reset.

The cancelled atomic (set by the stop-token, cancel(), and close() paths) is consulted before the raw error at every decode site, so a surviving ERROR_NETNAME_DELETED is always a genuine remote reset. Remove it from make_err's canceled branch and remap it per operation kind at the IOCP decode sites via a new iocp_make_err helper: connection_reset for stream read/write, connection_aborted for accept (mirroring Asio). make_err stays generic; the winsock-dependent remap lives in the IOCP layer.

Add test/unit/error_conditions.cpp: a backend-parameterized audit of the remote/connection error family (FIN->eof, RST->connection_reset, write-to-dead-peer->connection_reset|broken_pipe, connect-refused-> connection_refused), asserting portable conditions on every backend so the cross-platform contract is enforced. The cancellation family is already covered across all backends elsewhere and is not duplicated.

normalize_openssl_shutdown_read_error is left unchanged: it already excludes canceled (#301), and reset-during-shutdown genuinely means no close_notify was received -> stream_truncated.

@cppalliance-bot

cppalliance-bot commented Jul 16, 2026

Copy link
Copy Markdown

An automated preview of the documentation is available at https://319.corosio.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-07-17 17:12:05 UTC

@mvandeberg
mvandeberg force-pushed the pr/304-normalize-errors branch from bfa1e65 to fee9573 Compare July 16, 2026 22:55
@mvandeberg
mvandeberg changed the base branch from develop-2 to develop July 17, 2026 15:39
@cppalliance-bot

cppalliance-bot commented Jul 17, 2026

Copy link
Copy Markdown

GCOVR code coverage report https://319.corosio.prtest3.cppalliance.org/gcovr/index.html
LCOV code coverage report https://319.corosio.prtest3.cppalliance.org/genhtml/index.html
Coverage Diff Report https://319.corosio.prtest3.cppalliance.org/diff-report/index.html

Build time: 2026-07-17 17:21:45 UTC

…ppalliance#304)

Make cond::canceled mean only local, deliberate cancellation on every
backend, and surface remote/connection failures as the portable std::errc
condition consistently across epoll/io_uring/kqueue/select/IOCP.

Previously the IOCP and kqueue backends diverged from POSIX:

- IOCP mapped ERROR_NETNAME_DELETED unconditionally to canceled, so a
  remote RST looked identical to a local cancel. It is now disambiguated
  per operation kind in the new iocp_make_err (connection_reset for stream
  read/write, connection_aborted for accept); make_err no longer folds it
  into canceled. The cancelled flag, set before the raw error is consulted,
  keeps genuine local closes (close()/cancel()/stop-token) as canceled.

- IOCP surfaced NTSTATUS-derived Win32 socket codes (e.g.
  ERROR_CONNECTION_REFUSED 1225) that MSVC's system_category does not map to
  std::errc. iocp_make_err now normalizes the observed ones to their Winsock
  equivalents (connection_refused, network_unreachable, timed_out) so they
  compare equal to the portable conditions like POSIX does.

- IOCP close_socket() flagged only the aux-reactor wait op cancelled,
  relying on make_err's old NETNAME_DELETED->canceled fold for the overlapped
  read/write/connect/accept ops. With that fold gone, close_socket() now
  request_cancel()s every op before tearing down the handle (as cancel()
  does), so a local close stays canceled regardless of the CancelIoEx-vs-
  closesocket race. Applied across tcp, udp, and local-stream services.

- kqueue stripped a user-set SO_LINGER before close (a macOS workaround),
  turning an abortive close into a graceful FIN so the peer saw eof instead
  of connection_reset. RST is in fact delivered reliably (EV_EOF carries
  ECONNRESET in fflags), so the strip is removed and SO_LINGER is passed
  through, matching the other backends.

Add test/unit/error_conditions.cpp: a cross-backend audit (run under every
backend) asserting the portable contract for the remote/connection error
family -- FIN->eof, remote reset is never canceled, write-to-dead-peer is
connection_reset|broken_pipe, refused connect is never canceled.
@mvandeberg
mvandeberg force-pushed the pr/304-normalize-errors branch from c54648d to 320dee4 Compare July 17, 2026 17:05
@mvandeberg
mvandeberg marked this pull request as ready for review July 17, 2026 17:35
@mvandeberg
mvandeberg merged commit 471fc61 into cppalliance:develop Jul 17, 2026
42 of 43 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Beast2 Jul 17, 2026
@codecov

codecov Bot commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.80%. Comparing base (e06fca6) to head (320dee4).
⚠️ Report is 3 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #319      +/-   ##
===========================================
+ Coverage    77.79%   77.80%   +0.01%     
===========================================
  Files           96       96              
  Lines         6985     6984       -1     
  Branches      1682     1681       -1     
===========================================
  Hits          5434     5434              
  Misses        1055     1055              
+ Partials       496      495       -1     
Files with missing lines Coverage Δ
...t/corosio/native/detail/iocp/win_overlapped_op.hpp 83.33% <ø> (ø)
include/boost/corosio/native/detail/make_err.hpp 57.14% <ø> (+3.80%) ⬆️

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e06fca6...320dee4. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants