summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2015-03-11 21:36:30 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2015-03-11 21:36:30 +0000
commitff841ebf5a5d6864ff48571f607c32ce80dbb75a (patch)
tree027985142b90373268a5aca31c0a74874a1c92cd /src/util.c
parent360f2513ab12a9bf1e262d388dd2ea8a566590a3 (diff)
downloaddnsmasq-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.c63
1 files changed, 36 insertions, 27 deletions
diff --git a/src/util.c b/src/util.c
index 91d0241..648bc4d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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;
}