drivers: net: nsos: update unwatched file descriptor with poll()
zsock_poll_internal() iterates through all fds to call
ZFD_IOCTL_POLL_UPDATE on them. In cases when -EAGAIN is returned from one
of such syscalls (which happens for example for TLS sockets when in the
middle of a TLS handshake) whole fds array is iterated once again. This
means that ZFD_IOCTL_POLL_UPDATE can be called more than once for a single
preceding ZFD_IOCTL_POLL_PREPARE operation. This resulted in error in
nsos_adapt_poll_remove() call, which was not intended to be called twice.
In case ZFD_IOCTL_POLL_UPDATE is called second time, update 'revents' just
by calling poll() syscall on the host (Linux) side with 0 timeout.
Signed-off-by: Marcin Niestroj <m.niestroj@emb.dev>
diff --git a/drivers/net/nsos.h b/drivers/net/nsos.h
index 14b4951..e7ece3d 100644
--- a/drivers/net/nsos.h
+++ b/drivers/net/nsos.h
@@ -113,6 +113,7 @@
void nsos_adapt_poll_add(struct nsos_mid_pollfd *pollfd);
void nsos_adapt_poll_remove(struct nsos_mid_pollfd *pollfd);
+void nsos_adapt_poll_update(struct nsos_mid_pollfd *pollfd);
int nsos_adapt_fcntl_getfl(int fd);
int nsos_adapt_fcntl_setfl(int fd, int flags);
diff --git a/drivers/net/nsos_adapt.c b/drivers/net/nsos_adapt.c
index 9c8184b..5f44b33 100644
--- a/drivers/net/nsos_adapt.c
+++ b/drivers/net/nsos_adapt.c
@@ -533,6 +533,25 @@
nsos_adapt_nfds--;
}
+void nsos_adapt_poll_update(struct nsos_mid_pollfd *pollfd)
+{
+ struct pollfd fds = {
+ .fd = pollfd->fd,
+ .events = pollfd->events,
+ };
+ int ret;
+
+ ret = poll(&fds, 1, 0);
+ if (ret < 0) {
+ nsi_print_error_and_exit("error in poll(): errno=%d\n", errno);
+ return;
+ }
+
+ if (ret > 0) {
+ pollfd->revents = fds.revents;
+ }
+}
+
struct nsos_addrinfo_wrap {
struct nsos_mid_addrinfo addrinfo_mid;
struct nsos_mid_sockaddr_storage addr_storage;
diff --git a/drivers/net/nsos_sockets.c b/drivers/net/nsos_sockets.c
index 98d6c42..2e1ff45 100644
--- a/drivers/net/nsos_sockets.c
+++ b/drivers/net/nsos_sockets.c
@@ -298,6 +298,11 @@
signaled = 0;
flags = 0;
+ if (!sys_dnode_is_linked(&sock->node)) {
+ nsos_adapt_poll_update(&sock->pollfd);
+ return 0;
+ }
+
nsos_adapt_poll_remove(&sock->pollfd);
sys_dlist_remove(&sock->node);