📄 ntp_proto.c
字号:
#ifndef lintstatic char *rcsid = "$Header: /xtel/isode/isode/others/ntp/RCS/ntp_proto.c,v 9.0 1992/06/16 12:42:48 isode Rel $";#endif/* * This module actually implements the the bulk of the NTP protocol processing. * It contains a minimum of machine and operating system dependencies (or at * least that's the idea). Setup of UDP sockets, timers, etc is done in the * ntpd.c module, while arithmetic conversion routines are in ntpsubs.c * * Some of this is now factored out as it was too protocol specific. *//* * $Header: /xtel/isode/isode/others/ntp/RCS/ntp_proto.c,v 9.0 1992/06/16 12:42:48 isode Rel $ * * * Based on the ntp 3.4 code - but modified for use with OSI. * * $Log: ntp_proto.c,v $ * Revision 9.0 1992/06/16 12:42:48 isode * Release 8.0 * */#include "ntp.h"int peer_switches, peer_sw_inhibited;struct ntp_peer dummy_peer;extern double WayTooBig;extern unsigned long clock_watchdog;extern LLog *pgm_log;#ifdef DEBUGextern int debug;extern void dump_pkt();#endifextern unsigned int servport;extern int trusting, logstats;extern struct sysdata sys;extern struct list peer_list;extern struct ntp_peer *check_peer();extern char *ntoa();extern double drift_comp, compliance; /* logical clock variables */extern double s_fixed_to_double(), ul_fixed_to_double();extern void make_new_peer(), double_to_s_fixed(), tstamp(), receive ();extern int demobilize(); char actions[5][5] = { /* Sym Act Sym Pas Client Server Broadcast |Host / */ /* -------- -------- -------- --------- --------- | / Peer */ /* ------------ */ {ACT_PKT, ACT_PKT, ACT_RECV, ACT_XMIT, ACT_XMIT}, /* Sym Act */ {ACT_PKT, ACT_ERROR, ACT_RECV, ACT_ERROR, ACT_ERROR}, /* Sym Pas */ {ACT_XMIT, ACT_XMIT, ACT_ERROR, ACT_XMIT, ACT_XMIT}, /* Client */ {ACT_PKT, ACT_ERROR, ACT_RECV, ACT_ERROR, ACT_ERROR}, /* Server */ {ACT_PKT, ACT_ERROR, ACT_RECV, ACT_ERROR, ACT_ERROR}};/* Broadcast */#ifdef REFCLOCKvoid refclock_input();#endifvoid process_packet(), clock_update(), clear(), clock_filter(), receive(), select_clock(), poll_update();/* 3.4. Event Processing *//* 3.4.1. Transmit Procedure */voidtransmit(peer) struct ntp_peer *peer;{ struct timeval txtv; static struct ntpdata ntpframe; struct ntpdata *pkt = &ntpframe; int i; if (peer->src.type == AF_OSI) { (void) transmit_osi (peer); return; } pkt->status = sys.leap | peer->hmode; VERS2PKT (pkt -> status, peer -> vers); pkt->stratum = sys.stratum; pkt->ppoll = peer->hpoll; pkt->precision = (char) sys.precision; pkt->distance = sys.distance; pkt->dispersion = sys.dispersion; if (peer -> src.type == AF_INET) pkt->refid = sys.refid.rid_inet; pkt->reftime = sys.reftime; pkt->org = peer->org; pkt->rec = peer->rec; (void) gettimeofday(&txtv, (struct timezone *) 0);#ifdef notdef if (peer->flags & PEER_FL_AUTHENABLE && peer -> vers == 2 && authhavekey (peer -> keyid)) { pkt->keyid = htonl(peer -> keyid); auth1crypt (peer -> keyid, pkt, LEN_PKT_NOMAC); tstamp(&pkt->xmt, &txtv); auth2crypt (peer -> keyid, pkt, LEN_PKT_NOMAC); } else #endif {#ifdef notdef/* Not Yet in this version */ pkt->keyid = 0; /* XXX */#endif tstamp(&pkt->xmt, &txtv); } peer->xmt = pkt->xmt; if ((peer->flags & (PEER_FL_BCAST|PEER_FL_REFCLOCK)) == 0) { /* select correct socket to send reply on */ struct intf *ap; ap = &addrs[peer->sock < 0 ? 0 : peer-> sock]; switch (peer->src.type) { case AF_INET: if (send_inet (ap, (char *)pkt, sizeof (*pkt), &peer->src) < 0) return; break; }#ifdef REFCLOCK } else if (peer->flags & PEER_FL_REFCLOCK) { /* Special version of code below, adjusted for refclocks */ peer->pkt_sent++; i = peer->reach; /* save a copy */ peer->reach = (peer->reach << 1) & NTP_WINDOW_SHIFT_MASK; if (i && peer->reach == 0) { advise (LLOG_NOTICE, NULLCP, "Lost reachability with %.4s", peer->refid.rid_string); } if (peer->reach == 0) clear(peer); if (peer->valid < 2) peer->valid++; else { clock_filter(peer, 0.0, 0.0); /* call with invalid values */ select_clock(); /* and try to reselect clock */ } peer->timer = 1<<NTP_MINPOLL; /* poll refclocks frequently */ refclock_input(peer, pkt); return;#endif REFCLOCK } else {#ifdef BROADCAST_NTP if (addrs[peer->sock].addr.type == AF_INET) { if (send_inet (&addrs[peer->sock], pkt, peer) < 0) return; } else return;#else return;#endif }#ifdef DEBUG if (debug > 5) { (void) printf("\nSent "); dump_pkt(&peer->src, pkt, (struct ntp_peer *)NULL); }#endif peer->pkt_sent++; i = peer->reach; /* save a copy */ peer->reach = (peer->reach << 1) & NTP_WINDOW_SHIFT_MASK; if ((peer->reach == 0) && ((peer->flags & PEER_FL_CONFIG) == 0) && (peer != &dummy_peer) && demobilize(&peer_list, peer)) return; if (i && peer->reach == 0) { advise (LLOG_NOTICE, NULLCP, "Lost reachability with %s", paddr (&peer->src)); } if (peer->reach == 0) { clear(peer); if (peer->src.type == AF_INET) peer->sock = -1; /* since he fell off the end of the earth, don't depend on local address any longer */ } if (peer->valid < 2) peer->valid++; else { clock_filter(peer, 0.0, 0.0); /* call with invalid values */ select_clock(); /* and try to reselect clock */ if (sys.peer != NULL) poll_update(sys.peer, NTP_MINPOLL); } peer->timer = 1<<(MAX(MIN((int)peer->ppoll, MIN((int)peer->hpoll, NTP_MAXPOLL)), NTP_MINPOLL)); if (peer->reach == 0) { if (peer->backoff == 0) peer->backoff = BACKOFF_COUNT; else { if (peer->backoff == 1) poll_update (peer, (int)peer->hpoll + 1); peer->backoff --; } } else if (peer->estdisp > PEER_THRESHOLD) poll_update(peer, (int)peer->hpoll - 1); else poll_update(peer, (int)peer->hpoll + 1);}#ifdef REFCLOCKvoidrefclock_input(peer, pkt) struct ntpdata *pkt; struct ntp_peer *peer;{ struct timeval *tvp; struct timeval *otvp; if (read_clock(peer->sock, &tvp, &otvp)) return; tstamp(&pkt->rec, tvp); pkt->xmt = pkt->rec; pkt->reftime = pkt->rec; tstamp(&pkt->org, otvp); peer->xmt = pkt->org; pkt->refid = peer->refid.rid_inet; /* XXX */ pkt->status &= ~ALARM; pkt->stratum = peer->stratum; pkt->ppoll = 0xff; pkt->precision = peer->precision; double_to_s_fixed(&pkt->distance, 0.0); double_to_s_fixed(&pkt->dispersion, 0.0);#ifdef DEBUG if (debug > 5) { (void) printf("\nFaking packet "); dump_pkt(&peer->src, pkt, (struct ntp_peer *)NULL); }#endif receive((struct Naddr *)peer, pkt, otvp, -1); return;}#endif REFCLOCK/* 3.4.2. Receive Procedure */voidreceive(dst, pkt, tvp, sock) struct Naddr *dst; struct ntpdata *pkt; struct timeval *tvp; int sock;{ struct ntp_peer *peer; int peer_mode; /* if we're only going to support NTP Version 2 then this stuff isn't necessary, right? */ if ((peer_mode = pkt->status & MODEMASK) == 0 && dst) { /* packet from an older NTP implementation. Synthesize the correct mode. The mapping goes like this: pkt source port pkt dst port Mode --------------- ------------ ---- NTP Port NTP Port symmetric active NTP Port not NTP Port server not NTP Port NTP Port client not NTP Port not NTP Port <not possible> Now, since we only are processing packets with the destination being NTP Port, it reduces to the two cases: pkt source port pkt dst port Mode --------------- ------------ ---- NTP Port NTP Port symmetric active not NTP Port NTP Port client */ if (dst->inet_ad.sin_port == servport) peer_mode = MODE_SYM_ACT; else peer_mode = MODE_CLIENT; } if (peer_mode == MODE_CLIENT) { /* * Special case: Use the dummy peer item that we keep around * just for this type of thing */ peer = &dummy_peer; make_new_peer(peer); peer->src = *dst; peer->sock = sock; peer->hmode = MODE_SYM_PAS; peer->reach = 0; clear(peer);#ifdef REFCLOCK } else if (sock == -1) { /* we're begin called by refclock_input(), get peer ptr */ peer = (struct ntp_peer *)dst;#endif } else peer = check_peer(dst, sock); if (peer == NULL) { peer = (struct ntp_peer *) malloc(sizeof(struct ntp_peer)); if (peer == NULL) { advise (LLOG_EXCEPTIONS, "malloc", "peer"); return; } make_new_peer(peer); peer->src = *dst; peer->sock = sock; /* remember which socket we heard this from */ peer->hmode = MODE_SYM_PAS; peer->reach = 0; clear(peer); /* * If we decide to consider any random NTP peer that might * come as a peer we might sync to, then set the PEER_FL_SYNC * flag in the peer structure. * * Alternatively, we could change the hmode to MODE_SERVER, * but then the peer state wouldn't be persistant. */ if (trusting) peer->flags |= PEER_FL_SYNC; enqueue(&peer_list, peer); } /* * "pre-configured" peers are initially assigned a socket index of * -1, which means we don't know which interface we'll use to talk * to them. Once the first reply comes back, we'll update the * peer structure */ if (peer->sock == -1) peer->sock = sock;#ifdef BROADCAST_NTP /* * Input frame matched a funny broadcast peer; these peers only * exist to periodically generate broadcasts. If an input packet * matched, it means that it looked like it *came* from the broadcast * address. This is clearly bogus. */ if (peer->flags & PEER_FL_BCAST) { TRACE (1, ("receive: input frame for broadcast peer?")); return; }#endif /* BROADCAST_NTP */#if 0 if ((peer->flags & PEER_FL_AUTHENABLE) && pkt->mac) { /* verify computed crypto-checksum */ }#endif if (peer_mode < MODE_SYM_ACT || peer_mode > MODE_BROADCAST) { TRACE (1, ("Bogus peer_mode %d from %s", peer_mode, (struct ntp_peer *) dst == peer ? "refclock" : paddr (dst)));#ifdef DEBUG if (debug > 3) abort();#endif return; } if (peer->hmode < MODE_SYM_ACT || peer->hmode > MODE_BROADCAST) { advise (LLOG_EXCEPTIONS, NULLCP, "Bogus hmode %d for peer %s", peer->hmode, paddr (&peer->src)); abort(); } peer->backoff = 0; switch (actions[peer_mode - 1][peer->hmode - 1]) { case ACT_RECV: if (!(((peer->flags & PEER_FL_CONFIG) == 0) && STRMCMP((int)pkt->stratum, >, (int)sys.stratum))) { peer->flags &= ~PEER_FL_SNOOZE; peer->reach |= 1; process_packet(dst, pkt, tvp, peer); break; } /* Note fall-through */ case ACT_ERROR: if (((peer->flags & PEER_FL_CONFIG) == 0) && (peer != &dummy_peer) && demobilize(&peer_list, peer)) break; break; case ACT_PKT: if (!(((peer->flags & PEER_FL_CONFIG) == 0) && STRMCMP((int)pkt->stratum, >, (int)sys.stratum))) { peer->flags &= ~PEER_FL_SNOOZE; peer->reach |= 1; process_packet((struct ntp_peer *) dst == peer ? NULL : dst, pkt, tvp, peer); break; } /* Note fall-through */ case ACT_XMIT: process_packet((struct ntp_peer *) dst == peer ? NULL : dst, pkt, tvp, peer); poll_update(peer, (int)peer->ppoll); transmit(peer); break; default: abort(); }}/* 3.4.3 Packet procedure */voidprocess_packet(dst, pkt, tvp, peer) struct Naddr *dst; struct ntpdata *pkt; struct timeval *tvp; struct ntp_peer *peer;{ double t1, t2, t3, t4, offset, delay; short duplicate, bogus; duplicate = (pkt->xmt.int_part == peer->org.int_part) && (pkt->xmt.fraction == peer->org.fraction); bogus = ((pkt->org.int_part != peer->xmt.int_part) || (pkt->org.fraction != peer->xmt.fraction)) || (peer->xmt.int_part == 0); peer->pkt_rcvd++; peer->leap = pkt->status & LEAPMASK; peer->vers = PKT2VERS(pkt->status); peer->stratum = pkt->stratum; peer->ppoll = pkt->ppoll; peer->precision = pkt->precision; peer->distance = pkt->distance; peer->dispersion = pkt->dispersion; if (peer->src.type == AF_INET) { peer->refid.rid_type = peer -> stratum == 1 ? RID_STRING : RID_INET; peer->refid.rid_inet = pkt->refid; } peer->reftime = pkt->reftime; peer->org = pkt->xmt; tstamp(&peer->rec, tvp); poll_update(peer, (int)peer->hpoll); /* * may want to do something special here for Broadcast Mode peers to * allow these through */ if (bogus || duplicate || (pkt->org.int_part == 0 && pkt->org.fraction == 0) || (pkt->rec.int_part == 0 && pkt->rec.fraction == 0)) { peer->pkt_dropped++; TRACE (3, ("process_packet: dropped duplicate or bogus")); return; } /* * Now compute local adjusts */ t1 = ul_fixed_to_double(&pkt->org); t2 = ul_fixed_to_double(&pkt->rec); t3 = ul_fixed_to_double(&pkt->xmt); t4 = ul_fixed_to_double(&peer->rec); /* * although the delay computation looks different than the one in the * specification, it is correct. Think about it. */ delay = (t2 - t1) - (t3 - t4); offset = ((t2 - t1) + (t3 - t4)) / 2.0; delay += 1.0/(unsigned long)(1L << -sys.precision)#ifndef REFCLOCK + NTP_MAXSKW;#else + (peer->flags&PEER_FL_REFCLOCK) ? NTP_REFMAXSKW : NTP_MAXSKW;#endif if (peer->precision < 0 && -peer->precision < sizeof(long)*NBBY) delay += 1.0/(unsigned long)(1L << -peer->precision); if (delay < 0.0) { peer->pkt_dropped++; return; }#ifndef REFCLOCK delay = MAX(delay, NTP_MINDIST);#else delay = MAX(delay, (peer->flags & PEER_FL_REFCLOCK) ? NTP_REFMINDIST : NTP_MINDIST);#endif peer->valid = 0; clock_filter(peer, delay, offset); /* invoke clock filter procedure */ TRACE (1, ("host: %s : %f : %f : %f : %f : %f : %o", dst ? paddr (dst) : "refclock", delay, offset, peer->estdelay, peer->estoffset, peer->estdisp, peer->reach)); clock_update(peer); /* call clock update procedure */}/* 3.4.4 Primary clock procedure *//* * We don't have a primary clock. * * TODO: * * ``When a primary clock is connected to the host, it is convient to * incorporate its information into the database as if the clock was * represented as an ordinary peer. The clock can be polled once a * minute or so and the returned timecheck used to produce a new update * for the logical clock.'' *//* 3.4.5 Clock update procedure */voidclock_update(peer) struct ntp_peer *peer;{ double temp; extern int adj_logical(); select_clock(); if (sys.peer != NULL) poll_update(sys.peer, NTP_MINPOLL); /* * Did we just sync to this peer?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -