2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static int client_insane(struct server_info
**, int, server_info_t
);
45 client_main(struct server_info
**info_ary
, int count
)
47 struct server_info
*best_off
;
48 struct server_info
*best_freq
;
52 int calc_offset_correction
;
61 * Subtract the interval from poll_sleep and poll the client
64 * Because we do not compensate for offset corrections which are
65 * in progress, we cannot accumulate data for an offset correction
66 * while a prior correction is still being worked through by the
69 calc_offset_correction
= !sysntp_offset_correction_is_running();
70 for (i
= 0; i
< count
; ++i
)
71 client_poll(info_ary
[i
], min_sleep_opt
, calc_offset_correction
);
74 * Find the best client (or synthesize one). A different client
75 * can be chosen for frequency and offset. Note in particular
76 * that offset counters and averaging code gets reset when an
77 * offset correction is made (otherwise the averaging history will
78 * cause later corrections to overshoot).
80 * The regression used to calculate the frequency is a much
81 * longer-term entity and is NOT reset, so it is still possible
82 * for the offset correction code to make minor adjustments to
83 * the frequency if it so desires.
85 * client_check may replace the server_info pointer with a new
90 for (i
= 0; i
< count
; ++i
)
91 client_check(&info_ary
[i
], &best_off
, &best_freq
);
94 * Check for server insanity. In large NNTP pools some servers
95 * may just be dead wrong, but report that they are right.
98 insane
= client_insane(info_ary
, count
, best_off
);
101 * best_off meets the quorum requirements and is good
104 best_off
->server_insane
= 0;
105 } else if (insane
== 0) {
107 * best_off is probably good, but we do not have enough
108 * servers reporting yet to meet the quorum requirements.
113 * best_off is ugly, mark the server as being insane for
116 best_off
->server_insane
= 60 * 60;
117 logdebuginfo(best_off
, 1,
118 "excessive offset deviation, mapping out\n");
127 offset
= best_off
->lin_sumoffset
/ best_off
->lin_countoffset
;
128 lin_resetalloffsets(info_ary
, count
);
129 if (offset
< -COURSE_OFFSET_CORRECTION_LIMIT
||
130 offset
> COURSE_OFFSET_CORRECTION_LIMIT
||
133 freq
= sysntp_correct_course_offset(offset
);
136 freq
= sysntp_correct_offset(offset
);
143 * Frequency correction (throw away minor freq adjusts from the
144 * offset code if we can't do a frequency correction here). Do
145 * not reissue if it hasn't changed from the last issued correction.
148 freq
+= best_freq
->lin_cache_freq
;
149 if (last_freq
!= freq
) {
150 sysntp_correct_freq(freq
);
156 * This function is responsible for managing the polling mode and
157 * figures out how long we should sleep.
160 for (i
= 0; i
< count
; ++i
)
161 client_manage_polling_mode(info_ary
[i
], &didreconnect
);
163 client_check_duplicate_ips(info_ary
, count
);
166 * Polling loop sleep.
168 usleep(min_sleep_opt
* 1000000 + random() % 500000);
173 client_poll(server_info_t info
, int poll_interval
, int calc_offset_correction
)
181 * Adjust the insane-server countdown
183 if (info
->server_insane
> poll_interval
)
184 info
->server_insane
-= poll_interval
;
186 info
->server_insane
= 0;
189 * By default we always poll. If the polling interval comes under
190 * active management the poll_sleep will be non-zero.
192 if (info
->poll_sleep
> poll_interval
) {
193 info
->poll_sleep
-= poll_interval
;
196 info
->poll_sleep
= 0;
199 * If the client isn't open don't mess with the poll_failed count
200 * or anything else. We are left in the init or startup phase.
203 if (info
->poll_failed
< 0x7FFFFFFF)
208 logdebuginfo(info
, 4, "poll, ");
209 if (udp_ntptimereq(info
->fd
, &rtv
, <v
, &lbtv
) < 0) {
211 logdebug(4, "no response (%d failures in a row)\n", info
->poll_failed
);
212 if (info
->poll_failed
== POLL_FAIL_RESET
) {
213 if (info
->lin_count
!= 0) {
214 logdebuginfo(info
, 4, "resetting regression due to failures\n");
222 * Successful query. Update polling info for the polling mode manager.
225 info
->poll_failed
= 0;
228 * Figure out the offset (the difference between the reported
229 * time and our current time) for linear regression purposes.
231 offset
= tv_delta_double(&rtv
, <v
);
237 if (debug_level
>= 4) {
244 strftime(buf
, sizeof(buf
), "%d-%b-%Y %H:%M:%S", tp
);
245 logdebug(4, "%s.%03ld ", buf
, rtv
.tv_usec
/ 1000);
247 lin_regress(info
, <v
, &lbtv
, offset
, calc_offset_correction
);
248 info
= info
->altinfo
;
249 if (info
&& debug_level
>= 4) {
250 logdebug(4, "%*.*s: poll, ",
251 (int)strlen(info
->target
),
252 (int)strlen(info
->target
), "(alt)");
258 * Find the best client (or synthesize a fake info structure to return).
259 * We can find separate best clients for offset and frequency.
262 client_check(struct server_info
**checkp
,
263 struct server_info
**best_off
,
264 struct server_info
**best_freq
)
266 struct server_info
*check
= *checkp
;
267 struct server_info
*info
;
271 * Start an alternate linear regression once our current one
272 * has passed a certain point.
274 if (check
->lin_count
>= LIN_RESTART
/ 2 && check
->altinfo
== NULL
) {
275 info
= malloc(sizeof(*info
));
276 assert(info
!= NULL
);
277 /* note: check->altinfo is NULL as of the bcopy */
278 bcopy(check
, info
, sizeof(*info
));
279 check
->altinfo
= info
;
284 * Replace our current linear regression with the alternate once
285 * the current one has hit its limit (beyond a certain point the
286 * linear regression starts to work against us, preventing us from
287 * reacting to changing conditions).
289 * Report any significant change in the offset or ppm.
291 if (check
->lin_count
>= LIN_RESTART
) {
292 if ((info
= check
->altinfo
) && info
->lin_count
>= LIN_RESTART
/ 2) {
295 freq_diff
= info
->lin_cache_freq
- check
->lin_cache_freq
;
296 logdebuginfo(info
, 4, "Switching to alternate, Frequency "
297 "difference is %6.3f ppm\n",
306 * BEST CLIENT FOR FREQUENCY CORRECTION:
308 * Frequency corrections get better the longer the time separation
311 * 8 samples and a correlation > 0.99, or
312 * 16 samples and a correlation > 0.96
315 if ((check
->lin_count
>= 8 && fabs(check
->lin_cache_corr
) >= 0.99) ||
316 (check
->lin_count
>= 16 && fabs(check
->lin_cache_corr
) >= 0.96)
319 fabs(check
->lin_cache_corr
) > fabs(info
->lin_cache_corr
)
328 * BEST CLIENT FOR OFFSET CORRECTION:
330 * Use the standard-deviation and require at least 4 samples. An
331 * offset correction is valid if the standard deviation is less then
332 * the average offset divided by 4.
334 * If we are in maintainance mode, require 8 samples instead of 4.
335 * Offset corrections get better with more samples. This reduces
336 * ping-pong effects that can occur with a small number of samples.
338 * Servers marked as being insane are not allowed
341 if (info
&& info
->poll_mode
== POLL_MAINTAIN
)
345 if (check
->lin_countoffset
>= min_samples
&&
346 (check
->lin_cache_stddev
<
347 fabs(check
->lin_sumoffset
/ check
->lin_countoffset
/ 4)) &&
348 check
->server_insane
== 0
351 fabs(check
->lin_cache_stddev
) < fabs(info
->lin_cache_stddev
)
360 * Actively manage the polling interval. Note that the poll_* fields are
361 * always transfered to the alternate regression when the check code replaces
362 * the current regression with a new one.
364 * This routine is called from the main loop for each base info structure.
365 * The polling mode applies to all alternates so we do not have to iterate
369 client_manage_polling_mode(struct server_info
*info
, int *didreconnect
)
372 * Permanently failed servers are ignored.
374 if (info
->server_state
== -2)
378 * Our polling interval has not yet passed.
380 if (info
->poll_sleep
)
384 * Standard polling mode progression
386 switch(info
->poll_mode
) {
389 * Initial state after connect or when a reconnect is required.
392 logdebuginfo(info
, 2, "polling mode INIT, relookup & reconnect\n");
393 reconnect_server(info
);
396 if (info
->poll_failed
>= POLL_RECOVERY_RESTART
* 5)
397 info
->poll_sleep
= max_sleep_opt
;
398 else if (info
->poll_failed
>= POLL_RECOVERY_RESTART
)
399 info
->poll_sleep
= nom_sleep_opt
;
401 info
->poll_sleep
= min_sleep_opt
;
406 * Transition the server to the DNS lookup successful state.
407 * Note that the server state does not transition out of
408 * lookup successful if we relookup after a packet failure
409 * so the message is printed only once, usually.
411 client_setserverstate(info
, 0, "DNS lookup success");
414 * If we've failed many times switch to the startup state but
415 * do not fall through into it. break the switch and a single
416 * poll will be made after the nominal polling interval.
418 if (info
->poll_failed
>= POLL_RECOVERY_RESTART
* 5) {
419 logdebuginfo(info
, 2, "polling mode INIT->STARTUP (very slow)\n");
420 info
->poll_mode
= POLL_STARTUP
;
421 info
->poll_sleep
= max_sleep_opt
;
422 info
->poll_count
= 0;
424 } else if (info
->poll_failed
>= POLL_RECOVERY_RESTART
) {
425 logdebuginfo(info
, 2, "polling mode INIT->STARTUP (slow)\n");
426 info
->poll_mode
= POLL_STARTUP
;
427 info
->poll_count
= 0;
433 * Fall through to the startup state.
435 info
->poll_mode
= POLL_STARTUP
;
436 logdebuginfo(info
, 2, "polling mode INIT->STARTUP (normal)\n");
440 * Transition to a FAILED state if too many poll failures occured.
442 if (info
->poll_failed
>= POLL_FAIL_RESET
) {
443 logdebuginfo(info
, 2, "polling mode STARTUP->FAILED\n");
444 info
->poll_mode
= POLL_FAILED
;
445 info
->poll_count
= 0;
450 * Transition the server to operational. Do a number of minimum
451 * interval polls to try to get a good offset calculation quickly.
453 if (info
->poll_count
)
454 client_setserverstate(info
, 1, "connected ok");
455 if (info
->poll_count
< POLL_STARTUP_MAX
) {
456 info
->poll_sleep
= min_sleep_opt
;
461 * Once we've got our polls fall through to aquisition mode to
462 * do aquisition processing.
464 info
->poll_mode
= POLL_ACQUIRE
;
465 info
->poll_count
= 0;
466 logdebuginfo(info
, 2, "polling mode STARTUP->ACQUIRE\n");
470 * Transition to a FAILED state if too many poll failures occured.
472 if (info
->poll_failed
>= POLL_FAIL_RESET
) {
473 logdebuginfo(info
, 2, "polling mode STARTUP->FAILED\n");
474 info
->poll_mode
= POLL_FAILED
;
475 info
->poll_count
= 0;
480 * Acquisition mode using the nominal timeout. We do not shift
481 * to maintainance mode unless the correlation is at least 0.90
483 if (info
->poll_count
< POLL_ACQUIRE_MAX
||
484 info
->lin_count
< 8 ||
485 fabs(info
->lin_cache_corr
) < 0.85
487 if (info
->poll_count
>= POLL_ACQUIRE_MAX
&&
488 info
->lin_count
== LIN_RESTART
- 2
490 logdebuginfo(info
, 2,
491 "WARNING: Unable to shift this source to "
492 "maintenance mode. Target correlation is awful\n");
496 info
->poll_mode
= POLL_MAINTAIN
;
497 info
->poll_count
= 0;
498 logdebuginfo(info
, 2, "polling mode ACQUIRE->MAINTAIN\n");
502 * Transition to a FAILED state if too many poll failures occured.
504 if (info
->poll_failed
>= POLL_FAIL_RESET
) {
505 logdebuginfo(info
, 2, "polling mode STARTUP->FAILED\n");
506 info
->poll_mode
= POLL_FAILED
;
507 info
->poll_count
= 0;
512 * Maintaince mode, max polling interval.
514 * Transition back to acquisition mode if we are unable to maintain
515 * this mode due to the correlation going bad.
517 if (info
->lin_count
>= LIN_RESTART
/ 2 &&
518 fabs(info
->lin_cache_corr
) < 0.70
520 logdebuginfo(info
, 2,
521 "polling mode MAINTAIN->ACQUIRE. Unable to maintain\n"
522 "the maintenance mode because the correlation went"
524 info
->poll_mode
= POLL_ACQUIRE
;
525 info
->poll_count
= 0;
528 info
->poll_sleep
= max_sleep_opt
;
532 * We have a communications failure. A late recovery is possible
533 * if we enter this state with a good poll.
535 if (info
->poll_count
!= 0) {
536 logdebuginfo(info
, 2, "polling mode FAILED->ACQUIRE\n");
537 if (info
->poll_failed
>= POLL_FAIL_RESET
)
538 info
->poll_mode
= POLL_STARTUP
;
540 info
->poll_mode
= POLL_ACQUIRE
;
541 /* do not reset poll_count */
546 * If we have been failed too long, disconnect from the server
547 * and start us all over again. Note that the failed count is not
550 if (info
->poll_failed
>= POLL_RECOVERY_RESTART
) {
551 logdebuginfo(info
, 2, "polling mode FAILED->INIT\n");
552 client_setserverstate(info
, 0, "FAILED");
553 disconnect_server(info
);
554 info
->poll_mode
= POLL_FIXED
;
561 * If the above state machine has not set a polling interval, set a
562 * nominal polling interval.
564 if (info
->poll_sleep
== 0)
565 info
->poll_sleep
= nom_sleep_opt
;
569 * Look for duplicate IP addresses. This is done very inoften, so we do
570 * not use a particularly efficient algorithm.
572 * Only reconnect a client which has not done its initial poll.
575 client_check_duplicate_ips(struct server_info
**info_ary
, int count
)
583 for (i
= 0; i
< count
; ++i
) {
585 if (info1
->fd
< 0 || info1
->server_state
!= 0)
587 for (tries
= 0; tries
< 10; ++tries
) {
588 for (j
= 0; j
< count
; ++j
) {
590 if (i
== j
|| info2
->fd
< 0)
592 if (info1
->fd
< 0 || /* info1 was lost in previous reconnect */
593 strcmp(info1
->ipstr
, info2
->ipstr
) == 0) {
594 reconnect_server(info1
);
602 disconnect_server(info1
);
603 client_setserverstate(info1
, -2,
604 "permanently disabling duplicate server");
610 * Calculate whether the server pointed to by *bestp is insane or not.
611 * For some reason some servers in e.g. the ntp pool are sometimes an hour
612 * off. If we have at least three servers in the pool require that a
613 * quorum agree that the current best server's offset is reasonable.
615 * Allow +/- 0.5 seconds of error for now (settable with option).
617 * Returns -1 if insane, 0 if not enough samples, and 1 if ok
621 client_insane(struct server_info
**info_ary
, int count
, server_info_t best
)
633 * If only one ntp server we cannot check to see if it is insane
637 best_offset
= best
->lin_sumoffset
/ best
->lin_countoffset
;
640 * Calculated the quorum. Do not count permanently failed servers
641 * in the calculation.
643 * adjusted count quorum
650 for (i
= 0; i
< count
; ++i
) {
652 if (info
->server_state
== -2)
656 quorum
= quorum
/ 2 + 1;
662 * Find the good, the bad, and the ugly. We need at least four samples
663 * and a stddev within the deviation being checked to count a server
664 * in the calculation.
666 for (i
= 0; i
< count
; ++i
) {
668 if (info
->lin_countoffset
< 4 ||
669 info
->lin_cache_stddev
> insane_deviation
675 info_offset
= info
->lin_sumoffset
/ info
->lin_countoffset
;
676 info_offset
-= best_offset
;
677 if (info_offset
< -insane_deviation
|| info_offset
> insane_deviation
)
684 * Did we meet our quorum?
686 logdebuginfo(best
, 5, "insanecheck good=%d bad=%d skip=%d "
687 "quorum=%d (allowed=%-+8.6f)\n",
688 good
, bad
, skip
, quorum
, insane_deviation
);
691 if (good
+ skip
>= quorum
)
699 * ltv local time as of when the offset error was calculated between
700 * local time and remote time.
702 * lbtv base time as of when local time was obtained. Used to
703 * calculate the cumulative corrections made to the system's
704 * real time clock so we can de-correct the offset for the
707 * X is the time axis, in seconds.
708 * Y is the uncorrected offset, in seconds.
711 lin_regress(server_info_t info
, struct timeval
*ltv
, struct timeval
*lbtv
,
712 double offset
, int calc_offset_correction
)
715 double uncorrected_offset
;
718 * De-correcting the offset:
720 * The passed offset is (our_real_time - remote_real_time). To remove
721 * corrections from our_real_time we take the difference in the basetime
722 * (new_base_time - old_base_time) and subtract that from the offset.
723 * That is, if the basetime goesup, the uncorrected offset goes down.
725 if (info
->lin_count
== 0) {
727 info
->lin_btv
= *lbtv
;
729 uncorrected_offset
= offset
;
731 time_axis
= tv_delta_double(&info
->lin_tv
, ltv
);
732 uncorrected_offset
= offset
- tv_delta_double(&info
->lin_btv
, lbtv
);
736 * We have to use the uncorrected offset for frequency calculations.
739 info
->lin_sumx
+= time_axis
;
740 info
->lin_sumx2
+= time_axis
* time_axis
;
741 info
->lin_sumy
+= uncorrected_offset
;
742 info
->lin_sumy2
+= uncorrected_offset
* uncorrected_offset
;
743 info
->lin_sumxy
+= time_axis
* uncorrected_offset
;
746 * We have to use the corrected offset for offset calculations.
748 if (calc_offset_correction
) {
749 ++info
->lin_countoffset
;
750 info
->lin_sumoffset
+= offset
;
751 info
->lin_sumoffset2
+= offset
* offset
;
755 * Calculate various derived values. This gets us slope, y-intercept,
756 * and correlation from the linear regression.
758 if (info
->lin_count
> 1) {
759 info
->lin_cache_slope
=
760 (info
->lin_count
* info
->lin_sumxy
- info
->lin_sumx
* info
->lin_sumy
) /
761 (info
->lin_count
* info
->lin_sumx2
- info
->lin_sumx
* info
->lin_sumx
);
763 info
->lin_cache_yint
=
764 (info
->lin_sumy
- info
->lin_cache_slope
* info
->lin_sumx
) /
767 info
->lin_cache_corr
=
768 (info
->lin_count
* info
->lin_sumxy
- info
->lin_sumx
* info
->lin_sumy
) /
769 sqrt((info
->lin_count
* info
->lin_sumx2
-
770 info
->lin_sumx
* info
->lin_sumx
) *
771 (info
->lin_count
* info
->lin_sumy2
-
772 info
->lin_sumy
* info
->lin_sumy
)
777 * Calculate more derived values. This gets us the standard-deviation
778 * of offsets. The standard deviation approximately means that 68%
779 * of the samples fall within the calculated stddev of the mean.
781 if (info
->lin_countoffset
> 1) {
782 info
->lin_cache_stddev
=
783 sqrt((info
->lin_sumoffset2
-
784 ((info
->lin_sumoffset
* info
->lin_sumoffset
/
785 info
->lin_countoffset
))) /
786 (info
->lin_countoffset
- 1.0));
790 * Save the most recent offset, we might use it in the future.
791 * Save the frequency correction (we might scale the slope later so
792 * we have a separate field for the actual frequency correction in
793 * seconds per second).
795 info
->lin_cache_offset
= offset
;
796 info
->lin_cache_freq
= info
->lin_cache_slope
;
798 if (debug_level
>= 4) {
799 logdebuginfo(info
, 4, "iter=%2d time=%7.3f off=%+.6f uoff=%+.6f",
800 (int)info
->lin_count
,
801 time_axis
, offset
, uncorrected_offset
);
802 if (info
->lin_count
> 1) {
803 logdebug(4, " slope %+7.6f"
804 " yint %+3.2f corr %+7.6f freq_ppm %+4.2f",
805 info
->lin_cache_slope
,
806 info
->lin_cache_yint
,
807 info
->lin_cache_corr
,
808 info
->lin_cache_freq
* 1000000.0);
810 if (info
->lin_countoffset
> 1) {
811 logdebug(4, " stddev %7.6f", info
->lin_cache_stddev
);
812 } else if (calc_offset_correction
== 0) {
813 /* cannot calculate offset correction due to prior correction */
814 logdebug(4, " offset_ignored");
821 * Reset the linear regression data. The info structure will not again be
822 * a candidate for frequency or offset correction until sufficient data
823 * has been accumulated to make a decision.
826 lin_reset(server_info_t info
)
837 info
->lin_countoffset
= 0;
838 info
->lin_sumoffset
= 0;
839 info
->lin_sumoffset2
= 0;
841 info
->lin_cache_slope
= 0;
842 info
->lin_cache_yint
= 0;
843 info
->lin_cache_corr
= 0;
844 info
->lin_cache_offset
= 0;
845 info
->lin_cache_freq
= 0;
848 * Destroy any additional alternative regressions.
850 while ((scan
= info
->altinfo
) != NULL
) {
851 info
->altinfo
= scan
->altinfo
;
857 * Sometimes we want to clean out the offset calculations without
858 * destroying the linear regression used to figure out the frequency
859 * correction. This usually occurs whenever we issue an offset
860 * adjustment to the system, which invalidates any offset data accumulated
864 lin_resetalloffsets(struct server_info
**info_ary
, int count
)
869 for (i
= 0; i
< count
; ++i
) {
870 for (info
= info_ary
[i
]; info
; info
= info
->altinfo
)
871 lin_resetoffsets(info
);
876 lin_resetoffsets(server_info_t info
)
878 info
->lin_countoffset
= 0;
879 info
->lin_sumoffset
= 0;
880 info
->lin_sumoffset2
= 0;
884 client_setserverstate(server_info_t info
, int state
, const char *str
)
886 if (info
->server_state
!= state
) {
887 info
->server_state
= state
;
888 logdebuginfo(info
, 1, "%s\n", str
);