Calling WSAGetLastError () from an IOCP Stream Returns an Invalid Result

I called WSARecv() , which returned WSA_IO_PENDING . Then I sent the RST packet from the other end. The GetQueuedCompletionStatus() function, which exists in another thread, returned FALSE as expected, but when I called WSAGetLastError() , I got 64 instead of WSAECONNRESET .

So why did WSAGetLastError() not return WSAECONNRESET ?


Edit:

I forgot to mention that when I call WSAGetLastError() immediately after the failed WSARecv() (due to the received RST packet), the returned error code is WSAECONNRESET , not 64 .

Thus, it seems that the returned error code depends on whether WSARecv() worked right after it was called, or later it was not possible to get the completion packet.

+8
c ++ sockets iocp
source share
1 answer

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 :)

+12
source share

All Articles