From: Roy Marples Date: Thu, 24 Jul 2008 15:09:33 +0000 (+0000) Subject: Normalise tv_usecs. Also, send the fd ready back to the main loop so we don't have... X-Git-Tag: v4.0.2~133 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=318fbafe9e81b35ec47014418c05360448046e0b;p=thirdparty%2Fdhcpcd.git Normalise tv_usecs. Also, send the fd ready back to the main loop so we don't have to re-poll each fd. Saves bytes and is more efficient. --- diff --git a/client.c b/client.c index e04af39f..42459111 100644 --- a/client.c +++ b/client.c @@ -115,6 +115,14 @@ #define PROBE_MIN_U PROBE_MIN * USECS_SECOND #define PROBE_MAX_U PROBE_MAX * USECS_SECOND +#define timernorm(tvp) \ + do { \ + while ((tvp)->tv_usec >= 1000000) { \ + (tvp)->tv_sec++; \ + (tvp)->tv_usec -= 1000000; \ + } \ + } while (0 /* CONSTCOND */); \ + struct if_state { int options; struct interface *interface; @@ -722,12 +730,12 @@ drop_config(struct if_state *state, const char *reason, } static int -wait_for_packet(struct if_state *state) +wait_for_fd(struct if_state *state, int *fd) { struct pollfd fds[4]; /* signal, link, raw, arp */ - int retval, nfds = 0; - time_t timeout = 0; - struct timeval now, d, *ref; + int r, i, nfds = 0; + struct timeval now, tout, *ref; + time_t msecs = -1; static time_t last_stop_sec = 0, last_timeout_sec = 0; static long int last_stop_usec = 0, last_timeout_usec = 0; @@ -745,22 +753,24 @@ wait_for_packet(struct if_state *state) ref = NULL; clock_monotonic(&now); if (timerisset(&state->exit)) { - if (timercmp(&state->exit, &now, <=)) - return 0; - else + if (timercmp(&state->exit, &now, >)) ref = &state->exit; + else + return 0; } if (timerisset(&state->stop)) { - if (timercmp(&state->stop, &now, <=)) + if (timercmp(&state->stop, &now, >)) { + if (!ref || timercmp(&state->stop, ref, <)) + ref = &state->stop; + } else return 0; - else if (!ref || timercmp(&state->stop, ref, <)) - ref = &state->stop; } if (timerisset(&state->timeout)) { - if (timercmp(&state->timeout, &now, <=)) + if (timercmp(&state->timeout, &now, >)) { + if (!ref || timercmp(&state->timeout, ref, <)) + ref = &state->timeout; + } else return 0; - else if (!ref || timercmp(&state->timeout, ref, <)) - ref = &state->timeout; } if (state->lease.leasetime == ~0U && @@ -768,11 +778,11 @@ wait_for_packet(struct if_state *state) { if (last_stop_sec != INFTIM) logger(LOG_DEBUG, "waiting for infinity"); - timeout = INFTIM; + ref = NULL; } else if (state->carrier == LINK_DOWN && !ref) { if (last_stop_sec != INFTIM) logger(LOG_DEBUG, "waiting for carrier"); - timeout = INFTIM; + ref = NULL; } else { if (state->interface->raw_fd != -1) { fds[nfds].fd = state->interface->raw_fd; @@ -786,46 +796,40 @@ wait_for_packet(struct if_state *state) } } -wait_again: - clock_monotonic(&now); - if (timeout == INFTIM) - last_stop_sec = INFTIM; - else { - if (!ref) - return 0; - timersub(ref, &now, &d); - /* This should be safe and not overflow as the biggest - * diff is uint32_t seconds from the DHCP message. */ - timeout = d.tv_sec * 1000 + (d.tv_usec + 999) / 1000; + if (ref) { + timersub(ref, &now, &tout); + msecs = tout.tv_sec * 1000 + (tout.tv_usec + 999) / 1000; /* Only report waiting time if changed */ if (last_stop_sec != state->stop.tv_sec || last_stop_usec != state->stop.tv_usec || last_timeout_sec != state->timeout.tv_sec || last_timeout_usec != state->timeout.tv_usec) { - logger(LOG_DEBUG, "waiting for %0.2f seconds", - (float)timeout / 1000); + logger(LOG_DEBUG, "waiting for %.2f seconds", + (float)msecs / 1000); last_stop_sec = state->stop.tv_sec; last_stop_usec = state->stop.tv_usec; last_timeout_sec = state->timeout.tv_sec; last_timeout_usec = state->timeout.tv_usec; } - /* However, we could overflow INT_MAX and annoy poll. */ - if (timeout < 0 || timeout > INT_MAX) - timeout = INT_MAX; } - retval = poll(fds, nfds, timeout); - if (retval == -1) { - if (errno == EINTR) - return 0; - logger(LOG_ERR, "poll: %s", strerror(errno)); - } else if (retval == 0) { - /* If our timeout overflowed, wait again. */ - if (timeout == INT_MAX) - goto wait_again; + r = poll(fds, nfds, msecs); + if (r == -1) { + if (errno != EINTR) + logger(LOG_ERR, "poll: %s", strerror(errno)); + return -1; } - return retval; + + if (r != 0) { + /* We're only interested in the first ready fd */ + for (i = 0; i < nfds; i++) + if (fds[i].revents & POLLIN) { + *fd = fds[i].fd; + break; + } + } + return r; } static int @@ -1146,11 +1150,12 @@ handle_timeout(struct if_state *state, const struct options *options) state->probes++; logger(LOG_DEBUG, "sending ARP probe #%d", state->probes); - if (state->probes < PROBE_NUM) - tv.tv_usec = (arc4random() % - (PROBE_MAX_U - PROBE_MIN_U)) + - PROBE_MIN_U; - else + if (state->probes < PROBE_NUM) { + tv.tv_sec = PROBE_MIN_U; + tv.tv_usec = arc4random() % + (PROBE_MAX_U - PROBE_MIN_U); + timernorm(&tv); + } else tv.tv_sec = ANNOUNCE_WAIT; i = send_arp(iface, ARPOP_REQUEST, 0, state->offer->yiaddr); if (i == -1) @@ -1260,6 +1265,7 @@ handle_timeout(struct if_state *state, const struct options *options) if (!lease->addr.s_addr && !timerisset(&state->stop)) { tv.tv_sec = DHCP_MAX + DHCP_RAND_MIN; tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U); + timernorm(&tv); clock_monotonic(&state->stop); timeradd(&state->stop, &tv, &state->stop); } @@ -1298,6 +1304,7 @@ dhcp_timeout: } tv.tv_sec += DHCP_RAND_MIN; tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U); + timernorm(&tv); timeradd(&state->timeout, &tv, &state->timeout); return 0; } @@ -1664,8 +1671,7 @@ dhcp_run(const struct options *options, int *pid_fd) { struct interface *iface; struct if_state *state = NULL; - int retval = 0; - int sig; + int fd, r = 0, sig; iface = read_interface(options->interface, options->metric); if (!iface) { @@ -1697,33 +1703,33 @@ dhcp_run(const struct options *options, int *pid_fd) logger(LOG_INFO, "waiting for carrier"); for (;;) { - /* We should always handle our signals first */ - if ((sig = (signal_read(state->signal_fd))) != -1) { - retval = handle_signal(sig, state, options); - } else if (retval == 0) - retval = handle_timeout(state, options); - else if (retval == -1) { - if (errno == EINTR) - /* The interupt will be handled above */ - retval = 0; - } else if (retval > 0) { - if (fd_hasdata(iface->link_fd) == 1) { - retval = handle_link(state); - } else if (fd_hasdata(iface->raw_fd) == 1) { - retval = handle_dhcp_packet(state, options); - } else if (fd_hasdata(iface->arp_fd) == 1) { - retval = handle_arp_packet(state); - if (retval == -1) - retval = handle_arp_fail(state, options); + if (r == 0) { + r = handle_timeout(state, options); + if (r == 1) { + r = 0; + continue; + } + } + fd = -1; + r = wait_for_fd(state, &fd); + if (r == -1 && errno == EINTR) + r = 0; + else if (r > 0) { + if (fd == state->signal_fd) { + if ((sig = signal_read()) != -1) + r = handle_signal(sig, state, options); + } else if (fd == iface->link_fd) + r = handle_link(state); + else if (fd == iface->raw_fd) + r = handle_dhcp_packet(state, options); + else if (fd == iface->arp_fd) { + if ((r = handle_arp_packet(state)) -1) + r = handle_arp_fail(state, options); } else - retval = 0; + r = 0; } - if (retval == -1) + if (r == -1) break; - if (retval == 0) - retval = wait_for_packet(state); - else - retval = 0; } eexit: @@ -1739,7 +1745,7 @@ eexit: if (state) { if (state->options & DHCPCD_FORKED) - retval = 0; + r = 0; if (state->options & DHCPCD_DAEMONISED) unlink(options->pidfile); free(state->offer); @@ -1748,5 +1754,5 @@ eexit: free(state); } - return retval; + return r; } diff --git a/common.c b/common.c index 71095ebe..198ce5b4 100644 --- a/common.c +++ b/common.c @@ -33,7 +33,6 @@ #ifdef BSD # include #endif -#include #include #include #include @@ -150,25 +149,6 @@ close_fds(void) return 0; } -int -fd_hasdata(int fd) -{ - struct pollfd fds; - int retval; - - if (fd == -1) - return -1; - fds.fd = fd; - fds.events = POLLIN; - fds.revents = 0; - retval = poll(&fds, 1, 0); - if (retval == -1) - return -1; - if (retval > 0 && fds.revents & POLLIN) - return retval; - return 0; -} - int set_cloexec(int fd) { diff --git a/common.h b/common.h index 6836040a..755ae6af 100644 --- a/common.h +++ b/common.h @@ -74,7 +74,6 @@ int closefrom(int); int close_fds(void); int set_cloexec(int); int set_nonblock(int); -int fd_hasdata(int); ssize_t get_line(char **, size_t *, FILE *); int clock_monotonic(struct timeval *); time_t uptime(void); diff --git a/signals.c b/signals.c index fb986d7d..599bec16 100644 --- a/signals.c +++ b/signals.c @@ -62,31 +62,20 @@ signal_fd(void) return (signal_pipe[0]); } -/* Check if we have a signal or not */ -int -signal_exists(int fd) -{ - if (fd_hasdata(fd) == 1) - return 0; - return -1; -} - /* Read a signal from the signal pipe. Returns 0 if there is * no signal, -1 on error (and sets errno appropriately), and * your signal on success */ int -signal_read(int fd) +signal_read(void) { int sig = -1; char buf[16]; size_t bytes; - if (fd_hasdata(fd) == 1) { - memset(buf, 0, sizeof(buf)); - bytes = read(signal_pipe[0], buf, sizeof(buf)); - if (bytes >= sizeof(sig)) - memcpy(&sig, buf, sizeof(sig)); - } + memset(buf, 0, sizeof(buf)); + bytes = read(signal_pipe[0], buf, sizeof(buf)); + if (bytes >= sizeof(sig)) + memcpy(&sig, buf, sizeof(sig)); return sig; } diff --git a/signals.h b/signals.h index 5972b311..0956f519 100644 --- a/signals.h +++ b/signals.h @@ -34,7 +34,6 @@ int signal_init(void); int signal_setup(void); int signal_reset(void); int signal_fd(void); -int signal_exists(int fd); -int signal_read(int fd); +int signal_read(void); #endif