Commit 5e95a552 authored by Simon Kelley's avatar Simon Kelley

Avoid hanngs in DHCP ping code when system time goes backwards.

parent 90cb2225
...@@ -1755,14 +1755,22 @@ int icmp_ping(struct in_addr addr) ...@@ -1755,14 +1755,22 @@ int icmp_ping(struct in_addr addr)
better not use any resources our caller has in use...) better not use any resources our caller has in use...)
but we remain deaf to signals or further DHCP packets. */ but we remain deaf to signals or further DHCP packets. */
int fd; /* There can be a problem using dnsmasq_time() to end the loop, since
it's not monotonic, and can go backwards if the system clock is
tweaked, leading to the code getting stuck in this loop and
ignoring DHCP requests. To fix this, we check to see if select returned
as a result of a timeout rather than a socket becoming available. We
only allow this to happen as many times as it takes to get to the wait time
in quarter-second chunks. This provides a fallback way to end loop. */
int fd, rc;
struct sockaddr_in saddr; struct sockaddr_in saddr;
struct { struct {
struct ip ip; struct ip ip;
struct icmp icmp; struct icmp icmp;
} packet; } packet;
unsigned short id = rand16(); unsigned short id = rand16();
unsigned int i, j; unsigned int i, j, timeout_count;
int gotreply = 0; int gotreply = 0;
time_t start, now; time_t start, now;
...@@ -1794,8 +1802,8 @@ int icmp_ping(struct in_addr addr) ...@@ -1794,8 +1802,8 @@ int icmp_ping(struct in_addr addr)
while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0, while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
(struct sockaddr *)&saddr, sizeof(saddr)))); (struct sockaddr *)&saddr, sizeof(saddr))));
for (now = start = dnsmasq_time(); for (now = start = dnsmasq_time(), timeout_count = 0;
difftime(now, start) < (float)PING_WAIT;) (difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
{ {
struct timeval tv; struct timeval tv;
fd_set rset, wset; fd_set rset, wset;
...@@ -1820,11 +1828,15 @@ int icmp_ping(struct in_addr addr) ...@@ -1820,11 +1828,15 @@ int icmp_ping(struct in_addr addr)
} }
#endif #endif
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0) rc = select(maxfd+1, &rset, &wset, NULL, &tv);
if (rc < 0)
{ {
FD_ZERO(&rset); FD_ZERO(&rset);
FD_ZERO(&wset); FD_ZERO(&wset);
} }
else if (rc == 0)
timeout_count++;
now = dnsmasq_time(); now = dnsmasq_time();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment