[Windows] Report the errno equivalent of winsock errors - #3700
Open
jakepetroules wants to merge 2 commits into
Open
[Windows] Report the errno equivalent of winsock errors#3700jakepetroules wants to merge 2 commits into
jakepetroules wants to merge 2 commits into
Conversation
`CNIOWindows_sendmmsg` was a stub that asserted and then called `abort()`, so any code path reaching it took the whole process down. That is the datagram write path whenever more than one write is pending, which made `DatagramChannelTests` and `RawSocketBootstrapTests` unrunnable: both aborted partway through, taking the rest of the test process with them. Winsock has no `sendmmsg`, so emulate it by sending the messages one at a time, which is what the Darwin shim does for the same reason. Implement it in Swift alongside the existing `sendmsg`, rather than filling in the C shim, since everything needed is callable directly from Swift; the now-unused C stub and its declaration are removed. The `WSASendMsg` extension function is resolved once per batch rather than once per message, so the lookup is hoisted into a helper shared with `sendmsg`. The error semantics match the other implementations: a failure on the first message is reported to the caller, with `WSAEWOULDBLOCK` reported as `.wouldBlock` the way the POSIX implementation's `syscall(blocking: true)` wrapper does, while a failure after some messages have been sent is reported as a short send for the caller to retry. This does not yet make either test suite pass, so no skips are removed here. Both now get further before failing for unrelated reasons: the datagram tests reach a `fatalError` in `PendingDatagramWritesManager`, which reads `errnoCode` on an `IOError` that carries a winsock-domain code, and the raw socket tests fail with "Already closed". Crucially, neither aborts the test process any more.
Depends on apple#3699. `IOError.errnoCode` trapped with `fatalError("IOError domain is not errno")` whenever the error carried a winsock- or windows-domain code, which NIO's own error classification then walked straight into. `PendingDatagramWritesManager` compares against `EMSGSIZE` and `EHOSTUNREACH` to decide whether a datagram write error is recoverable, and `BaseSocket` compares against `EAFNOSUPPORT` when it turns off `IPV6_V6ONLY` -- the latter on the path of every IPv6 socket NIO creates. Winsock's error codes mean the same things as their errno counterparts, so translate them rather than trapping: `WSAEMSGSIZE` reports `EMSGSIZE`, and so on. Error handling written against errno then keeps working on Windows, which also matters for the tests, where there are ~38 comparisons against errno constants. Codes with no errno counterpart, and windows-domain codes, are reported unchanged rather than trapping. That is unambiguous: Windows CRT errno values never exceed 140, while winsock and Win32 codes are far larger, so such a value cannot be mistaken for an errno. Note that the Windows CRT gives `EWOULDBLOCK` and `EAGAIN` distinct values, unlike the platforms where they are synonyms, so `WSAEWOULDBLOCK` is paired with `EWOULDBLOCK`. With this and apple#3699, `DatagramChannelTests` runs to completion on Windows for the first time (74 tests: 38 pass, 19 fail, 17 skipped) rather than aborting the test process. The remaining failures are unrelated gaps, so the suite stays skipped for now and no skips are removed here.
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation:
Depends on #3699. That PR is the first commit on this branch. Please review only the second commit, or wait until #3699 is merged.
IOError.errnoCodecalledfatalErrorwhen the error came from Winsock. NIO's own code readserrnoCodeto classify errors, so it walked into that trap:PendingDatagramWritesManagercompares the error withEMSGSIZEandEHOSTUNREACH. It uses the result to decide if a datagram write error can be recovered.BaseSocketcompares it withEAFNOSUPPORTwhen it turns offIPV6_V6ONLY. This code runs for every IPv6 socket NIO creates.The tests also compare
errnoCodewith errno values in about 38 places.Modifications:
A Winsock code means the same thing as its errno counterpart, so this translates it.
WSAEMSGSIZEreportsEMSGSIZE, and so on for about 34 codes. Code that checks errno then works on Windows with no changes at the comparison sites.A code with no errno counterpart is returned unchanged instead of trapping. This is safe, not only convenient: errno values on Windows are never higher than 140, and Winsock codes start at 10004. A test checks this.
One detail for reviewers: on Windows,
EWOULDBLOCKandEAGAINhave different values. Winsock reports would-block asWSAEWOULDBLOCK, so it maps toEWOULDBLOCK. All of NIO'sEAGAINchecks are in POSIX-only code today.Result:
With this and #3699,
DatagramChannelTestsruns to the end on Windows for the first time: 74 tests, 38 pass, 19 fail, 17 skipped. Before, the test process stopped in the middle.The 19 failures are separate gaps, so the suite stays skipped. This PR removes no skips.
Tested on a Windows ARM64 machine (Swift 6.3.2): a full
swift testpasses (2360 tests).NIOCorestill builds on macOS.