Annotation of embedaddon/ntp/ntpdate/ntptimeset.c, revision 1.1
1.1 ! misho 1: /*
! 2: * ntptimeset - get/set the time via ntp
! 3: *
! 4: * GOAL:
! 5: * The goal of ntptime is to set the current time on system startup
! 6: * to the best possible time using the network very wisely. It is assumed
! 7: * that after a resonable time has been sett then ntp daemon will
! 8: * maintain it.
! 9: *
! 10: * PROBLEM DOMAIN:
! 11: * We have three sets of issues related to acheiving the goal. The first
! 12: * issue is using the network when normal traffic is happening or when
! 13: * the entire network world is recovering from a campus wide power failure
! 14: * and is restarting. The second issue is the class of machine whether it
! 15: * is a user's office workstation being handled by an uneducated user or
! 16: * a server computer being handled by a trained operations staff. The third
! 17: * issue is whether the ratio of people to computers and whether the
! 18: * environment is stable and viable or not.
! 19: *
! 20: * NETWORK USAGE:
! 21: * The first issue of using the network wisely is a question of whether
! 22: * the network load and time server load and state are normal. If things
! 23: * are normal ntptime can do what ntpdate does of sending out 4 packets
! 24: * quickly to each server (new transmit done with each ack). However
! 25: * if network or time load is high then this scheme will simply contribute
! 26: * to problems. Given we have minimal state, we simply weight lost packets
! 27: * significantly and make sure we throttle output as much as possible
! 28: * without performance lost for quick startups.
! 29: *
! 30: * TRAINING AND KNOWLEDGE:
! 31: * The second issue of uneducated user of a office workstation versus a
! 32: * trained operation staff of a server machine translates into simply an
! 33: * issue of untrained and trained users.
! 34: *
! 35: * The training issue implies that for the sake of the users involved in the
! 36: * handling of their office workstation, problems and options should be
! 37: * communicated simply and effectively and not in terse expert related
! 38: * descriptions without possible options to be taken. The operator's training
! 39: * and education enables them to deal with either type of communication and
! 40: * control.
! 41: *
! 42: * AUTOMATION AND MANUAL CONTROL:
! 43: * The last issue boils down to a design problem. If the design tends to go
! 44: * into a manual mode when the environment is non-viable then one person
! 45: * handling many computers all at the same time will be heavily impacted. On
! 46: * the other hand, if the design tends to be automatic and does not indicate
! 47: * a way for the user to take over control then the computer will be
! 48: * unavailable for the user until the proble is resolved by someone else or
! 49: * the user.
! 50: *
! 51: * NOTE: Please do not have this program print out every minute some line,
! 52: * of output. If this happens and the environment is in trouble then
! 53: * many pages of paper on many different machines will be filled up.
! 54: * Save some tress in your lifetime.
! 55: *
! 56: * CONCLUSION:
! 57: * The behavior of the program derived from these three issues should be
! 58: * that during normal situations it quickly sets the time and allow the
! 59: * system to startup.
! 60: *
! 61: * However during abnormal conditions as detected by unresponsive servers,
! 62: * out-of-sync or bad responses and other detections, it should print out
! 63: * a simple but clear message and continue in a mellow way to get the best
! 64: * possible time. It may never get the time and if so should also indicate
! 65: * this.
! 66: *
! 67: * Rudy Nedved
! 68: * 18-May-1993
! 69: *
! 70: ****************************************************************
! 71: *
! 72: * Much of the above is confusing or no longer relevant. For example,
! 73: * it is rare these days for a machine's console to be a printing terminal,
! 74: * so the comment about saving trees doesn't mean much. Nonetheless,
! 75: * the basic principles still stand:
! 76: *
! 77: * - Work automatically, without human control or intervention. To
! 78: * this end, we use the same configuration file as ntpd itself, so
! 79: * you don't have to specify servers or other information on the
! 80: * command line. We also recognize that sometimes we won't be able
! 81: * to contact any servers, and give up in that event instead of
! 82: * hanging forever.
! 83: *
! 84: * - Behave in a sane way, both internally and externally, even in the
! 85: * face of insane conditions. That means we back off quickly when
! 86: * we don't hear a response, to avoid network congestion. Like
! 87: * ntpd, we verify responses from several servers before accepting
! 88: * the new time data.
! 89: *
! 90: * However, we don't assume that the local clock is right, or even
! 91: * close, because it might not be at boot time, and we want to catch
! 92: * and correct that situation. This behaviour has saved us in several
! 93: * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which
! 94: * would cause the time to be set to some wild value, making the machine
! 95: * essentially unusable (we use Kerberos authentication pervasively,
! 96: * and it requires workstations and servers to have a time within five
! 97: * minutes of the Kerberos server). We also have problems on PC's
! 98: * running both Linux and some Microsoft OS -- they tend to disagree
! 99: * on what the BIOS clock should say, and who should update it, and
! 100: * when. On those systems, we not only run ntptimeset at boot, we
! 101: * also reset the BIOS clock based on the result, so the correct
! 102: * time will be retained across reboots.
! 103: *
! 104: * For these reasons, and others, we have continued to use this tool
! 105: * rather than ntpdate. It is run automatically at boot time on every
! 106: * workstation and server in our facility.
! 107: *
! 108: * In the past, we called this program 'ntptime'. Unfortunately, the
! 109: * ntp v4 distribution also includes a program with that name. In
! 110: * order to avoid confusion, we have renamed our program 'ntptimeset',
! 111: * which more accurately describes what it does.
! 112: *
! 113: * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu>
! 114: * School of Computer Science - Research Computing Facility
! 115: * Carnegie Mellon University - Pittsburgh, PA
! 116: * 16-Aug-1999
! 117: *
! 118: */
! 119:
! 120: #ifdef HAVE_CONFIG_H
! 121: # include <config.h>
! 122: #endif
! 123:
! 124: #include "ntp_machine.h"
! 125: #include "ntp_fp.h"
! 126: #include "ntp.h"
! 127: #include "ntp_io.h"
! 128: #include "iosignal.h"
! 129: #include "ntp_unixtime.h"
! 130: #include "ntpdate.h"
! 131: #include "ntp_string.h"
! 132: #include "ntp_syslog.h"
! 133: #include "ntp_select.h"
! 134: #include "ntp_stdlib.h"
! 135:
! 136: #ifdef HAVE_UNISTD_H
! 137: # include <unistd.h>
! 138: #endif
! 139:
! 140: #include <stdio.h>
! 141: #include <signal.h>
! 142: #include <ctype.h>
! 143: #ifndef SYS_WINNT
! 144: # ifdef HAVE_SYS_SIGNAL_H
! 145: # include <sys/signal.h>
! 146: # else
! 147: # include <signal.h>
! 148: # endif
! 149: # include <sys/ioctl.h>
! 150: #endif /* SYS_WINNT */
! 151:
! 152: #ifdef HAVE_SYS_RESOURCE_H
! 153: # include <sys/resource.h>
! 154: #endif /* HAVE_SYS_RESOURCE_H */
! 155:
! 156: #ifdef SYS_VXWORKS
! 157: # include "ioLib.h"
! 158: # include "sockLib.h"
! 159: # include "timers.h"
! 160: #endif
! 161:
! 162: #include "recvbuff.h"
! 163:
! 164: #ifdef SYS_WINNT
! 165: # define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy
! 166: on Windows NT timers. */
! 167: #pragma comment(lib, "winmm")
! 168: #endif /* SYS_WINNT */
! 169:
! 170: /*
! 171: * Scheduling priority we run at
! 172: */
! 173: #ifndef SYS_VXWORKS
! 174: # define NTPDATE_PRIO (-12)
! 175: #else
! 176: # define NTPDATE_PRIO (100)
! 177: #endif
! 178:
! 179: #if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
! 180: /* POSIX TIMERS - vxWorks doesn't have itimer - casey */
! 181: static timer_t ntpdate_timerid;
! 182: #endif
! 183:
! 184: /*
! 185: * Compatibility stuff for Version 2
! 186: */
! 187: #define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */
! 188: #define NTP_MINDIST 0x51f /* 0.02 sec in fp format */
! 189: #define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */
! 190: #define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */
! 191: #define NTP_MAXLIST 5 /* maximum select list size */
! 192: #define PEER_SHIFT 8 /* 8 suitable for crystal time base */
! 193:
! 194: /*
! 195: * Debugging flag
! 196: */
! 197: volatile int debug = 0;
! 198:
! 199: /*
! 200: * File descriptor masks etc. for call to select
! 201: */
! 202: int fd;
! 203: fd_set fdmask;
! 204:
! 205: /*
! 206: * Initializing flag. All async routines watch this and only do their
! 207: * thing when it is clear.
! 208: */
! 209: int initializing = 1;
! 210:
! 211: /*
! 212: * Alarm flag. Set when an alarm occurs
! 213: */
! 214: volatile int alarm_flag = 0;
! 215:
! 216: /*
! 217: * Set the time if valid time determined
! 218: */
! 219: int set_time = 0;
! 220:
! 221: /*
! 222: * transmission rate control
! 223: */
! 224: #define MINTRANSMITS (3) /* minimum total packets per server */
! 225: #define MAXXMITCOUNT (2) /* maximum packets per time interrupt */
! 226:
! 227: /*
! 228: * time setting constraints
! 229: */
! 230: #define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */
! 231: int max_period = DEFMAXPERIOD;
! 232: int min_servers = DEFMINSERVERS;
! 233: int min_valid = DEFMINVALID;
! 234:
! 235: /*
! 236: * counters related to time setting constraints
! 237: */
! 238: int contacted = 0; /* # of servers we have sent to */
! 239: int responding = 0; /* servers responding */
! 240: int validcount = 0; /* servers with valid time */
! 241: int valid_n_low = 0; /* valid time servers with low dispersion */
! 242:
! 243: /*
! 244: * Unpriviledged port flag.
! 245: */
! 246: int unpriv_port = 0;
! 247:
! 248: /*
! 249: * Program name.
! 250: */
! 251: char *progname;
! 252:
! 253: /*
! 254: * Systemwide parameters and flags
! 255: */
! 256: struct server **sys_servers; /* the server list */
! 257: int sys_numservers = 0; /* number of servers to poll */
! 258: int sys_authenticate = 0; /* true when authenticating */
! 259: u_int32 sys_authkey = 0; /* set to authentication key in use */
! 260: u_long sys_authdelay = 0; /* authentication delay */
! 261:
! 262: /*
! 263: * The current internal time
! 264: */
! 265: u_long current_time = 0;
! 266:
! 267: /*
! 268: * File of encryption keys
! 269: */
! 270:
! 271: #ifndef KEYFILE
! 272: # ifndef SYS_WINNT
! 273: #define KEYFILE "/etc/ntp.keys"
! 274: # else
! 275: #define KEYFILE "%windir%\\ntp.keys"
! 276: # endif /* SYS_WINNT */
! 277: #endif /* KEYFILE */
! 278:
! 279: #ifndef SYS_WINNT
! 280: const char *key_file = KEYFILE;
! 281: #else
! 282: char key_file_storage[MAX_PATH+1], *key_file ;
! 283: #endif /* SYS_WINNT */
! 284:
! 285: /*
! 286: * total packet counts
! 287: */
! 288: u_long total_xmit = 0;
! 289: u_long total_recv = 0;
! 290:
! 291: /*
! 292: * Miscellaneous flags
! 293: */
! 294: int verbose = 0;
! 295: #define HORRIBLEOK 3 /* how many packets to let out */
! 296: int horrible = 0; /* how many packets we drop for testing */
! 297: int secondhalf = 0; /* second half of timeout period */
! 298: int printmsg = 0; /* print time response analysis */
! 299:
! 300: /*
! 301: * The half time and finish time in internal time
! 302: */
! 303: u_long half_time = 0;
! 304: u_long finish_time = 0;
! 305:
! 306:
! 307: int ntptimesetmain P((int argc, char *argv[]));
! 308: static void analysis P((int final));
! 309: static int have_enough P((void));
! 310: static void transmit P((register struct server *server));
! 311: static void receive P((struct recvbuf *rbufp));
! 312: static void clock_filter P((register struct server *server, s_fp d, l_fp *c));
! 313: static void clock_count P((void));
! 314: static struct server *clock_select P((void));
! 315: static void set_local_clock P((void));
! 316: static struct server *findserver P((struct sockaddr_in *addr));
! 317: static void timer P((void));
! 318: #ifndef SYS_WINNT
! 319: static RETSIGTYPE alarming P((int sig));
! 320: #endif /* SYS_WINNT */
! 321: static void init_alarm P((void));
! 322: static void init_io P((void));
! 323: static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len));
! 324: void input_handler P((l_fp *xts));
! 325: static void printserver P((register struct server *pp, FILE *fp));
! 326: #if !defined(HAVE_VSPRINTF)
! 327: int vsprintf P((char *str, const char *fmt, va_list ap));
! 328: #endif
! 329:
! 330: #ifdef HAVE_SIGNALED_IO
! 331: extern void wait_for_signal P((void));
! 332: extern void unblock_io_and_alarm P((void));
! 333: extern void block_io_and_alarm P((void));
! 334: #endif
! 335:
! 336:
! 337: #ifdef NO_MAIN_ALLOWED
! 338: CALL(ntptimeset,"ntptimeset",ntptimesetmain);
! 339:
! 340: void clear_globals()
! 341: {
! 342: /*
! 343: * Debugging flag
! 344: */
! 345: debug = 0;
! 346:
! 347: ntp_optind = 0;
! 348:
! 349: /*
! 350: * Initializing flag. All async routines watch this and only do their
! 351: * thing when it is clear.
! 352: */
! 353: initializing = 1;
! 354:
! 355: /*
! 356: * Alarm flag. Set when an alarm occurs
! 357: */
! 358: alarm_flag = 0;
! 359:
! 360: /*
! 361: * Unpriviledged port flag.
! 362: */
! 363: unpriv_port = 0;
! 364:
! 365: /*
! 366: * Systemwide parameters and flags
! 367: */
! 368: sys_numservers = 0; /* number of servers to poll */
! 369: sys_authenticate = 0; /* true when authenticating */
! 370: sys_authkey = 0; /* set to authentication key in use */
! 371: sys_authdelay = 0; /* authentication delay */
! 372:
! 373: /*
! 374: * The current internal time
! 375: */
! 376: current_time = 0;
! 377:
! 378: verbose = 0;
! 379: }
! 380: #endif /* NO_MAIN_ALLOWED */
! 381:
! 382: /*
! 383: * Main program. Initialize us and loop waiting for I/O and/or
! 384: * timer expiries.
! 385: */
! 386: #ifndef NO_MAIN_ALLOWED
! 387: int
! 388: main(
! 389: int argc,
! 390: char *argv[]
! 391: )
! 392: {
! 393: return ntptimesetmain(argc, argv);
! 394: }
! 395: #endif /* NO_MAIN_ALLOWED */
! 396:
! 397:
! 398: int
! 399: ntptimesetmain(
! 400: int argc,
! 401: char *argv[]
! 402: )
! 403: {
! 404: int was_alarmed;
! 405: int tot_recvbufs;
! 406: struct recvbuf *rbuf;
! 407: l_fp tmp;
! 408: int errflg;
! 409: int c;
! 410: extern char *ntp_optarg;
! 411: extern int ntp_optind;
! 412: int ltmp;
! 413: char *cfgpath;
! 414:
! 415: #ifdef SYS_WINNT
! 416: HANDLE process_handle;
! 417:
! 418: wVersionRequested = MAKEWORD(1,1);
! 419: if (WSAStartup(wVersionRequested, &wsaData)) {
! 420: msyslog(LOG_ERR, "No useable winsock.dll: %m");
! 421: exit(1);
! 422: }
! 423: #endif /* SYS_WINNT */
! 424:
! 425: #ifdef NO_MAIN_ALLOWED
! 426: clear_globals();
! 427: #endif
! 428:
! 429: errflg = 0;
! 430: cfgpath = 0;
! 431: progname = argv[0];
! 432: syslogit = 0;
! 433:
! 434: /*
! 435: * Decode argument list
! 436: */
! 437: while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF)
! 438: switch (c)
! 439: {
! 440: case 'a':
! 441: c = atoi(ntp_optarg);
! 442: sys_authenticate = 1;
! 443: sys_authkey = c;
! 444: break;
! 445: case 'c':
! 446: cfgpath = ntp_optarg;
! 447: break;
! 448: case 'd':
! 449: ++debug;
! 450: break;
! 451: case 'e':
! 452: if (!atolfp(ntp_optarg, &tmp)
! 453: || tmp.l_ui != 0) {
! 454: (void) fprintf(stderr,
! 455: "%s: encryption delay %s is unlikely\n",
! 456: progname, ntp_optarg);
! 457: errflg++;
! 458: } else {
! 459: sys_authdelay = tmp.l_uf;
! 460: }
! 461: break;
! 462: case 's':
! 463: set_time = 1;
! 464: break;
! 465: case 'l':
! 466: syslogit = 1;
! 467: break;
! 468: case 't':
! 469: ltmp = atoi(ntp_optarg);
! 470: if (ltmp <= 0) {
! 471: (void) fprintf(stderr,
! 472: "%s: maximum time period (%d) is invalid\n",
! 473: progname, ltmp);
! 474: errflg++;
! 475: }
! 476: else
! 477: max_period = ltmp;
! 478: break;
! 479: case 'u':
! 480: unpriv_port = 1;
! 481: break;
! 482: case 'v':
! 483: ++verbose;
! 484: break;
! 485: case 'H':
! 486: horrible++;
! 487: break;
! 488: case 'S':
! 489: ltmp = atoi(ntp_optarg);
! 490: if (ltmp <= 0) {
! 491: (void) fprintf(stderr,
! 492: "%s: minimum responding (%d) is invalid\n",
! 493: progname, ltmp);
! 494: errflg++;
! 495: }
! 496: else
! 497: min_servers = ltmp;
! 498: break;
! 499: case 'V':
! 500: ltmp = atoi(ntp_optarg);
! 501: if (ltmp <= 0) {
! 502: (void) fprintf(stderr,
! 503: "%s: minimum valid (%d) is invalid\n",
! 504: progname, ltmp);
! 505: errflg++;
! 506: }
! 507: else
! 508: min_valid = ltmp;
! 509: break;
! 510: case '?':
! 511: ++errflg;
! 512: break;
! 513: default:
! 514: break;
! 515: }
! 516:
! 517:
! 518: if (errflg || ntp_optind < argc) {
! 519: fprintf(stderr,"usage: %s [switches...]\n",progname);
! 520: fprintf(stderr," -v (verbose)\n");
! 521: fprintf(stderr," -c path (set config file path)\n");
! 522: fprintf(stderr," -a key (authenticate using key)\n");
! 523: fprintf(stderr," -e delay (authentication delay)\n");
! 524: fprintf(stderr," -S num (# of servers that must respond)\n");
! 525: fprintf(stderr," -V num (# of servers that must valid)\n");
! 526: fprintf(stderr," -s (set the time based if okay)\n");
! 527: fprintf(stderr," -t secs (time period before ending)\n");
! 528: fprintf(stderr," -l (use syslog facility)\n");
! 529: fprintf(stderr," -u (use unprivileged port)\n");
! 530: fprintf(stderr," -H (drop packets for debugging)\n");
! 531: fprintf(stderr," -d (debug output)\n");
! 532: exit(2);
! 533: }
! 534:
! 535: /*
! 536: * Logging. Open the syslog if we have to
! 537: */
! 538: if (syslogit) {
! 539: #if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32
! 540: # ifndef LOG_DAEMON
! 541: openlog("ntptimeset", LOG_PID);
! 542: # else
! 543:
! 544: # ifndef LOG_NTP
! 545: # define LOG_NTP LOG_DAEMON
! 546: # endif
! 547: openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP);
! 548: if (debug)
! 549: setlogmask(LOG_UPTO(LOG_DEBUG));
! 550: else
! 551: setlogmask(LOG_UPTO(LOG_INFO));
! 552: # endif /* LOG_DAEMON */
! 553: #endif /* SYS_WINNT */
! 554: }
! 555:
! 556: if (debug || verbose)
! 557: msyslog(LOG_INFO, "%s", Version);
! 558:
! 559: if (horrible)
! 560: msyslog(LOG_INFO, "Dropping %d out of %d packets",
! 561: horrible,horrible+HORRIBLEOK);
! 562: /*
! 563: * Add servers we are going to be polling
! 564: */
! 565: loadservers(cfgpath);
! 566:
! 567: if (sys_numservers < min_servers) {
! 568: msyslog(LOG_ERR, "Found %d servers, require %d servers",
! 569: sys_numservers,min_servers);
! 570: exit(2);
! 571: }
! 572:
! 573: /*
! 574: * determine when we will end at least
! 575: */
! 576: finish_time = max_period * TIMER_HZ;
! 577: half_time = finish_time >> 1;
! 578:
! 579: /*
! 580: * Initialize the time of day routines and the I/O subsystem
! 581: */
! 582: if (sys_authenticate) {
! 583: init_auth();
! 584: #ifdef SYS_WINNT
! 585: if (!key_file) key_file = KEYFILE;
! 586: if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH))
! 587: {
! 588: msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n",
! 589: key_file);
! 590: } else {
! 591: key_file = key_file_storage;
! 592: }
! 593: #endif /* SYS_WINNT */
! 594:
! 595: if (!authreadkeys(key_file)) {
! 596: msyslog(LOG_ERR, "no key file, exiting");
! 597: exit(1);
! 598: }
! 599: if (!authistrusted(sys_authkey)) {
! 600: char buf[10];
! 601:
! 602: (void) sprintf(buf, "%lu", (unsigned long)sys_authkey);
! 603: msyslog(LOG_ERR, "authentication key %s unknown", buf);
! 604: exit(1);
! 605: }
! 606: }
! 607: init_io();
! 608: init_alarm();
! 609:
! 610: /*
! 611: * Set the priority.
! 612: */
! 613: #ifdef SYS_VXWORKS
! 614: taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);
! 615: #endif
! 616: #if defined(HAVE_ATT_NICE)
! 617: nice (NTPDATE_PRIO);
! 618: #endif
! 619: #if defined(HAVE_BSD_NICE)
! 620: (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);
! 621: #endif
! 622: #ifdef SYS_WINNT
! 623: process_handle = GetCurrentProcess();
! 624: if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) {
! 625: msyslog(LOG_ERR, "SetPriorityClass failed: %m");
! 626: }
! 627: #endif /* SYS_WINNT */
! 628:
! 629: initializing = 0;
! 630:
! 631: /*
! 632: * Use select() on all on all input fd's for unlimited
! 633: * time. select() will terminate on SIGALARM or on the
! 634: * reception of input. Using select() means we can't do
! 635: * robust signal handling and we get a potential race
! 636: * between checking for alarms and doing the select().
! 637: * Mostly harmless, I think.
! 638: * Keep going until we have enough information, or time is up.
! 639: */
! 640: /* On VMS, I suspect that select() can't be interrupted
! 641: * by a "signal" either, so I take the easy way out and
! 642: * have select() time out after one second.
! 643: * System clock updates really aren't time-critical,
! 644: * and - lacking a hardware reference clock - I have
! 645: * yet to learn about anything else that is.
! 646: */
! 647: was_alarmed = 0;
! 648: while (finish_time > current_time) {
! 649: #if !defined(HAVE_SIGNALED_IO)
! 650: fd_set rdfdes;
! 651: int nfound;
! 652: #elif defined(HAVE_SIGNALED_IO)
! 653: block_io_and_alarm();
! 654: #endif
! 655:
! 656: tot_recvbufs = full_recvbuffs(); /* get received buffers */
! 657: if (printmsg) {
! 658: printmsg = 0;
! 659: analysis(0);
! 660: }
! 661: if (alarm_flag) { /* alarmed? */
! 662: was_alarmed = 1;
! 663: alarm_flag = 0;
! 664: }
! 665:
! 666: if (!was_alarmed && tot_recvbufs > 0) {
! 667: /*
! 668: * Nothing to do. Wait for something.
! 669: */
! 670: #ifndef HAVE_SIGNALED_IO
! 671: rdfdes = fdmask;
! 672: # if defined(VMS) || defined(SYS_VXWORKS)
! 673: /* make select() wake up after one second */
! 674: {
! 675: struct timeval t1;
! 676:
! 677: t1.tv_sec = 1; t1.tv_usec = 0;
! 678: nfound = select(fd+1, &rdfdes, (fd_set *)0,
! 679: (fd_set *)0, &t1);
! 680: }
! 681: # else
! 682: nfound = select(fd+1, &rdfdes, (fd_set *)0,
! 683: (fd_set *)0, (struct timeval *)0);
! 684: # endif /* VMS */
! 685: if (nfound > 0) {
! 686: l_fp ts;
! 687: get_systime(&ts);
! 688: (void)input_handler(&ts);
! 689: }
! 690: else if (nfound == -1 && errno != EINTR)
! 691: msyslog(LOG_ERR, "select() error: %m");
! 692: else if (debug) {
! 693: # if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */
! 694: msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
! 695: # endif
! 696: }
! 697: #else /* HAVE_SIGNALED_IO */
! 698:
! 699: wait_for_signal();
! 700: #endif /* HAVE_SIGNALED_IO */
! 701: if (alarm_flag) /* alarmed? */
! 702: {
! 703: was_alarmed = 1;
! 704: alarm_flag = 0;
! 705: }
! 706: tot_recvbufs = full_recvbuffs(); /* get received buffers */
! 707: }
! 708: #ifdef HAVE_SIGNALED_IO
! 709: unblock_io_and_alarm();
! 710: #endif /* HAVE_SIGNALED_IO */
! 711:
! 712: /*
! 713: * Out here, signals are unblocked. Call timer routine
! 714: * to process expiry.
! 715: */
! 716: if (was_alarmed)
! 717: {
! 718: timer();
! 719: was_alarmed = 0;
! 720: }
! 721:
! 722: /*
! 723: * Call the data procedure to handle each received
! 724: * packet.
! 725: */
! 726: rbuf = get_full_recv_buffer();
! 727: while (rbuf != NULL)
! 728: {
! 729: receive(rbuf);
! 730: freerecvbuf(rbuf);
! 731: rbuf = get_full_recv_buffer();
! 732: }
! 733:
! 734: /*
! 735: * Do we have enough information to stop now?
! 736: */
! 737: if (have_enough())
! 738: break; /* time to end */
! 739:
! 740: /*
! 741: * Go around again
! 742: */
! 743: }
! 744:
! 745: /*
! 746: * adjust the clock and exit accordingly
! 747: */
! 748: set_local_clock();
! 749:
! 750: /*
! 751: * if we get here then we are in trouble
! 752: */
! 753: return(1);
! 754: }
! 755:
! 756:
! 757: /*
! 758: * analysis - print a message indicating what is happening with time service
! 759: * must mimic have_enough() procedure.
! 760: */
! 761: static void
! 762: analysis(
! 763: int final
! 764: )
! 765: {
! 766: if (contacted < sys_numservers) {
! 767: printf("%d servers of %d have been probed with %d packets\n",
! 768: contacted,sys_numservers,MINTRANSMITS);
! 769: return;
! 770: }
! 771: if (!responding) {
! 772: printf("No response from any of %d servers, network problem?\n",
! 773: sys_numservers);
! 774: return;
! 775: }
! 776: else if (responding < min_servers) {
! 777: printf("%d servers out of %d responding, need at least %d.\n",
! 778: responding, sys_numservers, min_servers);
! 779: return;
! 780: }
! 781: if (!validcount) {
! 782: printf("%d servers responding but none have valid time\n",
! 783: responding);
! 784: return;
! 785: }
! 786: else if (validcount < min_valid) {
! 787: printf("%d servers responding, %d are valid, need %d valid\n",
! 788: responding,validcount,min_valid);
! 789: return;
! 790: }
! 791: if (!final && valid_n_low != validcount) {
! 792: printf("%d valid servers but only %d have low dispersion\n",
! 793: validcount,valid_n_low);
! 794: return;
! 795: }
! 796: }
! 797:
! 798:
! 799: /* have_enough - see if we have enough information to terminate probing
! 800: */
! 801: static int
! 802: have_enough(void)
! 803: {
! 804: /* have we contacted all servers yet? */
! 805: if (contacted < sys_numservers)
! 806: return 0; /* no...try some more */
! 807:
! 808: /* have we got at least minimum servers responding? */
! 809: if (responding < min_servers)
! 810: return 0; /* no...try some more */
! 811:
! 812: /* count the clocks */
! 813: (void) clock_count();
! 814:
! 815: /* have we got at least minimum valid clocks? */
! 816: if (validcount <= 0 || validcount < min_valid)
! 817: return 0; /* no...try some more */
! 818:
! 819: /* do we have all valid servers with low dispersion */
! 820: if (!secondhalf && valid_n_low != validcount)
! 821: return 0;
! 822:
! 823: /* if we get into the secondhalf then we ignore dispersion */
! 824:
! 825: /* all conditions have been met...end */
! 826: return 1;
! 827: }
! 828:
! 829:
! 830: /*
! 831: * transmit - transmit a packet to the given server, or mark it completed.
! 832: * This is called by the timeout routine and by the receive
! 833: * procedure.
! 834: */
! 835: static void
! 836: transmit(
! 837: register struct server *server
! 838: )
! 839: {
! 840: struct pkt xpkt;
! 841: int timeout;
! 842:
! 843: if (debug > 2)
! 844: printf("transmit(%s)\n", ntoa(&server->srcadr));
! 845:
! 846: if ((server->reach & 01) == 0) {
! 847: l_fp ts;
! 848: /*
! 849: * Last message to this server timed out. Shift
! 850: * zeros into the filter.
! 851: */
! 852: L_CLR(&ts);
! 853: clock_filter(server, 0, &ts);
! 854: }
! 855:
! 856: /*
! 857: * shift reachable register over
! 858: */
! 859: server->reach <<= 1;
! 860:
! 861: /*
! 862: * If we're here, send another message to the server. Fill in
! 863: * the packet and let 'er rip.
! 864: */
! 865: xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
! 866: server->version, MODE_CLIENT);
! 867: xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
! 868: xpkt.ppoll = NTP_MINPOLL;
! 869: xpkt.precision = NTPDATE_PRECISION;
! 870: xpkt.rootdelay = htonl(NTPDATE_DISTANCE);
! 871: xpkt.rootdispersion = htonl(NTPDATE_DISP);
! 872: xpkt.refid = htonl(NTPDATE_REFID);
! 873: L_CLR(&xpkt.reftime);
! 874: L_CLR(&xpkt.org);
! 875: L_CLR(&xpkt.rec);
! 876:
! 877: /*
! 878: * Determine whether to authenticate or not. If so,
! 879: * fill in the extended part of the packet and do it.
! 880: * If not, just timestamp it and send it away.
! 881: */
! 882: if (sys_authenticate) {
! 883: int len;
! 884:
! 885: xpkt.exten[0] = htonl(sys_authkey);
! 886: get_systime(&server->xmt);
! 887: L_ADDUF(&server->xmt, sys_authdelay);
! 888: HTONL_FP(&server->xmt, &xpkt.xmt);
! 889: len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC);
! 890: if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) {
! 891: if (debug > 1)
! 892: printf("failed transmit auth to %s\n",
! 893: ntoa(&(server->srcadr)));
! 894: return;
! 895: }
! 896:
! 897: if (debug > 1)
! 898: printf("transmit auth to %s\n",
! 899: ntoa(&(server->srcadr)));
! 900: } else {
! 901: get_systime(&(server->xmt));
! 902: HTONL_FP(&server->xmt, &xpkt.xmt);
! 903: if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) {
! 904: if (debug > 1)
! 905: printf("failed transmit to %s\n",
! 906: ntoa(&(server->srcadr)));
! 907: return;
! 908: }
! 909:
! 910: if (debug > 1)
! 911: printf("transmit to %s\n", ntoa(&(server->srcadr)));
! 912: }
! 913:
! 914: /*
! 915: * count transmits, record contacted count and set transmit time
! 916: */
! 917: if (++server->xmtcnt == MINTRANSMITS)
! 918: contacted++;
! 919: server->last_xmit = current_time;
! 920:
! 921: /*
! 922: * determine timeout for this packet. The more packets we send
! 923: * to the host, the slower we get. If the host indicates that
! 924: * it is not "sane" then we expect even less.
! 925: */
! 926: if (server->xmtcnt < MINTRANSMITS) {
! 927: /* we have not sent enough */
! 928: timeout = TIMER_HZ; /* 1 second probe */
! 929: }
! 930: else if (server->rcvcnt <= 0) {
! 931: /* we have heard nothing */
! 932: if (secondhalf)
! 933: timeout = TIMER_HZ<<4; /* 16 second probe */
! 934: else
! 935: timeout = TIMER_HZ<<3; /* 8 second probe */
! 936: }
! 937: else {
! 938: /* if we have low dispersion then probe infrequently */
! 939: if (server->dispersion <= DESIREDDISP)
! 940: timeout = TIMER_HZ<<4; /* 16 second probe */
! 941: /* if the server is not in sync then let it alone */
! 942: else if (server->leap == LEAP_NOTINSYNC)
! 943: timeout = TIMER_HZ<<4; /* 16 second probe */
! 944: /* if the server looks broken ignore it */
! 945: else if (server->org.l_ui < server->reftime.l_ui)
! 946: timeout = TIMER_HZ<<5; /* 32 second probe */
! 947: else if (secondhalf)
! 948: timeout = TIMER_HZ<<2; /* 4 second probe */
! 949: else
! 950: timeout = TIMER_HZ<<1; /* 2 second probe */
! 951: }
! 952:
! 953: /*
! 954: * set next transmit time based on timeout
! 955: */
! 956: server->event_time = current_time + timeout;
! 957: }
! 958:
! 959:
! 960: /*
! 961: * receive - receive and process an incoming frame
! 962: */
! 963: static void
! 964: receive(
! 965: struct recvbuf *rbufp
! 966: )
! 967: {
! 968: register struct pkt *rpkt;
! 969: register struct server *server;
! 970: register s_fp di;
! 971: l_fp t10, t23;
! 972: l_fp org;
! 973: l_fp rec;
! 974: l_fp ci;
! 975: int has_mac;
! 976: int is_authentic;
! 977:
! 978: if (debug > 2)
! 979: printf("receive(%s)\n", ntoa(&rbufp->srcadr));
! 980: /*
! 981: * Check to see if the packet basically looks like something
! 982: * intended for us.
! 983: */
! 984: if (rbufp->recv_length == LEN_PKT_NOMAC)
! 985: has_mac = 0;
! 986: else if (rbufp->recv_length >= LEN_PKT_NOMAC)
! 987: has_mac = 1;
! 988: else {
! 989: if (debug > 2)
! 990: printf("receive: packet length %d\n",
! 991: rbufp->recv_length);
! 992: return; /* funny length packet */
! 993: }
! 994:
! 995: rpkt = &(rbufp->recv_pkt);
! 996: if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
! 997: PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
! 998: if (debug > 1)
! 999: printf("receive: bad version %d\n",
! 1000: PKT_VERSION(rpkt->li_vn_mode));
! 1001: return;
! 1002: }
! 1003:
! 1004: if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
! 1005: && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE)
! 1006: || rpkt->stratum >=STRATUM_UNSPEC) {
! 1007: if (debug > 1)
! 1008: printf("receive: mode %d stratum %d\n",
! 1009: PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
! 1010: return;
! 1011: }
! 1012:
! 1013: /*
! 1014: * So far, so good. See if this is from a server we know.
! 1015: */
! 1016: server = findserver(&(rbufp->srcadr));
! 1017: if (server == NULL) {
! 1018: if (debug > 1)
! 1019: printf("receive: server not found\n");
! 1020: return;
! 1021: }
! 1022:
! 1023: /*
! 1024: * Decode the org timestamp and make sure we're getting a response
! 1025: * to our last request.
! 1026: */
! 1027: NTOHL_FP(&rpkt->org, &org);
! 1028: if (!L_ISEQU(&org, &server->xmt)) {
! 1029: if (debug > 1)
! 1030: printf("receive: pkt.org and peer.xmt differ\n");
! 1031: return;
! 1032: }
! 1033:
! 1034: /*
! 1035: * Check out the authenticity if we're doing that.
! 1036: */
! 1037: if (!sys_authenticate)
! 1038: is_authentic = 1;
! 1039: else {
! 1040: is_authentic = 0;
! 1041:
! 1042: if (debug > 3)
! 1043: printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n",
! 1044: (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey,
! 1045: (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt,
! 1046: LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC)));
! 1047:
! 1048: if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey &&
! 1049: authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC,
! 1050: (int)(rbufp->recv_length - LEN_PKT_NOMAC)))
! 1051: is_authentic = 1;
! 1052: if (debug)
! 1053: printf("receive: authentication %s\n",
! 1054: is_authentic ? "passed" : "failed");
! 1055: }
! 1056: server->trust <<= 1;
! 1057: if (!is_authentic)
! 1058: server->trust |= 1;
! 1059:
! 1060: /*
! 1061: * Looks good. Record info from the packet.
! 1062: */
! 1063: server->leap = PKT_LEAP(rpkt->li_vn_mode);
! 1064: server->stratum = PKT_TO_STRATUM(rpkt->stratum);
! 1065: server->precision = rpkt->precision;
! 1066: server->rootdelay = ntohl(rpkt->rootdelay);
! 1067: server->rootdispersion = ntohl(rpkt->rootdispersion);
! 1068: server->refid = rpkt->refid;
! 1069: NTOHL_FP(&rpkt->reftime, &server->reftime);
! 1070: NTOHL_FP(&rpkt->rec, &rec);
! 1071: NTOHL_FP(&rpkt->xmt, &server->org);
! 1072:
! 1073: /*
! 1074: * count this guy as responding
! 1075: */
! 1076: server->reach |= 1;
! 1077: if (server->rcvcnt++ == 0)
! 1078: responding++;
! 1079:
! 1080: /*
! 1081: * Make sure the server is at least somewhat sane. If not, ignore
! 1082: * it for later.
! 1083: */
! 1084: if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
! 1085: if (debug > 1)
! 1086: printf("receive: pkt insane\n");
! 1087: return;
! 1088: }
! 1089:
! 1090: /*
! 1091: * Calculate the round trip delay (di) and the clock offset (ci).
! 1092: * We use the equations (reordered from those in the spec):
! 1093: *
! 1094: * d = (t2 - t3) - (t1 - t0)
! 1095: * c = ((t2 - t3) + (t1 - t0)) / 2
! 1096: */
! 1097: t10 = server->org; /* pkt.xmt == t1 */
! 1098: L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/
! 1099:
! 1100: t23 = rec; /* pkt.rec == t2 */
! 1101: L_SUB(&t23, &org); /* pkt->org == t3 */
! 1102:
! 1103: /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */
! 1104: ci = t10;
! 1105: L_ADD(&ci, &t23);
! 1106: L_RSHIFT(&ci);
! 1107:
! 1108: /*
! 1109: * Calculate di in t23 in full precision, then truncate
! 1110: * to an s_fp.
! 1111: */
! 1112: L_SUB(&t23, &t10);
! 1113: di = LFPTOFP(&t23);
! 1114:
! 1115: if (debug > 3)
! 1116: printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5));
! 1117:
! 1118: di += (FP_SECOND >> (-(int)NTPDATE_PRECISION))
! 1119: + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW;
! 1120:
! 1121: if (di <= 0) { /* value still too raunchy to use? */
! 1122: L_CLR(&ci);
! 1123: di = 0;
! 1124: } else {
! 1125: di = max(di, NTP_MINDIST);
! 1126: }
! 1127:
! 1128:
! 1129: /*
! 1130: * This one is valid. Give it to clock_filter(),
! 1131: */
! 1132: clock_filter(server, di, &ci);
! 1133: if (debug > 1)
! 1134: printf("receive from %s\n", ntoa(&rbufp->srcadr));
! 1135:
! 1136: /*
! 1137: * See if we should goes the transmission. If not return now
! 1138: * otherwise have the next event time be shortened
! 1139: */
! 1140: if (server->stratum <= NTP_INFIN)
! 1141: return; /* server does not have a stratum */
! 1142: if (server->leap == LEAP_NOTINSYNC)
! 1143: return; /* just booted server or out of sync */
! 1144: if (!L_ISHIS(&server->org, &server->reftime))
! 1145: return; /* broken host */
! 1146: if (server->trust != 0)
! 1147: return; /* can not trust it */
! 1148:
! 1149: if (server->dispersion < DESIREDDISP)
! 1150: return; /* we have the desired dispersion */
! 1151:
! 1152: server->event_time -= (TIMER_HZ+1);
! 1153: }
! 1154:
! 1155:
! 1156: /*
! 1157: * clock_filter - add clock sample, determine a server's delay, dispersion
! 1158: * and offset
! 1159: */
! 1160: static void
! 1161: clock_filter(
! 1162: register struct server *server,
! 1163: s_fp di,
! 1164: l_fp *c
! 1165: )
! 1166: {
! 1167: register int i, j;
! 1168: int ord[NTP_SHIFT];
! 1169:
! 1170: /*
! 1171: * Insert sample and increment nextpt
! 1172: */
! 1173:
! 1174: i = server->filter_nextpt;
! 1175: server->filter_delay[i] = di;
! 1176: server->filter_offset[i] = *c;
! 1177: server->filter_soffset[i] = LFPTOFP(c);
! 1178: server->filter_nextpt++;
! 1179: if (server->filter_nextpt >= NTP_SHIFT)
! 1180: server->filter_nextpt = 0;
! 1181:
! 1182: /*
! 1183: * Sort indices into increasing delay order
! 1184: */
! 1185: for (i = 0; i < NTP_SHIFT; i++)
! 1186: ord[i] = i;
! 1187:
! 1188: for (i = 0; i < (NTP_SHIFT-1); i++) {
! 1189: for (j = i+1; j < NTP_SHIFT; j++) {
! 1190: if (server->filter_delay[ord[j]] == 0)
! 1191: continue;
! 1192: if (server->filter_delay[ord[i]] == 0
! 1193: || (server->filter_delay[ord[i]]
! 1194: > server->filter_delay[ord[j]])) {
! 1195: register int tmp;
! 1196:
! 1197: tmp = ord[i];
! 1198: ord[i] = ord[j];
! 1199: ord[j] = tmp;
! 1200: }
! 1201: }
! 1202: }
! 1203:
! 1204: /*
! 1205: * Now compute the dispersion, and assign values to delay and
! 1206: * offset. If there are no samples in the register, delay and
! 1207: * offset go to zero and dispersion is set to the maximum.
! 1208: */
! 1209: if (server->filter_delay[ord[0]] == 0) {
! 1210: server->delay = 0;
! 1211: L_CLR(&server->offset);
! 1212: server->soffset = 0;
! 1213: server->dispersion = PEER_MAXDISP;
! 1214: } else {
! 1215: register s_fp d;
! 1216:
! 1217: server->delay = server->filter_delay[ord[0]];
! 1218: server->offset = server->filter_offset[ord[0]];
! 1219: server->soffset = LFPTOFP(&server->offset);
! 1220: server->dispersion = 0;
! 1221: for (i = 1; i < NTP_SHIFT; i++) {
! 1222: if (server->filter_delay[ord[i]] == 0)
! 1223: d = PEER_MAXDISP;
! 1224: else {
! 1225: d = server->filter_soffset[ord[i]]
! 1226: - server->filter_soffset[ord[0]];
! 1227: if (d < 0)
! 1228: d = -d;
! 1229: if (d > PEER_MAXDISP)
! 1230: d = PEER_MAXDISP;
! 1231: }
! 1232: /*
! 1233: * XXX This *knows* PEER_FILTER is 1/2
! 1234: */
! 1235: server->dispersion += (u_fp)(d) >> i;
! 1236: }
! 1237: }
! 1238: /*
! 1239: * We're done
! 1240: */
! 1241: }
! 1242:
! 1243:
! 1244: /* clock_count - count the clock sources we have
! 1245: */
! 1246: static void
! 1247: clock_count(void)
! 1248: {
! 1249: register struct server *server;
! 1250: register int n;
! 1251:
! 1252: /* reset counts */
! 1253: validcount = valid_n_low = 0;
! 1254:
! 1255: /* go through the list of servers and count the clocks we believe
! 1256: * and that have low dispersion
! 1257: */
! 1258: for (n = 0; n < sys_numservers; n++) {
! 1259: server = sys_servers[n];
! 1260: if (server->delay == 0) {
! 1261: continue; /* no data */
! 1262: }
! 1263: if (server->stratum > NTP_INFIN) {
! 1264: continue; /* stratum no good */
! 1265: }
! 1266: if (server->delay > NTP_MAXWGT) {
! 1267: continue; /* too far away */
! 1268: }
! 1269: if (server->leap == LEAP_NOTINSYNC)
! 1270: continue; /* he's in trouble */
! 1271: if (!L_ISHIS(&server->org, &server->reftime)) {
! 1272: continue; /* very broken host */
! 1273: }
! 1274: if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) {
! 1275: continue; /* too long without sync */
! 1276: }
! 1277: if (server->trust != 0) {
! 1278: continue;
! 1279: }
! 1280:
! 1281: /*
! 1282: * This one is a valid time source..
! 1283: */
! 1284: validcount++;
! 1285:
! 1286: /*
! 1287: * See if this one has a okay low dispersion
! 1288: */
! 1289: if (server->dispersion <= DESIREDDISP)
! 1290: valid_n_low++;
! 1291: }
! 1292:
! 1293: if (debug > 1)
! 1294: printf("have %d, valid %d, low %d\n",
! 1295: responding, validcount, valid_n_low);
! 1296: }
! 1297:
! 1298:
! 1299: /*
! 1300: * clock_select - select the pick-of-the-litter clock from the samples
! 1301: * we've got.
! 1302: */
! 1303: static struct server *
! 1304: clock_select(void)
! 1305: {
! 1306: register struct server *server;
! 1307: register int i;
! 1308: register int nlist;
! 1309: register s_fp d;
! 1310: register int j;
! 1311: register int n;
! 1312: s_fp local_threshold;
! 1313: struct server *server_list[NTP_MAXCLOCK];
! 1314: u_fp server_badness[NTP_MAXCLOCK];
! 1315: struct server *sys_server;
! 1316:
! 1317: /*
! 1318: * This first chunk of code is supposed to go through all
! 1319: * servers we know about to find the NTP_MAXLIST servers which
! 1320: * are most likely to succeed. We run through the list
! 1321: * doing the sanity checks and trying to insert anyone who
! 1322: * looks okay. We are at all times aware that we should
! 1323: * only keep samples from the top two strata and we only need
! 1324: * NTP_MAXLIST of them.
! 1325: */
! 1326: nlist = 0; /* none yet */
! 1327: for (n = 0; n < sys_numservers; n++) {
! 1328: server = sys_servers[n];
! 1329: if (server->delay == 0)
! 1330: continue; /* no data */
! 1331: if (server->stratum > NTP_INFIN)
! 1332: continue; /* stratum no good */
! 1333: if (server->delay > NTP_MAXWGT) {
! 1334: continue; /* too far away */
! 1335: }
! 1336: if (server->leap == LEAP_NOTINSYNC)
! 1337: continue; /* he's in trouble */
! 1338: if (!L_ISHIS(&server->org, &server->reftime)) {
! 1339: continue; /* very broken host */
! 1340: }
! 1341: if ((server->org.l_ui - server->reftime.l_ui)
! 1342: >= NTP_MAXAGE) {
! 1343: continue; /* too long without sync */
! 1344: }
! 1345: if (server->trust != 0) {
! 1346: continue;
! 1347: }
! 1348:
! 1349: /*
! 1350: * This one seems sane. Find where he belongs
! 1351: * on the list.
! 1352: */
! 1353: d = server->dispersion + server->dispersion;
! 1354: for (i = 0; i < nlist; i++)
! 1355: if (server->stratum <= server_list[i]->stratum)
! 1356: break;
! 1357: for ( ; i < nlist; i++) {
! 1358: if (server->stratum < server_list[i]->stratum)
! 1359: break;
! 1360: if (d < (s_fp) server_badness[i])
! 1361: break;
! 1362: }
! 1363:
! 1364: /*
! 1365: * If i points past the end of the list, this
! 1366: * guy is a loser, else stick him in.
! 1367: */
! 1368: if (i >= NTP_MAXLIST)
! 1369: continue;
! 1370: for (j = nlist; j > i; j--)
! 1371: if (j < NTP_MAXLIST) {
! 1372: server_list[j] = server_list[j-1];
! 1373: server_badness[j]
! 1374: = server_badness[j-1];
! 1375: }
! 1376:
! 1377: server_list[i] = server;
! 1378: server_badness[i] = d;
! 1379: if (nlist < NTP_MAXLIST)
! 1380: nlist++;
! 1381: }
! 1382:
! 1383: /*
! 1384: * Got the five-or-less best. Cut the list where the number of
! 1385: * strata exceeds two.
! 1386: */
! 1387: j = 0;
! 1388: for (i = 1; i < nlist; i++)
! 1389: if (server_list[i]->stratum > server_list[i-1]->stratum)
! 1390: if (++j == 2) {
! 1391: nlist = i;
! 1392: break;
! 1393: }
! 1394:
! 1395: /*
! 1396: * Whew! What we should have by now is 0 to 5 candidates for
! 1397: * the job of syncing us. If we have none, we're out of luck.
! 1398: * If we have one, he's a winner. If we have more, do falseticker
! 1399: * detection.
! 1400: */
! 1401:
! 1402: if (nlist == 0)
! 1403: sys_server = 0;
! 1404: else if (nlist == 1) {
! 1405: sys_server = server_list[0];
! 1406: } else {
! 1407: /*
! 1408: * Re-sort by stratum, bdelay estimate quality and
! 1409: * server.delay.
! 1410: */
! 1411: for (i = 0; i < nlist-1; i++)
! 1412: for (j = i+1; j < nlist; j++) {
! 1413: if (server_list[i]->stratum
! 1414: < server_list[j]->stratum)
! 1415: break; /* already sorted by stratum */
! 1416: if (server_list[i]->delay
! 1417: < server_list[j]->delay)
! 1418: continue;
! 1419: server = server_list[i];
! 1420: server_list[i] = server_list[j];
! 1421: server_list[j] = server;
! 1422: }
! 1423:
! 1424: /*
! 1425: * Calculate the fixed part of the dispersion limit
! 1426: */
! 1427: local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION))
! 1428: + NTP_MAXSKW;
! 1429:
! 1430: /*
! 1431: * Now drop samples until we're down to one.
! 1432: */
! 1433: while (nlist > 1) {
! 1434: for (n = 0; n < nlist; n++) {
! 1435: server_badness[n] = 0;
! 1436: for (j = 0; j < nlist; j++) {
! 1437: if (j == n) /* with self? */
! 1438: continue;
! 1439: d = server_list[j]->soffset
! 1440: - server_list[n]->soffset;
! 1441: if (d < 0) /* absolute value */
! 1442: d = -d;
! 1443: /*
! 1444: * XXX This code *knows* that
! 1445: * NTP_SELECT is 3/4
! 1446: */
! 1447: for (i = 0; i < j; i++)
! 1448: d = (d>>1) + (d>>2);
! 1449: server_badness[n] += d;
! 1450: }
! 1451: }
! 1452:
! 1453: /*
! 1454: * We now have an array of nlist badness
! 1455: * coefficients. Find the badest. Find
! 1456: * the minimum precision while we're at
! 1457: * it.
! 1458: */
! 1459: i = 0;
! 1460: n = server_list[0]->precision;;
! 1461: for (j = 1; j < nlist; j++) {
! 1462: if (server_badness[j] >= server_badness[i])
! 1463: i = j;
! 1464: if (n > server_list[j]->precision)
! 1465: n = server_list[j]->precision;
! 1466: }
! 1467:
! 1468: /*
! 1469: * i is the index of the server with the worst
! 1470: * dispersion. If his dispersion is less than
! 1471: * the threshold, stop now, else delete him and
! 1472: * continue around again.
! 1473: */
! 1474: if (server_badness[i] < (local_threshold
! 1475: + (FP_SECOND >> (-n))))
! 1476: break;
! 1477: for (j = i + 1; j < nlist; j++)
! 1478: server_list[j-1] = server_list[j];
! 1479: nlist--;
! 1480: }
! 1481:
! 1482: /*
! 1483: * What remains is a list of less than 5 servers. Take
! 1484: * the best.
! 1485: */
! 1486: sys_server = server_list[0];
! 1487: }
! 1488:
! 1489: /*
! 1490: * That's it. Return our server.
! 1491: */
! 1492: return sys_server;
! 1493: }
! 1494:
! 1495:
! 1496: /*
! 1497: * set_local_clock -- handle setting the local clock or displaying info.
! 1498: */
! 1499: static void
! 1500: set_local_clock(void)
! 1501: {
! 1502: register int i;
! 1503: register struct server *server;
! 1504: time_t tmp;
! 1505: double dtemp;
! 1506:
! 1507: /*
! 1508: * if setting time then print final analysis
! 1509: */
! 1510: if (set_time)
! 1511: analysis(1);
! 1512:
! 1513: /*
! 1514: * pick a clock
! 1515: */
! 1516: server = clock_select();
! 1517:
! 1518: /*
! 1519: * do some display of information
! 1520: */
! 1521: if (debug || verbose) {
! 1522: for (i = 0; i < sys_numservers; i++)
! 1523: printserver(sys_servers[i], stdout);
! 1524: if (debug)
! 1525: printf("packets sent %ld, received %ld\n",
! 1526: total_xmit, total_recv);
! 1527: }
! 1528:
! 1529: /*
! 1530: * see if we have a server to set the time with
! 1531: */
! 1532: if (server == 0) {
! 1533: if (!set_time || verbose)
! 1534: fprintf(stdout,"No servers available to sync time with\n");
! 1535: exit(1);
! 1536: }
! 1537:
! 1538: /*
! 1539: * we have a valid and selected time to use!!!!!
! 1540: */
! 1541:
! 1542: /*
! 1543: * if we are not setting the time then display offset and exit
! 1544: */
! 1545: if (!set_time) {
! 1546: fprintf(stdout,
! 1547: "Your clock is off by %s seconds. (%s) [%ld/%ld]\n",
! 1548: lfptoa(&server->offset, 7),
! 1549: ntoa(&server->srcadr),
! 1550: total_xmit, total_recv);
! 1551: exit(0);
! 1552: }
! 1553:
! 1554: /*
! 1555: * set the clock
! 1556: * XXX: Examine the more flexible approach used by ntpdate.
! 1557: * Note that a design consideration here is that we sometimes
! 1558: * _want_ to step the clock by a _huge_ amount in either
! 1559: * direction, because the local clock is completely bogus.
! 1560: * This condition must be recognized and dealt with, so
! 1561: * that we always get a good time when this completes.
! 1562: * -- jhutz+@cmu.edu, 16-Aug-1999
! 1563: */
! 1564: LFPTOD(&server->offset, dtemp);
! 1565: step_systime(dtemp);
! 1566: time(&tmp);
! 1567: fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n",
! 1568: ctime(&tmp)+4,
! 1569: ntoa(&server->srcadr),
! 1570: lfptoa(&server->offset, 7),
! 1571: total_xmit, total_recv);
! 1572: exit(0);
! 1573: }
! 1574:
! 1575:
! 1576: /*
! 1577: * findserver - find a server in the list given its address
! 1578: */
! 1579: static struct server *
! 1580: findserver(
! 1581: struct sockaddr_in *addr
! 1582: )
! 1583: {
! 1584: register int i;
! 1585: register u_int32 netnum;
! 1586:
! 1587: if (htons(addr->sin_port) != NTP_PORT)
! 1588: return 0;
! 1589: netnum = addr->sin_addr.s_addr;
! 1590:
! 1591: for (i = 0; i < sys_numservers; i++) {
! 1592: if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr)
! 1593: return sys_servers[i];
! 1594: }
! 1595: return 0;
! 1596: }
! 1597:
! 1598:
! 1599: /*
! 1600: * timer - process a timer interrupt
! 1601: */
! 1602: static void
! 1603: timer(void)
! 1604: {
! 1605: register int k;
! 1606:
! 1607: /*
! 1608: * Bump the current idea of the time
! 1609: */
! 1610: current_time++;
! 1611:
! 1612: /*
! 1613: * see if we have reached half time
! 1614: */
! 1615: if (current_time >= half_time && !secondhalf) {
! 1616: secondhalf++;
! 1617: if (debug)
! 1618: printf("\nSecond Half of Timeout!\n");
! 1619: printmsg++;
! 1620: }
! 1621:
! 1622: /*
! 1623: * We only want to send a few packets per transmit interrupt
! 1624: * to throttle things
! 1625: */
! 1626: for(k = 0;k < MAXXMITCOUNT;k++) {
! 1627: register int i, oldi;
! 1628: register u_long oldxtime;
! 1629:
! 1630: /*
! 1631: * We want to send a packet out for a server that has an
! 1632: * expired event time. However to be mellow about this, we only
! 1633: * use one expired event timer and to avoid starvation we use
! 1634: * the one with the oldest last transmit time.
! 1635: */
! 1636: oldi = -1;
! 1637: oldxtime = 0;
! 1638: for (i = 0; i < sys_numservers; i++) {
! 1639: if (sys_servers[i]->event_time <= current_time) {
! 1640: if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) {
! 1641: oldxtime = sys_servers[i]->last_xmit;
! 1642: oldi = i;
! 1643: }
! 1644: }
! 1645: }
! 1646: if (oldi >= 0)
! 1647: transmit(sys_servers[oldi]);
! 1648: else
! 1649: break; /* no expired event */
! 1650: } /* end of transmit loop */
! 1651: }
! 1652:
! 1653:
! 1654: #ifndef SYS_WINNT
! 1655: /*
! 1656: * alarming - record the occurance of an alarm interrupt
! 1657: */
! 1658: static RETSIGTYPE
! 1659: alarming(
! 1660: int sig
! 1661: )
! 1662: #else
! 1663: void CALLBACK
! 1664: alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
! 1665: #endif /* SYS_WINNT */
! 1666: {
! 1667: alarm_flag++;
! 1668: }
! 1669:
! 1670:
! 1671: /*
! 1672: * init_alarm - set up the timer interrupt
! 1673: */
! 1674: static void
! 1675: init_alarm(void)
! 1676: {
! 1677: #ifndef SYS_WINNT
! 1678: # ifndef HAVE_TIMER_SETTIME
! 1679: struct itimerval itimer;
! 1680: # else
! 1681: struct itimerspec ntpdate_itimer;
! 1682: # endif
! 1683: #else
! 1684: TIMECAPS tc;
! 1685: UINT wTimerRes, wTimerID;
! 1686: # endif /* SYS_WINNT */
! 1687: #if defined SYS_CYGWIN32 || defined SYS_WINNT
! 1688: HANDLE hToken;
! 1689: TOKEN_PRIVILEGES tkp;
! 1690: DWORD dwUser = 0;
! 1691: #endif /* SYS_WINNT */
! 1692:
! 1693: alarm_flag = 0;
! 1694:
! 1695: #ifndef SYS_WINNT
! 1696: # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
! 1697: alarm_flag = 0;
! 1698: /* this code was put in as setitimer() is non existant this us the
! 1699: * POSIX "equivalents" setup - casey
! 1700: */
! 1701: /* ntpdate_timerid is global - so we can kill timer later */
! 1702: if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) ==
! 1703: # ifdef SYS_VXWORKS
! 1704: ERROR
! 1705: # else
! 1706: -1
! 1707: # endif
! 1708: )
! 1709: {
! 1710: fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n");
! 1711: return;
! 1712: }
! 1713:
! 1714: /* TIMER_HZ = (5)
! 1715: * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
! 1716: * seconds from now and they continue on every 1/TIMER_HZ seconds.
! 1717: */
! 1718: (void) signal_no_reset(SIGALRM, alarming);
! 1719: ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
! 1720: ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
! 1721: ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
! 1722: timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
! 1723: # else
! 1724: /*
! 1725: * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
! 1726: * seconds from now and they continue on every 1/TIMER_HZ seconds.
! 1727: */
! 1728: (void) signal_no_reset(SIGALRM, alarming);
! 1729: itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
! 1730: itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
! 1731: itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
! 1732: setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
! 1733: # endif
! 1734: #if defined SYS_CYGWIN32
! 1735: /*
! 1736: * Get previleges needed for fiddling with the clock
! 1737: */
! 1738:
! 1739: /* get the current process token handle */
! 1740: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
! 1741: msyslog(LOG_ERR, "OpenProcessToken failed: %m");
! 1742: exit(1);
! 1743: }
! 1744: /* get the LUID for system-time privilege. */
! 1745: LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
! 1746: tkp.PrivilegeCount = 1; /* one privilege to set */
! 1747: tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
! 1748: /* get set-time privilege for this process. */
! 1749: AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
! 1750: /* cannot test return value of AdjustTokenPrivileges. */
! 1751: if (GetLastError() != ERROR_SUCCESS)
! 1752: msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
! 1753: #endif
! 1754: #else /* SYS_WINNT */
! 1755: _tzset();
! 1756:
! 1757: /*
! 1758: * Get previleges needed for fiddling with the clock
! 1759: */
! 1760:
! 1761: /* get the current process token handle */
! 1762: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
! 1763: msyslog(LOG_ERR, "OpenProcessToken failed: %m");
! 1764: exit(1);
! 1765: }
! 1766: /* get the LUID for system-time privilege. */
! 1767: LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
! 1768: tkp.PrivilegeCount = 1; /* one privilege to set */
! 1769: tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
! 1770: /* get set-time privilege for this process. */
! 1771: AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
! 1772: /* cannot test return value of AdjustTokenPrivileges. */
! 1773: if (GetLastError() != ERROR_SUCCESS)
! 1774: msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
! 1775:
! 1776: /*
! 1777: * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
! 1778: * Under Win/NT, expiry of timer interval leads to invocation
! 1779: * of a callback function (on a different thread) rather than
! 1780: * generating an alarm signal
! 1781: */
! 1782:
! 1783: /* determine max and min resolution supported */
! 1784: if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
! 1785: msyslog(LOG_ERR, "timeGetDevCaps failed: %m");
! 1786: exit(1);
! 1787: }
! 1788: wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
! 1789: /* establish the minimum timer resolution that we'll use */
! 1790: timeBeginPeriod(wTimerRes);
! 1791:
! 1792: /* start the timer event */
! 1793: wTimerID = timeSetEvent(
! 1794: (UINT) (1000/TIMER_HZ), /* Delay */
! 1795: wTimerRes, /* Resolution */
! 1796: (LPTIMECALLBACK) alarming, /* Callback function */
! 1797: (DWORD) dwUser, /* User data */
! 1798: TIME_PERIODIC); /* Event type (periodic) */
! 1799: if (wTimerID == 0) {
! 1800: msyslog(LOG_ERR, "timeSetEvent failed: %m");
! 1801: exit(1);
! 1802: }
! 1803: #endif /* SYS_WINNT */
! 1804: }
! 1805:
! 1806:
! 1807: /*
! 1808: * init_io - initialize I/O data and open socket
! 1809: */
! 1810: static void
! 1811: init_io(void)
! 1812: {
! 1813: #ifdef SYS_WINNT
! 1814: WORD wVersionRequested;
! 1815: WSADATA wsaData;
! 1816: init_transmitbuff();
! 1817: #endif /* SYS_WINNT */
! 1818:
! 1819: /*
! 1820: * Init buffer free list and stat counters
! 1821: */
! 1822: init_recvbuff(sys_numservers + 2);
! 1823:
! 1824: #if defined(HAVE_SIGNALED_IO)
! 1825: set_signal();
! 1826: #endif
! 1827:
! 1828: #ifdef SYS_WINNT
! 1829: wVersionRequested = MAKEWORD(1,1);
! 1830: if (WSAStartup(wVersionRequested, &wsaData))
! 1831: {
! 1832: msyslog(LOG_ERR, "No useable winsock.dll: %m");
! 1833: exit(1);
! 1834: }
! 1835: #endif /* SYS_WINNT */
! 1836:
! 1837: BLOCKIO();
! 1838:
! 1839: /* create a datagram (UDP) socket */
! 1840: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 1841: msyslog(LOG_ERR, "socket() failed: %m");
! 1842: exit(1);
! 1843: /*NOTREACHED*/
! 1844: }
! 1845:
! 1846: /*
! 1847: * bind the socket to the NTP port
! 1848: */
! 1849: if (!debug && set_time && !unpriv_port) {
! 1850: struct sockaddr_in addr;
! 1851:
! 1852: memset((char *)&addr, 0, sizeof addr);
! 1853: addr.sin_family = AF_INET;
! 1854: addr.sin_port = htons(NTP_PORT);
! 1855: addr.sin_addr.s_addr = htonl(INADDR_ANY);
! 1856: if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
! 1857: #ifndef SYS_WINNT
! 1858: if (errno == EADDRINUSE)
! 1859: #else
! 1860: if (WSAGetLastError() == WSAEADDRINUSE)
! 1861: #endif
! 1862: msyslog(LOG_ERR,
! 1863: "the NTP socket is in use, exiting");
! 1864: else
! 1865: msyslog(LOG_ERR, "bind() fails: %m");
! 1866: exit(1);
! 1867: }
! 1868: }
! 1869:
! 1870: FD_ZERO(&fdmask);
! 1871: FD_SET(fd, &fdmask);
! 1872:
! 1873: /*
! 1874: * set non-blocking,
! 1875: */
! 1876:
! 1877: #ifdef USE_FIONBIO
! 1878: /* in vxWorks we use FIONBIO, but the others are defined for old systems, so
! 1879: * all hell breaks loose if we leave them defined
! 1880: */
! 1881: #undef O_NONBLOCK
! 1882: #undef FNDELAY
! 1883: #undef O_NDELAY
! 1884: #endif
! 1885:
! 1886: #if defined(O_NONBLOCK) /* POSIX */
! 1887: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
! 1888: {
! 1889: msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m");
! 1890: exit(1);
! 1891: /*NOTREACHED*/
! 1892: }
! 1893: #elif defined(FNDELAY)
! 1894: if (fcntl(fd, F_SETFL, FNDELAY) < 0)
! 1895: {
! 1896: msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m");
! 1897: exit(1);
! 1898: /*NOTREACHED*/
! 1899: }
! 1900: #elif defined(O_NDELAY) /* generally the same as FNDELAY */
! 1901: if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
! 1902: {
! 1903: msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m");
! 1904: exit(1);
! 1905: /*NOTREACHED*/
! 1906: }
! 1907: #elif defined(FIONBIO)
! 1908: if (
! 1909: # if defined(VMS)
! 1910: (ioctl(fd,FIONBIO,&1) < 0)
! 1911: # elif defined(SYS_WINNT)
! 1912: (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR)
! 1913: # else
! 1914: (ioctl(fd,FIONBIO,&on) < 0)
! 1915: # endif
! 1916: )
! 1917: {
! 1918: msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m");
! 1919: exit(1);
! 1920: /*NOTREACHED*/
! 1921: }
! 1922: #elif defined(FIOSNBIO)
! 1923: if (ioctl(fd,FIOSNBIO,&on) < 0)
! 1924: {
! 1925: msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m");
! 1926: exit(1);
! 1927: /*NOTREACHED*/
! 1928: }
! 1929: #else
! 1930: # include "Bletch: Need non-blocking I/O!"
! 1931: #endif
! 1932:
! 1933: #ifdef HAVE_SIGNALED_IO
! 1934: init_socket_sig(fd);
! 1935: #endif /* not HAVE_SIGNALED_IO */
! 1936:
! 1937: UNBLOCKIO();
! 1938: }
! 1939:
! 1940:
! 1941: /*
! 1942: * sendpkt - send a packet to the specified destination
! 1943: */
! 1944: static int
! 1945: sendpkt(
! 1946: struct sockaddr_in *dest,
! 1947: struct pkt *pkt,
! 1948: int len
! 1949: )
! 1950: {
! 1951: int cc;
! 1952: static int horriblecnt = 0;
! 1953: #ifdef SYS_WINNT
! 1954: DWORD err;
! 1955: #endif /* SYS_WINNT */
! 1956:
! 1957: total_xmit++; /* count it */
! 1958:
! 1959: if (horrible) {
! 1960: if (++horriblecnt > HORRIBLEOK) {
! 1961: if (debug > 3)
! 1962: printf("dropping send (%s)\n", ntoa(dest));
! 1963: if (horriblecnt >= HORRIBLEOK+horrible)
! 1964: horriblecnt = 0;
! 1965: return 0;
! 1966: }
! 1967: }
! 1968:
! 1969:
! 1970: cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest,
! 1971: sizeof(struct sockaddr_in));
! 1972: #ifndef SYS_WINNT
! 1973: if (cc == -1) {
! 1974: if (errno != EWOULDBLOCK && errno != ENOBUFS)
! 1975: #else
! 1976: if (cc == SOCKET_ERROR) {
! 1977: err = WSAGetLastError();
! 1978: if (err != WSAEWOULDBLOCK && err != WSAENOBUFS)
! 1979: #endif /* SYS_WINNT */
! 1980: msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest));
! 1981: return -1;
! 1982: }
! 1983: return 0;
! 1984: }
! 1985:
! 1986:
! 1987: /*
! 1988: * input_handler - receive packets asynchronously
! 1989: */
! 1990: void
! 1991: input_handler(l_fp *xts)
! 1992: {
! 1993: register int n;
! 1994: register struct recvbuf *rb;
! 1995: struct timeval tvzero;
! 1996: int fromlen;
! 1997: fd_set fds;
! 1998: l_fp ts;
! 1999: ts = *xts; /* we ignore xts, but make the compiler happy */
! 2000:
! 2001: /*
! 2002: * Do a poll to see if we have data
! 2003: */
! 2004: for (;;) {
! 2005: fds = fdmask;
! 2006: tvzero.tv_sec = tvzero.tv_usec = 0;
! 2007: n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
! 2008:
! 2009: /*
! 2010: * If nothing to do, just return. If an error occurred,
! 2011: * complain and return. If we've got some, freeze a
! 2012: * timestamp.
! 2013: */
! 2014: if (n == 0)
! 2015: return;
! 2016: else if (n == -1) {
! 2017: if (errno != EINTR) {
! 2018: msyslog(LOG_ERR, "select() error: %m");
! 2019: }
! 2020: return;
! 2021: }
! 2022: get_systime(&ts);
! 2023:
! 2024: /*
! 2025: * Get a buffer and read the frame. If we
! 2026: * haven't got a buffer, or this is received
! 2027: * on the wild card socket, just dump the packet.
! 2028: */
! 2029: if (initializing || free_recvbuffs == 0) {
! 2030: char buf[100];
! 2031:
! 2032: #ifndef SYS_WINNT
! 2033: (void) read(fd, buf, sizeof buf);
! 2034: #else
! 2035: /* NT's _read does not operate on nonblocking sockets
! 2036: * either recvfrom or ReadFile() has to be used here.
! 2037: * ReadFile is used in [ntpd]ntp_intres() and ntpdc,
! 2038: * just to be different use recvfrom() here
! 2039: */
! 2040: recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL);
! 2041: #endif /* SYS_WINNT */
! 2042: continue;
! 2043: }
! 2044:
! 2045: rb = get_free_recv_buffer();
! 2046:
! 2047: fromlen = sizeof(struct sockaddr_in);
! 2048: rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt,
! 2049: sizeof(rb->recv_pkt), 0,
! 2050: (struct sockaddr *)&rb->srcadr, &fromlen);
! 2051: if (rb->recv_length == -1) {
! 2052: freerecvbuf(rb);
! 2053: continue;
! 2054: }
! 2055:
! 2056: /*
! 2057: * Got one. Mark how and when it got here,
! 2058: * put it on the full list.
! 2059: */
! 2060: rb->recv_time = ts;
! 2061: add_full_recv_buffer(rb);
! 2062: total_recv++; /* count it */
! 2063: }
! 2064: }
! 2065:
! 2066:
! 2067: /* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */
! 2068: /*
! 2069: * printserver - print detail information for a server
! 2070: */
! 2071: static void
! 2072: printserver(
! 2073: register struct server *pp,
! 2074: FILE *fp
! 2075: )
! 2076: {
! 2077: register int i;
! 2078: char junk[5];
! 2079: char *str;
! 2080:
! 2081: if (!debug) {
! 2082: (void) fprintf(fp,
! 2083: "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n",
! 2084: ntoa(&pp->srcadr),
! 2085: pp->xmtcnt,pp->rcvcnt,pp->reach,
! 2086: pp->version,pp->stratum,
! 2087: lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5),
! 2088: ufptoa(pp->dispersion, 4));
! 2089: return;
! 2090: }
! 2091:
! 2092: (void) fprintf(fp, "server %s, port %d\n",
! 2093: ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port));
! 2094:
! 2095: (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n",
! 2096: pp->stratum, pp->precision,
! 2097: pp->leap & 0x2 ? '1' : '0',
! 2098: pp->leap & 0x1 ? '1' : '0',
! 2099: pp->trust);
! 2100:
! 2101: if (pp->stratum == 1) {
! 2102: junk[4] = 0;
! 2103: memmove(junk, (char *)&pp->refid, 4);
! 2104: str = junk;
! 2105: } else {
! 2106: str = numtoa(pp->refid);
! 2107: }
! 2108: (void) fprintf(fp,
! 2109: "refid [%s], delay %s, dispersion %s\n",
! 2110: str, fptoa((s_fp)pp->delay, 5),
! 2111: ufptoa(pp->dispersion, 5));
! 2112:
! 2113: (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n",
! 2114: pp->xmtcnt, pp->rcvcnt, pp->reach);
! 2115:
! 2116: (void) fprintf(fp, "reference time: %s\n",
! 2117: prettydate(&pp->reftime));
! 2118: (void) fprintf(fp, "originate timestamp: %s\n",
! 2119: prettydate(&pp->org));
! 2120: (void) fprintf(fp, "transmit timestamp: %s\n",
! 2121: prettydate(&pp->xmt));
! 2122:
! 2123: (void) fprintf(fp, "filter delay: ");
! 2124: for (i = 0; i < NTP_SHIFT; i++) {
! 2125: (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5));
! 2126: if (i == (NTP_SHIFT>>1)-1)
! 2127: (void) fprintf(fp, "\n ");
! 2128: }
! 2129: (void) fprintf(fp, "\n");
! 2130:
! 2131: (void) fprintf(fp, "filter offset:");
! 2132: for (i = 0; i < PEER_SHIFT; i++) {
! 2133: (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6));
! 2134: if (i == (PEER_SHIFT>>1)-1)
! 2135: (void) fprintf(fp, "\n ");
! 2136: }
! 2137: (void) fprintf(fp, "\n");
! 2138:
! 2139: (void) fprintf(fp, "delay %s, dispersion %s\n",
! 2140: fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5));
! 2141:
! 2142: (void) fprintf(fp, "offset %s\n\n",
! 2143: lfptoa(&pp->offset, 6));
! 2144: }
! 2145:
! 2146: #if !defined(HAVE_VSPRINTF)
! 2147: int
! 2148: vsprintf(
! 2149: char *str,
! 2150: const char *fmt,
! 2151: va_list ap
! 2152: )
! 2153: {
! 2154: FILE f;
! 2155: int len;
! 2156:
! 2157: f._flag = _IOWRT+_IOSTRG;
! 2158: f._ptr = str;
! 2159: f._cnt = 32767;
! 2160: len = _doprnt(fmt, ap, &f);
! 2161: *f._ptr = 0;
! 2162: return (len);
! 2163: }
! 2164: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>