poll: Introduce and use BEFOREPOLL_WANT_FDS
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 20 Sep 2014 16:52:14 +0000 (17:52 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 6 Oct 2014 16:53:13 +0000 (17:53 +0100)
This helper macro provides a convenient implementation of the
beforepoll_fn interface for *nfds_io.  Use it everywhere.

This produces one bugfix: log_from_fd_beforepoll would fail to set
*nfds_io if it was finished,

This also arranges for many beforepoll callbacks to actually fail
properly with ERANGE if there is not enough space.  Previously they
would blithely write the next fd entry or two.  In practice the
provided fd array never runs out in the current code, so in these
cases we are just fixing latent bugs.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
log.c
process.c
secnet.h
site.c
slip.c
tun.c
udp.c

diff --git a/log.c b/log.c
index 326a891..95f01b6 100644 (file)
--- a/log.c
+++ b/log.c
@@ -485,9 +485,11 @@ static int log_from_fd_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
 {
     struct fdlog *st=sst;
     if (!st->finished) {
-       *nfds_io=1;
+       BEFOREPOLL_WANT_FDS(1);
        fds[0].fd=st->fd;
        fds[0].events=POLLIN;
+    } else {
+       BEFOREPOLL_WANT_FDS(0);
     }
     return 0;
 }
index 6468315..78d6536 100644 (file)
--- a/process.c
+++ b/process.c
@@ -183,11 +183,7 @@ static beforepoll_fn signal_beforepoll;
 static int signal_beforepoll(void *st, struct pollfd *fds, int *nfds_io,
                             int *timeout_io)
 {
-    if (*nfds_io<1) {
-       *nfds_io=1;
-       return ERANGE;
-    }
-    *nfds_io=1;
+    BEFOREPOLL_WANT_FDS(1);
     fds[0].fd=spr;
     fds[0].events=POLLIN;
     return 0;
index 629851b..0e2e1f7 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -13,6 +13,7 @@
 #include <assert.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -200,6 +201,16 @@ typedef int beforepoll_fn(void *st, struct pollfd *fds, int *nfds_io,
                          int *timeout_io);
 typedef void afterpoll_fn(void *st, struct pollfd *fds, int nfds);
 
+/* void BEFOREPOLL_WANT_FDS(int want);
+ *   Expects: int *nfds_io;
+ *   Can perform non-local exit.
+ * Checks whether there is space for want fds.  If so, sets *nfds_io.
+ * If not, sets *nfds_io and returns. */
+#define BEFOREPOLL_WANT_FDS(want) do{                          \
+    if (*nfds_io<(want)) { *nfds_io=(want); return ERANGE; }   \
+    *nfds_io=(want);                                           \
+  }while(0)
+
 /* Register interest in the main loop of the program. Before a call
    to poll() your supplied beforepoll function will be called. After
    the call to poll() the supplied afterpoll function will be called.
diff --git a/site.c b/site.c
index d0755da..abbaa1e 100644 (file)
--- a/site.c
+++ b/site.c
@@ -1600,7 +1600,7 @@ static int site_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
 {
     struct site *st=sst;
 
-    *nfds_io=0; /* We don't use any file descriptors */
+    BEFOREPOLL_WANT_FDS(0); /* We don't use any file descriptors */
     st->now=*now;
 
     /* Work out when our next timeout is. The earlier of 'timeout' or
diff --git a/slip.c b/slip.c
index d8b32d8..1a60f40 100644 (file)
--- a/slip.c
+++ b/slip.c
@@ -170,13 +170,13 @@ static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
     struct userv *st=sst;
 
     if (st->rxfd!=-1) {
-       *nfds_io=2;
+       BEFOREPOLL_WANT_FDS(2);
        fds[0].fd=st->txfd;
        fds[0].events=0; /* Might want to pick up POLLOUT sometime */
        fds[1].fd=st->rxfd;
        fds[1].events=POLLIN;
     } else {
-       *nfds_io=0;
+       BEFOREPOLL_WANT_FDS(0);
     }
     return 0;
 }
diff --git a/tun.c b/tun.c
index 9ef3a9d..102a24c 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -98,7 +98,7 @@ static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
                          int *timeout_io)
 {
     struct tun *st=sst;
-    *nfds_io=1;
+    BEFOREPOLL_WANT_FDS(1);
     fds[0].fd=st->fd;
     fds[0].events=POLLIN;
     return 0;
diff --git a/udp.c b/udp.c
index 8ae5671..98da30d 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -87,11 +87,7 @@ static int udp_beforepoll(void *state, struct pollfd *fds, int *nfds_io,
 {
     int i;
     struct udp *st=state;
-    if (*nfds_io<st->n_socks) {
-       *nfds_io=st->n_socks;
-       return ERANGE;
-    }
-    *nfds_io=st->n_socks;
+    BEFOREPOLL_WANT_FDS(st->n_socks);
     for (i=0; i<st->n_socks; i++) {
        fds[i].fd=st->socks[i].fd;
        fds[i].events=POLLIN;