ipfw: Use netisr wrappers
[dragonfly.git] / usr.sbin / dntpd / client.c
blobb6a7dc4559a7cc21786c50d7ed58f58e9d3ebfa6
1 /*
2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
35 #include "defs.h"
37 static int client_insane(struct server_info **, int, server_info_t);
39 void
40 client_init(void)
44 int
45 client_main(struct server_info **info_ary, int count)
47 struct server_info *best_off;
48 struct server_info *best_freq;
49 double last_freq;
50 double freq;
51 double offset;
52 int calc_offset_correction;
53 int didreconnect;
54 int i;
55 int insane;
57 last_freq = 0.0;
59 for (;;) {
61 * Subtract the interval from poll_sleep and poll the client
62 * if it reaches 0.
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
67 * system.
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
86 * one.
88 best_off = NULL;
89 best_freq = NULL;
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.
97 if (best_off) {
98 insane = client_insane(info_ary, count, best_off);
99 if (insane > 0) {
101 * best_off meets the quorum requirements and is good
102 * (keep best_off)
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.
110 best_off = NULL;
111 } else {
113 * best_off is ugly, mark the server as being insane for
114 * 60 minutes.
116 best_off->server_insane = 60 * 60;
117 logdebuginfo(best_off, 1,
118 "excessive offset deviation, mapping out\n");
119 best_off = NULL;
124 * Offset correction.
126 if (best_off) {
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 ||
131 quickset_opt
133 freq = sysntp_correct_course_offset(offset);
134 quickset_opt = 0;
135 } else {
136 freq = sysntp_correct_offset(offset);
138 } else {
139 freq = 0.0;
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.
147 if (best_freq) {
148 freq += best_freq->lin_cache_freq;
149 if (last_freq != freq) {
150 sysntp_correct_freq(freq);
151 last_freq = freq;
156 * This function is responsible for managing the polling mode and
157 * figures out how long we should sleep.
159 didreconnect = 0;
160 for (i = 0; i < count; ++i)
161 client_manage_polling_mode(info_ary[i], &didreconnect);
162 if (didreconnect)
163 client_check_duplicate_ips(info_ary, count);
166 * Polling loop sleep.
168 usleep(min_sleep_opt * 1000000 + random() % 500000);
172 void
173 client_poll(server_info_t info, int poll_interval, int calc_offset_correction)
175 struct timeval rtv;
176 struct timeval ltv;
177 struct timeval lbtv;
178 double offset;
181 * Adjust the insane-server countdown
183 if (info->server_insane > poll_interval)
184 info->server_insane -= poll_interval;
185 else
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;
194 return;
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.
202 if (info->fd < 0) {
203 if (info->poll_failed < 0x7FFFFFFF)
204 ++info->poll_failed;
205 return;
208 logdebuginfo(info, 4, "poll, ");
209 if (udp_ntptimereq(info->fd, &rtv, &ltv, &lbtv) < 0) {
210 ++info->poll_failed;
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");
216 lin_reset(info);
218 return;
222 * Successful query. Update polling info for the polling mode manager.
224 ++info->poll_count;
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, &ltv);
233 while (info) {
235 * Linear regression
237 if (debug_level >= 4) {
238 struct tm *tp;
239 char buf[64];
240 time_t t;
242 t = rtv.tv_sec;
243 tp = localtime(&t);
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, &ltv, &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.
261 void
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;
268 int min_samples;
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;
280 lin_reset(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) {
293 double freq_diff;
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",
298 freq_diff * 1.0E+6);
299 *checkp = info;
300 free(check);
301 check = info;
306 * BEST CLIENT FOR FREQUENCY CORRECTION:
308 * Frequency corrections get better the longer the time separation
309 * between samples.
311 * 8 samples and a correlation > 0.99, or
312 * 16 samples and a correlation > 0.96
314 info = *best_freq;
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)
318 if (info == NULL ||
319 fabs(check->lin_cache_corr) > fabs(info->lin_cache_corr)
321 info = check;
322 *best_freq = info;
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
340 info = *best_off;
341 if (info && info->poll_mode == POLL_MAINTAIN)
342 min_samples = 8;
343 else
344 min_samples = 4;
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
350 if (info == NULL ||
351 fabs(check->lin_cache_stddev) < fabs(info->lin_cache_stddev)
353 info = check;
354 *best_off = info;
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
366 * through the alt's.
368 void
369 client_manage_polling_mode(struct server_info *info, int *didreconnect)
372 * Permanently failed servers are ignored.
374 if (info->server_state == -2)
375 return;
378 * Our polling interval has not yet passed.
380 if (info->poll_sleep)
381 return;
384 * Standard polling mode progression
386 switch(info->poll_mode) {
387 case POLL_FIXED:
389 * Initial state after connect or when a reconnect is required.
391 if (info->fd < 0) {
392 logdebuginfo(info, 2, "polling mode INIT, relookup & reconnect\n");
393 reconnect_server(info);
394 *didreconnect = 1;
395 if (info->fd < 0) {
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;
400 else
401 info->poll_sleep = min_sleep_opt;
402 break;
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;
423 break;
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;
428 break;
433 * Fall through to the startup state.
435 info->poll_mode = POLL_STARTUP;
436 logdebuginfo(info, 2, "polling mode INIT->STARTUP (normal)\n");
437 /* fall through */
438 case POLL_STARTUP:
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;
446 break;
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;
457 break;
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");
467 /* fall through */
468 case POLL_ACQUIRE:
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;
476 break;
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");
494 break;
496 info->poll_mode = POLL_MAINTAIN;
497 info->poll_count = 0;
498 logdebuginfo(info, 2, "polling mode ACQUIRE->MAINTAIN\n");
499 /* fall through */
500 case POLL_MAINTAIN:
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;
508 break;
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"
523 " bad!\n");
524 info->poll_mode = POLL_ACQUIRE;
525 info->poll_count = 0;
526 break;
528 info->poll_sleep = max_sleep_opt;
529 break;
530 case POLL_FAILED:
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;
539 else
540 info->poll_mode = POLL_ACQUIRE;
541 /* do not reset poll_count */
542 break;
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
548 * reset to 0.
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;
555 break;
557 break;
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.
574 void
575 client_check_duplicate_ips(struct server_info **info_ary, int count)
577 server_info_t info1;
578 server_info_t info2;
579 int tries;
580 int i;
581 int j;
583 for (i = 0; i < count; ++i) {
584 info1 = info_ary[i];
585 if (info1->fd < 0 || info1->server_state != 0)
586 continue;
587 for (tries = 0; tries < 10; ++tries) {
588 for (j = 0; j < count; ++j) {
589 info2 = info_ary[j];
590 if (i == j || info2->fd < 0)
591 continue;
592 if (info1->fd < 0 || /* info1 was lost in previous reconnect */
593 strcmp(info1->ipstr, info2->ipstr) == 0) {
594 reconnect_server(info1);
595 break;
598 if (j == count)
599 break;
601 if (tries == 10) {
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
619 static
621 client_insane(struct server_info **info_ary, int count, server_info_t best)
623 server_info_t info;
624 double best_offset;
625 double info_offset;
626 int good;
627 int bad;
628 int skip;
629 int quorum;
630 int i;
633 * If only one ntp server we cannot check to see if it is insane
635 if (count < 2)
636 return(1);
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
644 * 2 2
645 * 3 2
646 * 4 3
647 * 5 3
649 quorum = count;
650 for (i = 0; i < count; ++i) {
651 info = info_ary[i];
652 if (info->server_state == -2)
653 --quorum;
656 quorum = quorum / 2 + 1;
657 good = 0;
658 bad = 0;
659 skip = 0;
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) {
667 info = info_ary[i];
668 if (info->lin_countoffset < 4 ||
669 info->lin_cache_stddev > insane_deviation
671 ++skip;
672 continue;
675 info_offset = info->lin_sumoffset / info->lin_countoffset;
676 info_offset -= best_offset;
677 if (info_offset < -insane_deviation || info_offset > insane_deviation)
678 ++bad;
679 else
680 ++good;
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);
689 if (good >= quorum)
690 return(1);
691 if (good + skip >= quorum)
692 return(0);
693 return(-1);
697 * Linear regression.
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
705 * linear regression.
707 * X is the time axis, in seconds.
708 * Y is the uncorrected offset, in seconds.
710 void
711 lin_regress(server_info_t info, struct timeval *ltv, struct timeval *lbtv,
712 double offset, int calc_offset_correction)
714 double time_axis;
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) {
726 info->lin_tv = *ltv;
727 info->lin_btv = *lbtv;
728 time_axis = 0;
729 uncorrected_offset = offset;
730 } else {
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.
738 ++info->lin_count;
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) /
765 (info->lin_count);
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");
816 logdebug(4, "\n");
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.
825 void
826 lin_reset(server_info_t info)
828 server_info_t scan;
830 info->lin_count = 0;
831 info->lin_sumx = 0;
832 info->lin_sumy = 0;
833 info->lin_sumxy = 0;
834 info->lin_sumx2 = 0;
835 info->lin_sumy2 = 0;
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;
852 free(scan);
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
861 * up to that point.
863 void
864 lin_resetalloffsets(struct server_info **info_ary, int count)
866 server_info_t info;
867 int i;
869 for (i = 0; i < count; ++i) {
870 for (info = info_ary[i]; info; info = info->altinfo)
871 lin_resetoffsets(info);
875 void
876 lin_resetoffsets(server_info_t info)
878 info->lin_countoffset = 0;
879 info->lin_sumoffset = 0;
880 info->lin_sumoffset2 = 0;
883 void
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);