Struggling with more inconsistant uses/assumptions around the global
time stamp (cur_time) I finally concluded it was fatally flawed. Or
at least more trouble than it is worth.

So,

1) Use time(NULL) to get current time where required,
2) Add local variables cur_time where the time is used mulitple
times in a single function,
3) Add set_timer_interval() so an accurate timeout is set from a
given interval.

Most obviously to me, this makes several machines that think a few
seconds to get link, or whose cards can't report link, work with
far few packet exchanges. Previously the cur_time was set before
the link state test. So timeouts of less than a few seconds always
triggered immediately causing multiple DHCPDISCOVER or REQUEST
packets to be sent immediately.

With this diff I consistantly get the minimal DISCOVER/OFFER/REQUEST/ACK
exchange.

Thoughts? Testing in intriguing environments?

.... Ken

Index: clparse.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.39
diff -u -p -r1.39 clparse.c
--- clparse.c   22 Aug 2012 00:14:42 -0000      1.39
+++ clparse.c   26 Aug 2012 03:53:20 -0000
@@ -471,7 +471,7 @@ parse_client_lease_statement(FILE *cfile
         * active.
         */
        if (client->active) {
-               if (client->active->expiry < cur_time)
+               if (client->active->expiry < time(NULL))
                        free_client_lease(client->active);
                else if (addr_eq(client->active->address, lease->address))
                        free_client_lease(client->active);
Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.151
diff -u -p -r1.151 dhclient.c
--- dhclient.c  22 Aug 2012 00:14:42 -0000      1.151
+++ dhclient.c  26 Aug 2012 03:53:21 -0000
@@ -66,8 +66,6 @@
 #define DEFAULT_LEASE_TIME     43200   /* 12 hours... */
 #define TIME_MAX               2147483647
 
-time_t cur_time;
-
 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
 char *path_dhclient_db = NULL;
 
@@ -220,7 +218,7 @@ routehandler(void)
                    ifam->ifam_addrs) != AF_INET)
                        break;
                /* XXX check addrs like RTM_NEWADDR instead of this? */
-               if (scripttime == 0 || cur_time < scripttime + 10)
+               if (scripttime == 0 || time(NULL) < scripttime + 10)
                        break;
                errmsg = "interface address deleted";
                goto die;
@@ -325,7 +323,6 @@ main(int argc, char *argv[])
                log_perror = 0;
 
        tzset();
-       time(&cur_time);
 
        memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
        sockaddr_broadcast.sin_family = AF_INET;
@@ -487,7 +484,7 @@ state_reboot(void)
           flags. */
        make_request(client->active);
        client->destination = iaddr_broadcast;
-       client->first_sending = cur_time;
+       client->first_sending = time(NULL);
        client->interval = 0;
 
        /* Send out the first DHCPREQUEST packet. */
@@ -507,7 +504,7 @@ state_init(void)
        client->xid = client->packet.xid;
        client->destination = iaddr_broadcast;
        client->state = S_SELECTING;
-       client->first_sending = cur_time;
+       client->first_sending = time(NULL);
        client->interval = 0;
 
        /* Add an immediate timeout to cause the first DHCPDISCOVER packet
@@ -523,6 +520,7 @@ void
 state_selecting(void)
 {
        struct client_lease *lp, *next, *picked;
+       time_t cur_time;
 
        /* Cancel state_selecting and send_discover timeouts, since either
           one could have got us here. */
@@ -554,6 +552,8 @@ state_selecting(void)
 
        picked->next = NULL;
 
+       time(&cur_time);
+
        /* If it was a BOOTREPLY, we can just take the address right now. */
        if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
                client->new = picked;
@@ -592,6 +592,7 @@ void
 dhcpack(struct iaddr client_addr, struct option_data *options)
 {
        struct client_lease *lease;
+       time_t cur_time;
 
        if (client->state != S_REBOOTING &&
            client->state != S_REQUESTING &&
@@ -640,6 +641,8 @@ dhcpack(struct iaddr client_addr, struct
                client->new->rebind = client->new->renewal +
                    client->new->renewal / 2 + client->new->renewal / 4;
 
+       time(&cur_time);
+
        client->new->expiry += cur_time;
        /* Lease lengths can never be negative. */
        if (client->new->expiry < cur_time)
@@ -680,7 +683,7 @@ bind_lease(void)
 
        note("bound to %s -- renewal in %lld seconds.",
            piaddr(client->active->address),
-           (long long)(client->active->renewal - cur_time));
+           (long long)(client->active->renewal - time(NULL)));
        client->state = S_BOUND;
        reinitialize_interface();
        go_daemon();
@@ -707,7 +710,7 @@ state_bound(void)
        } else
                client->destination = iaddr_broadcast;
 
-       client->first_sending = cur_time;
+       client->first_sending = time(NULL);
        client->interval = 0;
        client->state = S_RENEWING;
 
@@ -784,7 +787,7 @@ dhcpoffer(struct iaddr client_addr, stru
        /* If the selecting interval has expired, go immediately to
           state_selecting().  Otherwise, time out into
           state_selecting at the select interval. */
-       if (stop_selecting <= cur_time)
+       if (stop_selecting <= time(NULL))
                state_selecting();
        else {
                set_timeout(stop_selecting, state_selecting);
@@ -897,6 +900,7 @@ dhcpnak(struct iaddr client_addr, struct
 void
 send_discover(void)
 {
+       time_t cur_time;
        int interval, increase = 1;
 
        /* Figure out how long it's been since we started transmitting. */
@@ -953,7 +957,7 @@ send_discover(void)
        /* Send out a packet. */
        send_packet(inaddr_any, &sockaddr_broadcast, NULL);
 
-       set_timeout(cur_time + client->interval, send_discover);
+       set_timeout_interval(client->interval, send_discover);
 }
 
 /*
@@ -967,6 +971,7 @@ state_panic(void)
 {
        struct client_lease *loop = client->active;
        struct client_lease *lp;
+       time_t cur_time;
 
        note("No DHCPOFFERS received.");
 
@@ -976,6 +981,7 @@ state_panic(void)
                goto activate_next;
 
        /* Run through the list of leases and see if one can be used. */
+       time(&cur_time);
        while (client->active) {
                if (client->active->expiry > cur_time) {
                        note("Trying recorded lease %s",
@@ -989,8 +995,7 @@ state_panic(void)
                           yet need renewal, go into BOUND state and
                           timeout at the renewal time. */
                        if (!script_go()) {
-                               if (cur_time <
-                                   client->active->renewal) {
+                               if (cur_time < client->active->renewal) {
                                        client->state = S_BOUND;
                                        note("bound: renewal in %lld seconds.",
                                            (long long)(client->active->renewal
@@ -1042,7 +1047,7 @@ activate_next:
        script_init("FAIL");
        script_go();
        client->state = S_INIT;
-       set_timeout(cur_time + config->retry_interval, state_init);
+       set_timeout_interval(config->retry_interval, state_init);
        go_daemon();
 }
 
@@ -1051,10 +1056,13 @@ send_request(void)
 {
        struct sockaddr_in destination;
        struct in_addr from;
+       time_t cur_time;
        int interval;
 
+       time(&cur_time);
+
        /* Figure out how long it's been since we started transmitting. */
-       interval = cur_time - client->first_sending;
+       interval = (int)(cur_time - client->first_sending);
 
        /* If we're in the INIT-REBOOT or REQUESTING state and we're
           past the reboot timeout, go to INIT and see if we can
@@ -1142,7 +1150,7 @@ send_request(void)
        /* Send out a packet. */
        send_packet(from, &destination, NULL);
 
-       set_timeout(cur_time + client->interval, send_request);
+       set_timeout_interval(client->interval, send_request);
 }
 
 void
Index: dhcpd.h
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhcpd.h,v
retrieving revision 1.78
diff -u -p -r1.78 dhcpd.h
--- dhcpd.h     22 Aug 2012 00:14:42 -0000      1.78
+++ dhcpd.h     26 Aug 2012 03:53:21 -0000
@@ -252,6 +252,7 @@ void reinitialize_interface(void);
 void dispatch(void);
 void got_one(void);
 void set_timeout(time_t, void (*)(void));
+void set_timeout_interval(time_t, void (*)(void));
 void cancel_timeout(void);
 int interface_status(char *);
 int interface_link_forceup(char *);
@@ -279,7 +280,6 @@ char *piaddr(struct iaddr);
 /* dhclient.c */
 extern char *path_dhclient_conf;
 extern char *path_dhclient_db;
-extern time_t cur_time;
 extern int log_perror;
 extern int routefd;
 
Index: dispatch.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dispatch.c,v
retrieving revision 1.54
diff -u -p -r1.54 dispatch.c
--- dispatch.c  18 Aug 2012 00:20:01 -0000      1.54
+++ dispatch.c  26 Aug 2012 03:53:21 -0000
@@ -122,7 +122,7 @@ dispatch(void)
 {
        int count, to_msec;
        struct pollfd fds[2];
-       time_t howlong;
+       time_t cur_time, howlong;
        void (*func)(void);
 
        do {
@@ -174,9 +174,6 @@ another:
                /* Wait for a packet or a timeout... XXX */
                count = poll(fds, 2, to_msec);
 
-               /* Time may have moved on while we polled! */
-               time(&cur_time);
-
                /* Not likely to be transitory... */
                if (count == -1) {
                        if (errno == EAGAIN || errno == EINTR) {
@@ -319,6 +316,13 @@ void
 set_timeout(time_t when, void (*where)(void))
 {
        timeout.when = when;
+       timeout.func = where;
+}
+
+void
+set_timeout_interval(time_t secs, void (*where)(void))
+{
+       timeout.when = time(NULL) + secs; 
        timeout.func = where;
 }

Reply via email to