This is a common problem with IOCP, you are making a low-level call to the TCP / IP driver stack. Which, like all drivers in Windows, reports an error with NTSTATUS errors. The expected error here is: STATUS_CONNECTION_RESET.
These native error codes must be translated into the winapi error code. This translation usually depends on the context, it depends on which winapi library issued the driver command. In other words, you can only get the WSAECONNRESET error if it was the Winsock library that made the translation. But this is not what happened in your program since GetQueuedCompletionStatus () handled the error.
This is a universal helper function that handles IOCP for any device driver. There is no context; the OVERLAPPED structure is not enough to indicate how the I / O request began. Go to this article in KB , it documents the default mapping from NTSTATUS error codes to winapi error codes. A mapping that uses GetQueuedCompletionStatus (). Relevant entries in the list:
STATUS_NETWORK_NAME_DELETED ERROR_NETNAME_DELETED STATUS_LOCAL_DISCONNECT ERROR_NETNAME_DELETED STATUS_REMOTE_DISCONNECT ERROR_NETNAME_DELETED STATUS_ADDRESS_CLOSED ERROR_NETNAME_DELETED STATUS_CONNECTION_DISCONNECTED ERROR_NETNAME_DELETED STATUS_CONNECTION_RESET ERROR_NETNAME_DELETED
These were, um, not fantastic choices. He probably returned to very early Windows when Lanman became the network level of choice. WSAGetLastError () is pretty useless to map ERROR_NETNAME_DELETED back to a specific WSA error, NTSTATUS code was lost when GetQueuedCompletionStatus () set the last error code for the stream. So itβs not, it just returns what it can.
What would you expect is the WSAGetQueuedCompletionStatus () function, so this error conversion can happen correctly using the Winsock rules. Not. These days, I prefer to use maximum power over how to write Windows code correctly, the .NET Framework source available from the Reference Source . I am linked to a source for the SocketAsyncEventArgs.CompletionCallback () method. Which contains the key:
// The Async IO completed with a failure. // here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error. bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult( m_CurrentSocket.SafeHandle, m_PtrNativeOverlapped, out numBytes, false, out socketFlags); socketError = (SocketError)Marshal.GetLastWin32Error();
Or, in other words, you must make an extra call to WSAGetOverlappedResult () to get the correct return value from GetLastError (). This is not very intuitive :)