I'm currently reviewing a C application that implements POSIX sockets. This application intermittently checks to see if the connection to the server is valid by reading zero bytes from the socket. It then checks to see if an errno is set to determine whether or not the connection is okay. Is this a robust solution?
uint32_t IsConnected()
{
char dummy[10];
if(read(global_sockfd, dummy, 0) == -1)
{
if(errno != EWOULDBLOCK && errno != EAGAIN)
return FALSE;
else
return TRUE;
}
else
return TRUE;
}
No, this is not a robust solution, for two reasons.
First, for a connected TCP socket read
and recv
will return zero, not −1, after all incoming data has been read and the remote peer has closed its end of the connection (using close
or shutdown
). Your IsConnected
will return TRUE in this case, which is wrong.
Second, the specification of read
says (second paragraph of DESCRIPTION; all emphasis mine)
Before any action described below is taken, and if
nbyte
is zero, theread
function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, theread
function shall return zero and have no other results.
nbyte
is the third argument, which your IsConnected
is supplying as zero. Therefore, depending on the operating system, IsConnected
might always return TRUE, regardless of the state of the socket.
The specification of recv
does not say anything about what happens if the length
argument (equivalent to nbyte
for read
) is zero; I think this is probably an oversight and it (and recvfrom
, recvmsg
, etc.) is meant to have the same special behavior as read
. So changing read
to recv
will not fix the problem by itself. However, I think a complete fix is possible by using recv
with MSG_PEEK
:
bool is_connected(int sock)
{
char dummy[1];
ssize_t nread = recv(sock, dummy, sizeof dummy, MSG_PEEK);
if (nread > 0)
return true; // at least one byte of data available
else if (nread == 0)
return false; // EOF
else
return errno == EWOULDBLOCK || errno == EAGAIN;
}
Using MSG_PEEK
allows you to supply a nonzero length, because the data will not actually be consumed.
Depending on the details of the application and its network protocol, you may also want to consider enabling TCP keep-alive packets on the socket.