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