I just started using plib's NET library and noticed a minor bug...
It's not really a bug - it's more a windows xp problem (feature?) that
isn't handled properly.
i'm using a netSocket derivitive to listen
it passes socket handles to a netChannel derivitive to handle
connections
when a client connects with telnet and then disconnects,
the server prints:
WARNING: WSAGetLastError() => 10054
i looked up wsa error 10054
WSACONNRESET = 10054
the netChannel class has its own receive function for receiving its
special data and handling exeptions
---------------- code ----------------
int
netChannel::recv (void * buffer, int size, int flags)
{
int result = netSocket::recv (buffer, size, flags);
if (result > 0) {
return result;
} else if (result == 0) {
close();
return 0;
} else if (isNonBlockingError ()) {
return 0;
} else {
this->handleError (result);
close();
return -1;
}
}
------------- /code --------------
this function calls isNonBlockingError() which is defined in netSocket
here's some comments that should be in there:
(if result > 0) then there was data received, return how much
otherwise (if result == 0) then the socket reported action on the
connection, but there was no data -> signalling a disconnect, close
socket, return 0
otherwise, there was some error with the recv() function as called by
netSocket, check if it was a nonblocking error
if it wasn't a non-blocking error, which it wasn't, then call the
virtual overloadable handleError function (which i have overloaded to
print my stuff)
so it seems that, since WSAECONNRESET is not a nonblocking error, then
my virtual function should be allowed to handle the error however i want
it to
but somehow this error message is being printed, so i looked to see what
exactly isNonBlockingError does:
-------------- code ------------
bool
netSocket::isNonBlockingError ()
{
#if defined(__CYGWIN__) || !defined (WIN32)
switch (errno) {
case EWOULDBLOCK: // always == NET_EAGAIN?
case EALREADY:
case EINPROGRESS:
return true;
}
return false;
#else
int wsa_errno = WSAGetLastError();
if ( wsa_errno != 0 )
{
WSASetLastError(0);
ulSetError(UL_WARNING,"WSAGetLastError() => %d",wsa_errno);
switch (wsa_errno) {
case WSAEWOULDBLOCK: // always == NET_EAGAIN?
case WSAEALREADY:
case WSAEINPROGRESS:
return true;
}
}
return false;
#endif
}
--------------- /code -------------------
AHA!
so when netChannel's recv() function gets an error and checks to see if
it's a blocking error...
it registers a warning with ul saying that there was a winsock error,
and causing ul to print the error to the screen
it seems like the netChannel class is meant to take care of all socket
error handling on its own
and that the overloadable handleError() function takes care of errors
returned by recv()
but the WSACONNRESET error is unhandled...
also the cygwin version of the code (the first part of #if bracket)
seems like it doesn't record recv errors..
maybe the ulSetError line is unnecessary?
a suggestion might be to remove the isNonBlockingError from recv() and
instead store the value returned by WSAGetLastError in a variable in the
netChannel class
then allow the user to call getLastError() to find out why recv() called
handleError()
then you can keep the isNonBlockingError() function (with ulSetError
removed) and just have it check against variable it has stored.
Anyway, I hope this is helpful, and the code gets updated
-Brendan Batchelder
|