chiark / gitweb /
fds: Make many fds nonblocking
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 27 Sep 2014 12:56:35 +0000 (13:56 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 21 Oct 2014 00:06:55 +0000 (01:06 +0100)
Introduce iswouldblock to cope with POSIX not specifying which of
EAGAIN or EWOULDBLOCK you get).  In various subsystems, make more fds
nonblocking and handle errors appropriately.  Specifically:

* Logging self-pipe reading end.
* Signal self-pipe reading end.
* SLIP both ends.  Fixing the writing end involves breaking out a new
  function slip_write.  We have to set these nonblocking after reading
  the confiramation byte.
* tun's network interface fd.

In various of these we add code to handle EINTR, too.

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

diff --git a/log.c b/log.c
index 3748f91..cbe4a85 100644 (file)
--- a/log.c
+++ b/log.c
@@ -579,6 +579,7 @@ static void log_from_fd_afterpoll(void *sst, struct pollfd *fds, int nfds)
                    i=-1;
                }
            }
+       } else if (errno==EINTR || iswouldblock(errno)) {
        } else {
            Message(M_WARNING,"log_from_fd: %s\n",strerror(errno));
            st->finished=True;
@@ -598,6 +599,8 @@ void log_from_fd(int fd, cstring_t prefix, struct log_if *log)
     st->i=0;
     st->finished=False;
 
+    setnonblock(st->fd);
+
     register_for_poll(st,log_from_fd_beforepoll,log_from_fd_afterpoll,
                      prefix);
 }
index 12e2caa..a15e3a6 100644 (file)
--- a/process.c
+++ b/process.c
@@ -302,6 +302,7 @@ void start_signal_handling(void)
     spw=p[1];
     spr=p[0];
     setnonblock(spw);
+    setnonblock(spr);
 
     register_for_poll(NULL,signal_beforepoll,signal_afterpoll,"signal");
     signal_handling=True;
diff --git a/slip.c b/slip.c
index 3f7935a..4c0cac1 100644 (file)
--- a/slip.c
+++ b/slip.c
@@ -31,6 +31,27 @@ struct slip {
 
 /* Generic SLIP mangling code */
 
+static void slip_write(int fd, const uint8_t *p, size_t l)
+{
+    while (l) {
+       ssize_t written=write(fd,p,l);
+       if (written<0) {
+           if (errno==EINTR) {
+               continue;
+           } else if (iswouldblock(errno)) {
+               lg_perror(0,"slip",0,M_ERR,errno,"write() (packet(s) lost)");
+               return;
+           } else {
+               fatal_perror("slip_stuff: write()");
+           }
+       }
+       assert(written>0);
+       assert((size_t)written<=l);
+       p+=written;
+       l-=written;
+    }
+}
+
 static void slip_stuff(struct slip *st, struct buffer_if *buf, int fd)
 {
     uint8_t txbuf[DEFAULT_BUFSIZE];
@@ -56,16 +77,12 @@ static void slip_stuff(struct slip *st, struct buffer_if *buf, int fd)
            break;
        }
        if ((j+2)>DEFAULT_BUFSIZE) {
-           if (write(fd,txbuf,j)<0) {
-               fatal_perror("slip_stuff: write()");
-           }
+           slip_write(fd,txbuf,j);
            j=0;
        }
     }
     txbuf[j++]=SLIP_END;
-    if (write(fd,txbuf,j)<0) {
-       fatal_perror("slip_stuff: write()");
-    }
+    slip_write(fd,txbuf,j);
     BUF_FREE(buf);
 }
 
@@ -195,7 +212,7 @@ static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds)
     if (fds[1].revents&POLLIN) {
        l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE);
        if (l<0) {
-           if (errno!=EINTR)
+           if (errno!=EINTR && !iswouldblock(errno))
                fatal_perror("%s: userv_afterpoll: read(rxfd)",
                             st->slip.nl.name);
        } else if (l==0) {
@@ -366,6 +383,8 @@ static void userv_invoke_userv(struct userv *st)
                  st->slip.nl.name,confirm);
        }
     }
+    setnonblock(st->txfd);
+    setnonblock(st->rxfd);
 }
 
 static void userv_kill_userv(struct userv *st)
diff --git a/tun.c b/tun.c
index 6ecde61..2c84ed0 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -118,6 +118,7 @@ static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds)
        buffer_init(st->buff,calculate_max_start_pad());
        l=read(st->fd, st->buff->start, buf_remaining_space(st->buff));
        if (l<0) {
+           if (errno==EINTR || iswouldblock(errno)) return;
            fatal_perror("tun_afterpoll: read()");
        }
        if (l==0) {
@@ -353,6 +354,7 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
        our networks. */
 
     setcloexec(st->fd);
+    setnonblock(st->fd);
 
     hostaddr=ipaddr_to_string(st->nl.local_address);
     secnetaddr=ipaddr_to_string(st->nl.secnet_address);
diff --git a/util.h b/util.h
index 33b2b2b..c52c5b3 100644 (file)
--- a/util.h
+++ b/util.h
@@ -95,4 +95,7 @@ void string_item_to_iaddr(const item_t *item, uint16_t port, union iaddr *ia,
 #define MAX(a,b) MINMAX((a),(b),>)
 #define MIN(a,b) MINMAX((a),(b),<)
 
+static inline bool_t iswouldblock(int e)
+    { return e==EWOULDBLOCK || e==EAGAIN; }
+
 #endif /* util_h */