ntpd: make -w less cumbersome to use
[oweals/busybox.git] / networking / ntpd.c
index 08e51ef3f83ca7a862be421c2d81378c1f5128fc..ab1c58c9703d807b37847fabdf751d9a8e9964f3 100644 (file)
@@ -192,8 +192,9 @@ 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 {
@@ -299,7 +300,45 @@ 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)
@@ -902,7 +941,7 @@ select_and_cluster(void)
                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;
                }
@@ -1343,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();
        }
@@ -1369,7 +1408,7 @@ 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 valid root distance */
@@ -1427,19 +1466,31 @@ recv_and_process_peer_pkt(peer_t *p)
        }
 
        p->reachable_bits |= 1;
-       VERB1 {
-               bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f",
+       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->reachable_bits,
-                       datapoint->d_offset, p->lastpkt_delay);
+                       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);
        q = select_and_cluster();
        rc = -1;
-       if (q)
-               rc = update_local_clock(q);
+       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
@@ -1499,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.
@@ -1682,10 +1733,10 @@ static NOINLINE void ntp_init(char **argv)
 
        /* 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);