]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Fix WSAPoll (#1265)
authorYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Fri, 11 Apr 2025 13:05:52 +0000 (15:05 +0200)
committerYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Fri, 11 Apr 2025 13:09:07 +0000 (15:09 +0200)
* Fix calling WSAPoll.

* fast_reload: explicitly set tcp_wouldblock on Windows when there is no
  command to read from the fast_reload thread.

* For poll(), also check for ENOMEM (Linux).

* Remove ifdefs for ENOMEM.
* Some systems return EAGAIN for poll.

daemon/remote.c
util/netevent.c

index 3cf795a69943ab4f88c452d9112e976c88d337ac..89134efc92a8b0a2250ea0b62dd18232dc55833c 100644 (file)
@@ -3899,6 +3899,7 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
 {
        int loopcount = 0;
        /* Loop if the system call returns an errno to do so, like EINTR. */
+       log_assert(pollin || pollout);
        while(1) {
                struct pollfd p, *fds;
                int nfds, ret;
@@ -3916,11 +3917,11 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
                        nfds = 1;
                        memset(&p, 0, sizeof(p));
                        p.fd = fd;
-                       p.events = POLLERR
 #ifndef USE_WINSOCK
+                       p.events = POLLERR
                                | POLLHUP
-#endif
                                ;
+#endif
                        if(pollin)
                                p.events |= POLLIN;
                        if(pollout)
@@ -3937,19 +3938,20 @@ sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
                }
 #endif
                if(ret == -1) {
-                       if(
 #ifndef USE_WINSOCK
+                       if(
                                errno == EINTR || errno == EAGAIN
 #  ifdef EWOULDBLOCK
                                || errno == EWOULDBLOCK
 #  endif
-#else
-                               WSAGetLastError() == WSAEINTR ||
-                               WSAGetLastError() == WSAEINPROGRESS ||
-                               WSAGetLastError() == WSAEWOULDBLOCK
+                       ) continue; /* Try again. */
 #endif
-                               )
-                               continue; /* Try again. */
+                       /* For WSAPoll we only get errors here:
+                        * o WSAENETDOWN
+                        * o WSAEFAULT
+                        * o WSAEINVAL
+                        * o WSAENOBUFS
+                        */
                        log_err("poll: %s", sock_strerror(errno));
                        if(event)
                                *event = 0;
@@ -7398,11 +7400,17 @@ fr_main_handle_cmd(struct fast_reload_thread* fr)
 #  endif
 #else
                        WSAGetLastError() == WSAEINTR ||
-                       WSAGetLastError() == WSAEINPROGRESS ||
-                       WSAGetLastError() == WSAEWOULDBLOCK
+                       WSAGetLastError() == WSAEINPROGRESS
 #endif
                        )
                        return; /* Continue later. */
+#ifdef USE_WINSOCK
+               if(WSAGetLastError() == WSAEWOULDBLOCK) {
+                       ub_winsock_tcp_wouldblock(fr->service_event,
+                               UB_EV_READ);
+                       return; /* Continue later. */
+               }
+#endif
                log_err("read cmd from fast reload thread, recv: %s",
                        sock_strerror(errno));
                return;
@@ -7434,10 +7442,23 @@ fr_check_cmd_from_thread(struct fast_reload_thread* fr)
                if(!sock_poll_timeout(fr->commpair[0], 0, 1, 0, &inevent)) {
                        log_err("check for cmd from fast reload thread: "
                                "poll failed");
+#ifdef USE_WINSOCK
+                       if(worker->daemon->fast_reload_thread)
+                               ub_winsock_tcp_wouldblock(worker->daemon->
+                                       fast_reload_thread->service_event,
+                                       UB_EV_READ);
+#endif
                        return;
                }
-               if(!inevent)
+               if(!inevent) {
+#ifdef USE_WINSOCK
+                       if(worker->daemon->fast_reload_thread)
+                               ub_winsock_tcp_wouldblock(worker->daemon->
+                                       fast_reload_thread->service_event,
+                                       UB_EV_READ);
+#endif
                        return;
+               }
                fr_main_handle_cmd(fr);
        }
 }
index f9dff1f9aadb33b11a737e0e6eb8f04fdcfec021..0d0fff429c038a83eafd0716868efb3e758f2bfb 100644 (file)
@@ -456,9 +456,9 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
                                int pret;
                                memset(&p, 0, sizeof(p));
                                p.fd = c->fd;
-                               p.events = POLLOUT | POLLERR
+                               p.events = POLLOUT
 #ifndef USE_WINSOCK
-                                       | POLLHUP
+                                       | POLLERR | POLLHUP
 #endif
                                        ;
 #  ifndef USE_WINSOCK
@@ -483,7 +483,7 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
 #  ifdef EWOULDBLOCK
                                        errno != EWOULDBLOCK &&
 #  endif
-                                       errno != ENOBUFS
+                                       errno != ENOMEM && errno != ENOBUFS
 #else
                                        WSAGetLastError() != WSAEINPROGRESS &&
                                        WSAGetLastError() != WSAEINTR &&
@@ -496,15 +496,19 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
                                        return 0;
                                } else if((pret < 0 &&
 #ifndef USE_WINSOCK
-                                       errno == ENOBUFS
+                                       ( errno == ENOBUFS  /* Maybe some systems */
+                                       || errno == ENOMEM  /* Linux */
+                                       || errno == EAGAIN)  /* Macos, solaris, openbsd */
 #else
                                        WSAGetLastError() == WSAENOBUFS
 #endif
                                        ) || (send_nobufs && retries > 0)) {
-                                       /* ENOBUFS, and poll returned without
+                                       /* ENOBUFS/ENOMEM/EAGAIN, and poll
+                                        * returned without
                                         * a timeout. Or the retried send call
-                                        * returned ENOBUFS. It is good to
-                                        * wait a bit for the error to clear. */
+                                        * returned ENOBUFS/ENOMEM/EAGAIN.
+                                        * It is good to wait a bit for the
+                                        * error to clear. */
                                        /* The timeout is 20*(2^(retries+1)),
                                         * it increases exponentially, starting
                                         * at 40 msec. After 5 tries, 1240 msec
@@ -517,18 +521,15 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
                                        Sleep((SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
                                        pret = 0;
 #endif
-                                       if(pret < 0 &&
+                                       if(pret < 0
 #ifndef USE_WINSOCK
-                                               errno != EAGAIN && errno != EINTR &&
+                                               && errno != EAGAIN && errno != EINTR &&
 #  ifdef EWOULDBLOCK
                                                errno != EWOULDBLOCK &&
 #  endif
-                                               errno != ENOBUFS
+                                               errno != ENOMEM && errno != ENOBUFS
 #else
-                                               WSAGetLastError() != WSAEINPROGRESS &&
-                                               WSAGetLastError() != WSAEINTR &&
-                                               WSAGetLastError() != WSAENOBUFS &&
-                                               WSAGetLastError() != WSAEWOULDBLOCK
+                                               /* Sleep does not error */
 #endif
                                        ) {
                                                log_err("poll udp out timer failed: %s",
@@ -770,9 +771,9 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
                                int pret;
                                memset(&p, 0, sizeof(p));
                                p.fd = c->fd;
-                               p.events = POLLOUT | POLLERR
+                               p.events = POLLOUT
 #ifndef USE_WINSOCK
-                                       | POLLHUP
+                                       | POLLERR | POLLHUP
 #endif
                                        ;
 #  ifndef USE_WINSOCK
@@ -797,7 +798,7 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
 #  ifdef EWOULDBLOCK
                                        errno != EWOULDBLOCK &&
 #  endif
-                                       errno != ENOBUFS
+                                       errno != ENOMEM && errno != ENOBUFS
 #else
                                        WSAGetLastError() != WSAEINPROGRESS &&
                                        WSAGetLastError() != WSAEINTR &&
@@ -810,15 +811,19 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
                                        return 0;
                                } else if((pret < 0 &&
 #ifndef USE_WINSOCK
-                                       errno == ENOBUFS
+                                       ( errno == ENOBUFS  /* Maybe some systems */
+                                       || errno == ENOMEM  /* Linux */
+                                       || errno == EAGAIN)  /* Macos, solaris, openbsd */
 #else
                                        WSAGetLastError() == WSAENOBUFS
 #endif
                                        ) || (send_nobufs && retries > 0)) {
-                                       /* ENOBUFS, and poll returned without
+                                       /* ENOBUFS/ENOMEM/EAGAIN, and poll
+                                        * returned without
                                         * a timeout. Or the retried send call
-                                        * returned ENOBUFS. It is good to
-                                        * wait a bit for the error to clear. */
+                                        * returned ENOBUFS/ENOMEM/EAGAIN.
+                                        * It is good to wait a bit for the
+                                        * error to clear. */
                                        /* The timeout is 20*(2^(retries+1)),
                                         * it increases exponentially, starting
                                         * at 40 msec. After 5 tries, 1240 msec
@@ -831,18 +836,15 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
                                        Sleep((SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
                                        pret = 0;
 #endif
-                                       if(pret < 0 &&
+                                       if(pret < 0
 #ifndef USE_WINSOCK
-                                               errno != EAGAIN && errno != EINTR &&
+                                               && errno != EAGAIN && errno != EINTR &&
 #  ifdef EWOULDBLOCK
                                                errno != EWOULDBLOCK &&
 #  endif
-                                               errno != ENOBUFS
-#else
-                                               WSAGetLastError() != WSAEINPROGRESS &&
-                                               WSAGetLastError() != WSAEINTR &&
-                                               WSAGetLastError() != WSAENOBUFS &&
-                                               WSAGetLastError() != WSAEWOULDBLOCK
+                                               errno != ENOMEM && errno != ENOBUFS
+#else  /* USE_WINSOCK */
+                                               /* Sleep does not error */
 #endif
                                        ) {
                                                log_err("poll udp out timer failed: %s",