]>
Commit | Line | Data |
---|---|---|
c6ce1e7e MT |
1 | From ff841ebf5a5d6864ff48571f607c32ce80dbb75a Mon Sep 17 00:00:00 2001 |
2 | From: Simon Kelley <simon@thekelleys.org.uk> | |
3 | Date: Wed, 11 Mar 2015 21:36:30 +0000 | |
efbd3a9a | 4 | Subject: [PATCH 58/98] Fix boilerplate code for re-running system calls on |
c6ce1e7e MT |
5 | EINTR and EAGAIN etc. |
6 | ||
7 | The nasty code with static variable in retry_send() which | |
8 | avoids looping forever needs to be called on success of the syscall, | |
9 | to reset the static variable. | |
10 | --- | |
11 | src/bpf.c | 2 +- | |
12 | src/dhcp.c | 2 +- | |
13 | src/dhcp6.c | 6 +++--- | |
14 | src/dnsmasq.c | 35 +++++++++++++++++---------------- | |
15 | src/dnsmasq.h | 2 +- | |
16 | src/forward.c | 41 ++++++++++++++++++-------------------- | |
17 | src/ipset.c | 8 ++++---- | |
18 | src/loop.c | 5 +++-- | |
19 | src/netlink.c | 8 ++++---- | |
20 | src/radv.c | 5 +++-- | |
21 | src/util.c | 63 ++++++++++++++++++++++++++++++++++------------------------- | |
22 | 11 files changed, 93 insertions(+), 84 deletions(-) | |
23 | ||
24 | diff --git a/src/bpf.c b/src/bpf.c | |
25 | index 997d87421bed..a066641f969f 100644 | |
26 | --- a/src/bpf.c | |
27 | +++ b/src/bpf.c | |
28 | @@ -359,7 +359,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len, | |
29 | iov[3].iov_base = mess; | |
30 | iov[3].iov_len = len; | |
31 | ||
32 | - while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send()); | |
33 | + while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4))); | |
34 | } | |
35 | ||
36 | #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */ | |
37 | diff --git a/src/dhcp.c b/src/dhcp.c | |
38 | index f29be9b489a7..5c3089ab94ff 100644 | |
39 | --- a/src/dhcp.c | |
40 | +++ b/src/dhcp.c | |
41 | @@ -443,7 +443,7 @@ void dhcp_packet(time_t now, int pxe_fd) | |
42 | setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index)); | |
43 | #endif | |
44 | ||
45 | - while(sendmsg(fd, &msg, 0) == -1 && retry_send()); | |
46 | + while(retry_send(sendmsg(fd, &msg, 0))); | |
47 | } | |
48 | ||
49 | /* check against secondary interface addresses */ | |
50 | diff --git a/src/dhcp6.c b/src/dhcp6.c | |
51 | index c7144f5fee7c..ee2aa5d3bf3c 100644 | |
52 | --- a/src/dhcp6.c | |
53 | +++ b/src/dhcp6.c | |
54 | @@ -225,9 +225,9 @@ void dhcp6_packet(time_t now) | |
55 | if (port != 0) | |
56 | { | |
57 | from.sin6_port = htons(port); | |
58 | - while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0), | |
59 | - 0, (struct sockaddr *)&from, sizeof(from)) == -1 && | |
60 | - retry_send()); | |
61 | + while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, | |
62 | + save_counter(0), 0, (struct sockaddr *)&from, | |
63 | + sizeof(from)))); | |
64 | } | |
65 | } | |
66 | ||
67 | diff --git a/src/dnsmasq.c b/src/dnsmasq.c | |
68 | index f3e5bcffec4f..b784951950d4 100644 | |
69 | --- a/src/dnsmasq.c | |
70 | +++ b/src/dnsmasq.c | |
71 | @@ -444,7 +444,7 @@ int main (int argc, char **argv) | |
72 | char *msg; | |
73 | ||
74 | /* close our copy of write-end */ | |
75 | - close(err_pipe[1]); | |
76 | + while (retry_send(close(err_pipe[1]))); | |
77 | ||
78 | /* check for errors after the fork */ | |
79 | if (read_event(err_pipe[0], &ev, &msg)) | |
80 | @@ -453,7 +453,7 @@ int main (int argc, char **argv) | |
81 | _exit(EC_GOOD); | |
82 | } | |
83 | ||
84 | - close(err_pipe[0]); | |
85 | + while (retry_send(close(err_pipe[0]))); | |
86 | ||
87 | /* NO calls to die() from here on. */ | |
88 | ||
89 | @@ -505,10 +505,12 @@ int main (int argc, char **argv) | |
90 | { | |
91 | if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0)) | |
92 | err = 1; | |
93 | - | |
94 | - while (!err && close(fd) == -1) | |
95 | - if (!retry_send()) | |
96 | - err = 1; | |
97 | + else | |
98 | + { | |
99 | + while (retry_send(close(fd))); | |
100 | + if (errno != 0) | |
101 | + err = 1; | |
102 | + } | |
103 | } | |
104 | ||
105 | if (err) | |
106 | @@ -813,7 +815,7 @@ int main (int argc, char **argv) | |
107 | ||
108 | /* finished start-up - release original process */ | |
109 | if (err_pipe[1] != -1) | |
110 | - close(err_pipe[1]); | |
111 | + while (retry_send(close(err_pipe[1]))); | |
112 | ||
113 | if (daemon->port != 0) | |
114 | check_servers(); | |
115 | @@ -1319,7 +1321,7 @@ static void async_event(int pipe, time_t now) | |
116 | do { | |
117 | helper_write(); | |
118 | } while (!helper_buf_empty() || do_script_run(now)); | |
119 | - close(daemon->helperfd); | |
120 | + while (retry_send(close(daemon->helperfd))); | |
121 | } | |
122 | #endif | |
123 | ||
124 | @@ -1544,7 +1546,7 @@ static void check_dns_listeners(fd_set *set, time_t now) | |
125 | ||
126 | if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1) | |
127 | { | |
128 | - close(confd); | |
129 | + while (retry_send(close(confd))); | |
130 | continue; | |
131 | } | |
132 | ||
133 | @@ -1609,7 +1611,7 @@ static void check_dns_listeners(fd_set *set, time_t now) | |
134 | if (!client_ok) | |
135 | { | |
136 | shutdown(confd, SHUT_RDWR); | |
137 | - close(confd); | |
138 | + while (retry_send(close(confd))); | |
139 | } | |
140 | #ifndef NO_FORK | |
141 | else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0) | |
142 | @@ -1624,7 +1626,7 @@ static void check_dns_listeners(fd_set *set, time_t now) | |
143 | break; | |
144 | } | |
145 | } | |
146 | - close(confd); | |
147 | + while (retry_send(close(confd))); | |
148 | ||
149 | /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */ | |
150 | daemon->log_id += TCP_MAX_QUERIES; | |
151 | @@ -1669,7 +1671,7 @@ static void check_dns_listeners(fd_set *set, time_t now) | |
152 | buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns); | |
153 | ||
154 | shutdown(confd, SHUT_RDWR); | |
155 | - close(confd); | |
156 | + while (retry_send(close(confd))); | |
157 | ||
158 | if (buff) | |
159 | free(buff); | |
160 | @@ -1678,7 +1680,7 @@ static void check_dns_listeners(fd_set *set, time_t now) | |
161 | if (s->tcpfd != -1) | |
162 | { | |
163 | shutdown(s->tcpfd, SHUT_RDWR); | |
164 | - close(s->tcpfd); | |
165 | + while (retry_send(close(s->tcpfd))); | |
166 | } | |
167 | #ifndef NO_FORK | |
168 | if (!option_bool(OPT_DEBUG)) | |
169 | @@ -1756,9 +1758,8 @@ int icmp_ping(struct in_addr addr) | |
170 | j = (j & 0xffff) + (j >> 16); | |
171 | packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j; | |
172 | ||
173 | - while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0, | |
174 | - (struct sockaddr *)&saddr, sizeof(saddr)) == -1 && | |
175 | - retry_send()); | |
176 | + while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0, | |
177 | + (struct sockaddr *)&saddr, sizeof(saddr)))); | |
178 | ||
179 | for (now = start = dnsmasq_time(); | |
180 | difftime(now, start) < (float)PING_WAIT;) | |
181 | @@ -1820,7 +1821,7 @@ int icmp_ping(struct in_addr addr) | |
182 | } | |
183 | ||
184 | #if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK) | |
185 | - close(fd); | |
186 | + while (retry_send(close(fd))); | |
187 | #else | |
188 | opt = 1; | |
189 | setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); | |
190 | diff --git a/src/dnsmasq.h b/src/dnsmasq.h | |
191 | index fc7259881358..de95d0e875e3 100644 | |
192 | --- a/src/dnsmasq.h | |
193 | +++ b/src/dnsmasq.h | |
194 | @@ -1177,7 +1177,7 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen); | |
195 | u64 addr6part(struct in6_addr *addr); | |
196 | void setaddr6part(struct in6_addr *addr, u64 host); | |
197 | #endif | |
198 | -int retry_send(void); | |
199 | +int retry_send(ssize_t rc); | |
200 | void prettyprint_time(char *buf, unsigned int t); | |
201 | int prettyprint_addr(union mysockaddr *addr, char *buf); | |
202 | int parse_hex(char *in, unsigned char *out, int maxlen, | |
203 | diff --git a/src/forward.c b/src/forward.c | |
204 | index 438e9fa490b8..7c0fa8da3fdf 100644 | |
205 | --- a/src/forward.c | |
206 | +++ b/src/forward.c | |
207 | @@ -103,15 +103,11 @@ int send_from(int fd, int nowild, char *packet, size_t len, | |
208 | #endif | |
209 | } | |
210 | ||
211 | - while (sendmsg(fd, &msg, 0) == -1) | |
212 | + while (retry_send(sendmsg(fd, &msg, 0))); | |
213 | + | |
214 | + /* If interface is still in DAD, EINVAL results - ignore that. */ | |
215 | + if (errno != 0 && errno != EINVAL) | |
216 | { | |
217 | - if (retry_send()) | |
218 | - continue; | |
219 | - | |
220 | - /* If interface is still in DAD, EINVAL results - ignore that. */ | |
221 | - if (errno == EINVAL) | |
222 | - break; | |
223 | - | |
224 | my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); | |
225 | return 0; | |
226 | } | |
227 | @@ -297,9 +293,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
228 | fd = forward->rfd4->fd; | |
229 | } | |
230 | ||
231 | - while (sendto(fd, (char *)header, plen, 0, | |
232 | - &forward->sentto->addr.sa, | |
233 | - sa_len(&forward->sentto->addr)) == -1 && retry_send()); | |
234 | + while (retry_send( sendto(fd, (char *)header, plen, 0, | |
235 | + &forward->sentto->addr.sa, | |
236 | + sa_len(&forward->sentto->addr)))); | |
237 | ||
238 | return 1; | |
239 | } | |
240 | @@ -469,14 +465,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, | |
241 | #endif | |
242 | } | |
243 | ||
244 | - if (sendto(fd, (char *)header, plen, 0, | |
245 | - &start->addr.sa, | |
246 | - sa_len(&start->addr)) == -1) | |
247 | - { | |
248 | - if (retry_send()) | |
249 | - continue; | |
250 | - } | |
251 | - else | |
252 | + if (retry_send(sendto(fd, (char *)header, plen, 0, | |
253 | + &start->addr.sa, | |
254 | + sa_len(&start->addr)))) | |
255 | + continue; | |
256 | + | |
257 | + if (errno == 0) | |
258 | { | |
259 | /* Keep info in case we want to re-send this packet */ | |
260 | daemon->srv_save = start; | |
261 | @@ -932,7 +926,9 @@ void reply_query(int fd, int family, time_t now) | |
262 | ||
263 | if (fd != -1) | |
264 | { | |
265 | - while (sendto(fd, (char *)header, nn, 0, &server->addr.sa, sa_len(&server->addr)) == -1 && retry_send()); | |
266 | + while (retry_send(sendto(fd, (char *)header, nn, 0, | |
267 | + &server->addr.sa, | |
268 | + sa_len(&server->addr)))); | |
269 | server->queries++; | |
270 | } | |
271 | ||
272 | @@ -2228,8 +2224,9 @@ void resend_query() | |
273 | else | |
274 | return; | |
275 | ||
276 | - while(sendto(fd, daemon->packet, daemon->packet_len, 0, | |
277 | - &daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); | |
278 | + while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0, | |
279 | + &daemon->srv_save->addr.sa, | |
280 | + sa_len(&daemon->srv_save->addr)))); | |
281 | } | |
282 | } | |
283 | ||
284 | diff --git a/src/ipset.c b/src/ipset.c | |
285 | index 8c5b72722371..a315e86bc7f4 100644 | |
286 | --- a/src/ipset.c | |
287 | +++ b/src/ipset.c | |
288 | @@ -121,7 +121,6 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, | |
289 | struct my_nlattr *nested[2]; | |
290 | uint8_t proto; | |
291 | int addrsz = INADDRSZ; | |
292 | - ssize_t rc; | |
293 | ||
294 | #ifdef HAVE_IPV6 | |
295 | if (af == AF_INET6) | |
296 | @@ -162,9 +161,10 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, | |
297 | nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1]; | |
298 | nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0]; | |
299 | ||
300 | - while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0, | |
301 | - (struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send()); | |
302 | - return rc; | |
303 | + while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0, | |
304 | + (struct sockaddr *)&snl, sizeof(snl)))); | |
305 | + | |
306 | + return errno == 0 ? 0 : -1; | |
307 | } | |
308 | ||
309 | ||
310 | diff --git a/src/loop.c b/src/loop.c | |
311 | index 565f7d8e58e0..c9ed075670de 100644 | |
312 | --- a/src/loop.c | |
313 | +++ b/src/loop.c | |
314 | @@ -45,8 +45,9 @@ void loop_send_probes() | |
315 | fd = rfd->fd; | |
316 | } | |
317 | ||
318 | - while (sendto(fd, daemon->packet, len, 0, &serv->addr.sa, sa_len(&serv->addr)) == -1 && retry_send()); | |
319 | - | |
320 | + while (retry_send(sendto(fd, daemon->packet, len, 0, | |
321 | + &serv->addr.sa, sa_len(&serv->addr)))); | |
322 | + | |
323 | free_rfd(rfd); | |
324 | } | |
325 | } | |
326 | diff --git a/src/netlink.c b/src/netlink.c | |
327 | index 10f94db25a14..753784dc20b4 100644 | |
328 | --- a/src/netlink.c | |
329 | +++ b/src/netlink.c | |
330 | @@ -169,10 +169,10 @@ int iface_enumerate(int family, void *parm, int (*callback)()) | |
331 | req.g.rtgen_family = family; | |
332 | ||
333 | /* Don't block in recvfrom if send fails */ | |
334 | - while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, | |
335 | - (struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send()); | |
336 | - | |
337 | - if (len == -1) | |
338 | + while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, | |
339 | + (struct sockaddr *)&addr, sizeof(addr)))); | |
340 | + | |
341 | + if (errno != 0) | |
342 | return 0; | |
343 | ||
344 | while (1) | |
345 | diff --git a/src/radv.c b/src/radv.c | |
346 | index 6da125b864ae..d0faddf8684a 100644 | |
347 | --- a/src/radv.c | |
348 | +++ b/src/radv.c | |
349 | @@ -479,8 +479,9 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de | |
350 | setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface)); | |
351 | } | |
352 | ||
353 | - while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0, | |
354 | - (struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send()); | |
355 | + while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, | |
356 | + save_counter(0), 0, (struct sockaddr *)&addr, | |
357 | + sizeof(addr)))); | |
358 | ||
359 | } | |
360 | ||
361 | diff --git a/src/util.c b/src/util.c | |
362 | index 91d02410b13f..648bc4d4b428 100644 | |
363 | --- a/src/util.c | |
364 | +++ b/src/util.c | |
365 | @@ -569,17 +569,27 @@ void bump_maxfd(int fd, int *max) | |
366 | *max = fd; | |
367 | } | |
368 | ||
369 | -int retry_send(void) | |
370 | +/* rc is return from sendto and friends. | |
371 | + Return 1 if we should retry. | |
372 | + Set errno to zero if we succeeded. */ | |
373 | +int retry_send(ssize_t rc) | |
374 | { | |
375 | + static int retries = 0; | |
376 | + struct timespec waiter; | |
377 | + | |
378 | + if (rc != -1) | |
379 | + { | |
380 | + retries = 0; | |
381 | + errno = 0; | |
382 | + return 0; | |
383 | + } | |
384 | + | |
385 | /* Linux kernels can return EAGAIN in perpetuity when calling | |
386 | sendmsg() and the relevant interface has gone. Here we loop | |
387 | retrying in EAGAIN for 1 second max, to avoid this hanging | |
388 | dnsmasq. */ | |
389 | ||
390 | - static int retries = 0; | |
391 | - struct timespec waiter; | |
392 | - | |
393 | - if (errno == EAGAIN || errno == EWOULDBLOCK) | |
394 | + if (errno == EAGAIN || errno == EWOULDBLOCK) | |
395 | { | |
396 | waiter.tv_sec = 0; | |
397 | waiter.tv_nsec = 10000; | |
398 | @@ -587,13 +597,13 @@ int retry_send(void) | |
399 | if (retries++ < 1000) | |
400 | return 1; | |
401 | } | |
402 | - | |
403 | - retries = 0; | |
404 | - | |
405 | - if (errno == EINTR) | |
406 | - return 1; | |
407 | - | |
408 | - return 0; | |
409 | + | |
410 | + retries = 0; | |
411 | + | |
412 | + if (errno == EINTR) | |
413 | + return 1; | |
414 | + | |
415 | + return 0; | |
416 | } | |
417 | ||
418 | int read_write(int fd, unsigned char *packet, int size, int rw) | |
419 | @@ -602,22 +612,21 @@ int read_write(int fd, unsigned char *packet, int size, int rw) | |
420 | ||
421 | for (done = 0; done < size; done += n) | |
422 | { | |
423 | - retry: | |
424 | - if (rw) | |
425 | - n = read(fd, &packet[done], (size_t)(size - done)); | |
426 | - else | |
427 | - n = write(fd, &packet[done], (size_t)(size - done)); | |
428 | - | |
429 | - if (n == 0) | |
430 | - return 0; | |
431 | - else if (n == -1) | |
432 | - { | |
433 | - if (retry_send() || errno == ENOMEM || errno == ENOBUFS) | |
434 | - goto retry; | |
435 | - else | |
436 | - return 0; | |
437 | - } | |
438 | + do { | |
439 | + if (rw) | |
440 | + n = read(fd, &packet[done], (size_t)(size - done)); | |
441 | + else | |
442 | + n = write(fd, &packet[done], (size_t)(size - done)); | |
443 | + | |
444 | + if (n == 0) | |
445 | + return 0; | |
446 | + | |
447 | + } while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS); | |
448 | + | |
449 | + if (errno != 0) | |
450 | + return 0; | |
451 | } | |
452 | + | |
453 | return 1; | |
454 | } | |
455 | ||
456 | -- | |
457 | 2.1.0 | |
458 |