📄 ntptimeset.c
字号:
# ifndef LOG_NTP# define LOG_NTP LOG_DAEMON# endif openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP); if (debug) setlogmask(LOG_UPTO(LOG_DEBUG)); else setlogmask(LOG_UPTO(LOG_INFO));# endif /* LOG_DAEMON */#endif /* SYS_WINNT */ } if (debug || verbose) msyslog(LOG_INFO, "%s", Version); if (horrible) msyslog(LOG_INFO, "Dropping %d out of %d packets", horrible,horrible+HORRIBLEOK); /* * Add servers we are going to be polling */ loadservers(cfgpath); if (sys_numservers < min_servers) { msyslog(LOG_ERR, "Found %d servers, require %d servers", sys_numservers,min_servers); exit(2); } /* * determine when we will end at least */ finish_time = max_period * TIMER_HZ; half_time = finish_time >> 1; /* * Initialize the time of day routines and the I/O subsystem */ if (sys_authenticate) { init_auth();#ifdef SYS_WINNT if (!key_file) key_file = KEYFILE; if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH)) { msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n", key_file); } else { key_file = key_file_storage; }#endif /* SYS_WINNT */ if (!authreadkeys(key_file)) { msyslog(LOG_ERR, "no key file, exiting"); exit(1); } if (!authistrusted(sys_authkey)) { char buf[10]; (void) sprintf(buf, "%lu", (unsigned long)sys_authkey); msyslog(LOG_ERR, "authentication key %s unknown", buf); exit(1); } } init_io(); init_alarm(); /* * Set the priority. */#ifdef SYS_VXWORKS taskPrioritySet( taskIdSelf(), NTPDATE_PRIO);#endif#if defined(HAVE_ATT_NICE) nice (NTPDATE_PRIO);#endif#if defined(HAVE_BSD_NICE) (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO);#endif#ifdef SYS_WINNT process_handle = GetCurrentProcess(); if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) { msyslog(LOG_ERR, "SetPriorityClass failed: %m"); }#endif /* SYS_WINNT */ initializing = 0; /* * Use select() on all on all input fd's for unlimited * time. select() will terminate on SIGALARM or on the * reception of input. Using select() means we can't do * robust signal handling and we get a potential race * between checking for alarms and doing the select(). * Mostly harmless, I think. * Keep going until we have enough information, or time is up. */ /* On VMS, I suspect that select() can't be interrupted * by a "signal" either, so I take the easy way out and * have select() time out after one second. * System clock updates really aren't time-critical, * and - lacking a hardware reference clock - I have * yet to learn about anything else that is. */ was_alarmed = 0; rbuflist = (struct recvbuf *)0; while (finish_time > current_time) {#if !defined(HAVE_SIGNALED_IO) fd_set rdfdes; int nfound;#elif defined(HAVE_SIGNALED_IO) block_io_and_alarm();#endif rbuflist = getrecvbufs(); /* get received buffers */ if (printmsg) { printmsg = 0; analysis(0); } if (alarm_flag) { /* alarmed? */ was_alarmed = 1; alarm_flag = 0; } if (!was_alarmed && rbuflist == (struct recvbuf *)0) { /* * Nothing to do. Wait for something. */#ifndef HAVE_SIGNALED_IO rdfdes = fdmask;# if defined(VMS) || defined(SYS_VXWORKS) /* make select() wake up after one second */ { struct timeval t1; t1.tv_sec = 1; t1.tv_usec = 0; nfound = select(fd+1, &rdfdes, (fd_set *)0, (fd_set *)0, &t1); }# else nfound = select(fd+1, &rdfdes, (fd_set *)0, (fd_set *)0, (struct timeval *)0);# endif /* VMS */ if (nfound > 0) { l_fp ts; get_systime(&ts); (void)input_handler(&ts); } else if (nfound == -1 && errno != EINTR) msyslog(LOG_ERR, "select() error: %m"); else if (debug) {# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */ msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);# endif }#else /* HAVE_SIGNALED_IO */ wait_for_signal();#endif /* HAVE_SIGNALED_IO */ if (alarm_flag) /* alarmed? */ { was_alarmed = 1; alarm_flag = 0; } rbuflist = getrecvbufs(); /* get received buffers */ }#ifdef HAVE_SIGNALED_IO unblock_io_and_alarm();#endif /* HAVE_SIGNALED_IO */ /* * Out here, signals are unblocked. Call timer routine * to process expiry. */ if (was_alarmed) { timer(); was_alarmed = 0; } /* * Call the data procedure to handle each received * packet. */ while (rbuflist != (struct recvbuf *)0) { rbuf = rbuflist; rbuflist = rbuf->next; receive(rbuf); freerecvbuf(rbuf); }#if defined DEBUG && defined SYS_WINNT if (debug > 4) printf("getrecvbufs: %ld handler interrupts, %ld frames\n", handler_calls, handler_pkts);#endif /* * Do we have enough information to stop now? */ if (have_enough()) break; /* time to end */ /* * Go around again */ } /* * adjust the clock and exit accordingly */ set_local_clock(); /* * if we get here then we are in trouble */ return(1);}/* * analysis - print a message indicating what is happening with time service * must mimic have_enough() procedure. */static voidanalysis( int final ){ if (contacted < sys_numservers) { printf("%d servers of %d have been probed with %d packets\n", contacted,sys_numservers,MINTRANSMITS); return; } if (!responding) { printf("No response from any of %d servers, network problem?\n", sys_numservers); return; } else if (responding < min_servers) { printf("%d servers out of %d responding, need at least %d.\n", responding, sys_numservers, min_servers); return; } if (!validcount) { printf("%d servers responding but none have valid time\n", responding); return; } else if (validcount < min_valid) { printf("%d servers responding, %d are valid, need %d valid\n", responding,validcount,min_valid); return; } if (!final && valid_n_low != validcount) { printf("%d valid servers but only %d have low dispersion\n", validcount,valid_n_low); return; }}/* have_enough - see if we have enough information to terminate probing */static inthave_enough(void){ /* have we contacted all servers yet? */ if (contacted < sys_numservers) return 0; /* no...try some more */ /* have we got at least minimum servers responding? */ if (responding < min_servers) return 0; /* no...try some more */ /* count the clocks */ (void) clock_count(); /* have we got at least minimum valid clocks? */ if (validcount <= 0 || validcount < min_valid) return 0; /* no...try some more */ /* do we have all valid servers with low dispersion */ if (!secondhalf && valid_n_low != validcount) return 0; /* if we get into the secondhalf then we ignore dispersion */ /* all conditions have been met...end */ return 1;}/* * transmit - transmit a packet to the given server, or mark it completed. * This is called by the timeout routine and by the receive * procedure. */static voidtransmit( register struct server *server ){ struct pkt xpkt; int timeout; if (debug > 2) printf("transmit(%s)\n", ntoa(&server->srcadr)); if ((server->reach & 01) == 0) { l_fp ts; /* * Last message to this server timed out. Shift * zeros into the filter. */ L_CLR(&ts); clock_filter(server, 0, &ts); } /* * shift reachable register over */ server->reach <<= 1; /* * If we're here, send another message to the server. Fill in * the packet and let 'er rip. */ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, server->version, MODE_CLIENT); xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); xpkt.ppoll = NTP_MINPOLL; xpkt.precision = NTPDATE_PRECISION; xpkt.rootdelay = htonl(NTPDATE_DISTANCE); xpkt.rootdispersion = htonl(NTPDATE_DISP); xpkt.refid = htonl(NTPDATE_REFID); L_CLR(&xpkt.reftime); L_CLR(&xpkt.org); L_CLR(&xpkt.rec); /* * Determine whether to authenticate or not. If so, * fill in the extended part of the packet and do it. * If not, just timestamp it and send it away. */ if (sys_authenticate) { int len; xpkt.exten[0] = htonl(sys_authkey); get_systime(&server->xmt); L_ADDUF(&server->xmt, sys_authdelay); HTONL_FP(&server->xmt, &xpkt.xmt); len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC); if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) { if (debug > 1) printf("failed transmit auth to %s\n", ntoa(&(server->srcadr))); return; } if (debug > 1) printf("transmit auth to %s\n", ntoa(&(server->srcadr))); } else { get_systime(&(server->xmt)); HTONL_FP(&server->xmt, &xpkt.xmt); if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) { if (debug > 1) printf("failed transmit to %s\n", ntoa(&(server->srcadr))); return; } if (debug > 1) printf("transmit to %s\n", ntoa(&(server->srcadr))); } /* * count transmits, record contacted count and set transmit time */ if (++server->xmtcnt == MINTRANSMITS) contacted++; server->last_xmit = current_time; /* * determine timeout for this packet. The more packets we send * to the host, the slower we get. If the host indicates that * it is not "sane" then we expect even less. */ if (server->xmtcnt < MINTRANSMITS) { /* we have not sent enough */ timeout = TIMER_HZ; /* 1 second probe */ } else if (server->rcvcnt <= 0) { /* we have heard nothing */ if (secondhalf) timeout = TIMER_HZ<<4; /* 16 second probe */ else timeout = TIMER_HZ<<3; /* 8 second probe */ } else { /* if we have low dispersion then probe infrequently */ if (server->dispersion <= DESIREDDISP) timeout = TIMER_HZ<<4; /* 16 second probe */ /* if the server is not in sync then let it alone */ else if (server->leap == LEAP_NOTINSYNC) timeout = TIMER_HZ<<4; /* 16 second probe */ /* if the server looks broken ignore it */ else if (server->org.l_ui < server->reftime.l_ui) timeout = TIMER_HZ<<5; /* 32 second probe */ else if (secondhalf) timeout = TIMER_HZ<<2; /* 4 second probe */ else timeout = TIMER_HZ<<1; /* 2 second probe */ } /* * set next transmit time based on timeout */ server->event_time = current_time + timeout;}/* * receive - receive and process an incoming frame */static voidreceive( struct recvbuf *rbufp ){ register struct pkt *rpkt; register struct server *server; register s_fp di; l_fp t10, t23; l_fp org; l_fp rec; l_fp ci; int has_mac; int is_authentic; if (debug > 2) printf("receive(%s)\n", ntoa(&rbufp->srcadr)); /* * Check to see if the packet basically looks like something * intended for us. */ if (rbufp->recv_length == LEN_PKT_NOMAC) has_mac = 0; else if (rbufp->recv_length >= LEN_PKT_NOMAC) has_mac = 1; else { if (debug > 2) printf("receive: packet length %d\n", rbufp->recv_length); return; /* funny length packet */ } rpkt = &(rbufp->recv_pkt); if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { if (debug > 1) printf("receive: bad version %d\n", PKT_VERSION(rpkt->li_vn_mode)); return; } if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) || rpkt->stratum >=STRATUM_UNSPEC) { if (debug > 1) printf("receive: mode %d stratum %d\n", PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); return; } /* * So far, so good. See if this is from a server we know. */ server = findserver(&(rbufp->srcadr)); if (server == NULL) { if (debug > 1) printf("receive: server not found\n"); return; } /* * Decode the org timestamp and make sure we're getting a response * to our last request. */ NTOHL_FP(&rpkt->org, &org); if (!L_ISEQU(&org, &server->xmt)) { if (debug > 1) printf("receive: pkt.org and peer.xmt differ\n"); return; } /* * Check out the authenticity if we're doing that. */ if (!sys_authenticate) is_authentic = 1; else { is_authentic = 0; if (debug > 3) printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n", (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey, (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))); if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey && authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))) is_authentic = 1; if (debug) printf("receive: authentication %s\n", is_authentic ? "passed" : "failed"); } server->trust <<= 1; if (!is_authentic) server->trust |= 1; /* * Looks good. Record info from the packet. */ server->leap = PKT_LEAP(rpkt->li_vn_mode); server->stratum = PKT_TO_STRATUM(rpkt->stratum); server->precision = rpkt->precision; server->rootdelay = ntohl(rpkt->rootdelay); server->rootdispersion = ntohl(rpkt->rootdispersion); server->refid = rpkt->refid; NTOHL_FP(&rpkt->reftime, &server->reftime); NTOHL_FP(&rpkt->rec, &rec); NTOHL_FP(&rpkt->xmt, &server->org); /* * count this guy as responding */ server->reach |= 1; if (server->rcvcnt++ == 0) responding++; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -