From ba703386fd742f46f83430a7c48a9bfe53167eae Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 27 Sep 2014 13:56:35 +0100 Subject: [PATCH] fds: Make many fds nonblocking 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 --- log.c | 3 +++ process.c | 1 + slip.c | 33 ++++++++++++++++++++++++++------- tun.c | 2 ++ util.h | 3 +++ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/log.c b/log.c index 3748f91..cbe4a85 100644 --- 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); } diff --git a/process.c b/process.c index 12e2caa..a15e3a6 100644 --- 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 --- 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 --- 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 --- 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 */ -- 2.30.2