I have a set of TCP sockets with keep-alive (interval 1 min), controlled by a select(2) loop (selecting for read).
select(2)
return an erro
select()
sets a bit in the FDSET
that indicates which socket has triggered. Use FD_ISSET macro to determine which socket asked for service.
select()
itself does not return an error if an error is signalled for one of the sockets it is selecting for. [Indeed, the API can't indicate per-socket errors this way, because two different sockets could each acquire a pending error during a single call of select()
. Which one would select()
return?]select()
loop, you instead use the FD_ISSET macro to attempt a read()
on each socket marked readable.select()
returns, allowing you to pick up timed-out errors due to keep-alive immediately. Note that select marking a socket for read does not indicate that there is data to read, only that an attempt to read will not block. If the socket has a pending error to retrieve, reading will not block. Both read(2)
and write(2)
first retrieve any pending error on the socket before even attempting to handle any data.
A descriptor shall be considered ready for reading when a call to an input function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully. (The function might return data, an end-of-file indication, or an error other than one indicating that it is blocked, and in each of these cases the descriptor shall be considered ready for reading.) [POSIX:select()]
ETIMEDOUT
if the other end vanishes totally. If a packet delivery error occurs, you'll get that through instead (so if the keep-alive packet gets an ICMP error reply, like "host unreachable", you'll have EHOSTUNREACH
delivered). [For more details on these cases, see Stevens, "Unix Network Programming, vol 1".]