ntpd: make -w less cumbersome to use
[oweals/busybox.git] / networking / ntpd.c
index 5431b74991e03a30aa5d7a6c960b064548f930ec..ab1c58c9703d807b37847fabdf751d9a8e9964f3 100644 (file)
 
 
 #define RETRY_INTERVAL  5       /* on error, retry in N secs */
-#define QUERYTIME_MAX   15      /* wait for reply up to N secs */
+#define RESPONSE_INTERVAL 15    /* wait for reply up to N secs */
 
 #define FREQ_TOLERANCE  0.000015 /* % frequency tolerance (15 PPM) */
+#define BURSTPOLL       0
 #define MINPOLL         4       /* % minimum poll interval (6: 64 s) */
 #define MAXPOLL         12      /* % maximum poll interval (12: 1.1h, 17: 36.4h) (was 17) */
 #define MINDISP         0.01    /* % minimum dispersion (s) */
@@ -162,13 +163,13 @@ typedef struct {
        char             *p_dotted;
        /* when to send new query (if p_fd == -1)
         * or when receive times out (if p_fd >= 0): */
-       time_t           next_action_time;
        int              p_fd;
        int              datapoint_idx;
        uint32_t         lastpkt_refid;
-       uint8_t          lastpkt_leap;
+       uint8_t          lastpkt_status;
        uint8_t          lastpkt_stratum;
-       uint8_t          p_reachable_bits;
+       uint8_t          reachable_bits;
+       double           next_action_time;
        double           p_xmttime;
        double           lastpkt_recv_time;
        double           lastpkt_delay;
@@ -191,11 +192,13 @@ enum {
        OPT_x = (1 << 3),
        /* Insert new options above this line. */
        /* Non-compat options: */
-       OPT_p = (1 << 4),
-       OPT_l = (1 << 5) * ENABLE_FEATURE_NTPD_SERVER,
+       OPT_w = (1 << 4),
+       OPT_p = (1 << 5),
+       OPT_l = (1 << 6) * ENABLE_FEATURE_NTPD_SERVER,
 };
 
 struct globals {
+       double   cur_time;
        /* total round trip delay to currently selected reference clock */
        double   rootdelay;
        /* reference timestamp: time when the system clock was last set or corrected */
@@ -216,7 +219,7 @@ struct globals {
         *  in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6
         */
        uint32_t refid;
-       uint8_t  leap;
+       uint8_t  ntp_status;
        /* precision is defined as the larger of the resolution and time to
         * read the clock, in log2 units.  For instance, the precision of a
         * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the
@@ -245,9 +248,8 @@ struct globals {
 #define G_precision_sec  (1.0 / (1 << (- G_precision_exp)))
        uint8_t  stratum;
        /* Bool. After set to 1, never goes back to 0: */
-//TODO: fix logic:
-//     uint8_t  time_was_stepped;
-       uint8_t  adjtimex_was_done;
+       smallint adjtimex_was_done;
+       smallint initial_poll_complete;
 
        uint8_t  discipline_state;      // doc calls it c.state
        uint8_t  poll_exp;              // s.poll
@@ -298,14 +300,53 @@ static ALWAYS_INLINE double MIND(double a, double b)
                return a;
        return b;
 }
-#define SQRT(x) (sqrt(x))
+static NOINLINE double my_SQRT(double X)
+{
+       union {
+               float   f;
+               int32_t i;
+       } v;
+       double invsqrt;
+       double Xhalf = X * 0.5;
+
+       /* Fast and good approximation to 1/sqrt(X), black magic */
+       v.f = X;
+       /*v.i = 0x5f3759df - (v.i >> 1);*/
+       v.i = 0x5f375a86 - (v.i >> 1); /* - this constant is slightly better */
+       invsqrt = v.f; /* better than 0.2% accuracy */
+
+       /* Refining it using Newton's method: x1 = x0 - f(x0)/f'(x0)
+        * f(x) = 1/(x*x) - X  (f==0 when x = 1/sqrt(X))
+        * f'(x) = -2/(x*x*x)
+        * f(x)/f'(x) = (X - 1/(x*x)) / (2/(x*x*x)) = X*x*x*x/2 - x/2
+        * x1 = x0 - (X*x0*x0*x0/2 - x0/2) = 1.5*x0 - X*x0*x0*x0/2 = x0*(1.5 - (X/2)*x0*x0)
+        */
+       invsqrt = invsqrt * (1.5 - Xhalf * invsqrt * invsqrt); /* ~0.05% accuracy */
+       /* invsqrt = invsqrt * (1.5 - Xhalf * invsqrt * invsqrt); 2nd iter: ~0.0001% accuracy */
+       /* With 4 iterations, more than half results will be exact,
+        * at 6th iterations result stabilizes with about 72% results exact.
+        * We are well satisfied with 0.05% accuracy.
+        */
+
+       return X * invsqrt; /* X * 1/sqrt(X) ~= sqrt(X) */
+}
+static ALWAYS_INLINE double SQRT(double X)
+{
+       /* If this arch doesn't use IEEE 754 floats, fall back to using libm */
+       if (sizeof(float) != 4)
+               return sqrt(X);
+
+       /* This avoids needing libm, saves about 0.5k on x86-32 */
+       return my_SQRT(X);
+}
 
 static double
 gettime1900d(void)
 {
        struct timeval tv;
        gettimeofday(&tv, NULL); /* never fails */
-       return (tv.tv_sec + 1.0e-6 * tv.tv_usec + OFFSET_1900_1970);
+       G.cur_time = tv.tv_sec + (1.0e-6 * tv.tv_usec) + OFFSET_1900_1970;
+       return G.cur_time;
 }
 
 static void
@@ -357,13 +398,13 @@ d_to_sfp(double d)
 #endif
 
 static double
-dispersion(const datapoint_t *dp, double t)
+dispersion(const datapoint_t *dp)
 {
-       return dp->d_dispersion + FREQ_TOLERANCE * (t - dp->d_recv_time);
+       return dp->d_dispersion + FREQ_TOLERANCE * (G.cur_time - dp->d_recv_time);
 }
 
 static double
-root_distance(peer_t *p, double t)
+root_distance(peer_t *p)
 {
        /* The root synchronization distance is the maximum error due to
         * all causes of the local clock relative to the primary server.
@@ -373,25 +414,30 @@ root_distance(peer_t *p, double t)
        return MAXD(MINDISP, p->lastpkt_rootdelay + p->lastpkt_delay) / 2
                + p->lastpkt_rootdisp
                + p->filter_dispersion
-               + FREQ_TOLERANCE * (t - p->lastpkt_recv_time)
+               + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time)
                + p->filter_jitter;
 }
 
 static void
 set_next(peer_t *p, unsigned t)
 {
-       p->next_action_time = time(NULL) + t;
+       p->next_action_time = G.cur_time + t;
 }
 
 /*
  * Peer clock filter and its helpers
  */
 static void
-filter_datapoints(peer_t *p, double t)
+filter_datapoints(peer_t *p)
 {
        int i, idx;
+       int got_newest;
        double minoff, maxoff, wavg, sum, w;
-       double x = x;
+       double x = x; /* for compiler */
+       double oldest_off = oldest_off;
+       double oldest_age = oldest_age;
+       double newest_off = newest_off;
+       double newest_age = newest_age;
 
        minoff = maxoff = p->filter_datapoint[0].d_offset;
        for (i = 1; i < NUM_DATAPOINTS; i++) {
@@ -410,26 +456,28 @@ filter_datapoints(peer_t *p, double t)
         */
        wavg = 0;
        w = 0.5;
-       //                     n-1
-       //                     ---    dispersion(i)
-       // filter_dispersion =  \     -------------
-       //                      /       (i+1)
-       //                     ---     2
-       //                     i=0
+       /*                     n-1
+        *                     ---    dispersion(i)
+        * filter_dispersion =  \     -------------
+        *                      /       (i+1)
+        *                     ---     2
+        *                     i=0
+        */
+       got_newest = 0;
        sum = 0;
        for (i = 0; i < NUM_DATAPOINTS; i++) {
                VERB4 {
                        bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s",
                                i,
                                p->filter_datapoint[idx].d_offset,
-                               p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx], t),
-                               t - p->filter_datapoint[idx].d_recv_time,
+                               p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]),
+                               G.cur_time - p->filter_datapoint[idx].d_recv_time,
                                (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset)
                                        ? " (outlier by offset)" : ""
                        );
                }
 
-               sum += dispersion(&p->filter_datapoint[idx], t) / (2 << i);
+               sum += dispersion(&p->filter_datapoint[idx]) / (2 << i);
 
                if (minoff == p->filter_datapoint[idx].d_offset) {
                        minoff -= 1; /* so that we don't match it ever again */
@@ -437,48 +485,67 @@ filter_datapoints(peer_t *p, double t)
                if (maxoff == p->filter_datapoint[idx].d_offset) {
                        maxoff += 1;
                } else {
-                       x = p->filter_datapoint[idx].d_offset * w;
+                       oldest_off = p->filter_datapoint[idx].d_offset;
+                       oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time;
+                       if (!got_newest) {
+                               got_newest = 1;
+                               newest_off = oldest_off;
+                               newest_age = oldest_age;
+                       }
+                       x = oldest_off * w;
                        wavg += x;
                        w /= 2;
                }
 
                idx = (idx - 1) & (NUM_DATAPOINTS - 1);
        }
+       p->filter_dispersion = sum;
        wavg += x; /* add another older6/64 to form older6/32 */
+       /* Fix systematic underestimation with large poll intervals.
+        * Imagine that we still have a bit of uncorrected drift,
+        * and poll interval is big (say, 100 sec). Offsets form a progression:
+        * 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 - 0.7 is most recent.
+        * The algorithm above drops 0.0 and 0.7 as outliers,
+        * and then we have this estimation, ~25% off from 0.7:
+        * 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125
+        */
+       x = oldest_age - newest_age;
+       if (x != 0) {
+               x = newest_age / x; /* in above example, 100 / (600 - 100) */
+               if (x < 1) { /* paranoia check */
+                       x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */
+                       wavg += x;
+               }
+       }
        p->filter_offset = wavg;
-       p->filter_dispersion = sum;
-//TODO: fix systematic underestimation with large poll intervals.
-// Imagine that we still have a bit of uncorrected drift,
-// and poll interval is big. Offsets form a progression:
-// 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7, 0.7 is most recent.
-// The algorithm above drops 0.0 and 0.7 as outliers,
-// and then we have this estimation, ~25% off from 0.7:
-// 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125
-
-       //                       +-----            -----+ ^ 1/2
-       //                       |  n-1                 |
-       //                       |  ---                 |
-       //                  1    |  \                2  |
-       // filter_jitter = --- * |  /  (avg-offset_j)   |
-       //                  n    |  ---                 |
-       //                       |  j=0                 |
-       //                       +-----            -----+
-       // where n is the number of valid datapoints in the filter (n > 1);
-       // if filter_jitter < precision then filter_jitter = precision
+
+       /*                  +-----                 -----+ ^ 1/2
+        *                  |       n-1                 |
+        *                  |       ---                 |
+        *                  |  1    \                2  |
+        * filter_jitter =  | --- * /  (avg-offset_j)   |
+        *                  |  n    ---                 |
+        *                  |       j=0                 |
+        *                  +-----                 -----+
+        * where n is the number of valid datapoints in the filter (n > 1);
+        * if filter_jitter < precision then filter_jitter = precision
+        */
        sum = 0;
        for (i = 0; i < NUM_DATAPOINTS; i++) {
                sum += SQUARE(wavg - p->filter_datapoint[i].d_offset);
        }
-       sum = SQRT(sum) / NUM_DATAPOINTS;
+       sum = SQRT(sum / NUM_DATAPOINTS);
        p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec;
 
-       VERB3 bb_error_msg("filter offset:%f disp:%f jitter:%f",
-                       p->filter_offset, p->filter_dispersion, p->filter_jitter);
+       VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f",
+                       p->filter_offset, x,
+                       p->filter_dispersion,
+                       p->filter_jitter);
 
 }
 
 static void
-reset_peer_stats(peer_t *p, double t, double offset)
+reset_peer_stats(peer_t *p, double offset)
 {
        int i;
        for (i = 0; i < NUM_DATAPOINTS; i++) {
@@ -488,7 +555,7 @@ reset_peer_stats(peer_t *p, double t, double offset)
                                p->filter_datapoint[i].d_offset -= offset;
                        }
                } else {
-                       p->filter_datapoint[i].d_recv_time  = t;
+                       p->filter_datapoint[i].d_recv_time  = G.cur_time;
                        p->filter_datapoint[i].d_offset     = 0;
                        p->filter_datapoint[i].d_dispersion = MAXDISP;
                }
@@ -496,11 +563,11 @@ reset_peer_stats(peer_t *p, double t, double offset)
        if (offset < 16 * STEP_THRESHOLD) {
                p->lastpkt_recv_time -= offset;
        } else {
-               p->p_reachable_bits = 0;
-               p->lastpkt_recv_time = t;
+               p->reachable_bits = 0;
+               p->lastpkt_recv_time = G.cur_time;
        }
-       filter_datapoints(p, t); /* recalc p->filter_xxx */
-       p->next_action_time -= (time_t)offset;
+       filter_datapoints(p); /* recalc p->filter_xxx */
+       p->next_action_time -= offset;
        VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
 }
 
@@ -514,13 +581,8 @@ add_peers(char *s)
        p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa);
        p->p_fd = -1;
        p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3);
-       p->next_action_time = time(NULL); /* = set_next(p, 0); */
-       reset_peer_stats(p, gettime1900d(), 16 * STEP_THRESHOLD);
-       /* Speed up initial sync: with small offsets from peers,
-        * 3 samples will sync
-        */
-       p->filter_datapoint[6].d_dispersion = 0;
-       p->filter_datapoint[7].d_dispersion = 0;
+       p->next_action_time = G.cur_time; /* = set_next(p, 0); */
+       reset_peer_stats(p, 16 * STEP_THRESHOLD);
 
        llist_add_to(&G.ntp_peers, p);
        G.peer_cnt++;
@@ -546,25 +608,26 @@ do_sendto(int fd,
        return 0;
 }
 
-static int
+static void
 send_query_to_peer(peer_t *p)
 {
-       // Why do we need to bind()?
-       // See what happens when we don't bind:
-       //
-       // socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
-       // setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
-       // gettimeofday({1259071266, 327885}, NULL) = 0
-       // sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48
-       // ^^^ we sent it from some source port picked by kernel.
-       // time(NULL)              = 1259071266
-       // write(2, "ntpd: entering poll 15 secs\n", 28) = 28
-       // poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
-       // recv(3, "yyy", 68, MSG_DONTWAIT) = 48
-       // ^^^ this recv will receive packets to any local port!
-       //
-       // Uncomment this and use strace to see it in action:
-#define PROBE_LOCAL_ADDR // { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); }
+       /* Why do we need to bind()?
+        * See what happens when we don't bind:
+        *
+        * socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
+        * setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
+        * gettimeofday({1259071266, 327885}, NULL) = 0
+        * sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48
+        * ^^^ we sent it from some source port picked by kernel.
+        * time(NULL)              = 1259071266
+        * write(2, "ntpd: entering poll 15 secs\n", 28) = 28
+        * poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
+        * recv(3, "yyy", 68, MSG_DONTWAIT) = 48
+        * ^^^ this recv will receive packets to any local port!
+        *
+        * Uncomment this and use strace to see it in action:
+        */
+#define PROBE_LOCAL_ADDR /* { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); } */
 
        if (p->p_fd == -1) {
                int fd, family;
@@ -610,20 +673,19 @@ send_query_to_peer(peer_t *p)
                close(p->p_fd);
                p->p_fd = -1;
                set_next(p, RETRY_INTERVAL);
-               return -1;
+               return;
        }
 
-       p->p_reachable_bits <<= 1;
+       p->reachable_bits <<= 1;
        VERB1 bb_error_msg("sent query to %s", p->p_dotted);
-       set_next(p, QUERYTIME_MAX);
-
-       return 0;
+       set_next(p, RESPONSE_INTERVAL);
 }
 
 
-static void
+static NOINLINE void
 step_time(double offset)
 {
+       llist_t *item;
        double dtime;
        struct timeval tv;
        char buf[80];
@@ -642,7 +704,16 @@ step_time(double offset)
 
        bb_error_msg("setting clock to %s (offset %fs)", buf, offset);
 
-//     G.time_was_stepped = 1;
+       /* Correct various fields which contain time-relative values: */
+
+       /* p->lastpkt_recv_time, p->next_action_time and such: */
+       for (item = G.ntp_peers; item != NULL; item = item->link) {
+               peer_t *pp = (peer_t *) item->data;
+               reset_peer_stats(pp, offset);
+       }
+       /* Globals: */
+       G.cur_time -= offset;
+       G.last_update_recv_time -= offset;
 }
 
 
@@ -673,25 +744,28 @@ compare_survivor_metric(const void *aa, const void *bb)
 {
        const survivor_t *a = aa;
        const survivor_t *b = bb;
-       if (a->metric < b->metric)
+       if (a->metric < b->metric) {
                return -1;
+       }
        return (a->metric > b->metric);
 }
 static int
 fit(peer_t *p, double rd)
 {
-       if (p->p_reachable_bits == 0) {
+       if ((p->reachable_bits & (p->reachable_bits-1)) == 0) {
+               /* One or zero bits in reachable_bits */
                VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
                return 0;
        }
-//TODO: we never accept such packets anyway, right?
-       if ((p->lastpkt_leap & LI_ALARM) == LI_ALARM
+#if 0  /* we filter out such packets earlier */
+       if ((p->lastpkt_status & LI_ALARM) == LI_ALARM
         || p->lastpkt_stratum >= MAXSTRAT
        ) {
                VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted);
                return 0;
        }
-       /* rd is root_distance(p, t) */
+#endif
+       /* rd is root_distance(p) */
        if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) {
                VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted);
                return 0;
@@ -703,7 +777,7 @@ fit(peer_t *p, double rd)
         return 1;
 }
 static peer_t*
-select_and_cluster(double t)
+select_and_cluster(void)
 {
        llist_t    *item;
        int        i, j;
@@ -721,9 +795,9 @@ select_and_cluster(double t)
 
        num_points = 0;
        item = G.ntp_peers;
-       while (item != NULL) {
+       if (G.initial_poll_complete) while (item != NULL) {
                peer_t *p = (peer_t *) item->data;
-               double rd = root_distance(p, t);
+               double rd = root_distance(p);
                double offset = p->filter_offset;
 
                if (!fit(p, rd)) {
@@ -754,7 +828,7 @@ select_and_cluster(double t)
        num_candidates = num_points / 3;
        if (num_candidates == 0) {
                VERB3 bb_error_msg("no valid datapoints, no peer selected");
-               return NULL; /* never happers? */
+               return NULL;
        }
 //TODO: sorting does not seem to be done in reference code
        qsort(point, num_points, sizeof(point[0]), compare_point_edge);
@@ -835,7 +909,7 @@ select_and_cluster(double t)
                p = point[i].p;
                survivor[num_survivors].p = p;
 //TODO: save root_distance in point_t and reuse here?
-               survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p, t);
+               survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p);
                VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s",
                        num_survivors, survivor[num_survivors].metric, p->p_dotted);
                num_survivors++;
@@ -867,7 +941,7 @@ select_and_cluster(double t)
                double min_jitter = min_jitter;
 
                if (num_survivors <= MIN_CLUSTERED) {
-                       bb_error_msg("num_survivors %d <= %d, not discarding more",
+                       VERB3 bb_error_msg("num_survivors %d <= %d, not discarding more",
                                        num_survivors, MIN_CLUSTERED);
                        break;
                }
@@ -887,7 +961,6 @@ select_and_cluster(double t)
                        selection_jitter_sq = 0;
                        for (j = 0; j < num_survivors; j++) {
                                peer_t *q = survivor[j].p;
-//TODO: where is 1/(n-1) * ... multiplier?
                                selection_jitter_sq += SQUARE(p->filter_offset - q->filter_offset);
                        }
                        if (i == 0 || selection_jitter_sq > max_selection_jitter) {
@@ -897,7 +970,7 @@ select_and_cluster(double t)
                        VERB5 bb_error_msg("survivor %d selection_jitter^2:%f",
                                        i, selection_jitter_sq);
                }
-               max_selection_jitter = SQRT(max_selection_jitter);
+               max_selection_jitter = SQRT(max_selection_jitter / num_survivors);
                VERB4 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f",
                                max_idx, max_selection_jitter, min_jitter);
 
@@ -932,7 +1005,7 @@ select_and_cluster(double t)
        VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f",
                        survivor[0].p->p_dotted,
                        survivor[0].p->filter_offset,
-                       t - survivor[0].p->lastpkt_recv_time
+                       G.cur_time - survivor[0].p->lastpkt_recv_time
        );
        return survivor[0].p;
 }
@@ -948,7 +1021,7 @@ set_new_values(int disc_state, double offset, double recv_time)
         * of the last clock filter sample, which must be earlier than
         * the current time.
         */
-       VERB3 bb_error_msg("disc_state=%d last_update_offset=%f last_update_recv_time=%f",
+       VERB3 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f",
                        disc_state, offset, recv_time);
        G.discipline_state = disc_state;
        G.last_update_offset = offset;
@@ -961,8 +1034,8 @@ set_new_values(int disc_state, double offset, double recv_time)
 #define STATE_FREQ      3       /* initial frequency */
 #define STATE_SYNC      4       /* clock synchronized (normal operation) */
 /* Return: -1: decrease poll interval, 0: leave as is, 1: increase */
-static int
-update_local_clock(peer_t *p, double t)
+static NOINLINE int
+update_local_clock(peer_t *p)
 {
        int rc;
        long old_tmx_offset;
@@ -970,7 +1043,9 @@ update_local_clock(peer_t *p, double t)
        double offset = p->filter_offset;
        double recv_time = p->lastpkt_recv_time;
        double abs_offset;
+#if !USING_KERNEL_PLL_LOOP
        double freq_drift;
+#endif
        double since_last_update;
        double etemp, dtemp;
 
@@ -996,7 +1071,9 @@ update_local_clock(peer_t *p, double t)
         * and frequency errors.
         */
        since_last_update = recv_time - G.reftime;
+#if !USING_KERNEL_PLL_LOOP
        freq_drift = 0;
+#endif
        if (G.discipline_state == STATE_FREQ) {
                /* Ignore updates until the stepout threshold */
                if (since_last_update < WATCH_THRESHOLD) {
@@ -1004,15 +1081,15 @@ update_local_clock(peer_t *p, double t)
                                        WATCH_THRESHOLD - since_last_update);
                        return 0; /* "leave poll interval as is" */
                }
+#if !USING_KERNEL_PLL_LOOP
                freq_drift = (offset - G.last_update_offset) / since_last_update;
+#endif
        }
 
        /* There are two main regimes: when the
         * offset exceeds the step threshold and when it does not.
         */
        if (abs_offset > STEP_THRESHOLD) {
-               llist_t *item;
-
                switch (G.discipline_state) {
                case STATE_SYNC:
                        /* The first outlyer: ignore it, switch to SPIK state */
@@ -1063,10 +1140,6 @@ update_local_clock(peer_t *p, double t)
                G.polladj_count = 0;
                G.poll_exp = MINPOLL;
                G.stratum = MAXSTRAT;
-               for (item = G.ntp_peers; item != NULL; item = item->link) {
-                       peer_t *pp = (peer_t *) item->data;
-                       reset_peer_stats(pp, t, offset);
-               }
                if (G.discipline_state == STATE_NSET) {
                        set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time);
                        return 1; /* "ok to increase poll interval" */
@@ -1075,8 +1148,9 @@ update_local_clock(peer_t *p, double t)
 
        } else { /* abs_offset <= STEP_THRESHOLD */
 
-               if (G.poll_exp < MINPOLL) {
-                       VERB3 bb_error_msg("saw small offset %f, disabling burst mode", offset);
+               if (G.poll_exp < MINPOLL && G.initial_poll_complete) {
+                       VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset);
+                       G.polladj_count = 0;
                        G.poll_exp = MINPOLL;
                }
 
@@ -1102,7 +1176,7 @@ update_local_clock(peer_t *p, double t)
                         */
                        set_new_values(STATE_FREQ, offset, recv_time);
                        VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored");
-                       return -1; /* "decrease poll interval" */
+                       return 0; /* "leave poll interval as is" */
 
 #if 0 /* this is dead code for now */
                case STATE_FSET:
@@ -1124,6 +1198,7 @@ update_local_clock(peer_t *p, double t)
                        break;
 
                default:
+#if !USING_KERNEL_PLL_LOOP
                        /* Compute freq_drift due to PLL and FLL contributions.
                         *
                         * The FLL and PLL frequency gain constants
@@ -1146,18 +1221,19 @@ update_local_clock(peer_t *p, double t)
                        etemp = MIND(since_last_update, (1 << G.poll_exp));
                        dtemp = (4 * PLL) << G.poll_exp;
                        freq_drift += offset * etemp / SQUARE(dtemp);
+#endif
                        set_new_values(STATE_SYNC, offset, recv_time);
                        break;
                }
                G.stratum = p->lastpkt_stratum + 1;
        }
 
-       G.reftime = t;
-       G.leap = p->lastpkt_leap;
+       G.reftime = G.cur_time;
+       G.ntp_status = p->lastpkt_status;
        G.refid = p->lastpkt_refid;
        G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay;
        dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter));
-       dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (t - p->lastpkt_recv_time) + abs_offset, MINDISP);
+       dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP);
        G.rootdisp = p->lastpkt_rootdisp + dtemp;
        VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted);
 
@@ -1220,54 +1296,35 @@ update_local_clock(peer_t *p, double t)
                        /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */
                        + old_tmx_offset; /* almost always 0 */
        tmx.status = STA_PLL;
-       //if (sys_leap == LEAP_ADDSECOND)
-       //      tmx.status |= STA_INS;
-       //else if (sys_leap == LEAP_DELSECOND)
-       //      tmx.status |= STA_DEL;
+       if (G.ntp_status & LI_PLUSSEC)
+               tmx.status |= STA_INS;
+       if (G.ntp_status & LI_MINUSSEC)
+               tmx.status |= STA_DEL;
        tmx.constant = G.poll_exp - 4;
        //tmx.esterror = (u_int32)(clock_jitter * 1e6);
        //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6);
-       VERB3 bb_error_msg("b adjtimex freq:%ld offset:%ld constant:%ld status:0x%x",
-                       tmx.freq, tmx.offset, tmx.constant, tmx.status);
        rc = adjtimex(&tmx);
        if (rc < 0)
                bb_perror_msg_and_die("adjtimex");
-       if (G.kernel_freq_drift != tmx.freq / 65536) {
-               G.kernel_freq_drift = tmx.freq / 65536;
-               VERB2 bb_error_msg("kernel clock drift: %ld ppm", G.kernel_freq_drift);
-       }
-       VERB3 {
-               bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x",
+       /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4.
+        * Not sure why. Perhaps it is normal.
+        */
+       VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x",
                                rc, tmx.freq, tmx.offset, tmx.constant, tmx.status);
 #if 0
+       VERB3 {
                /* always gives the same output as above msg */
                memset(&tmx, 0, sizeof(tmx));
                if (adjtimex(&tmx) < 0)
                        bb_perror_msg_and_die("adjtimex");
                VERB3 bb_error_msg("c adjtimex freq:%ld offset:%ld constant:%ld status:0x%x",
                                tmx.freq, tmx.offset, tmx.constant, tmx.status);
+       }
 #endif
+       if (G.kernel_freq_drift != tmx.freq / 65536) {
+               G.kernel_freq_drift = tmx.freq / 65536;
+               VERB2 bb_error_msg("kernel clock drift: %ld ppm", G.kernel_freq_drift);
        }
-// #define STA_MODE 0x4000  /* mode (0 = PLL, 1 = FLL) (ro) */ - ?
-// it appeared after a while:
-//ntpd: p adjtimex freq:-14545653 offset:-5396 constant:10 status:0x41
-//ntpd: c adjtimex freq:-14547835 offset:-8307 constant:10 status:0x1
-//ntpd: p adjtimex freq:-14547835 offset:-6398 constant:10 status:0x41
-//ntpd: c adjtimex freq:-14550486 offset:-10158 constant:10 status:0x1
-//ntpd: p adjtimex freq:-14550486 offset:-6132 constant:10 status:0x41
-//ntpd: c adjtimex freq:-14636129 offset:-10158 constant:10 status:0x4001
-//ntpd: p adjtimex freq:-14636129 offset:-10002 constant:10 status:0x4041
-//ntpd: c adjtimex freq:-14636245 offset:-7497 constant:10 status:0x1
-//ntpd: p adjtimex freq:-14636245 offset:-4573 constant:10 status:0x41
-//ntpd: c adjtimex freq:-14642034 offset:-11715 constant:10 status:0x1
-//ntpd: p adjtimex freq:-14642034 offset:-4098 constant:10 status:0x41
-//ntpd: c adjtimex freq:-14699112 offset:-11746 constant:10 status:0x4001
-//ntpd: p adjtimex freq:-14699112 offset:-4239 constant:10 status:0x4041
-//ntpd: c adjtimex freq:-14762330 offset:-12786 constant:10 status:0x4001
-//ntpd: p adjtimex freq:-14762330 offset:-4434 constant:10 status:0x4041
-//ntpd: b adjtimex freq:0 offset:-9669 constant:8 status:0x1
-//ntpd: adjtimex:0 freq:-14809095 offset:-9669 constant:10 status:0x4001
-//ntpd: c adjtimex freq:-14809095 offset:-9669 constant:10 status:0x4001
 
        return 1; /* "ok to increase poll interval" */
 }
@@ -1289,19 +1346,19 @@ retry_interval(void)
        return interval;
 }
 static unsigned
-poll_interval(int exponent) /* exp is always -1 or 0 */
+poll_interval(int exponent)
 {
-       /* Want to send next packet at (1 << G.poll_exp) + small random value */
        unsigned interval, r;
-       exponent += G.poll_exp; /* G.poll_exp is always > 0 */
-       /* never true: if (exp < 0) exp = 0; */
+       exponent = G.poll_exp + exponent;
+       if (exponent < 0)
+               exponent = 0;
        interval = 1 << exponent;
        r = random();
        interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */
        VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent);
        return interval;
 }
-static void
+static NOINLINE void
 recv_and_process_peer_pkt(peer_t *p)
 {
        int         rc;
@@ -1325,8 +1382,8 @@ recv_and_process_peer_pkt(peer_t *p)
                 || errno == EAGAIN
                ) {
 //TODO: always do this?
-                       set_next(p, retry_interval());
-                       goto close_sock;
+                       interval = retry_interval();
+                       goto set_next_and_close_sock;
                }
                xfunc_die();
        }
@@ -1351,21 +1408,15 @@ recv_and_process_peer_pkt(peer_t *p)
 // "RATE" - peer is overloaded, reduce polling freq
                interval = poll_interval(0);
                bb_error_msg("reply from %s: not synced, next query in %us", p->p_dotted, interval);
-               goto close_sock;
+               goto set_next_and_close_sock;
        }
 
-//     /*
-//      * Verify the server is synchronized with valid stratum and
-//      * reference time not later than the transmit time.
-//      */
-//     if (p->lastpkt_leap == NOSYNC || p->lastpkt_stratum >= MAXSTRAT)
-//             return;                 /* unsynchronized */
-//
 //     /* Verify valid root distance */
 //     if (msg.m_rootdelay / 2 + msg.m_rootdisp >= MAXDISP || p->lastpkt_reftime > msg.m_xmt)
 //             return;                 /* invalid header values */
 
-       p->lastpkt_leap = msg.m_status;
+       p->lastpkt_status = msg.m_status;
+       p->lastpkt_stratum = msg.m_stratum;
        p->lastpkt_rootdelay = sfp_to_d(msg.m_rootdelay);
        p->lastpkt_rootdisp = sfp_to_d(msg.m_rootdisp);
        p->lastpkt_refid = msg.m_refid;
@@ -1387,12 +1438,12 @@ recv_and_process_peer_pkt(peer_t *p)
        T1 = p->p_xmttime;
        T2 = lfp_to_d(msg.m_rectime);
        T3 = lfp_to_d(msg.m_xmttime);
-       T4 = gettime1900d();
+       T4 = G.cur_time;
 
        p->lastpkt_recv_time = T4;
 
        VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
-       p->datapoint_idx = p->p_reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
+       p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
        datapoint = &p->filter_datapoint[p->datapoint_idx];
        datapoint->d_recv_time = T4;
        datapoint->d_offset    = ((T2 - T1) + (T3 - T4)) / 2;
@@ -1406,7 +1457,7 @@ recv_and_process_peer_pkt(peer_t *p)
        if (p->lastpkt_delay < G_precision_sec)
                p->lastpkt_delay = G_precision_sec;
        datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec;
-       if (!p->p_reachable_bits) {
+       if (!p->reachable_bits) {
                /* 1st datapoint ever - replicate offset in every element */
                int i;
                for (i = 1; i < NUM_DATAPOINTS; i++) {
@@ -1414,20 +1465,32 @@ recv_and_process_peer_pkt(peer_t *p)
                }
        }
 
-       p->p_reachable_bits |= 1;
-       VERB1 {
-               bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f",
+       p->reachable_bits |= 1;
+       if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
+               bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f",
                        p->p_dotted,
-                       p->p_reachable_bits,
-                       datapoint->d_offset, p->lastpkt_delay);
+                       p->reachable_bits,
+                       datapoint->d_offset,
+                       p->lastpkt_delay,
+                       p->lastpkt_status,
+                       p->lastpkt_stratum,
+                       p->lastpkt_refid,
+                       p->lastpkt_rootdelay
+                       /* not shown: m_ppoll, m_precision_exp, m_rootdisp,
+                        * m_reftime, m_orgtime, m_rectime, m_xmttime
+                        */
+               );
        }
 
        /* Muck with statictics and update the clock */
-       filter_datapoints(p, T4);
-       q = select_and_cluster(T4);
+       filter_datapoints(p);
+       q = select_and_cluster();
        rc = -1;
-       if (q)
-               rc = update_local_clock(q, T4);
+       if (q) {
+               rc = 0;
+               if (!(option_mask32 & OPT_w))
+                       rc = update_local_clock(q);
+       }
 
        if (rc != 0) {
                /* Adjust the poll interval by comparing the current offset
@@ -1462,7 +1525,20 @@ recv_and_process_peer_pkt(peer_t *p)
                        if (G.polladj_count < -POLLADJ_LIMIT) {
                                G.polladj_count = 0;
                                if (G.poll_exp > MINPOLL) {
+                                       llist_t *item;
+
                                        G.poll_exp--;
+                                       /* Correct p->next_action_time in each peer
+                                        * which waits for sending, so that they send earlier.
+                                        * Old pp->next_action_time are on the order
+                                        * of t + (1 << old_poll_exp) + small_random,
+                                        * we simply need to subtract ~half of that.
+                                        */
+                                       for (item = G.ntp_peers; item != NULL; item = item->link) {
+                                               peer_t *pp = (peer_t *) item->data;
+                                               if (pp->p_fd < 0)
+                                                       pp->next_action_time -= (1 << G.poll_exp);
+                                       }
                                        VERB3 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d",
                                                        G.discipline_jitter, G.poll_exp);
                                }
@@ -1474,9 +1550,9 @@ recv_and_process_peer_pkt(peer_t *p)
 
        /* Decide when to send new query for this peer */
        interval = poll_interval(0);
-       set_next(p, interval);
 
- close_sock:
+ set_next_and_close_sock:
+       set_next(p, interval);
        /* We do not expect any more packets from this peer for now.
         * Closing the socket informs kernel about it.
         * We open a new socket when we send a new query.
@@ -1488,12 +1564,11 @@ recv_and_process_peer_pkt(peer_t *p)
 }
 
 #if ENABLE_FEATURE_NTPD_SERVER
-static void
+static NOINLINE void
 recv_and_process_client_pkt(void /*int fd*/)
 {
        ssize_t          size;
        uint8_t          version;
-       double           rectime;
        len_and_sockaddr *to;
        struct sockaddr  *from;
        msg_t            msg;
@@ -1522,15 +1597,16 @@ recv_and_process_client_pkt(void /*int fd*/)
 
        /* Build a reply packet */
        memset(&msg, 0, sizeof(msg));
-       msg.m_status = G.stratum < MAXSTRAT ? G.leap : LI_ALARM;
+       msg.m_status = G.stratum < MAXSTRAT ? G.ntp_status : LI_ALARM;
        msg.m_status |= (query_status & VERSION_MASK);
        msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ?
                         MODE_SERVER : MODE_SYM_PAS;
        msg.m_stratum = G.stratum;
        msg.m_ppoll = G.poll_exp;
        msg.m_precision_exp = G_precision_exp;
-       rectime = gettime1900d();
-       msg.m_xmttime = msg.m_rectime = d_to_lfp(rectime);
+       /* this time was obtained between poll() and recv() */
+       msg.m_rectime = d_to_lfp(G.cur_time);
+       msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */
        msg.m_reftime = d_to_lfp(G.reftime);
        msg.m_orgtime = query_xmttime;
        msg.m_rootdelay = d_to_sfp(G.rootdelay);
@@ -1650,40 +1726,17 @@ static NOINLINE void ntp_init(char **argv)
                bb_error_msg_and_die(bb_msg_you_must_be_root);
 
        /* Set some globals */
-#if 0
-       /* With constant b = 100, G.precision_exp is also constant -6.
-        * Uncomment this to verify.
-        */
-       {
-               int prec = 0;
-               int b;
-# if 0
-               struct timespec tp;
-               /* We can use sys_clock_getres but assuming 10ms tick should be fine */
-               clock_getres(CLOCK_REALTIME, &tp);
-               tp.tv_sec = 0;
-               tp.tv_nsec = 10000000;
-               b = 1000000000 / tp.tv_nsec;  /* convert to Hz */
-# else
-               b = 100; /* b = 1000000000/10000000 = 100 */
-# endif
-               while (b > 1)
-                       prec--, b >>= 1;
-               /*G.precision_exp = prec;*/
-               /*G.precision_sec = (1.0 / (1 << (- prec)));*/
-               bb_error_msg("G.precision_exp:%d sec:%f", prec, G_precision_sec); /* -6 */
-       }
-#endif
        G.stratum = MAXSTRAT;
-       G.poll_exp = 1; /* should use MINPOLL, but 1 speeds up initial sync */
-       G.reftime = G.last_update_recv_time = gettime1900d();
+       if (BURSTPOLL != 0)
+               G.poll_exp = BURSTPOLL; /* speeds up initial sync */
+       G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */
 
        /* Parse options */
        peers = NULL;
-       opt_complementary = "dd:p::"; /* d: counter, p: list */
+       opt_complementary = "dd:p::wn"; /* d: counter; p: list; -w implies -n */
        opts = getopt32(argv,
                        "nqNx" /* compat */
-                       "p:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
+                       "wp:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
                        "d" /* compat */
                        "46aAbgL", /* compat, ignored */
                        &peers, &G.verbose);
@@ -1716,61 +1769,66 @@ static NOINLINE void ntp_init(char **argv)
 int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int ntpd_main(int argc UNUSED_PARAM, char **argv)
 {
-       struct globals g;
+#undef G
+       struct globals G;
        struct pollfd *pfd;
        peer_t **idx2peer;
+       unsigned cnt;
 
-       memset(&g, 0, sizeof(g));
-       SET_PTR_TO_GLOBALS(&g);
+       memset(&G, 0, sizeof(G));
+       SET_PTR_TO_GLOBALS(&G);
 
        ntp_init(argv);
 
-       {
-               /* if ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */
-               unsigned cnt = g.peer_cnt + ENABLE_FEATURE_NTPD_SERVER;
-               idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt);
-               pfd = xzalloc(sizeof(pfd[0]) * cnt);
-       }
+       /* If ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */
+       cnt = G.peer_cnt + ENABLE_FEATURE_NTPD_SERVER;
+       idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt);
+       pfd = xzalloc(sizeof(pfd[0]) * cnt);
+
+       /* Countdown: we never sync before we sent 5 packets to each peer
+        * NB: if some peer is not responding, we may end up sending
+        * fewer packets to it and more to other peers.
+        * NB2: sync usually happens using 5-1=4 packets, since last reply
+        * does not come back instantaneously.
+        */
+       cnt = G.peer_cnt * 5;
 
        while (!bb_got_signal) {
                llist_t *item;
                unsigned i, j;
-               unsigned sent_cnt, trial_cnt;
                int nfds, timeout;
-               time_t cur_time, nextaction;
+               double nextaction;
 
                /* Nothing between here and poll() blocks for any significant time */
 
-               cur_time = time(NULL);
-               nextaction = cur_time + 3600;
+               nextaction = G.cur_time + 3600;
 
                i = 0;
 #if ENABLE_FEATURE_NTPD_SERVER
-               if (g.listen_fd != -1) {
-                       pfd[0].fd = g.listen_fd;
+               if (G.listen_fd != -1) {
+                       pfd[0].fd = G.listen_fd;
                        pfd[0].events = POLLIN;
                        i++;
                }
 #endif
                /* Pass over peer list, send requests, time out on receives */
-               sent_cnt = trial_cnt = 0;
-               for (item = g.ntp_peers; item != NULL; item = item->link) {
+               for (item = G.ntp_peers; item != NULL; item = item->link) {
                        peer_t *p = (peer_t *) item->data;
 
-                       /* Overflow-safe "if (p->next_action_time <= cur_time) ..." */
-                       if ((int)(cur_time - p->next_action_time) >= 0) {
+                       if (p->next_action_time <= G.cur_time) {
                                if (p->p_fd == -1) {
                                        /* Time to send new req */
-                                       trial_cnt++;
-                                       if (send_query_to_peer(p) == 0)
-                                               sent_cnt++;
+                                       if (--cnt == 0) {
+                                               G.initial_poll_complete = 1;
+                                       }
+                                       send_query_to_peer(p);
                                } else {
                                        /* Timed out waiting for reply */
                                        close(p->p_fd);
                                        p->p_fd = -1;
-                                       timeout = poll_interval(-1); /* try a bit faster */
+                                       timeout = poll_interval(-2); /* -2: try a bit sooner */
                                        bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us",
-                                                       p->p_dotted, p->p_reachable_bits, timeout);
+                                                       p->p_dotted, p->reachable_bits, timeout);
                                        set_next(p, timeout);
                                }
                        }
@@ -1787,27 +1845,26 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
                        }
                }
 
-//             if ((trial_cnt > 0 && sent_cnt == 0) || g.peer_cnt == 0) {
-//                     G.time_was_stepped = 1;
-//             }
-
-               timeout = nextaction - cur_time;
-               if (timeout < 1)
-                       timeout = 1;
+               timeout = nextaction - G.cur_time;
+               if (timeout < 0)
+                       timeout = 0;
+               timeout++; /* (nextaction - G.cur_time) rounds down, compensating */
 
                /* Here we may block */
                VERB2 bb_error_msg("poll %us, sockets:%u", timeout, i);
                nfds = poll(pfd, i, timeout * 1000);
+               gettime1900d(); /* sets G.cur_time */
                if (nfds <= 0)
                        continue;
 
                /* Process any received packets */
                j = 0;
 #if ENABLE_FEATURE_NTPD_SERVER
-               if (g.listen_fd != -1) {
+               if (G.listen_fd != -1) {
                        if (pfd[0].revents /* & (POLLIN|POLLERR)*/) {
                                nfds--;
-                               recv_and_process_client_pkt(/*g.listen_fd*/);
+                               recv_and_process_client_pkt(/*G.listen_fd*/);
+                               gettime1900d(); /* sets G.cur_time */
                        }
                        j = 1;
                }
@@ -1816,6 +1873,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
                        if (pfd[j].revents /* & (POLLIN|POLLERR)*/) {
                                nfds--;
                                recv_and_process_peer_pkt(idx2peer[j]);
+                               gettime1900d(); /* sets G.cur_time */
                        }
                }
        } /* while (!bb_got_signal) */