Is there a way to wait with select(2) for a socket where the peer has called shutdown(SHUT_RD) on its socket or has completely closed its socket?
Trying to write to such a socket will return EPIPE (Broken Pipe). I'd like to be notified of this condition before I try to write.
In a server I use select(2) to wait for new subscribers connecting via TCP, and for input on other fds to be forwarded to subscribers. If a subscriber closes its connection, or only shuts down its READ side, I'd like to close my side of the socket immediately and free associated resources.
I tried waiting for exceptions with select(2) but that didn't report closed sockets. Waiting for read on the sockets to the subscribers also won't work, since waiting for read will only return if the socket is closed completely and read(2) would return with EOF.
Shutting down the socket for reading (
SHUT_RD) is a purely local action and it is not propagated to the peer in any way. So it is not possible to wait for this. Only shutting down the socket for writing (SHUT_WR) is propagated by sending a FIN. And this is the same for completely closing the socket, which is thus indistinguishable by the peer fromSHUT_WR.Waiting for the peer to close the socket or to
SHUT_WRis the same as waiting for the socket to be readable. Only thatrecvwill not return any data in this case but return 0, i.e. no data but no error.But even if there would be a notification by the peer when
SHUT_RDis done (again, there is no such notification) it would not actually be safe rely on it before writing. Because it would take some time for this notification to arrive from the peer, i.e. there would be an unavoidable race condition.Therefore, you need to structure your code so that it can properly handle
EPIPE.