diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2015-03-11 21:36:30 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2015-03-11 21:36:30 +0000 |
commit | ff841ebf5a5d6864ff48571f607c32ce80dbb75a (patch) | |
tree | 027985142b90373268a5aca31c0a74874a1c92cd /src/util.c | |
parent | 360f2513ab12a9bf1e262d388dd2ea8a566590a3 (diff) | |
download | dnsmasq-ff841ebf5a5d6864ff48571f607c32ce80dbb75a.tar.gz |
Fix boilerplate code for re-running system calls on EINTR and EAGAIN etc.
The nasty code with static variable in retry_send() which
avoids looping forever needs to be called on success of the syscall,
to reset the static variable.
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 63 |
1 files changed, 36 insertions, 27 deletions
@@ -569,17 +569,27 @@ void bump_maxfd(int fd, int *max) *max = fd; } -int retry_send(void) +/* rc is return from sendto and friends. + Return 1 if we should retry. + Set errno to zero if we succeeded. */ +int retry_send(ssize_t rc) { + static int retries = 0; + struct timespec waiter; + + if (rc != -1) + { + retries = 0; + errno = 0; + return 0; + } + /* Linux kernels can return EAGAIN in perpetuity when calling sendmsg() and the relevant interface has gone. Here we loop retrying in EAGAIN for 1 second max, to avoid this hanging dnsmasq. */ - static int retries = 0; - struct timespec waiter; - - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (errno == EAGAIN || errno == EWOULDBLOCK) { waiter.tv_sec = 0; waiter.tv_nsec = 10000; @@ -587,13 +597,13 @@ int retry_send(void) if (retries++ < 1000) return 1; } - - retries = 0; - - if (errno == EINTR) - return 1; - - return 0; + + retries = 0; + + if (errno == EINTR) + return 1; + + return 0; } int read_write(int fd, unsigned char *packet, int size, int rw) @@ -602,22 +612,21 @@ int read_write(int fd, unsigned char *packet, int size, int rw) for (done = 0; done < size; done += n) { - retry: - if (rw) - n = read(fd, &packet[done], (size_t)(size - done)); - else - n = write(fd, &packet[done], (size_t)(size - done)); - - if (n == 0) - return 0; - else if (n == -1) - { - if (retry_send() || errno == ENOMEM || errno == ENOBUFS) - goto retry; - else - return 0; - } + do { + if (rw) + n = read(fd, &packet[done], (size_t)(size - done)); + else + n = write(fd, &packet[done], (size_t)(size - done)); + + if (n == 0) + return 0; + + } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS); + + if (errno != 0) + return 0; } + return 1; } |