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 (info1->fd < 0 || /* info1 was lost in previous reconnect */ 583 strcmp(info1->ipstr, info2->ipstr) == 0) { 584 reconnect_server(info1); 585 break; 586 } 587 } 588 if (j == count) 589 break; 590 } 591 if (tries == 10) { 592 disconnect_server(info1); 593 client_setserverstate(info1, -2, 594 "permanently disabling duplicate server"); 595 } 596 } 597 } 598 599 /* 600 * Calculate whether the server pointed to by *bestp is insane or not. 601 * For some reason some servers in e.g. the ntp pool are sometimes an hour 602 * off. If we have at least three servers in the pool require that a 603 * quorum agree that the current best server's offset is reasonable. 604 * 605 * Allow +/- 0.5 seconds of error for now (settable with option). 606 * 607 * Returns -1 if insane, 0 if not enough samples, and 1 if ok 608 */ 609 static 610 int 611 client_insane(struct server_info **info_ary, int count, server_info_t best) 612 { 613 server_info_t info; 614 double best_offset; 615 double info_offset; 616 int good; 617 int bad; 618 int skip; 619 int quorum; 620 int i; 621 622 /* 623 * If only one ntp server we cannot check to see if it is insane 624 */ 625 if (count < 2) 626 return(1); 627 best_offset = best->lin_sumoffset / best->lin_countoffset; 628 629 /* 630 * Calculated the quorum. Do not count permanently failed servers 631 * in the calculation. 632 * 633 * adjusted count quorum 634 * 2 2 635 * 3 2 636 * 4 3 637 * 5 3 638 */ 639 quorum = count; 640 for (i = 0; i < count; ++i) { 641 info = info_ary[i]; 642 if (info->server_state == -2) 643 --quorum; 644 } 645 646 quorum = quorum / 2 + 1; 647 good = 0; 648 bad = 0; 649 skip = 0; 650 651 /* 652 * Find the good, the bad, and the ugly. We need at least four samples 653 * and a stddev within the deviation being checked to count a server 654 * in the calculation. 655 */ 656 for (i = 0; i < count; ++i) { 657 info = info_ary[i]; 658 if (info->lin_countoffset < 4 || 659 info->lin_cache_stddev > insane_deviation 660 ) { 661 ++skip; 662 continue; 663 } 664 665 info_offset = info->lin_sumoffset / info->lin_countoffset; 666 info_offset -= best_offset; 667 if (info_offset < -insane_deviation || info_offset > insane_deviation) 668 ++bad; 669 else 670 ++good; 671 } 672 673 /* 674 * Did we meet our quorum? 675 */ 676 logdebuginfo(best, 5, "insanecheck good=%d bad=%d skip=%d " 677 "quorum=%d (allowed=%-+8.6f)\n", 678 good, bad, skip, quorum, insane_deviation); 679 if (good >= quorum) 680 return(1); 681 if (good + skip >= quorum) 682 return(0); 683 return(-1); 684 } 685 686 /* 687 * Linear regression. 688 * 689 * ltv local time as of when the offset error was calculated between 690 * local time and remote time. 691 * 692 * lbtv base time as of when local time was obtained. Used to 693 * calculate the cumulative corrections made to the system's 694 * real time clock so we can de-correct the offset for the 695 * linear regression. 696 * 697 * X is the time axis, in seconds. 698 * Y is the uncorrected offset, in seconds. 699 */ 700 void 701 lin_regress(server_info_t info, struct timeval *ltv, struct timeval *lbtv, 702 double offset, int calc_offset_correction) 703 { 704 double time_axis; 705 double uncorrected_offset; 706 707 /* 708 * De-correcting the offset: 709 * 710 * The passed offset is (our_real_time - remote_real_time). To remove 711 * corrections from our_real_time we take the difference in the basetime 712 * (new_base_time - old_base_time) and subtract that from the offset. 713 * That is, if the basetime goesup, the uncorrected offset goes down. 714 */ 715 if (info->lin_count == 0) { 716 info->lin_tv = *ltv; 717 info->lin_btv = *lbtv; 718 time_axis = 0; 719 uncorrected_offset = offset; 720 } else { 721 time_axis = tv_delta_double(&info->lin_tv, ltv); 722 uncorrected_offset = offset - tv_delta_double(&info->lin_btv, lbtv); 723 } 724 725 /* 726 * We have to use the uncorrected offset for frequency calculations. 727 */ 728 ++info->lin_count; 729 info->lin_sumx += time_axis; 730 info->lin_sumx2 += time_axis * time_axis; 731 info->lin_sumy += uncorrected_offset; 732 info->lin_sumy2 += uncorrected_offset * uncorrected_offset; 733 info->lin_sumxy += time_axis * uncorrected_offset; 734 735 /* 736 * We have to use the corrected offset for offset calculations. 737 */ 738 if (calc_offset_correction) { 739 ++info->lin_countoffset; 740 info->lin_sumoffset += offset; 741 info->lin_sumoffset2 += offset * offset; 742 } 743 744 /* 745 * Calculate various derived values. This gets us slope, y-intercept, 746 * and correlation from the linear regression. 747 */ 748 if (info->lin_count > 1) { 749 info->lin_cache_slope = 750 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 751 (info->lin_count * info->lin_sumx2 - info->lin_sumx * info->lin_sumx); 752 753 info->lin_cache_yint = 754 (info->lin_sumy - info->lin_cache_slope * info->lin_sumx) / 755 (info->lin_count); 756 757 info->lin_cache_corr = 758 (info->lin_count * info->lin_sumxy - info->lin_sumx * info->lin_sumy) / 759 sqrt((info->lin_count * info->lin_sumx2 - 760 info->lin_sumx * info->lin_sumx) * 761 (info->lin_count * info->lin_sumy2 - 762 info->lin_sumy * info->lin_sumy) 763 ); 764 } 765 766 /* 767 * Calculate more derived values. This gets us the standard-deviation 768 * of offsets. The standard deviation approximately means that 68% 769 * of the samples fall within the calculated stddev of the mean. 770 */ 771 if (info->lin_countoffset > 1) { 772 info->lin_cache_stddev = 773 sqrt((info->lin_sumoffset2 - 774 ((info->lin_sumoffset * info->lin_sumoffset / 775 info->lin_countoffset))) / 776 (info->lin_countoffset - 1.0)); 777 } 778 779 /* 780 * Save the most recent offset, we might use it in the future. 781 * Save the frequency correction (we might scale the slope later so 782 * we have a separate field for the actual frequency correction in 783 * seconds per second). 784 */ 785 info->lin_cache_offset = offset; 786 info->lin_cache_freq = info->lin_cache_slope; 787 788 if (debug_level >= 4) { 789 logdebuginfo(info, 4, "iter=%2d time=%7.3f off=%+.6f uoff=%+.6f", 790 (int)info->lin_count, 791 time_axis, offset, uncorrected_offset); 792 if (info->lin_count > 1) { 793 logdebug(4, " slope %+7.6f" 794 " yint %+3.2f corr %+7.6f freq_ppm %+4.2f", 795 info->lin_cache_slope, 796 info->lin_cache_yint, 797 info->lin_cache_corr, 798 info->lin_cache_freq * 1000000.0); 799 } 800 if (info->lin_countoffset > 1) { 801 logdebug(4, " stddev %7.6f", info->lin_cache_stddev); 802 } else if (calc_offset_correction == 0) { 803 /* cannot calculate offset correction due to prior correction */ 804 logdebug(4, " offset_ignored"); 805 } 806 logdebug(4, "\n"); 807 } 808 } 809 810 /* 811 * Reset the linear regression data. The info structure will not again be 812 * a candidate for frequency or offset correction until sufficient data 813 * has been accumulated to make a decision. 814 */ 815 void 816 lin_reset(server_info_t info) 817 { 818 server_info_t scan; 819 820 info->lin_count = 0; 821 info->lin_sumx = 0; 822 info->lin_sumy = 0; 823 info->lin_sumxy = 0; 824 info->lin_sumx2 = 0; 825 info->lin_sumy2 = 0; 826 827 info->lin_countoffset = 0; 828 info->lin_sumoffset = 0; 829 info->lin_sumoffset2 = 0; 830 831 info->lin_cache_slope = 0; 832 info->lin_cache_yint = 0; 833 info->lin_cache_corr = 0; 834 info->lin_cache_offset = 0; 835 info->lin_cache_freq = 0; 836 837 /* 838 * Destroy any additional alternative regressions. 839 */ 840 while ((scan = info->altinfo) != NULL) { 841 info->altinfo = scan->altinfo; 842 free(scan); 843 } 844 } 845 846 /* 847 * Sometimes we want to clean out the offset calculations without 848 * destroying the linear regression used to figure out the frequency 849 * correction. This usually occurs whenever we issue an offset 850 * adjustment to the system, which invalidates any offset data accumulated 851 * up to that point. 852 */ 853 void 854 lin_resetalloffsets(struct server_info **info_ary, int count) 855 { 856 server_info_t info; 857 int i; 858 859 for (i = 0; i < count; ++i) { 860 for (info = info_ary[i]; info; info = info->altinfo) 861 lin_resetoffsets(info); 862 } 863 } 864 865 void 866 lin_resetoffsets(server_info_t info) 867 { 868 info->lin_countoffset = 0; 869 info->lin_sumoffset = 0; 870 info->lin_sumoffset2 = 0; 871 } 872 873 void 874 client_setserverstate(server_info_t info, int state, const char *str) 875 { 876 if (info->server_state != state) { 877 info->server_state = state; 878 logdebuginfo(info, 1, "%s\n", str); 879 } 880 } 881 882