Topics

Socket Poll functionality in case of socket is closed

Ravi kumar Veeramally
 

Hi,

what should be the return value or behavior of socket poll() call in case of TCP socket is closed from peer side.

As per https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1018, zsock_poll_prepare_ctx() call returns -EALREADY. 

But https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1088. Return value of z_fdtable_call_ioctl() function call handler assumes " If POLL_PREPARE returned with EALREADY, it means it already detected that some socket is ready."

I did a simple test with few modifications in echo-client and echo-server in net tools. echo-server closes the client connection. poll(fds, nfds, 0) call returns "> 0" and error value set to 0. But send failed with return value -ve and error value set to ESHUTDOWN.

Any thoughts @rlubos @pfalcon?

Regards,

Ravi.

Paul Sokolovsky
 

Hello,

On Wed, 18 Mar 2020 11:34:00 +0200
"Ravi kumar Veeramally" <ravikumar.veeramally@...> wrote:

Hi,

what should be the return value or behavior of socket poll() call in
case of TCP socket is closed from peer side.
If a peer closes TCP connection from its side, it's effectively an
analog of EOF condition. In this case, poll() should return POLLIN.
This will cause a client to issue a recv()/read() call, which will
return 0, and will let a client detect the EOF condition.

This is one of the "most basic" of "not immediately obvious" API
contracts re: sockets and polling. It's definitely something like that,
because quickly looking for normative references in the POSIX standard,
I can't find them, e.g. in
https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
this particular case isn't described (some other "not immediately
obvious" cases are). So, it's a kind of common knowledge, and a lot of
software relies on that behavior (well, it's not possible to write
async socket code without it). If you google for it, you should be able
to find a lot of references.

Note that there's also a POLLHUP flag, behavior of which in regard to
sockets is "less clear" and "somewhat of a gray area".



As per
https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1018,
zsock_poll_prepare_ctx() call returns -EALREADY.
zsock_poll_prepare_ctx() is an internal function, which uses a special
internal API contract, where particular error codes are used to signal
very specific conditions. -EALREADY is one of such codes. It doesn't
reach public API clients (and doesn't have the same meaning as POSIX
EALREADY error).

But
https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1088.
Return value of z_fdtable_call_ioctl() function call handler assumes
"If POLL_PREPARE returned with EALREADY, it means it already detected
that some socket is ready."
Right, to achieve the behavior described above.

I did a simple test with few modifications in echo-client and
echo-server in net tools. echo-server closes the client connection.
poll(fds, nfds, 0) call returns "> 0" and error value set to 0. But
send failed with return value -ve and error value set to ESHUTDOWN.
That sounds *about* right. Except that POSIX requires EPIPE to be
returned trying to write to a socket with underlying connection closed.
Or to be more exact, with the quote
(https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html):

-------
[EPIPE]
The socket is shut down for writing, or the socket is
connection-mode and is no longer connected. In the latter case, and if
the socket is of type SOCK_STREAM or SOCK_SEQPACKET and the
MSG_NOSIGNAL flag is not set, the SIGPIPE signal is generated to the
calling thread.
-------

So, if we return ESHUTDOWN, we should change that to EPIPE.


If your mail trails to the ultimate question of "how to detect
peer-closed socket if we called poll with POLLOUT?", then to keep it
short:

a) Hmm, I don't have an answer right away, though I bet I used to
consider it (likely outside Zephyr context).
b) I bet that's where POLLHUP return status kicks in.
c) In all cases like that, where we can't "extract" normative behavior
description from POSIX, we should check and follow the behavior of a
well-know implementation, and that's definitely Linux.



Any thoughts @rlubos <https://github.com/rlubos> @pfalcon
<https://github.com/pfalcon>?
Please don't hesitate to cc: me on mails like this, I may sometimes not
check the mailing list for a few days.


Regards,

Ravi.
[]

--
Best Regards,
Paul

Linaro.org | Open source software for ARM SoCs
Follow Linaro: http://www.facebook.com/pages/Linaro
http://twitter.com/#!/linaroorg - http://www.linaro.org/linaro-blog

Ravi kumar Veeramally
 

Hi,

Thanks for clarification.

Ravi

On 19/03/2020 14.30, Paul Sokolovsky wrote:
Hello,

On Wed, 18 Mar 2020 11:34:00 +0200
"Ravi kumar Veeramally" <ravikumar.veeramally@...> wrote:

Hi,

what should be the return value or behavior of socket poll() call in
case of TCP socket is closed from peer side.
If a peer closes TCP connection from its side, it's effectively an
analog of EOF condition. In this case, poll() should return POLLIN.
This will cause a client to issue a recv()/read() call, which will
return 0, and will let a client detect the EOF condition.

This is one of the "most basic" of "not immediately obvious" API
contracts re: sockets and polling. It's definitely something like that,
because quickly looking for normative references in the POSIX standard,
I can't find them, e.g. in
https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
this particular case isn't described (some other "not immediately
obvious" cases are). So, it's a kind of common knowledge, and a lot of
software relies on that behavior (well, it's not possible to write
async socket code without it). If you google for it, you should be able
to find a lot of references.

Note that there's also a POLLHUP flag, behavior of which in regard to
sockets is "less clear" and "somewhat of a gray area".


As per
https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1018,
zsock_poll_prepare_ctx() call returns -EALREADY.
zsock_poll_prepare_ctx() is an internal function, which uses a special
internal API contract, where particular error codes are used to signal
very specific conditions. -EALREADY is one of such codes. It doesn't
reach public API clients (and doesn't have the same meaning as POSIX
EALREADY error).

But
https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/sockets/sockets.c#L1088.
Return value of z_fdtable_call_ioctl() function call handler assumes
"If POLL_PREPARE returned with EALREADY, it means it already detected
that some socket is ready."
Right, to achieve the behavior described above.

I did a simple test with few modifications in echo-client and
echo-server in net tools. echo-server closes the client connection.
poll(fds, nfds, 0) call returns "> 0" and error value set to 0. But
send failed with return value -ve and error value set to ESHUTDOWN.
That sounds *about* right. Except that POSIX requires EPIPE to be
returned trying to write to a socket with underlying connection closed.
Or to be more exact, with the quote
(https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html):

-------
[EPIPE]
The socket is shut down for writing, or the socket is
connection-mode and is no longer connected. In the latter case, and if
the socket is of type SOCK_STREAM or SOCK_SEQPACKET and the
MSG_NOSIGNAL flag is not set, the SIGPIPE signal is generated to the
calling thread.
-------

So, if we return ESHUTDOWN, we should change that to EPIPE.


If your mail trails to the ultimate question of "how to detect
peer-closed socket if we called poll with POLLOUT?", then to keep it
short:

a) Hmm, I don't have an answer right away, though I bet I used to
consider it (likely outside Zephyr context).
b) I bet that's where POLLHUP return status kicks in.
c) In all cases like that, where we can't "extract" normative behavior
description from POSIX, we should check and follow the behavior of a
well-know implementation, and that's definitely Linux.


Any thoughts @rlubos <https://github.com/rlubos> @pfalcon
<https://github.com/pfalcon>?
Please don't hesitate to cc: me on mails like this, I may sometimes not
check the mailing list for a few days.

Regards,

Ravi.
[]