How to handle the Linux socket revents POLLERR, POLLHUP and POLLNVAL?
A POLLHUP
means the socket is no longer connected. In TCP, this means FIN has been received and sent.
A POLLERR
means the socket got an asynchronous error. In TCP, this typically means a RST has been received or sent. If the file descriptor is not a socket, POLLERR
might mean the device does not support polling.
For both of the conditions above, the socket file descriptor is still open, and has not yet been closed (but shutdown()
may have already been called). A close()
on the file descriptor will release resources that are still being reserved on behalf of the socket. In theory, it should be possible to reuse the socket immediately (e.g., with another connect()
call).
A POLLNVAL
means the socket file descriptor is not open. It would be an error to close()
it.
when does poll() return POLLERR
It's implementation dependent. Most applications just treat POLLERR the same as normal readiness, allowing the subsequent operation to fail.
POLLHUP vs POLLNVAL, or what is POLLHUP?
POLLNVAL
is equivalent to EBADF
: it means the file descriptor does not actually refer to any open file, i.e. it was close
d or never open to begin with. This can never happen except as a result of a programming error or intentional attempt to query whether a file descriptor is invalid. External conditions, such as a peer closing its end of a network socket or pipe, can never close your file descriptor to your end of the socket or pipe. If it could, this would lead to massive vulnerabilities in basically any program using sockets/pipes/etc.
POLLHUP
, on the other hand, indicates that your file descriptor is valid, but that it's in a state where:
A device has been disconnected, or a pipe or FIFO has been closed by the last process that had it open for writing. Once set, the hangup state of a FIFO shall persist until some process opens the FIFO for writing or until all read-only file descriptors for the FIFO are closed. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
If you want to see POLLHUP
, simply open a pipe
, close the reading end, and query the writing end with poll
.
check revents into struct pollfd
According to man(2) poll indeed...
The field revents is an output parameter, filled by the kernel
with the events that actually occurred. The bits returned in
revents can include any of those specified in events, or one of
the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are
meaningless in the events field, and will be set in the revents
field whenever the corresponding condition is true.)
poll.h
defines those as
#define POLLIN 0x001 /* There is data to read. */
#define POLLPRI 0x002 /* There is urgent data to read. */
#define POLLOUT 0x004 /* Writing now will not block. */
// etc...
so armed with this knowledge,
if(!(fds.revents & 1))
is the same as
if(!(fds.revents & POLLIN))
which means "if the "there is data to read" bit is not set", i.e. "if there is no data to read".
Unexpected revents value in poll for non blocking socket connect
The value of poll.revents
is a bitfield.
From the header file poll.h
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
So your value 0x28
is comprised of POLLERR|POLLNVAL
, which can occur, when the filedescriptor polled for is not open:
POLLNVAL
Invalid request: fd not open (only returned in revents; ignored in events).
These values can always occur, even when not asked for in poll.events
.
As you can see, the socket error is 111
(first call to getsockopt()
), which means Connection refused
. After this, the filedescriptor is invalid to poll for, because it is no longer connected.
POLLHUP vs. POLLRDHUP?
No, when poll()
ing a socket, POLLHUP
will signal that the connection was closed in both directions.
POLLRDHUP
will be set when the other end has called shutdown(SHUT_WR)
or when this end has called shutdown(SHUT_RD)
, but the connection may still be alive in the other direction.
You can have a look at net/ipv4/tcp.c
the kernel source:
if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
mask |= EPOLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
SHUTDOWN_MASK
is RCV_SHUTDOWN|SEND_SHUTDOWN
. RCV_SHUTDOWN
is set when a FIN
packet is received, and SEND_SHUTDOWN
is set when a FIN
packet is acknowledged by the other end, and the socket moves to the FIN-WAIT2
state.
[except for the TCP_CLOSE
part, that snippet is replicated by all protocols; and the whole thing works similarly for unix sockets, etc]
There are other important differences -- POLLRDHUP
(unlike POLLHUP
) has to be set explicitly in .events
in order to be returned in .revents
.
And POLLRDHUP
only works on sockets, not on fifos/pipes or ttys.
Related Topics
Creating Permanent Executable Aliases
How to Find the Main Function's Entry Point of Elf Executable File Without Any Symbolic Information
Cpu Affinity Masks (Putting Threads on Different Cpus)
Running Docker on Ubuntu: Mounted Host Volume Is Not Writable from Container
Using Perf Probe to Monitor Performance Stats During a Particular Function
Performance - Multithreaded or Multiprocess Applications
Force Cmake to Use the Full Library Path
Git Permission Denied (Publickey,Gssapi-Keyex,Gssapi-With-Mic)
How to Create Opengl Context via Drm (Linux)
Shell Script Get Ctrl+Z with Trap
How to Make Binary Distribution of Qt Application for Linux
Building a Simple (Hello-World-Esque) Example of Using Ld's Option -Rpath with $Origin
Set Environment Variable with Space in Linux
How to Return Spawned Process Exit Code in Expect Script
PDF Lib Install Fail on Linux Server. Using Pecl Install PDFlib