I'm writing a tcp server in Windows NT using completion ports to exploit asynchronous I/O. I have a TcpSocket class, a TcpServer class and some (virtual functions) callbacks to call when an I/O operation is completed, e.g. onRead() for when a read is completed. I have also onOpen() for when the connection is established and onEof() for when the connection is closed, and so on. I always have a pending read for the socket, so if the socket effectively gets data (the read will be completed with size > 0) it calls onRead(), instead if the client closes the socket from the client side (the read will be completed with size == 0) it calls onEof(), and the server is aware of when the client closes the socket with closesocket(server_socket); from its side.
All works gracefully, but I have noticed a thing:
when i call closesocket(client_socket); on the server's side endpoint of the connection, instead of the client side, (either with setting linger {true, 0} or not), the pending read will be completed as erroneous, that is, the read size will not only be == 0, but also GetLastError() returns an error: 64, or 'ERROR_NETNAME_DELETED'. I have searched much about this on the web, but didn't find nothing interesting.
Then I asked myself: but is this a real error? I mean, can this really be considered an error?
The problem is that on the server side, the onError() callback will be called when I closesocket(client_socket); instead of the onEof(). So I thought this:
What about if I, when this 'ERROR_NETNAME_DELETED' "error" is received, call onEof() instead of onError() ? Would that introduce some bugs or undefined behavior? Another important point that made me ask this question is this:
When I have received this read completion with 'ERROR_NETNAME_DELETED', I have checked the OVERLAPPED structure, in particular the overlapped->Internal parameter which contain the NTSTATUS error code of the underlying driver. If we see a list of NTSTATUS error codes [ http://www.tenox.tc/links/ntstatus.html ] we can clearly see that the 'ERROR_NETNAME_DELETED' is generated by the NTSTATUS 0xC000013B, which is an error, but it is called 'STATUS_LOCAL_DISCONNECT'. Well, it doesn't look like a name for an error. It seems more like `ERROR_IO_PENDING' which is an error, but also a status for a correct behavior.
So what about checking the OVERLAPPED structure's Internal parameter, and when this is == to 'STATUS_LOCAL_DISCONNECT' a call to the onEof() callback is performed? Would mess things up?
In addition, I have to say that from the server side, if I call DisconnectEx() before calling closesocket(client_socket); I will not receive that error. But what about I don't want to call DisconnectEx() ? E.g. when the server is shutting down and doesn't want to wait all DisconnectEx() completions, but just want to close all client's connected.