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: 10 * 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. 20 * 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. 33 * 34 * $DragonFly: src/usr.sbin/dntpd/client.c,v 1.13 2007/06/26 02:40:20 dillon Exp $ 35 */ 36 37 #include "defs.h" 38 39 static int client_insane(struct server_info **, int, server_info_t); 40 41 void 42 client_init(void) 43 { 44 } 45 46 int 47 client_main(struct server_info **info_ary, int count) 48 { 49 struct server_info *best_off; 50 struct server_info *best_freq; 51 double last_freq; 52 double freq; 53 double offset; 54 int calc_offset_correction; 55 int didreconnect; 56 int i; 57 int insane; 58 59 last_freq = 0.0; 60 61 for (;;) { 62 /* 63 * Subtract the interval from poll_sleep and poll the client 64 * if it reaches 0. 65 * 66 * Because we do not compensate for offset corrections which are 67 * in progress, we cannot accumulate data for an offset correction 68 * while a prior correction is still being worked through by the 69 * system. 70 */ 71 calc_offset_correction = !sysntp_offset_correction_is_running(); 72 for (i = 0; i < count; ++i) 73 client_poll(info_ary[i], min_sleep_opt, calc_offset_correction); 74 75 /* 76 * Find the best client (or synthesize one). A different client 77 * can be chosen for frequency and offset. Note in particular 78 * that offset counters and averaging code gets reset when an 79 * offset correction is made (otherwise the averaging history will 80 * cause later corrections to overshoot). 81 * 82 * The regression used to calculate the frequency is a much 83 * longer-term entity and is NOT reset, so it is still possible 84 * for the offset correction code to make minor adjustments to 85 * the frequency if it so desires. 86 * 87 * client_check may replace the server_info pointer with a new 88 * one. 89 */ 90 best_off = NULL; 91 best_freq = NULL; 92 for (i = 0; i < count; ++i) 93 client_check(&info_ary[i], &best_off, &best_freq); 94 95 /* 96 * Check for server insanity. In large NNTP pools some servers 97 * may just be dead wrong, but report that they are right. 98 */ 99 if (best_off) { 100 insane = client_insane(info_ary, count, best_off); 101 if (insane > 0) { 102 /* 103 * best_off meets the quorum requirements and is good 104 * (keep best_off) 105 */ 106 best_off->server_insane = 0; 107 } else if (insane == 0) { 108 /* 109 * best_off is probably good, but we do not have enough 110 * servers reporting yet to meet the quorum requirements. 111 */ 112 best_off = NULL; 113 } else { 114 /* 115 * best_off is ugly, mark the server as being insane for 116 * 60 minutes. 117 */ 118 best_off->server_insane = 60 * 60; 119 logdebuginfo(best_off, 1, 120 "excessive offset deviation, mapping out\n"); 121 best_off = NULL; 122 } 123 } 124 125 /* 126 * Offset correction. 127 */ 128 if (best_off) { 129 offset = best_off->lin_sumoffset / best_off->lin_countoffset; 130 lin_resetalloffsets(info_ary, count); 131 if (offset < -COURSE_OFFSET_CORRECTION_LIMIT || 132 offset > COURSE_OFFSET_CORRECTION_LIMIT || 133 quickset_opt 134 ) { 135 freq = sysntp_correct_course_offset(offset); 136 quickset_opt = 0; 137 } else { 138 freq = sysntp_correct_offset(offset); 139 } 140 } else { 141 freq = 0.0; 142 } 143 144 /* 145 * Frequency correction (throw away minor freq adjusts from the 146 * offset code if we can't do a frequency correction here). Do 147 * not reissue if it hasn't changed from the last issued correction. 148 */ 149 if (best_freq) { 150 freq += best_freq->lin_cache_freq; 151 if (last_freq != freq) { 152 sysntp_correct_freq(freq); 153 last_freq = freq; 154 } 155 } 156 157 /* 158 * This function is responsible for managing the polling mode and 159 * figures out how long we should sleep. 160 */ 161 didreconnect = 0; 162 for (i = 0; i < count; ++i) 163 client_manage_polling_mode(info_ary[i], &didreconnect); 164 if (didreconnect) 165 client_check_duplicate_ips(info_ary, count); 166 167 /* 168 * Polling loop sleep. 169 */ 170 usleep(min_sleep_opt * 1000000 + random() % 500000); 171 } 172 } 173 174 void 175 client_poll(server_info_t info, int poll_interval, int calc_offset_correction) 176 { 177 struct timeval rtv; 178 struct timeval ltv; 179 struct timeval lbtv; 180 double offset; 181 182 /* 183 * Adjust the insane-server countdown 184 */ 185 if (info->server_insane > poll_interval) 186 info->server_insane -= poll_interval; 187 else 188 info->server_insane = 0; 189 190 /* 191 * By default we always poll. If the polling interval comes under 192 * active management the poll_sleep will be non-zero. 193 */ 194 if (info->poll_sleep > poll_interval) { 195 info->poll_sleep -= poll_interval; 196 return; 197 } 198 info->poll_sleep = 0; 199 200 /* 201 * If the client isn't open don't mess with the poll_failed count 202 * or anything else. We are left in the init or startup phase. 203 */ 204 if (info->fd < 0) { 205 if (info->poll_failed < 0x7FFFFFFF) 206 ++info->poll_failed; 207 return; 208 } 209 210 logdebuginfo(info, 4, "poll, "); 211 if (udp_ntptimereq(info->fd, &rtv, <v, &lbtv) < 0) { 212 ++info->poll_failed; 213 logdebug(4, "no response (%d failures in a row)\n", info->poll_failed); 214 if (info->poll_failed == POLL_FAIL_RESET) { 215 if (info->lin_count != 0) { 216 logdebuginfo(info, 4, "resetting regression due to failures\n"); 217 } 218 lin_reset(info); 219 } 220 return; 221 } 222 223 /* 224 * Successful query. Update polling info for the polling mode manager. 225 */ 226 ++info->poll_count; 227 info->poll_failed = 0; 228 229 /* 230 * Figure out the offset (the difference between the reported 231 * time and our current time) for linear regression purposes. 232 */ 233 offset = tv_delta_double(&rtv, <v); 234 235 while (info) { 236 /* 237 * Linear regression 238 */ 239 if (debug_level >= 4) { 240 struct tm *tp; 241 char buf[64]; 242 time_t t; 243 244 t = rtv.tv_sec; 245 tp = localtime(&t); 246 strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tp); 247 logdebug(4, "%s.%03ld ", buf, rtv.tv_usec / 1000); 248 } 249 lin_regress(info, <v, &lbtv, offset, calc_offset_correction); 250 info = info->altinfo; 251 if (info && debug_level >= 4) { 252 logdebug(4, "%*.*s: poll, ", 253 (int)strlen(info->target), 254 (int)strlen(info->target), "(alt)"); 255 } 256 } 257 } 258 259 /* 260 * Find the best client (or synthesize a fake info structure to return). 261 * We can find separate best clients for offset and frequency. 262 */ 263 void 264 client_check(struct server_info **checkp, 265 struct server_info **best_off, 266 struct server_info **best_freq) 267 { 268 struct server_info *check = *checkp; 269 struct server_info *info; 270 271 /* 272 * Start an alternate linear regression once our current one 273 * has passed a certain point. 274 */ 275 if (check->lin_count >= LIN_RESTART / 2 && check->altinfo == NULL) { 276 info = malloc(sizeof(*info)); 277 assert(info != NULL); 278 /* note: check->altinfo is NULL as of the bcopy */ 279 bcopy(check, info, sizeof(*info)); 280 check->altinfo = info; 281 lin_reset(info); 282 } 283 284 /* 285 * Replace our current linear regression with the alternate once 286 * the current one has hit its limit (beyond a certain point the 287 * linear regression starts to work against us, preventing us from 288 * reacting to changing conditions). 289 * 290 * Report any significant change in the offset or ppm. 291 */ 292 if (check->lin_count >= LIN_RESTART) { 293 if ((info = check->altinfo) && info->lin_count >= LIN_RESTART / 2) { 294 double freq_diff; 295 296 freq_diff = info->lin_cache_freq - check->lin_cache_freq; 297 logdebuginfo(info, 4, "Switching to alternate, Frequence " 298 "difference is %6.3f ppm\n", 299 freq_diff * 1.0E+6); 300 *checkp = info; 301 free(check); 302 check = info; 303 } 304 } 305 306 /* 307 * BEST CLIENT FOR FREQUENCY CORRECTION: 308 * 309 * 8 samples and a correlation > 0.99, or 310 * 16 samples and a correlation > 0.96 311 */ 312 info = *best_freq; 313 if ((check->lin_count >= 8 && fabs(check->lin_cache_corr) >= 0.99) || 314 (check->lin_count >= 16 && fabs(check->lin_cache_corr) >= 0.96) 315 ) { 316 if (info == NULL || 317 fabs(check->lin_cache_corr) > fabs(info->lin_cache_corr) 318 ) { 319 info = check; 320 *best_freq = info; 321 } 322 323 } 324 325 /* 326 * BEST CLIENT FOR OFFSET CORRECTION: 327 * 328 * Use the standard-deviation and require at least 4 samples. An 329 * offset correction is valid if the standard deviation is less then 330 * the average offset divided by 4. 331 * 332 * Servers marked as being insane are not allowed 333 */ 334 info = *best_off; 335 if (check->lin_countoffset >= 4 && 336 (check->lin_cache_stddev < 337 fabs(check->lin_sumoffset / check->lin_countoffset / 4)) && 338 check->server_insane == 0 339 ) { 340 if (info == NULL || 341 fabs(check->lin_cache_stddev) < fabs(info->lin_cache_stddev) 342 ) { 343 info = check; 344 *best_off = info; 345 } 346 } 347 } 348 349 /* 350 * Actively manage the polling interval. Note that the poll_* fields are 351 * always transfered to the alternate regression when the check code replaces 352 * the current regression with a new one. 353 * 354 * This routine is called from the main loop for each base info structure. 355 * The polling mode applies to all alternates so we do not have to iterate 356 * through the alt's. 357 */ 358 void 359 client_manage_polling_mode(struct server_info *info, int *didreconnect) 360 { 361 /* 362 * Permanently failed servers are ignored. 363 */ 364 if (info->server_state == -2) 365 return; 366 367 /* 368 * Our polling interval has not yet passed. 369 */ 370 if (info->poll_sleep) 371 return; 372 373 /* 374 * Standard polling mode progression 375 */ 376 switch(info->poll_mode) { 377 case POLL_FIXED: 378 /* 379 * Initial state after connect or when a reconnect is required. 380 */ 381 if (info->fd < 0) { 382 logdebuginfo(info, 2, "polling mode INIT, relookup & reconnect\n"); 383 reconnect_server(info); 384 *didreconnect = 1; 385 if (info->fd < 0) { 386 if (info->poll_failed >= POLL_RECOVERY_RESTART * 5) 387 info->poll_sleep = max_sleep_opt; 388 else if (info->poll_failed >= POLL_RECOVERY_RESTART) 389 info->poll_sleep = nom_sleep_opt; 390 else 391 info->poll_sleep = min_sleep_opt; 392 break; 393 } 394 395 /* 396 * Transition the server to the DNS lookup successful state. 397 * Note that the server state does not transition out of 398 * lookup successful if we relookup after a packet failure 399 * so the message is printed only once, usually. 400 */ 401 client_setserverstate(info, 0, "DNS lookup success"); 402 403 /* 404 * If we've failed many times switch to the startup state but 405 * do not fall through into it. break the switch and a single 406 * poll will be made after the nominal polling interval. 407 */ 408 if (info->poll_failed >= POLL_RECOVERY_RESTART * 5) { 409 logdebuginfo(info, 2, "polling mode INIT->STARTUP (very slow)\n"); 410 info->poll_mode = POLL_STARTUP; 411 info->poll_sleep = max_sleep_opt; 412 info->poll_count = 0; 413 break; 414 } else if (info->poll_failed >= POLL_RECOVERY_RESTART) { 415 logdebuginfo(info, 2, "polling mode INIT->STARTUP (slow)\n"); 416 info->poll_mode = POLL_STARTUP; 417 info->poll_count = 0; 418 break; 419 } 420 } 421 422 /* 423 * Fall through to the startup state. 424 */ 425 info->poll_mode = POLL_STARTUP; 426 logdebuginfo(info, 2, "polling mode INIT->STARTUP (normal)\n"); 427 /* fall through */ 428 case POLL_STARTUP: 429 /* 430 * Transition to a FAILED state if too many poll failures occured. 431 */ 432 if (info->poll_failed >= POLL_FAIL_RESET) { 433 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 434 info->poll_mode = POLL_FAILED; 435 info->poll_count = 0; 436 break; 437 } 438 439 /* 440 * Transition the server to operational. Do a number of minimum 441 * interval polls to try to get a good offset calculation quickly. 442 */ 443 if (info->poll_count) 444 client_setserverstate(info, 1, "connected ok"); 445 if (info->poll_count < POLL_STARTUP_MAX) { 446 info->poll_sleep = min_sleep_opt; 447 break; 448 } 449 450 /* 451 * Once we've got our polls fall through to aquisition mode to 452 * do aquisition processing. 453 */ 454 info->poll_mode = POLL_ACQUIRE; 455 info->poll_count = 0; 456 logdebuginfo(info, 2, "polling mode STARTUP->ACQUIRE\n"); 457 /* fall through */ 458 case POLL_ACQUIRE: 459 /* 460 * Transition to a FAILED state if too many poll failures occured. 461 */ 462 if (info->poll_failed >= POLL_FAIL_RESET) { 463 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 464 info->poll_mode = POLL_FAILED; 465 info->poll_count = 0; 466 break; 467 } 468 469 /* 470 * Acquisition mode using the nominal timeout. We do not shift 471 * to maintainance mode unless the correlation is at least 0.90 472 */ 473 if (info->poll_count < POLL_ACQUIRE_MAX || 474 info->lin_count < 8 || 475 fabs(info->lin_cache_corr) < 0.85 476 ) { 477 if (info->poll_count >= POLL_ACQUIRE_MAX && 478 info->lin_count == LIN_RESTART - 2 479 ) { 480 logdebuginfo(info, 2, 481 "WARNING: Unable to shift this source to " 482 "maintenance mode. Target correlation is aweful\n"); 483 } 484 break; 485 } 486 info->poll_mode = POLL_MAINTAIN; 487 info->poll_count = 0; 488 logdebuginfo(info, 2, "polling mode ACQUIRE->MAINTAIN\n"); 489 /* fall through */ 490 case POLL_MAINTAIN: 491 /* 492 * Transition to a FAILED state if too many poll failures occured. 493 */ 494 if (info->poll_failed >= POLL_FAIL_RESET) { 495 logdebuginfo(info, 2, "polling mode STARTUP->FAILED\n"); 496 info->poll_mode = POLL_FAILED; 497 info->poll_count = 0; 498 break; 499 } 500 501 /* 502 * Maintaince mode, max polling interval. 503 * 504 * Transition back to acquisition mode if we are unable to maintain 505 * this mode due to the correlation going bad. 506 */ 507 if (info->lin_count >= LIN_RESTART / 2 && 508 fabs(info->lin_cache_corr) < 0.70 509 ) { 510 logdebuginfo(info, 2, 511 "polling mode MAINTAIN->ACQUIRE. Unable to maintain\n" 512 "the maintenance mode because the correlation went" 513 " bad!\n"); 514 info->poll_mode = POLL_ACQUIRE; 515 info->poll_count = 0; 516 break; 517 } 518 info->poll_sleep = max_sleep_opt; 519 break; 520 case POLL_FAILED: 521 /* 522 * We have a communications failure. A late recovery is possible 523 * if we enter this state with a good poll. 524 */ 525 if (info->poll_count != 0) { 526 logdebuginfo(info, 2, "polling mode FAILED->ACQUIRE\n"); 527 if (info->poll_failed >= POLL_FAIL_RESET) 528 info->poll_mode = POLL_STARTUP; 529 else 530 info->poll_mode = POLL_ACQUIRE; 531 /* do not reset poll_count */ 532 break; 533 } 534 535 /* 536 * If we have been failed too long, disconnect from the server 537 * and start us all over again. Note that the failed count is not 538 * reset to 0. 539 */ 540 if (info->poll_failed >= POLL_RECOVERY_RESTART) { 541 logdebuginfo(info, 2, "polling mode FAILED->INIT\n"); 542 client_setserverstate(info, 0, "FAILED"); 543 disconnect_server(info); 544 info->poll_mode = POLL_FIXED; 545 break; 546 } 547 break; 548 } 549 550 /* 551 * If the above state machine has not set a polling interval, set a 552 * nominal polling interval. 553 */ 554 if (info->poll_sleep == 0) 555 info->poll_sleep = nom_sleep_opt; 556 } 557 558 /* 559 * Look for duplicate IP addresses. This is done very inoften, so we do 560 * not use a particularly efficient algorithm. 561 * 562 * Only reconnect a client which has not done its initial poll. 563 */ 564 void 565 client_check_duplicate_ips(struct server_info **info_ary, int count) 566 { 567 server_info_t info1; 568 server_info_t info2; 569 int tries; 570 int i; 571 int j; 572 573 for (i = 0; i < count; ++i) { 574 info1 = info_ary[i]; 575 if (info1->fd < 0 || info1->server_state != 0) 576 continue; 577 for (tries = 0; tries < 10; ++tries) { 578 for (j = 0; j < count; ++j) { 579 info2 = info_ary[j]; 580 if (i == j || info2->fd < 0) 581 continue; 582 if (strcmp(info1->ipstr, info2->ipstr) == 0) { 583 reconnect_server(info1); 584 break; 585 } 586 } 587 if (j == count) 588 break; 589 } 590 if (tries == 10) { 591 disconnect_server(info1); 592 client_setserverstate(info1, -2, 593 "permanently disabling duplicate server"); 594 } 595 } 596 } 597 598 /* 599 * Calculate whether the server pointed to by *bestp is insane or not. 600 * For some reason some servers in e.g. the ntp pool are sometimes an hour 601 * off. If we have at least three servers in the pool require that a 602 * quorum agree that the current best server's offset is reasonable. 603 * 604 * Allow +/- 0.5 seconds of error for now (settable with option). 605 * 606 * Returns -1 if insane, 0 if not enough samples, and 1 if ok 607 */ 608 static 609 int 610 client_insane(struct server_info **info_ary, int count, server_info_t best) 611 { 612 server_info_t info; 613 double best_offset; 614 double info_offset; 615 int good; 616 int bad; 617 int skip; 618 int quorum; 619 int i; 620 621 /* 622 * If only one ntp server we cannot check to see if it is insane 623 */ 624 if (count < 2) 625 return(1); 626 best_offset = best->lin_sumoffset / best->lin_countoffset; 627 628 /* 629 * Calculated the quorum. Do not count permanently failed servers 630 * in the calculation. 631 * 632 * adjusted count quorum 633 * 2 2 634 * 3 2 635 * 4 3 636 * 5 3 637 */ 638 quorum = count; 639 for (i = 0; i < count; ++i) { 640 info = info_ary[i]; 641 if (info->server_state == -2) 642 --quorum; 643 } 644 645 quorum = quorum / 2 + 1; 646 good = 0; 647 bad = 0; 648 skip = 0; 649 650 /* 651 * Find the good, the bad, and the ugly. We need at least four samples 652 * and a stddev within the deviation being checked to count a server 653 * in the calculation. 654 */ 655 for (i = 0; i < count; ++i) { 656 info = info_ary[i]; 657 if (info->lin_countoffset < 4 || 658 info->lin_cache_stddev > insane_deviation 659 ) { 660 ++skip; 661 continue; 662 } 663 664 info_offset = info->lin_sumoffset / info->lin_countoffset; 665 info_offset -= best_offset; 666 if (info_offset < -insane_deviation || info_offset > insane_deviation) 667 ++bad; 668 else 669 ++good; 670 } 671 672 /* 673 * Did we meet our quorum? 674 */ 675 logdebuginfo(best, 5, "insanecheck good=%d bad=%d skip=%d " 676 "quorum=%d (allowed=%-+8.6f)\n", 677 good, bad, skip, quorum, insane_deviation); 678 if (good >= quorum) 679 return(1); 680 if (good + skip >= quorum) 681 return(0); 682 return(-1); 683 } 684 685 /* 686 * Linear regression. 687 * 688 * ltv local time as of when the offset error was calculated between 689 * local time and remote time. 690 * 691 * lbtv base time as of when local time was obtained. Used to 692 * calculate the cumulative corrections made to the system's 693 * real time clock so we can de-correct the offset for the 694 * linear regression. 695 * 696 * X is the time axis, in seconds. 697 * Y is the uncorrected offset, in seconds. 698 */ 699 void 700 lin_regress(server_info_t info, struct timeval *ltv, struct timeval *lbtv, 701 double offset, int calc_offset_correction) 702 { 703 double time_axis; 704 double uncorrected_offset; 705 706 /* 707 * De-correcting the offset: 708 * 709 * The passed offset is (our_real_time - remote_real_time). To remove 710 * corrections from our_real_time we take the difference in the basetime 711 * (new_base_time - old_base_time) and subtract that from the offset. 712 * That is, if the basetime goesup, the uncorrected offset goes down. 713 */ 714 if (info->lin_count == 0) { 715 info->lin_tv = *ltv; 716 info->lin_btv = *lbtv; 717 time_axis = 0; 718 uncorrected_offset = offset; 719 } else { 720 time_axis = tv_delta_double(&info->lin_tv, ltv); 721 uncorrected_offset = offset - tv_delta_double(&info->lin_btv, lbtv); 722 } 723 724 /* 725 * We have to use the uncorrected offset for frequency calculations. 726 */ 727 ++info->lin_count; 728 info->lin_sumx += time_axis; 729 info->lin_sumx2 += time_axis * time_axis; 730 info->lin_sumy += uncorrected_offset; 731 info->lin_sumy2 += uncorrected_offset * uncorrected_offset; 732 info->lin_sumxy += time_axis * uncorrected_offset; 733 734 /* 735 * We have to use the corrected offset for offset calculations. 736 */ 737 if (calc_offset_correction) { 738 ++info->lin_countoffset; 739 info->lin_sumoffset += offset; 740 info->lin_sumoffset2 += offset * offset; 741 } 742 743 /* 744 * Calculate various derived values. This gets us slope, y-intercept, 745 * and correlation from the linear regression. 746 */ 747 if (info->lin_count > 1) { 748 info->lin_cache_slope = 749 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 750 (info->lin_count * info->lin_sumx2 - info->lin_sumx * info->lin_sumx); 751 752 info->lin_cache_yint = 753 (info->lin_sumy - info->lin_cache_slope * info->lin_sumx) / 754 (info->lin_count); 755 756 info->lin_cache_corr = 757 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 758 sqrt((info->lin_count * info->lin_sumx2 - 759 info->lin_sumx * info->lin_sumx) * 760 (info->lin_count * info->lin_sumy2 - 761 info->lin_sumy * info->lin_sumy) 762 ); 763 } 764 765 /* 766 * Calculate more derived values. This gets us the standard-deviation 767 * of offsets. The standard deviation approximately means that 68% 768 * of the samples fall within the calculated stddev of the mean. 769 */ 770 if (info->lin_countoffset > 1) { 771 info->lin_cache_stddev = 772 sqrt((info->lin_sumoffset2 - 773 ((info->lin_sumoffset * info->lin_sumoffset / 774 info->lin_countoffset))) / 775 (info->lin_countoffset - 1.0)); 776 } 777 778 /* 779 * Save the most recent offset, we might use it in the future. 780 * Save the frequency correction (we might scale the slope later so 781 * we have a separate field for the actual frequency correction in 782 * seconds per second). 783 */ 784 info->lin_cache_offset = offset; 785 info->lin_cache_freq = info->lin_cache_slope; 786 787 if (debug_level >= 4) { 788 logdebuginfo(info, 4, "iter=%2d time=%7.3f off=%+.6f uoff=%+.6f", 789 (int)info->lin_count, 790 time_axis, offset, uncorrected_offset); 791 if (info->lin_count > 1) { 792 logdebug(4, " slope %+7.6f" 793 " yint %+3.2f corr %+7.6f freq_ppm %+4.2f", 794 info->lin_cache_slope, 795 info->lin_cache_yint, 796 info->lin_cache_corr, 797 info->lin_cache_freq * 1000000.0); 798 } 799 if (info->lin_countoffset > 1) { 800 logdebug(4, " stddev %7.6f", info->lin_cache_stddev); 801 } else if (calc_offset_correction == 0) { 802 /* cannot calculate offset correction due to prior correction */ 803 logdebug(4, " offset_ignored"); 804 } 805 logdebug(4, "\n"); 806 } 807 } 808 809 /* 810 * Reset the linear regression data. The info structure will not again be 811 * a candidate for frequency or offset correction until sufficient data 812 * has been accumulated to make a decision. 813 */ 814 void 815 lin_reset(server_info_t info) 816 { 817 server_info_t scan; 818 819 info->lin_count = 0; 820 info->lin_sumx = 0; 821 info->lin_sumy = 0; 822 info->lin_sumxy = 0; 823 info->lin_sumx2 = 0; 824 info->lin_sumy2 = 0; 825 826 info->lin_countoffset = 0; 827 info->lin_sumoffset = 0; 828 info->lin_sumoffset2 = 0; 829 830 info->lin_cache_slope = 0; 831 info->lin_cache_yint = 0; 832 info->lin_cache_corr = 0; 833 info->lin_cache_offset = 0; 834 info->lin_cache_freq = 0; 835 836 /* 837 * Destroy any additional alternative regressions. 838 */ 839 while ((scan = info->altinfo) != NULL) { 840 info->altinfo = scan->altinfo; 841 free(scan); 842 } 843 } 844 845 /* 846 * Sometimes we want to clean out the offset calculations without 847 * destroying the linear regression used to figure out the frequency 848 * correction. This usually occurs whenever we issue an offset 849 * adjustment to the system, which invalidates any offset data accumulated 850 * up to that point. 851 */ 852 void 853 lin_resetalloffsets(struct server_info **info_ary, int count) 854 { 855 server_info_t info; 856 int i; 857 858 for (i = 0; i < count; ++i) { 859 for (info = info_ary[i]; info; info = info->altinfo) 860 lin_resetoffsets(info); 861 } 862 } 863 864 void 865 lin_resetoffsets(server_info_t info) 866 { 867 info->lin_countoffset = 0; 868 info->lin_sumoffset = 0; 869 info->lin_sumoffset2 = 0; 870 } 871 872 void 873 client_setserverstate(server_info_t info, int state, const char *str) 874 { 875 if (info->server_state != state) { 876 info->server_state = state; 877 logdebuginfo(info, 1, "%s\n", str); 878 } 879 } 880 881