diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-01-03 08:59:59 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-01-03 08:59:59 +0100 |
commit | 0b002812a8c2a95ab18374452fd0ab2065ed4029 (patch) | |
tree | 2a942698ee6d8597e2b867d8da453f47979dae79 /networking/ntpd.c | |
parent | 185e691ec129f9dc0c7150348766b86da08c1abb (diff) | |
download | busybox-w32-0b002812a8c2a95ab18374452fd0ab2065ed4029.tar.gz busybox-w32-0b002812a8c2a95ab18374452fd0ab2065ed4029.tar.bz2 busybox-w32-0b002812a8c2a95ab18374452fd0ab2065ed4029.zip |
ntpd: better selection of initial sync; fewer gettimeofday calls
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/ntpd.c')
-rw-r--r-- | networking/ntpd.c | 252 |
1 files changed, 126 insertions, 126 deletions
diff --git a/networking/ntpd.c b/networking/ntpd.c index 92e2723a5..520dcd16b 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -47,9 +47,10 @@ | |||
47 | 47 | ||
48 | 48 | ||
49 | #define RETRY_INTERVAL 5 /* on error, retry in N secs */ | 49 | #define RETRY_INTERVAL 5 /* on error, retry in N secs */ |
50 | #define QUERYTIME_MAX 15 /* wait for reply up to N secs */ | 50 | #define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ |
51 | 51 | ||
52 | #define FREQ_TOLERANCE 0.000015 /* % frequency tolerance (15 PPM) */ | 52 | #define FREQ_TOLERANCE 0.000015 /* % frequency tolerance (15 PPM) */ |
53 | #define BURSTPOLL 0 | ||
53 | #define MINPOLL 4 /* % minimum poll interval (6: 64 s) */ | 54 | #define MINPOLL 4 /* % minimum poll interval (6: 64 s) */ |
54 | #define MAXPOLL 12 /* % maximum poll interval (12: 1.1h, 17: 36.4h) (was 17) */ | 55 | #define MAXPOLL 12 /* % maximum poll interval (12: 1.1h, 17: 36.4h) (was 17) */ |
55 | #define MINDISP 0.01 /* % minimum dispersion (s) */ | 56 | #define MINDISP 0.01 /* % minimum dispersion (s) */ |
@@ -162,13 +163,13 @@ typedef struct { | |||
162 | char *p_dotted; | 163 | char *p_dotted; |
163 | /* when to send new query (if p_fd == -1) | 164 | /* when to send new query (if p_fd == -1) |
164 | * or when receive times out (if p_fd >= 0): */ | 165 | * or when receive times out (if p_fd >= 0): */ |
165 | time_t next_action_time; | ||
166 | int p_fd; | 166 | int p_fd; |
167 | int datapoint_idx; | 167 | int datapoint_idx; |
168 | uint32_t lastpkt_refid; | 168 | uint32_t lastpkt_refid; |
169 | uint8_t lastpkt_status; | 169 | uint8_t lastpkt_status; |
170 | uint8_t lastpkt_stratum; | 170 | uint8_t lastpkt_stratum; |
171 | uint8_t p_reachable_bits; | 171 | uint8_t reachable_bits; |
172 | double next_action_time; | ||
172 | double p_xmttime; | 173 | double p_xmttime; |
173 | double lastpkt_recv_time; | 174 | double lastpkt_recv_time; |
174 | double lastpkt_delay; | 175 | double lastpkt_delay; |
@@ -196,6 +197,7 @@ enum { | |||
196 | }; | 197 | }; |
197 | 198 | ||
198 | struct globals { | 199 | struct globals { |
200 | double cur_time; | ||
199 | /* total round trip delay to currently selected reference clock */ | 201 | /* total round trip delay to currently selected reference clock */ |
200 | double rootdelay; | 202 | double rootdelay; |
201 | /* reference timestamp: time when the system clock was last set or corrected */ | 203 | /* reference timestamp: time when the system clock was last set or corrected */ |
@@ -245,7 +247,8 @@ struct globals { | |||
245 | #define G_precision_sec (1.0 / (1 << (- G_precision_exp))) | 247 | #define G_precision_sec (1.0 / (1 << (- G_precision_exp))) |
246 | uint8_t stratum; | 248 | uint8_t stratum; |
247 | /* Bool. After set to 1, never goes back to 0: */ | 249 | /* Bool. After set to 1, never goes back to 0: */ |
248 | uint8_t adjtimex_was_done; | 250 | smallint adjtimex_was_done; |
251 | smallint initial_poll_complete; | ||
249 | 252 | ||
250 | uint8_t discipline_state; // doc calls it c.state | 253 | uint8_t discipline_state; // doc calls it c.state |
251 | uint8_t poll_exp; // s.poll | 254 | uint8_t poll_exp; // s.poll |
@@ -303,7 +306,8 @@ gettime1900d(void) | |||
303 | { | 306 | { |
304 | struct timeval tv; | 307 | struct timeval tv; |
305 | gettimeofday(&tv, NULL); /* never fails */ | 308 | gettimeofday(&tv, NULL); /* never fails */ |
306 | return (tv.tv_sec + 1.0e-6 * tv.tv_usec + OFFSET_1900_1970); | 309 | G.cur_time = tv.tv_sec + (1.0e-6 * tv.tv_usec) + OFFSET_1900_1970; |
310 | return G.cur_time; | ||
307 | } | 311 | } |
308 | 312 | ||
309 | static void | 313 | static void |
@@ -355,13 +359,13 @@ d_to_sfp(double d) | |||
355 | #endif | 359 | #endif |
356 | 360 | ||
357 | static double | 361 | static double |
358 | dispersion(const datapoint_t *dp, double t) | 362 | dispersion(const datapoint_t *dp) |
359 | { | 363 | { |
360 | return dp->d_dispersion + FREQ_TOLERANCE * (t - dp->d_recv_time); | 364 | return dp->d_dispersion + FREQ_TOLERANCE * (G.cur_time - dp->d_recv_time); |
361 | } | 365 | } |
362 | 366 | ||
363 | static double | 367 | static double |
364 | root_distance(peer_t *p, double t) | 368 | root_distance(peer_t *p) |
365 | { | 369 | { |
366 | /* The root synchronization distance is the maximum error due to | 370 | /* The root synchronization distance is the maximum error due to |
367 | * all causes of the local clock relative to the primary server. | 371 | * all causes of the local clock relative to the primary server. |
@@ -371,21 +375,21 @@ root_distance(peer_t *p, double t) | |||
371 | return MAXD(MINDISP, p->lastpkt_rootdelay + p->lastpkt_delay) / 2 | 375 | return MAXD(MINDISP, p->lastpkt_rootdelay + p->lastpkt_delay) / 2 |
372 | + p->lastpkt_rootdisp | 376 | + p->lastpkt_rootdisp |
373 | + p->filter_dispersion | 377 | + p->filter_dispersion |
374 | + FREQ_TOLERANCE * (t - p->lastpkt_recv_time) | 378 | + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) |
375 | + p->filter_jitter; | 379 | + p->filter_jitter; |
376 | } | 380 | } |
377 | 381 | ||
378 | static void | 382 | static void |
379 | set_next(peer_t *p, unsigned t) | 383 | set_next(peer_t *p, unsigned t) |
380 | { | 384 | { |
381 | p->next_action_time = time(NULL) + t; | 385 | p->next_action_time = G.cur_time + t; |
382 | } | 386 | } |
383 | 387 | ||
384 | /* | 388 | /* |
385 | * Peer clock filter and its helpers | 389 | * Peer clock filter and its helpers |
386 | */ | 390 | */ |
387 | static void | 391 | static void |
388 | filter_datapoints(peer_t *p, double t) | 392 | filter_datapoints(peer_t *p) |
389 | { | 393 | { |
390 | int i, idx; | 394 | int i, idx; |
391 | int got_newest; | 395 | int got_newest; |
@@ -427,14 +431,14 @@ filter_datapoints(peer_t *p, double t) | |||
427 | bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", | 431 | bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", |
428 | i, | 432 | i, |
429 | p->filter_datapoint[idx].d_offset, | 433 | p->filter_datapoint[idx].d_offset, |
430 | p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx], t), | 434 | p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]), |
431 | t - p->filter_datapoint[idx].d_recv_time, | 435 | G.cur_time - p->filter_datapoint[idx].d_recv_time, |
432 | (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) | 436 | (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) |
433 | ? " (outlier by offset)" : "" | 437 | ? " (outlier by offset)" : "" |
434 | ); | 438 | ); |
435 | } | 439 | } |
436 | 440 | ||
437 | sum += dispersion(&p->filter_datapoint[idx], t) / (2 << i); | 441 | sum += dispersion(&p->filter_datapoint[idx]) / (2 << i); |
438 | 442 | ||
439 | if (minoff == p->filter_datapoint[idx].d_offset) { | 443 | if (minoff == p->filter_datapoint[idx].d_offset) { |
440 | minoff -= 1; /* so that we don't match it ever again */ | 444 | minoff -= 1; /* so that we don't match it ever again */ |
@@ -443,7 +447,7 @@ filter_datapoints(peer_t *p, double t) | |||
443 | maxoff += 1; | 447 | maxoff += 1; |
444 | } else { | 448 | } else { |
445 | oldest_off = p->filter_datapoint[idx].d_offset; | 449 | oldest_off = p->filter_datapoint[idx].d_offset; |
446 | oldest_age = t - p->filter_datapoint[idx].d_recv_time; | 450 | oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time; |
447 | if (!got_newest) { | 451 | if (!got_newest) { |
448 | got_newest = 1; | 452 | got_newest = 1; |
449 | newest_off = oldest_off; | 453 | newest_off = oldest_off; |
@@ -466,10 +470,13 @@ filter_datapoints(peer_t *p, double t) | |||
466 | * and then we have this estimation, ~25% off from 0.7: | 470 | * and then we have this estimation, ~25% off from 0.7: |
467 | * 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125 | 471 | * 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125 |
468 | */ | 472 | */ |
469 | x = newest_age / (oldest_age - newest_age); /* in above example, 100 / (600 - 100) */ | 473 | x = oldest_age - newest_age; |
470 | if (x < 1) { | 474 | if (x != 0) { |
471 | x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */ | 475 | x = newest_age / x; /* in above example, 100 / (600 - 100) */ |
472 | wavg += x; | 476 | if (x < 1) { /* paranoia check */ |
477 | x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */ | ||
478 | wavg += x; | ||
479 | } | ||
473 | } | 480 | } |
474 | p->filter_offset = wavg; | 481 | p->filter_offset = wavg; |
475 | 482 | ||
@@ -499,7 +506,7 @@ filter_datapoints(peer_t *p, double t) | |||
499 | } | 506 | } |
500 | 507 | ||
501 | static void | 508 | static void |
502 | reset_peer_stats(peer_t *p, double t, double offset) | 509 | reset_peer_stats(peer_t *p, double offset) |
503 | { | 510 | { |
504 | int i; | 511 | int i; |
505 | for (i = 0; i < NUM_DATAPOINTS; i++) { | 512 | for (i = 0; i < NUM_DATAPOINTS; i++) { |
@@ -509,7 +516,7 @@ reset_peer_stats(peer_t *p, double t, double offset) | |||
509 | p->filter_datapoint[i].d_offset -= offset; | 516 | p->filter_datapoint[i].d_offset -= offset; |
510 | } | 517 | } |
511 | } else { | 518 | } else { |
512 | p->filter_datapoint[i].d_recv_time = t; | 519 | p->filter_datapoint[i].d_recv_time = G.cur_time; |
513 | p->filter_datapoint[i].d_offset = 0; | 520 | p->filter_datapoint[i].d_offset = 0; |
514 | p->filter_datapoint[i].d_dispersion = MAXDISP; | 521 | p->filter_datapoint[i].d_dispersion = MAXDISP; |
515 | } | 522 | } |
@@ -517,11 +524,11 @@ reset_peer_stats(peer_t *p, double t, double offset) | |||
517 | if (offset < 16 * STEP_THRESHOLD) { | 524 | if (offset < 16 * STEP_THRESHOLD) { |
518 | p->lastpkt_recv_time -= offset; | 525 | p->lastpkt_recv_time -= offset; |
519 | } else { | 526 | } else { |
520 | p->p_reachable_bits = 0; | 527 | p->reachable_bits = 0; |
521 | p->lastpkt_recv_time = t; | 528 | p->lastpkt_recv_time = G.cur_time; |
522 | } | 529 | } |
523 | filter_datapoints(p, t); /* recalc p->filter_xxx */ | 530 | filter_datapoints(p); /* recalc p->filter_xxx */ |
524 | p->next_action_time -= (time_t)offset; | 531 | p->next_action_time -= offset; |
525 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); | 532 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); |
526 | } | 533 | } |
527 | 534 | ||
@@ -535,8 +542,8 @@ add_peers(char *s) | |||
535 | p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa); | 542 | p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa); |
536 | p->p_fd = -1; | 543 | p->p_fd = -1; |
537 | p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3); | 544 | p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3); |
538 | p->next_action_time = time(NULL); /* = set_next(p, 0); */ | 545 | p->next_action_time = G.cur_time; /* = set_next(p, 0); */ |
539 | reset_peer_stats(p, gettime1900d(), 16 * STEP_THRESHOLD); | 546 | reset_peer_stats(p, 16 * STEP_THRESHOLD); |
540 | /* Speed up initial sync: with small offsets from peers, | 547 | /* Speed up initial sync: with small offsets from peers, |
541 | * 3 samples will sync | 548 | * 3 samples will sync |
542 | */ | 549 | */ |
@@ -567,7 +574,7 @@ do_sendto(int fd, | |||
567 | return 0; | 574 | return 0; |
568 | } | 575 | } |
569 | 576 | ||
570 | static int | 577 | static void |
571 | send_query_to_peer(peer_t *p) | 578 | send_query_to_peer(peer_t *p) |
572 | { | 579 | { |
573 | /* Why do we need to bind()? | 580 | /* Why do we need to bind()? |
@@ -632,20 +639,19 @@ send_query_to_peer(peer_t *p) | |||
632 | close(p->p_fd); | 639 | close(p->p_fd); |
633 | p->p_fd = -1; | 640 | p->p_fd = -1; |
634 | set_next(p, RETRY_INTERVAL); | 641 | set_next(p, RETRY_INTERVAL); |
635 | return -1; | 642 | return; |
636 | } | 643 | } |
637 | 644 | ||
638 | p->p_reachable_bits <<= 1; | 645 | p->reachable_bits <<= 1; |
639 | VERB1 bb_error_msg("sent query to %s", p->p_dotted); | 646 | VERB1 bb_error_msg("sent query to %s", p->p_dotted); |
640 | set_next(p, QUERYTIME_MAX); | 647 | set_next(p, RESPONSE_INTERVAL); |
641 | |||
642 | return 0; | ||
643 | } | 648 | } |
644 | 649 | ||
645 | 650 | ||
646 | static void | 651 | static NOINLINE void |
647 | step_time(double offset) | 652 | step_time(double offset) |
648 | { | 653 | { |
654 | llist_t *item; | ||
649 | double dtime; | 655 | double dtime; |
650 | struct timeval tv; | 656 | struct timeval tv; |
651 | char buf[80]; | 657 | char buf[80]; |
@@ -663,6 +669,17 @@ step_time(double offset) | |||
663 | strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); | 669 | strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); |
664 | 670 | ||
665 | bb_error_msg("setting clock to %s (offset %fs)", buf, offset); | 671 | bb_error_msg("setting clock to %s (offset %fs)", buf, offset); |
672 | |||
673 | /* Correct various fields which contain time-relative values: */ | ||
674 | |||
675 | /* p->lastpkt_recv_time, p->next_action_time and such: */ | ||
676 | for (item = G.ntp_peers; item != NULL; item = item->link) { | ||
677 | peer_t *pp = (peer_t *) item->data; | ||
678 | reset_peer_stats(pp, offset); | ||
679 | } | ||
680 | /* Globals: */ | ||
681 | G.cur_time -= offset; | ||
682 | G.last_update_recv_time -= offset; | ||
666 | } | 683 | } |
667 | 684 | ||
668 | 685 | ||
@@ -700,7 +717,8 @@ compare_survivor_metric(const void *aa, const void *bb) | |||
700 | static int | 717 | static int |
701 | fit(peer_t *p, double rd) | 718 | fit(peer_t *p, double rd) |
702 | { | 719 | { |
703 | if (p->p_reachable_bits == 0) { | 720 | if ((p->reachable_bits & (p->reachable_bits-1)) == 0) { |
721 | /* One or zero bits in reachable_bits */ | ||
704 | VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); | 722 | VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); |
705 | return 0; | 723 | return 0; |
706 | } | 724 | } |
@@ -712,7 +730,7 @@ fit(peer_t *p, double rd) | |||
712 | return 0; | 730 | return 0; |
713 | } | 731 | } |
714 | #endif | 732 | #endif |
715 | /* rd is root_distance(p, t) */ | 733 | /* rd is root_distance(p) */ |
716 | if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) { | 734 | if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) { |
717 | VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted); | 735 | VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted); |
718 | return 0; | 736 | return 0; |
@@ -724,7 +742,7 @@ fit(peer_t *p, double rd) | |||
724 | return 1; | 742 | return 1; |
725 | } | 743 | } |
726 | static peer_t* | 744 | static peer_t* |
727 | select_and_cluster(double t) | 745 | select_and_cluster(void) |
728 | { | 746 | { |
729 | llist_t *item; | 747 | llist_t *item; |
730 | int i, j; | 748 | int i, j; |
@@ -742,9 +760,9 @@ select_and_cluster(double t) | |||
742 | 760 | ||
743 | num_points = 0; | 761 | num_points = 0; |
744 | item = G.ntp_peers; | 762 | item = G.ntp_peers; |
745 | while (item != NULL) { | 763 | if (G.initial_poll_complete) while (item != NULL) { |
746 | peer_t *p = (peer_t *) item->data; | 764 | peer_t *p = (peer_t *) item->data; |
747 | double rd = root_distance(p, t); | 765 | double rd = root_distance(p); |
748 | double offset = p->filter_offset; | 766 | double offset = p->filter_offset; |
749 | 767 | ||
750 | if (!fit(p, rd)) { | 768 | if (!fit(p, rd)) { |
@@ -775,7 +793,7 @@ select_and_cluster(double t) | |||
775 | num_candidates = num_points / 3; | 793 | num_candidates = num_points / 3; |
776 | if (num_candidates == 0) { | 794 | if (num_candidates == 0) { |
777 | VERB3 bb_error_msg("no valid datapoints, no peer selected"); | 795 | VERB3 bb_error_msg("no valid datapoints, no peer selected"); |
778 | return NULL; /* never happers? */ | 796 | return NULL; |
779 | } | 797 | } |
780 | //TODO: sorting does not seem to be done in reference code | 798 | //TODO: sorting does not seem to be done in reference code |
781 | qsort(point, num_points, sizeof(point[0]), compare_point_edge); | 799 | qsort(point, num_points, sizeof(point[0]), compare_point_edge); |
@@ -856,7 +874,7 @@ select_and_cluster(double t) | |||
856 | p = point[i].p; | 874 | p = point[i].p; |
857 | survivor[num_survivors].p = p; | 875 | survivor[num_survivors].p = p; |
858 | //TODO: save root_distance in point_t and reuse here? | 876 | //TODO: save root_distance in point_t and reuse here? |
859 | survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p, t); | 877 | survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p); |
860 | VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", | 878 | VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", |
861 | num_survivors, survivor[num_survivors].metric, p->p_dotted); | 879 | num_survivors, survivor[num_survivors].metric, p->p_dotted); |
862 | num_survivors++; | 880 | num_survivors++; |
@@ -952,7 +970,7 @@ select_and_cluster(double t) | |||
952 | VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", | 970 | VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", |
953 | survivor[0].p->p_dotted, | 971 | survivor[0].p->p_dotted, |
954 | survivor[0].p->filter_offset, | 972 | survivor[0].p->filter_offset, |
955 | t - survivor[0].p->lastpkt_recv_time | 973 | G.cur_time - survivor[0].p->lastpkt_recv_time |
956 | ); | 974 | ); |
957 | return survivor[0].p; | 975 | return survivor[0].p; |
958 | } | 976 | } |
@@ -981,8 +999,8 @@ set_new_values(int disc_state, double offset, double recv_time) | |||
981 | #define STATE_FREQ 3 /* initial frequency */ | 999 | #define STATE_FREQ 3 /* initial frequency */ |
982 | #define STATE_SYNC 4 /* clock synchronized (normal operation) */ | 1000 | #define STATE_SYNC 4 /* clock synchronized (normal operation) */ |
983 | /* Return: -1: decrease poll interval, 0: leave as is, 1: increase */ | 1001 | /* Return: -1: decrease poll interval, 0: leave as is, 1: increase */ |
984 | static int | 1002 | static NOINLINE int |
985 | update_local_clock(peer_t *p, double t) | 1003 | update_local_clock(peer_t *p) |
986 | { | 1004 | { |
987 | int rc; | 1005 | int rc; |
988 | long old_tmx_offset; | 1006 | long old_tmx_offset; |
@@ -1037,8 +1055,6 @@ update_local_clock(peer_t *p, double t) | |||
1037 | * offset exceeds the step threshold and when it does not. | 1055 | * offset exceeds the step threshold and when it does not. |
1038 | */ | 1056 | */ |
1039 | if (abs_offset > STEP_THRESHOLD) { | 1057 | if (abs_offset > STEP_THRESHOLD) { |
1040 | llist_t *item; | ||
1041 | |||
1042 | switch (G.discipline_state) { | 1058 | switch (G.discipline_state) { |
1043 | case STATE_SYNC: | 1059 | case STATE_SYNC: |
1044 | /* The first outlyer: ignore it, switch to SPIK state */ | 1060 | /* The first outlyer: ignore it, switch to SPIK state */ |
@@ -1089,10 +1105,6 @@ update_local_clock(peer_t *p, double t) | |||
1089 | G.polladj_count = 0; | 1105 | G.polladj_count = 0; |
1090 | G.poll_exp = MINPOLL; | 1106 | G.poll_exp = MINPOLL; |
1091 | G.stratum = MAXSTRAT; | 1107 | G.stratum = MAXSTRAT; |
1092 | for (item = G.ntp_peers; item != NULL; item = item->link) { | ||
1093 | peer_t *pp = (peer_t *) item->data; | ||
1094 | reset_peer_stats(pp, t, offset); | ||
1095 | } | ||
1096 | if (G.discipline_state == STATE_NSET) { | 1108 | if (G.discipline_state == STATE_NSET) { |
1097 | set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time); | 1109 | set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time); |
1098 | return 1; /* "ok to increase poll interval" */ | 1110 | return 1; /* "ok to increase poll interval" */ |
@@ -1101,8 +1113,9 @@ update_local_clock(peer_t *p, double t) | |||
1101 | 1113 | ||
1102 | } else { /* abs_offset <= STEP_THRESHOLD */ | 1114 | } else { /* abs_offset <= STEP_THRESHOLD */ |
1103 | 1115 | ||
1104 | if (G.poll_exp < MINPOLL) { | 1116 | if (G.poll_exp < MINPOLL && G.initial_poll_complete) { |
1105 | VERB3 bb_error_msg("saw small offset %f, disabling burst mode", offset); | 1117 | VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset); |
1118 | G.polladj_count = 0; | ||
1106 | G.poll_exp = MINPOLL; | 1119 | G.poll_exp = MINPOLL; |
1107 | } | 1120 | } |
1108 | 1121 | ||
@@ -1128,7 +1141,7 @@ update_local_clock(peer_t *p, double t) | |||
1128 | */ | 1141 | */ |
1129 | set_new_values(STATE_FREQ, offset, recv_time); | 1142 | set_new_values(STATE_FREQ, offset, recv_time); |
1130 | VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored"); | 1143 | VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored"); |
1131 | return -1; /* "decrease poll interval" */ | 1144 | return 0; /* "leave poll interval as is" */ |
1132 | 1145 | ||
1133 | #if 0 /* this is dead code for now */ | 1146 | #if 0 /* this is dead code for now */ |
1134 | case STATE_FSET: | 1147 | case STATE_FSET: |
@@ -1180,12 +1193,12 @@ update_local_clock(peer_t *p, double t) | |||
1180 | G.stratum = p->lastpkt_stratum + 1; | 1193 | G.stratum = p->lastpkt_stratum + 1; |
1181 | } | 1194 | } |
1182 | 1195 | ||
1183 | G.reftime = t; | 1196 | G.reftime = G.cur_time; |
1184 | G.ntp_status = p->lastpkt_status; | 1197 | G.ntp_status = p->lastpkt_status; |
1185 | G.refid = p->lastpkt_refid; | 1198 | G.refid = p->lastpkt_refid; |
1186 | G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; | 1199 | G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; |
1187 | dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter)); | 1200 | dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter)); |
1188 | dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (t - p->lastpkt_recv_time) + abs_offset, MINDISP); | 1201 | dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); |
1189 | G.rootdisp = p->lastpkt_rootdisp + dtemp; | 1202 | G.rootdisp = p->lastpkt_rootdisp + dtemp; |
1190 | VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); | 1203 | VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); |
1191 | 1204 | ||
@@ -1318,19 +1331,20 @@ retry_interval(void) | |||
1318 | return interval; | 1331 | return interval; |
1319 | } | 1332 | } |
1320 | static unsigned | 1333 | static unsigned |
1321 | poll_interval(int exponent) /* exp is always -1 or 0 */ | 1334 | poll_interval(int exponent) |
1322 | { | 1335 | { |
1323 | /* Want to send next packet at (1 << G.poll_exp) + small random value */ | 1336 | /* Want to send next packet at (1 << G.poll_exp) + small random value */ |
1324 | unsigned interval, r; | 1337 | unsigned interval, r; |
1325 | exponent += G.poll_exp; /* G.poll_exp is always > 0 */ | 1338 | exponent = G.poll_exp + exponent; |
1326 | /* never true: if (exp < 0) exp = 0; */ | 1339 | if (exponent < 0) |
1340 | exponent = 0; | ||
1327 | interval = 1 << exponent; | 1341 | interval = 1 << exponent; |
1328 | r = random(); | 1342 | r = random(); |
1329 | interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */ | 1343 | interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */ |
1330 | VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); | 1344 | VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); |
1331 | return interval; | 1345 | return interval; |
1332 | } | 1346 | } |
1333 | static void | 1347 | static NOINLINE void |
1334 | recv_and_process_peer_pkt(peer_t *p) | 1348 | recv_and_process_peer_pkt(peer_t *p) |
1335 | { | 1349 | { |
1336 | int rc; | 1350 | int rc; |
@@ -1410,12 +1424,12 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1410 | T1 = p->p_xmttime; | 1424 | T1 = p->p_xmttime; |
1411 | T2 = lfp_to_d(msg.m_rectime); | 1425 | T2 = lfp_to_d(msg.m_rectime); |
1412 | T3 = lfp_to_d(msg.m_xmttime); | 1426 | T3 = lfp_to_d(msg.m_xmttime); |
1413 | T4 = gettime1900d(); | 1427 | T4 = G.cur_time; |
1414 | 1428 | ||
1415 | p->lastpkt_recv_time = T4; | 1429 | p->lastpkt_recv_time = T4; |
1416 | 1430 | ||
1417 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); | 1431 | VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); |
1418 | p->datapoint_idx = p->p_reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; | 1432 | p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; |
1419 | datapoint = &p->filter_datapoint[p->datapoint_idx]; | 1433 | datapoint = &p->filter_datapoint[p->datapoint_idx]; |
1420 | datapoint->d_recv_time = T4; | 1434 | datapoint->d_recv_time = T4; |
1421 | datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2; | 1435 | datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2; |
@@ -1429,7 +1443,7 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1429 | if (p->lastpkt_delay < G_precision_sec) | 1443 | if (p->lastpkt_delay < G_precision_sec) |
1430 | p->lastpkt_delay = G_precision_sec; | 1444 | p->lastpkt_delay = G_precision_sec; |
1431 | datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec; | 1445 | datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec; |
1432 | if (!p->p_reachable_bits) { | 1446 | if (!p->reachable_bits) { |
1433 | /* 1st datapoint ever - replicate offset in every element */ | 1447 | /* 1st datapoint ever - replicate offset in every element */ |
1434 | int i; | 1448 | int i; |
1435 | for (i = 1; i < NUM_DATAPOINTS; i++) { | 1449 | for (i = 1; i < NUM_DATAPOINTS; i++) { |
@@ -1437,20 +1451,20 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1437 | } | 1451 | } |
1438 | } | 1452 | } |
1439 | 1453 | ||
1440 | p->p_reachable_bits |= 1; | 1454 | p->reachable_bits |= 1; |
1441 | VERB1 { | 1455 | VERB1 { |
1442 | bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f", | 1456 | bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f", |
1443 | p->p_dotted, | 1457 | p->p_dotted, |
1444 | p->p_reachable_bits, | 1458 | p->reachable_bits, |
1445 | datapoint->d_offset, p->lastpkt_delay); | 1459 | datapoint->d_offset, p->lastpkt_delay); |
1446 | } | 1460 | } |
1447 | 1461 | ||
1448 | /* Muck with statictics and update the clock */ | 1462 | /* Muck with statictics and update the clock */ |
1449 | filter_datapoints(p, T4); | 1463 | filter_datapoints(p); |
1450 | q = select_and_cluster(T4); | 1464 | q = select_and_cluster(); |
1451 | rc = -1; | 1465 | rc = -1; |
1452 | if (q) | 1466 | if (q) |
1453 | rc = update_local_clock(q, T4); | 1467 | rc = update_local_clock(q); |
1454 | 1468 | ||
1455 | if (rc != 0) { | 1469 | if (rc != 0) { |
1456 | /* Adjust the poll interval by comparing the current offset | 1470 | /* Adjust the poll interval by comparing the current offset |
@@ -1524,12 +1538,11 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1524 | } | 1538 | } |
1525 | 1539 | ||
1526 | #if ENABLE_FEATURE_NTPD_SERVER | 1540 | #if ENABLE_FEATURE_NTPD_SERVER |
1527 | static void | 1541 | static NOINLINE void |
1528 | recv_and_process_client_pkt(void /*int fd*/) | 1542 | recv_and_process_client_pkt(void /*int fd*/) |
1529 | { | 1543 | { |
1530 | ssize_t size; | 1544 | ssize_t size; |
1531 | uint8_t version; | 1545 | uint8_t version; |
1532 | double rectime; | ||
1533 | len_and_sockaddr *to; | 1546 | len_and_sockaddr *to; |
1534 | struct sockaddr *from; | 1547 | struct sockaddr *from; |
1535 | msg_t msg; | 1548 | msg_t msg; |
@@ -1565,8 +1578,9 @@ recv_and_process_client_pkt(void /*int fd*/) | |||
1565 | msg.m_stratum = G.stratum; | 1578 | msg.m_stratum = G.stratum; |
1566 | msg.m_ppoll = G.poll_exp; | 1579 | msg.m_ppoll = G.poll_exp; |
1567 | msg.m_precision_exp = G_precision_exp; | 1580 | msg.m_precision_exp = G_precision_exp; |
1568 | rectime = gettime1900d(); | 1581 | /* this time was obtained between poll() and recv() */ |
1569 | msg.m_xmttime = msg.m_rectime = d_to_lfp(rectime); | 1582 | msg.m_rectime = d_to_lfp(G.cur_time); |
1583 | msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */ | ||
1570 | msg.m_reftime = d_to_lfp(G.reftime); | 1584 | msg.m_reftime = d_to_lfp(G.reftime); |
1571 | msg.m_orgtime = query_xmttime; | 1585 | msg.m_orgtime = query_xmttime; |
1572 | msg.m_rootdelay = d_to_sfp(G.rootdelay); | 1586 | msg.m_rootdelay = d_to_sfp(G.rootdelay); |
@@ -1686,33 +1700,10 @@ static NOINLINE void ntp_init(char **argv) | |||
1686 | bb_error_msg_and_die(bb_msg_you_must_be_root); | 1700 | bb_error_msg_and_die(bb_msg_you_must_be_root); |
1687 | 1701 | ||
1688 | /* Set some globals */ | 1702 | /* Set some globals */ |
1689 | #if 0 | ||
1690 | /* With constant b = 100, G.precision_exp is also constant -6. | ||
1691 | * Uncomment this to verify. | ||
1692 | */ | ||
1693 | { | ||
1694 | int prec = 0; | ||
1695 | int b; | ||
1696 | # if 0 | ||
1697 | struct timespec tp; | ||
1698 | /* We can use sys_clock_getres but assuming 10ms tick should be fine */ | ||
1699 | clock_getres(CLOCK_REALTIME, &tp); | ||
1700 | tp.tv_sec = 0; | ||
1701 | tp.tv_nsec = 10000000; | ||
1702 | b = 1000000000 / tp.tv_nsec; /* convert to Hz */ | ||
1703 | # else | ||
1704 | b = 100; /* b = 1000000000/10000000 = 100 */ | ||
1705 | # endif | ||
1706 | while (b > 1) | ||
1707 | prec--, b >>= 1; | ||
1708 | /*G.precision_exp = prec;*/ | ||
1709 | /*G.precision_sec = (1.0 / (1 << (- prec)));*/ | ||
1710 | bb_error_msg("G.precision_exp:%d sec:%f", prec, G_precision_sec); /* -6 */ | ||
1711 | } | ||
1712 | #endif | ||
1713 | G.stratum = MAXSTRAT; | 1703 | G.stratum = MAXSTRAT; |
1714 | G.poll_exp = 1; /* should use MINPOLL, but 1 speeds up initial sync */ | 1704 | if (BURSTPOLL != 0) |
1715 | G.reftime = G.last_update_recv_time = gettime1900d(); | 1705 | G.poll_exp = BURSTPOLL; /* speeds up initial sync */ |
1706 | G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */ | ||
1716 | 1707 | ||
1717 | /* Parse options */ | 1708 | /* Parse options */ |
1718 | peers = NULL; | 1709 | peers = NULL; |
@@ -1752,61 +1743,66 @@ static NOINLINE void ntp_init(char **argv) | |||
1752 | int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1743 | int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1753 | int ntpd_main(int argc UNUSED_PARAM, char **argv) | 1744 | int ntpd_main(int argc UNUSED_PARAM, char **argv) |
1754 | { | 1745 | { |
1755 | struct globals g; | 1746 | #undef G |
1747 | struct globals G; | ||
1756 | struct pollfd *pfd; | 1748 | struct pollfd *pfd; |
1757 | peer_t **idx2peer; | 1749 | peer_t **idx2peer; |
1750 | unsigned cnt; | ||
1758 | 1751 | ||
1759 | memset(&g, 0, sizeof(g)); | 1752 | memset(&G, 0, sizeof(G)); |
1760 | SET_PTR_TO_GLOBALS(&g); | 1753 | SET_PTR_TO_GLOBALS(&G); |
1761 | 1754 | ||
1762 | ntp_init(argv); | 1755 | ntp_init(argv); |
1763 | 1756 | ||
1764 | { | 1757 | /* If ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */ |
1765 | /* if ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */ | 1758 | cnt = G.peer_cnt + ENABLE_FEATURE_NTPD_SERVER; |
1766 | unsigned cnt = g.peer_cnt + ENABLE_FEATURE_NTPD_SERVER; | 1759 | idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); |
1767 | idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); | 1760 | pfd = xzalloc(sizeof(pfd[0]) * cnt); |
1768 | pfd = xzalloc(sizeof(pfd[0]) * cnt); | 1761 | |
1769 | } | 1762 | /* Countdown: we never sync before we sent 5 packets to each peer |
1763 | * NB: if some peer is not responding, we may end up sending | ||
1764 | * fewer packets to it and more to other peers. | ||
1765 | * NB2: sync usually happens using 5-1=4 packets, since last reply | ||
1766 | * does not come back instantaneously. | ||
1767 | */ | ||
1768 | cnt = G.peer_cnt * 5; | ||
1770 | 1769 | ||
1771 | while (!bb_got_signal) { | 1770 | while (!bb_got_signal) { |
1772 | llist_t *item; | 1771 | llist_t *item; |
1773 | unsigned i, j; | 1772 | unsigned i, j; |
1774 | unsigned sent_cnt, trial_cnt; | ||
1775 | int nfds, timeout; | 1773 | int nfds, timeout; |
1776 | time_t cur_time, nextaction; | 1774 | double nextaction; |
1777 | 1775 | ||
1778 | /* Nothing between here and poll() blocks for any significant time */ | 1776 | /* Nothing between here and poll() blocks for any significant time */ |
1779 | 1777 | ||
1780 | cur_time = time(NULL); | 1778 | nextaction = G.cur_time + 3600; |
1781 | nextaction = cur_time + 3600; | ||
1782 | 1779 | ||
1783 | i = 0; | 1780 | i = 0; |
1784 | #if ENABLE_FEATURE_NTPD_SERVER | 1781 | #if ENABLE_FEATURE_NTPD_SERVER |
1785 | if (g.listen_fd != -1) { | 1782 | if (G.listen_fd != -1) { |
1786 | pfd[0].fd = g.listen_fd; | 1783 | pfd[0].fd = G.listen_fd; |
1787 | pfd[0].events = POLLIN; | 1784 | pfd[0].events = POLLIN; |
1788 | i++; | 1785 | i++; |
1789 | } | 1786 | } |
1790 | #endif | 1787 | #endif |
1791 | /* Pass over peer list, send requests, time out on receives */ | 1788 | /* Pass over peer list, send requests, time out on receives */ |
1792 | sent_cnt = trial_cnt = 0; | 1789 | for (item = G.ntp_peers; item != NULL; item = item->link) { |
1793 | for (item = g.ntp_peers; item != NULL; item = item->link) { | ||
1794 | peer_t *p = (peer_t *) item->data; | 1790 | peer_t *p = (peer_t *) item->data; |
1795 | 1791 | ||
1796 | /* Overflow-safe "if (p->next_action_time <= cur_time) ..." */ | 1792 | if (p->next_action_time <= G.cur_time) { |
1797 | if ((int)(cur_time - p->next_action_time) >= 0) { | ||
1798 | if (p->p_fd == -1) { | 1793 | if (p->p_fd == -1) { |
1799 | /* Time to send new req */ | 1794 | /* Time to send new req */ |
1800 | trial_cnt++; | 1795 | if (--cnt == 0) { |
1801 | if (send_query_to_peer(p) == 0) | 1796 | G.initial_poll_complete = 1; |
1802 | sent_cnt++; | 1797 | } |
1798 | send_query_to_peer(p); | ||
1803 | } else { | 1799 | } else { |
1804 | /* Timed out waiting for reply */ | 1800 | /* Timed out waiting for reply */ |
1805 | close(p->p_fd); | 1801 | close(p->p_fd); |
1806 | p->p_fd = -1; | 1802 | p->p_fd = -1; |
1807 | timeout = poll_interval(-1); /* try a bit faster */ | 1803 | timeout = poll_interval(-2); /* -2: try a bit sooner */ |
1808 | bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", | 1804 | bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", |
1809 | p->p_dotted, p->p_reachable_bits, timeout); | 1805 | p->p_dotted, p->reachable_bits, timeout); |
1810 | set_next(p, timeout); | 1806 | set_next(p, timeout); |
1811 | } | 1807 | } |
1812 | } | 1808 | } |
@@ -1823,23 +1819,26 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) | |||
1823 | } | 1819 | } |
1824 | } | 1820 | } |
1825 | 1821 | ||
1826 | timeout = nextaction - cur_time; | 1822 | timeout = nextaction - G.cur_time; |
1827 | if (timeout < 1) | 1823 | if (timeout < 0) |
1828 | timeout = 1; | 1824 | timeout = 0; |
1825 | timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ | ||
1829 | 1826 | ||
1830 | /* Here we may block */ | 1827 | /* Here we may block */ |
1831 | VERB2 bb_error_msg("poll %us, sockets:%u", timeout, i); | 1828 | VERB2 bb_error_msg("poll %us, sockets:%u", timeout, i); |
1832 | nfds = poll(pfd, i, timeout * 1000); | 1829 | nfds = poll(pfd, i, timeout * 1000); |
1830 | gettime1900d(); /* sets G.cur_time */ | ||
1833 | if (nfds <= 0) | 1831 | if (nfds <= 0) |
1834 | continue; | 1832 | continue; |
1835 | 1833 | ||
1836 | /* Process any received packets */ | 1834 | /* Process any received packets */ |
1837 | j = 0; | 1835 | j = 0; |
1838 | #if ENABLE_FEATURE_NTPD_SERVER | 1836 | #if ENABLE_FEATURE_NTPD_SERVER |
1839 | if (g.listen_fd != -1) { | 1837 | if (G.listen_fd != -1) { |
1840 | if (pfd[0].revents /* & (POLLIN|POLLERR)*/) { | 1838 | if (pfd[0].revents /* & (POLLIN|POLLERR)*/) { |
1841 | nfds--; | 1839 | nfds--; |
1842 | recv_and_process_client_pkt(/*g.listen_fd*/); | 1840 | recv_and_process_client_pkt(/*G.listen_fd*/); |
1841 | gettime1900d(); /* sets G.cur_time */ | ||
1843 | } | 1842 | } |
1844 | j = 1; | 1843 | j = 1; |
1845 | } | 1844 | } |
@@ -1848,6 +1847,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) | |||
1848 | if (pfd[j].revents /* & (POLLIN|POLLERR)*/) { | 1847 | if (pfd[j].revents /* & (POLLIN|POLLERR)*/) { |
1849 | nfds--; | 1848 | nfds--; |
1850 | recv_and_process_peer_pkt(idx2peer[j]); | 1849 | recv_and_process_peer_pkt(idx2peer[j]); |
1850 | gettime1900d(); /* sets G.cur_time */ | ||
1851 | } | 1851 | } |
1852 | } | 1852 | } |
1853 | } /* while (!bb_got_signal) */ | 1853 | } /* while (!bb_got_signal) */ |