From 40d66380a56651751c7aa8fc46aca4d0671243ba 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. * 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..c846b39 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) { @@ -320,6 +337,8 @@ static void userv_invoke_userv(struct userv *st) pipe_cloexec(c_stdout); st->txfd=c_stdin[1]; st->rxfd=c_stdout[0]; + setnonblock(st->rxfd); + setnonblock(st->txfd); er->in=c_stdin[0]; er->out=c_stdout[1]; 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 1693d60..a3e3e11 100644 --- a/util.h +++ b/util.h @@ -71,4 +71,7 @@ void text2iaddr(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