📄 ntpdate.c
字号:
#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; was_alarmed = 0; rbuflist = (struct recvbuf *)0; while (complete_servers < sys_numservers) {#ifdef HAVE_POLL_H struct pollfd* rdfdes; rdfdes = fdmask;#else fd_set rdfdes; rdfdes = fdmask;#endif if (alarm_flag) { /* alarmed? */ was_alarmed = 1; alarm_flag = 0; } rbuflist = getrecvbufs(); /* get received buffers */ if (!was_alarmed && rbuflist == (struct recvbuf *)0) { /* * Nothing to do. Wait for something. */#ifdef HAVE_POLL_H nfound = poll(rdfdes, (unsigned int)nbsock, timeout.tv_sec * 1000);#else nfound = select(maxfd, &rdfdes, (fd_set *)0, (fd_set *)0, &timeout);#endif if (nfound > 0) input_handler(); else if (nfound == SOCKET_ERROR) {#ifndef SYS_WINNT if (errno != EINTR)#else if (WSAGetLastError() != WSAEINTR)#endif netsyslog(LOG_ERR,#ifdef HAVE_POLL_H "poll() error: %m"#else "select() error: %m"#endif ); } else if (errno != 0) {#ifndef SYS_VXWORKS netsyslog(LOG_DEBUG,#ifdef HAVE_POLL_H "poll(): nfound = %d, error: %m",#else "select(): nfound = %d, error: %m",#endif nfound);#endif } if (alarm_flag) { /* alarmed? */ was_alarmed = 1; alarm_flag = 0; } rbuflist = getrecvbufs(); /* get received buffers */ } /* * Out here, signals are unblocked. Call receive * procedure for each incoming packet. */ while (rbuflist != (struct recvbuf *)0) { rbuf = rbuflist; rbuflist = rbuf->next; receive(rbuf); freerecvbuf(rbuf); } /* * Call timer to process any timeouts */ if (was_alarmed) { timer(); was_alarmed = 0; } /* * Go around again */ } /* * When we get here we've completed the polling of all servers. * Adjust the clock, then exit. */#ifdef SYS_WINNT WSACleanup();#endif#ifdef SYS_VXWORKS close (fd); timer_delete(ntpdate_timerid);#endif return clock_adjust();}/* * 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; if (debug) printf("transmit(%s)\n", stoa(&(server->srcadr))); if (server->filter_nextpt < server->xmtcnt) { l_fp ts; /* * Last message to this server timed out. Shift * zeros into the filter. */ L_CLR(&ts); server_data(server, 0, &ts, 0); } if ((int)server->filter_nextpt >= sys_samples) { /* * Got all the data we need. Mark this guy * completed and return. */ server->event_time = 0; complete_servers++; return; } /* * 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, sys_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); sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len)); if (debug > 1) printf("transmit auth to %s\n", stoa(&(server->srcadr))); } else { get_systime(&(server->xmt)); HTONL_FP(&server->xmt, &xpkt.xmt); sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC); if (debug > 1) printf("transmit to %s\n", stoa(&(server->srcadr))); } /* * Update the server timeout and transmit count */ server->event_time = current_time + sys_timeout; server->xmtcnt++;}/* * 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, tmp; l_fp org; l_fp rec; l_fp ci; int has_mac; int is_authentic; if (debug) printf("receive(%s)\n", stoa(&rbufp->recv_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) 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) { return; } if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) || rpkt->stratum >= STRATUM_UNSPEC) { if (debug) 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->recv_srcadr)); if (server == NULL) { if (debug) 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) 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); /* * Make sure the server is at least somewhat sane. If not, try * again. */ if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) { transmit(server); return; } /* * Calculate the round trip delay (di) and the clock offset (ci). * We use the equations (reordered from those in the spec): * * d = (t2 - t3) - (t1 - t0) * c = ((t2 - t3) + (t1 - t0)) / 2 */ t10 = server->org; /* pkt.xmt == t1 */ L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ t23 = rec; /* pkt.rec == t2 */ L_SUB(&t23, &org); /* pkt->org == t3 */ /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ /* * Calculate (ci) = ((t1 - t0) / 2) + ((t2 - t3) / 2) * For large offsets this may prevent an overflow on '+' */ ci = t10; L_RSHIFT(&ci); tmp = t23; L_RSHIFT(&tmp); L_ADD(&ci, &tmp); /* * Calculate di in t23 in full precision, then truncate * to an s_fp. */ L_SUB(&t23, &t10); di = LFPTOFP(&t23); if (debug > 3) printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5)); di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; if (di <= 0) { /* value still too raunchy to use? */ L_CLR(&ci); di = 0; } else { di = max(di, NTP_MINDIST); } /* * Shift this data in, then transmit again. */ server_data(server, (s_fp) di, &ci, 0); transmit(server);}/* * server_data - add a sample to the server's filter registers */static voidserver_data( register struct server *server, s_fp d, l_fp *c, u_fp e ){ u_short i; i = server->filter_nextpt; if (i < NTP_SHIFT) { server->filter_delay[i] = d; server->filter_offset[i] = *c; server->filter_soffset[i] = LFPTOFP(c); server->filter_error[i] = e; server->filter_nextpt = (u_short)(i + 1); }}/* * clock_filter - determine a server's delay, dispersion and offset */static voidclock_filter( register struct server *server ){ register int i, j; int ord[NTP_SHIFT]; /* * Sort indices into increasing delay order */ for (i = 0; i < sys_samples; i++) ord[i] = i; for (i = 0; i < (sys_samples-1); i++) { for (j = i+1; j < sys_samples; j++) { if (server->filter_delay[ord[j]] == 0) continue; if (server->filter_delay[ord[i]] == 0 || (server->filter_delay[ord[i]] > server->filter_delay[ord[j]])) { register int tmp; tmp = ord[i]; ord[i] = ord[j]; ord[j] = tmp; } } } /* * Now compute the dispersion, and assign values to delay and * offset. If there are no samples in the register, delay and * offset go to zero and dispersion is set to the maximum. */ if (server->filter_delay[ord[0]] == 0) { server->delay = 0; L_CLR(&server->offset); server->soffset = 0; server->dispersion = PEER_MAXDISP; } else { register s_fp d; server->delay = server->filter_delay[ord[0]]; server->offset = server->filter_offset[ord[0]]; server->soffset = LFPTOFP(&server->offset); server->dispersion = 0; for (i = 1; i < sys_samples; i++) { if (server->filter_delay[ord[i]] == 0) d = PEER_MAXDISP; else { d = server->filter_soffset[ord[i]] - server->filter_soffset[ord[0]]; if (d < 0) d = -d; if (d > PEER_MAXDISP) d = PEER_MAXDISP; } /* * XXX This *knows* PEER_FILTER is 1/2 */ server->dispersion += (u_fp)(d) >> i; } } /* * We're done */}/* * clock_select - select the pick-of-the-litter clock from the samples * we've got. */static struct server *clock_select(void){ register struct server *server; register int i; register int nlist; register s_fp d; register int j; register int n; s_fp local_threshold; struct server *server_list[NTP_MAXCLOCK]; u_fp server_badness[NTP_MAXCLOCK]; struct server *sys_server; /* * This first chunk of code is supposed to go through all * servers we know about to find the NTP_MAXLIST servers which * are most likely to succeed. We run through the list * doing the sanity checks and trying to insert anyone who * looks okay. We are at all times aware that we should * only keep samples from the top two strata and we only need * NTP_MAXLIST of them. */ nlist = 0; /* none yet */ for (server = sys_servers; server != NULL; server = server->next_server) { if (server->delay == 0) { if (debug) printf("%s: Server dropped: no data\n", ntoa(&server->srcadr)); continue; /* no data */ } if (server->stratum > NTP_INFIN) { if (debug) printf("%s: Server dropped: strata too high\n", ntoa(&server->srcadr)); continue; /* stratum no good */ } if (server->delay > NTP_MAXWGT) { if (debug) printf("%s: Server dropped: server too far away\n", ntoa(&server->srcadr)); continue; /* too far away */ } if (server->leap == LEAP_NOTINSYNC) { if (debug) printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr)); continue; /* he's in trouble */ } if (!L_ISHIS(&server->org, &server->reftime)) { if (debug) printf("%s: Server dropped: server is very broken\n", ntoa(&server->srcadr)); continue; /* very broken host */ } if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) { if (debug) printf("%s: Server dropped: Server has gone too long without sync\n", ntoa(&server->srcadr)); continue; /* too long without sync */ } if (server->trust != 0) { if (debug) printf("%s: Server dropped: Server is untrusted\n", ntoa(&server->srcadr)); continue; } /* * This one seems sane. Find where he belongs * on the list. */ d = server->dispersion + server->dispersion; for (i = 0; i < nlist; i++) if (server->stratum <= server_list[i]->stratum) break; for ( ; i < nlist; i++) { if (server->stratum < server_list[i]->stratum) break; if (d < (s_fp) server_badness[i]) break; } /* * If i points past the end of the list, this * guy is a loser, else stick him in. */ if (i >= NTP_MAXLIST) continue; for (j = nlist; j > i; j--) if (j < NTP_MAXLIST) { server_list[j] = server_list[j-1]; server_badness[j] = server_badness[j-1]; } server_list[i] = server; server_badness[i] = d; if (nlist < NTP_MAXLIST) nlist++; } /* * Got the five-or-less best. Cut the list where the number of * strata exceeds two. */ j = 0; for (i = 1; i < nlist; i++) if (server_list[i]->stratum > server_list[i-1]->stratum) if (++j == 2) { nlist = i; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -