]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- auth-load-thread, put create_socketpair and sock_poll_timeout into
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 26 Jun 2026 13:22:08 +0000 (15:22 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 26 Jun 2026 13:22:08 +0000 (15:22 +0200)
  util/net_help.h

daemon/remote.c
util/net_help.c
util/net_help.h

index 720f0daab4f1898a65f88f92d40e4a10df18d363..8d424520c4d728572dedca7f49bcdb82aa83956e 100644 (file)
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
 
 /* just for portability */
 #ifdef SQ
@@ -4354,92 +4351,6 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
        return 0;
 }
 
-/**
- * This routine polls a socket for readiness.
- * @param fd: file descriptor, -1 uses no fd for a timer only.
- * @param timeout: time in msec to wait. 0 means nonblocking test,
- *     -1 waits blocking for events.
- * @param pollin: check for input event.
- * @param pollout: check for output event.
- * @param event: output variable, set to true if the event happens.
- *     It is false if there was an error or timeout.
- * @return false is system call failure, also logged.
- */
-static int
-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;
-               if(++loopcount > IPC_LOOP_MAX) {
-                       log_err("sock_poll_timeout: loop");
-                       if(event)
-                               *event = 0;
-                       return 0;
-               }
-               if(fd == -1) {
-                       fds = NULL;
-                       nfds = 0;
-               } else {
-                       fds = &p;
-                       nfds = 1;
-                       memset(&p, 0, sizeof(p));
-                       p.fd = fd;
-#ifndef USE_WINSOCK
-                       p.events = POLLERR
-                               | POLLHUP
-                               ;
-#endif
-                       if(pollin)
-                               p.events |= POLLIN;
-                       if(pollout)
-                               p.events |= POLLOUT;
-               }
-#ifndef USE_WINSOCK
-               ret = poll(fds, nfds, timeout);
-#else
-               if(fds == NULL) {
-                       Sleep(timeout);
-                       ret = 0;
-               } else {
-                       ret = WSAPoll(fds, nfds, timeout);
-               }
-#endif
-               if(ret == -1) {
-#ifndef USE_WINSOCK
-                       if(
-                               errno == EINTR || errno == EAGAIN
-#  ifdef EWOULDBLOCK
-                               || errno == EWOULDBLOCK
-#  endif
-                       ) continue; /* Try again. */
-#endif
-                       /* 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;
-                       return 0;
-               } else if(ret == 0) {
-                       /* Timeout */
-                       if(event)
-                               *event = 0;
-                       return 1;
-               }
-               break;
-       }
-       if(event)
-               *event = 1;
-       return 1;
-}
-
 /** fast reload convert fast reload notification status to string */
 static const char*
 fr_notification_to_string(enum fast_reload_notification status)
@@ -6969,286 +6880,6 @@ done_error:
 }
 #endif /* !THREADS_DISABLED */
 
-/** create a socketpair for bidirectional communication, false on failure */
-static int
-create_socketpair(int* pair, struct ub_randstate* rand)
-{
-#ifndef USE_WINSOCK
-       if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
-               log_err("socketpair: %s", strerror(errno));
-               return 0;
-       }
-       (void)rand;
-#else
-       struct sockaddr_in addr, baddr, accaddr, connaddr;
-       socklen_t baddrlen, accaddrlen, connaddrlen;
-       uint8_t localhost[] = {127, 0, 0, 1};
-       uint8_t nonce[16], recvnonce[16];
-       size_t i;
-       int lst, pollin_event, bcount, loopcount;
-       int connect_poll_timeout = 200; /* msec to wait for connection */
-       ssize_t ret;
-       pair[0] = -1;
-       pair[1] = -1;
-       for(i=0; i<sizeof(nonce); i++) {
-               nonce[i] = ub_random_max(rand, 256);
-       }
-       lst = socket(AF_INET, SOCK_STREAM, 0);
-       if(lst == -1) {
-               log_err("create_socketpair: socket: %s", sock_strerror(errno));
-               return 0;
-       }
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_port = 0;
-       memcpy(&addr.sin_addr, localhost, 4);
-       if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
-               == -1) {
-               log_err("create socketpair: bind: %s", sock_strerror(errno));
-               sock_close(lst);
-               return 0;
-       }
-       if(listen(lst, 12) == -1) {
-               log_err("create socketpair: listen: %s", sock_strerror(errno));
-               sock_close(lst);
-               return 0;
-       }
-
-       pair[1] = socket(AF_INET, SOCK_STREAM, 0);
-       if(pair[1] == -1) {
-               log_err("create socketpair: socket: %s", sock_strerror(errno));
-               sock_close(lst);
-               return 0;
-       }
-       baddrlen = (socklen_t)sizeof(baddr);
-       if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
-               log_err("create socketpair: getsockname: %s",
-                       sock_strerror(errno));
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       if(baddrlen > (socklen_t)sizeof(baddr)) {
-               log_err("create socketpair: getsockname returned addr too big");
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       /* the socket is blocking */
-       if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
-               log_err("create socketpair: connect: %s",
-                       sock_strerror(errno));
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
-               log_err("create socketpair: poll for accept failed: %s",
-                       sock_strerror(errno));
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       if(!pollin_event) {
-               log_err("create socketpair: poll timeout for accept");
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       accaddrlen = (socklen_t)sizeof(accaddr);
-       pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
-       if(pair[0] == -1) {
-               log_err("create socketpair: accept: %s", sock_strerror(errno));
-               sock_close(lst);
-               sock_close(pair[1]);
-               pair[1] = -1;
-               return 0;
-       }
-       if(accaddrlen > (socklen_t)sizeof(accaddr)) {
-               log_err("create socketpair: accept returned addr too big");
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       if(accaddr.sin_family != AF_INET ||
-          memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
-               log_err("create socketpair: accept from wrong address");
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       connaddrlen = (socklen_t)sizeof(connaddr);
-       if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
-               == -1) {
-               log_err("create socketpair: getsockname connectedaddr: %s",
-                       sock_strerror(errno));
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       if(connaddrlen > (socklen_t)sizeof(connaddr)) {
-               log_err("create socketpair: getsockname connectedaddr returned addr too big");
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       if(connaddr.sin_family != AF_INET ||
-          memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
-               log_err("create socketpair: getsockname connectedaddr returned wrong address");
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       if(accaddr.sin_port != connaddr.sin_port) {
-               log_err("create socketpair: accept from wrong port");
-               sock_close(lst);
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       sock_close(lst);
-
-       loopcount = 0;
-       bcount = 0;
-       while(1) {
-               if(++loopcount > IPC_LOOP_MAX) {
-                       log_err("create socketpair: send failed due to loop");
-                       sock_close(pair[0]);
-                       sock_close(pair[1]);
-                       pair[0] = -1;
-                       pair[1] = -1;
-                       return 0;
-               }
-               ret = send(pair[1], (void*)(nonce+bcount),
-                       sizeof(nonce)-bcount, 0);
-               if(ret == -1) {
-                       if(
-#ifndef USE_WINSOCK
-                               errno == EINTR || errno == EAGAIN
-#  ifdef EWOULDBLOCK
-                               || errno == EWOULDBLOCK
-#  endif
-#else
-                               WSAGetLastError() == WSAEINTR ||
-                               WSAGetLastError() == WSAEINPROGRESS ||
-                               WSAGetLastError() == WSAEWOULDBLOCK
-#endif
-                               )
-                               continue; /* Try again. */
-                       log_err("create socketpair: send: %s", sock_strerror(errno));
-                       sock_close(pair[0]);
-                       sock_close(pair[1]);
-                       pair[0] = -1;
-                       pair[1] = -1;
-                       return 0;
-               } else if(ret+(ssize_t)bcount != sizeof(nonce)) {
-                       bcount += ret;
-                       if((size_t)bcount < sizeof(nonce))
-                               continue;
-               }
-               break;
-       }
-
-       if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
-               log_err("create socketpair: poll failed: %s",
-                       sock_strerror(errno));
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-       if(!pollin_event) {
-               log_err("create socketpair: poll timeout for recv");
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-
-       loopcount = 0;
-       bcount = 0;
-       while(1) {
-               if(++loopcount > IPC_LOOP_MAX) {
-                       log_err("create socketpair: recv failed due to loop");
-                       sock_close(pair[0]);
-                       sock_close(pair[1]);
-                       pair[0] = -1;
-                       pair[1] = -1;
-                       return 0;
-               }
-               ret = recv(pair[0], (void*)(recvnonce+bcount),
-                       sizeof(nonce)-bcount, 0);
-               if(ret == -1) {
-                       if(
-#ifndef USE_WINSOCK
-                               errno == EINTR || errno == EAGAIN
-#  ifdef EWOULDBLOCK
-                               || errno == EWOULDBLOCK
-#  endif
-#else
-                               WSAGetLastError() == WSAEINTR ||
-                               WSAGetLastError() == WSAEINPROGRESS ||
-                               WSAGetLastError() == WSAEWOULDBLOCK
-#endif
-                               )
-                               continue; /* Try again. */
-                       log_err("create socketpair: recv: %s", sock_strerror(errno));
-                       sock_close(pair[0]);
-                       sock_close(pair[1]);
-                       pair[0] = -1;
-                       pair[1] = -1;
-                       return 0;
-               } else if(ret == 0) {
-                       log_err("create socketpair: stream closed");
-                       sock_close(pair[0]);
-                       sock_close(pair[1]);
-                       pair[0] = -1;
-                       pair[1] = -1;
-                       return 0;
-               } else if(ret+(ssize_t)bcount != sizeof(nonce)) {
-                       bcount += ret;
-                       if((size_t)bcount < sizeof(nonce))
-                               continue;
-               }
-               break;
-       }
-
-       if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
-               log_err("create socketpair: recv wrong nonce");
-               sock_close(pair[0]);
-               sock_close(pair[1]);
-               pair[0] = -1;
-               pair[1] = -1;
-               return 0;
-       }
-#endif
-       return 1;
-}
-
 /** fast reload thread. setup the thread info */
 static int
 fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
index 2bf4f47edff76fad1308dfb75d0fbf446b5cfae4..f61bbed46bf35f967daf3707c2b6e04b13ec2f1d 100644 (file)
@@ -58,6 +58,9 @@
 #include "sldns/wire2str.h"
 #include "sldns/str2wire.h"
 #include <fcntl.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
 #ifdef HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
 #include <openssl/evp.h>
@@ -92,6 +95,9 @@ int RRSET_ROUNDROBIN = 1;
 /** log tag queries with name instead of 'info' for filtering */
 int LOG_TAG_QUERYREPLY = 0;
 
+/** What number of loop iterations is too much for sock poll retries */
+#define SOCK_POLL_LOOP_MAX 200
+
 #ifdef HAVE_SSL
 static struct tls_session_ticket_key {
        unsigned char *key_name;
@@ -2083,3 +2089,357 @@ hex_pton(const char* src, uint8_t* target, size_t targsize)
        }
        return t-target;
 }
+
+int
+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;
+               if(++loopcount > SOCK_POLL_LOOP_MAX) {
+                       log_err("sock_poll_timeout: loop");
+                       if(event)
+                               *event = 0;
+                       return 0;
+               }
+               if(fd == -1) {
+                       fds = NULL;
+                       nfds = 0;
+               } else {
+                       fds = &p;
+                       nfds = 1;
+                       memset(&p, 0, sizeof(p));
+                       p.fd = fd;
+#ifndef USE_WINSOCK
+                       p.events = POLLERR
+                               | POLLHUP
+                               ;
+#endif
+                       if(pollin)
+                               p.events |= POLLIN;
+                       if(pollout)
+                               p.events |= POLLOUT;
+               }
+#ifndef USE_WINSOCK
+               ret = poll(fds, nfds, timeout);
+#else
+               if(fds == NULL) {
+                       Sleep(timeout);
+                       ret = 0;
+               } else {
+                       ret = WSAPoll(fds, nfds, timeout);
+               }
+#endif
+               if(ret == -1) {
+#ifndef USE_WINSOCK
+                       if(
+                               errno == EINTR || errno == EAGAIN
+#  ifdef EWOULDBLOCK
+                               || errno == EWOULDBLOCK
+#  endif
+                       ) continue; /* Try again. */
+#endif
+                       /* 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;
+                       return 0;
+               } else if(ret == 0) {
+                       /* Timeout */
+                       if(event)
+                               *event = 0;
+                       return 1;
+               }
+               break;
+       }
+       if(event)
+               *event = 1;
+       return 1;
+}
+
+int
+create_socketpair(int* pair, struct ub_randstate* rand)
+{
+#ifndef USE_WINSOCK
+       if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+               log_err("socketpair: %s", strerror(errno));
+               return 0;
+       }
+       (void)rand;
+#else
+       struct sockaddr_in addr, baddr, accaddr, connaddr;
+       socklen_t baddrlen, accaddrlen, connaddrlen;
+       uint8_t localhost[] = {127, 0, 0, 1};
+       uint8_t nonce[16], recvnonce[16];
+       size_t i;
+       int lst, pollin_event, bcount, loopcount;
+       int connect_poll_timeout = 200; /* msec to wait for connection */
+       ssize_t ret;
+       pair[0] = -1;
+       pair[1] = -1;
+       for(i=0; i<sizeof(nonce); i++) {
+               nonce[i] = ub_random_max(rand, 256);
+       }
+       lst = socket(AF_INET, SOCK_STREAM, 0);
+       if(lst == -1) {
+               log_err("create_socketpair: socket: %s", sock_strerror(errno));
+               return 0;
+       }
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = 0;
+       memcpy(&addr.sin_addr, localhost, 4);
+       if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
+               == -1) {
+               log_err("create socketpair: bind: %s", sock_strerror(errno));
+               sock_close(lst);
+               return 0;
+       }
+       if(listen(lst, 12) == -1) {
+               log_err("create socketpair: listen: %s", sock_strerror(errno));
+               sock_close(lst);
+               return 0;
+       }
+
+       pair[1] = socket(AF_INET, SOCK_STREAM, 0);
+       if(pair[1] == -1) {
+               log_err("create socketpair: socket: %s", sock_strerror(errno));
+               sock_close(lst);
+               return 0;
+       }
+       baddrlen = (socklen_t)sizeof(baddr);
+       if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
+               log_err("create socketpair: getsockname: %s",
+                       sock_strerror(errno));
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       if(baddrlen > (socklen_t)sizeof(baddr)) {
+               log_err("create socketpair: getsockname returned addr too big");
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       /* the socket is blocking */
+       if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
+               log_err("create socketpair: connect: %s",
+                       sock_strerror(errno));
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
+               log_err("create socketpair: poll for accept failed: %s",
+                       sock_strerror(errno));
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       if(!pollin_event) {
+               log_err("create socketpair: poll timeout for accept");
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       accaddrlen = (socklen_t)sizeof(accaddr);
+       pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
+       if(pair[0] == -1) {
+               log_err("create socketpair: accept: %s", sock_strerror(errno));
+               sock_close(lst);
+               sock_close(pair[1]);
+               pair[1] = -1;
+               return 0;
+       }
+       if(accaddrlen > (socklen_t)sizeof(accaddr)) {
+               log_err("create socketpair: accept returned addr too big");
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       if(accaddr.sin_family != AF_INET ||
+          memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
+               log_err("create socketpair: accept from wrong address");
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       connaddrlen = (socklen_t)sizeof(connaddr);
+       if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
+               == -1) {
+               log_err("create socketpair: getsockname connectedaddr: %s",
+                       sock_strerror(errno));
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       if(connaddrlen > (socklen_t)sizeof(connaddr)) {
+               log_err("create socketpair: getsockname connectedaddr returned addr too big");
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       if(connaddr.sin_family != AF_INET ||
+          memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
+               log_err("create socketpair: getsockname connectedaddr returned wrong address");
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       if(accaddr.sin_port != connaddr.sin_port) {
+               log_err("create socketpair: accept from wrong port");
+               sock_close(lst);
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       sock_close(lst);
+
+       loopcount = 0;
+       bcount = 0;
+       while(1) {
+               if(++loopcount > SOCK_POLL_LOOP_MAX) {
+                       log_err("create socketpair: send failed due to loop");
+                       sock_close(pair[0]);
+                       sock_close(pair[1]);
+                       pair[0] = -1;
+                       pair[1] = -1;
+                       return 0;
+               }
+               ret = send(pair[1], (void*)(nonce+bcount),
+                       sizeof(nonce)-bcount, 0);
+               if(ret == -1) {
+                       if(
+#ifndef USE_WINSOCK
+                               errno == EINTR || errno == EAGAIN
+#  ifdef EWOULDBLOCK
+                               || errno == EWOULDBLOCK
+#  endif
+#else
+                               WSAGetLastError() == WSAEINTR ||
+                               WSAGetLastError() == WSAEINPROGRESS ||
+                               WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+                               )
+                               continue; /* Try again. */
+                       log_err("create socketpair: send: %s", sock_strerror(errno));
+                       sock_close(pair[0]);
+                       sock_close(pair[1]);
+                       pair[0] = -1;
+                       pair[1] = -1;
+                       return 0;
+               } else if(ret+(ssize_t)bcount != sizeof(nonce)) {
+                       bcount += ret;
+                       if((size_t)bcount < sizeof(nonce))
+                               continue;
+               }
+               break;
+       }
+
+       if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
+               log_err("create socketpair: poll failed: %s",
+                       sock_strerror(errno));
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+       if(!pollin_event) {
+               log_err("create socketpair: poll timeout for recv");
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+
+       loopcount = 0;
+       bcount = 0;
+       while(1) {
+               if(++loopcount > SOCK_POLL_LOOP_MAX) {
+                       log_err("create socketpair: recv failed due to loop");
+                       sock_close(pair[0]);
+                       sock_close(pair[1]);
+                       pair[0] = -1;
+                       pair[1] = -1;
+                       return 0;
+               }
+               ret = recv(pair[0], (void*)(recvnonce+bcount),
+                       sizeof(nonce)-bcount, 0);
+               if(ret == -1) {
+                       if(
+#ifndef USE_WINSOCK
+                               errno == EINTR || errno == EAGAIN
+#  ifdef EWOULDBLOCK
+                               || errno == EWOULDBLOCK
+#  endif
+#else
+                               WSAGetLastError() == WSAEINTR ||
+                               WSAGetLastError() == WSAEINPROGRESS ||
+                               WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+                               )
+                               continue; /* Try again. */
+                       log_err("create socketpair: recv: %s", sock_strerror(errno));
+                       sock_close(pair[0]);
+                       sock_close(pair[1]);
+                       pair[0] = -1;
+                       pair[1] = -1;
+                       return 0;
+               } else if(ret == 0) {
+                       log_err("create socketpair: stream closed");
+                       sock_close(pair[0]);
+                       sock_close(pair[1]);
+                       pair[0] = -1;
+                       pair[1] = -1;
+                       return 0;
+               } else if(ret+(ssize_t)bcount != sizeof(nonce)) {
+                       bcount += ret;
+                       if((size_t)bcount < sizeof(nonce))
+                               continue;
+               }
+               break;
+       }
+
+       if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
+               log_err("create socketpair: recv wrong nonce");
+               sock_close(pair[0]);
+               sock_close(pair[1]);
+               pair[0] = -1;
+               pair[1] = -1;
+               return 0;
+       }
+#endif
+       return 1;
+}
index e9f6f3516ae503aae1a131ddd1605f1eb45246c8..6bc23a08fbc6bf216f67baabb2c1b8f17513f0e4 100644 (file)
@@ -604,4 +604,20 @@ ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target,
 /** Convert hexadecimal data to binary. */
 ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize);
 
+/**
+ * This routine polls a socket for readiness.
+ * @param fd: file descriptor, -1 uses no fd for a timer only.
+ * @param timeout: time in msec to wait. 0 means nonblocking test,
+ *     -1 waits blocking for events.
+ * @param pollin: check for input event.
+ * @param pollout: check for output event.
+ * @param event: output variable, set to true if the event happens.
+ *     It is false if there was an error or timeout.
+ * @return false is system call failure, also logged.
+ */
+int sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event);
+
+/** create a socketpair for bidirectional communication, false on failure */
+int create_socketpair(int* pair, struct ub_randstate* rand);
+
 #endif /* NET_HELP_H */