2022-11-17 - Tests involving poll() return states upon a pending connect(). - connect() to a closed port returns OUT and HUP: $ dev/poll/poll -v -l clo -c pol #### BEGIN #### cmd #1 stp #1: clo(l=3): ret=0 cmd #2 stp #0: con(c=4): ret=-1 (Connection refused) cmd #2 stp #1: pol(c=4): ret=1 ev=0x14 (OUT HUP) #### END #### => with HUP we *know* the connection failed, since we never asked for a SHUTW before connecting. It is indeed an error as can be seen with connect() returning -1 ECONNREFUSED. - connect() to a port that does close(accept()) does return IN and RDHUP: $ dev/poll/poll -v -s clo -c pol #### BEGIN #### cmd #1 stp #0: con(c=4): ret=0 cmd #1 stp #0: acc(l=3): ret=5 cmd #1 stp #1: clo(s=5): ret=0 cmd #2 stp #1: pol(c=4): ret=1 ev=0x2005 (IN OUT RDHUP) #### END #### => here there's no HUP, only RDHUP because the FIN is pending in the socket buffers, waiting to be read. - for a HUP to happen after a connect() to a valid port, one would have to perform a shutw() on the client, which is normally not the case, indicating that HUP is reliable here: $ dev/poll/poll -v -s clo -c shw,pol #### BEGIN #### cmd #1 stp #0: con(c=4): ret=0 cmd #1 stp #0: acc(l=3): ret=5 cmd #1 stp #1: clo(s=5): ret=0 cmd #2 stp #1: shw(c=4): ret=0 cmd #2 stp #2: pol(c=4): ret=1 ev=0x2015 (IN OUT HUP RDHUP) #### END #### - one case that may happen is when sending a request and immediately shutw() (which leaves a TIME_WAIT so not recommended): $ dev/poll/poll -v -c snd,shw -s clo -c pol,rcv,pol #### BEGIN #### cmd #1 stp #0: con(c=4): ret=0 cmd #1 stp #1: snd(c=4): ret=3 cmd #1 stp #2: shw(c=4): ret=0 cmd #2 stp #0: acc(l=3): ret=5 cmd #2 stp #1: clo(s=5): ret=0 cmd #3 stp #1: pol(c=4): ret=1 ev=0x201d (IN OUT ERR HUP RDHUP) cmd #3 stp #2: rcv(c=4): ret=-1 (Connection reset by peer) cmd #3 stp #3: pol(c=4): ret=1 ev=0x2015 (IN OUT HUP RDHUP) #### END #### => here it's impossible to know from the client whether the server consumed the data or not, which is normal since a close on the server causes an RST to be emitted for the data in flight, hence the ERR here. It's also worth noting that once POLL_ERR is consumed by recv() it disappears. - for the server, sending a shutw() before closing here delivers an ACK in time that prevents the RST from being sent, thus connect() is not notified (but if the server has too much to send, it will truncate and emit an RST): $ dev/poll/poll -v -c snd,shw -s shw,clo -c pol,rcv,pol #### BEGIN #### cmd #1 stp #0: con(c=4): ret=0 cmd #1 stp #1: snd(c=4): ret=3 cmd #1 stp #2: shw(c=4): ret=0 cmd #2 stp #0: acc(l=3): ret=5 cmd #2 stp #1: shw(s=5): ret=0 cmd #2 stp #2: clo(s=5): ret=0 cmd #3 stp #1: pol(c=4): ret=1 ev=0x2015 (IN OUT HUP RDHUP) cmd #3 stp #2: rcv(c=4): ret=0 cmd #3 stp #3: pol(c=4): ret=1 ev=0x2015 (IN OUT HUP RDHUP) #### END #### - if the server sends a response, disables lingering and closes with RST, it is possible to get HUP and ERR at the same time during the connect() phase, and recv() can still receive the pending response: $ dev/poll/poll -v -s snd,lin,clo -c pol,rcv,pol #### BEGIN #### cmd #1 stp #0: con(c=4): ret=0 cmd #1 stp #0: acc(l=3): ret=5 cmd #1 stp #1: snd(s=5): ret=3 cmd #1 stp #2: lin(s=5): ret=0 cmd #1 stp #3: clo(s=5): ret=0 cmd #2 stp #1: pol(c=4): ret=1 ev=0x201d (IN OUT ERR HUP RDHUP) cmd #2 stp #2: rcv(c=4): ret=3 cmd #2 stp #3: pol(c=4): ret=1 ev=0x201d (IN OUT ERR HUP RDHUP) #### END ####