📄 ntp_proto.c
字号:
* Popcorn spike or step threshold exceeded. Pretend it never * happened. */ default: break; } if (ostratum != sys_stratum) report_event(EVNT_PEERSTCHG, NULL);}/* * poll_update - update peer poll interval */voidpoll_update( struct peer *peer, int mpoll ){ int hpoll; /* * This routine figures out when the next poll should be sent. * That turns out to be wickedly complicated. The big problem is * that sometimes the time for the next poll is in the past. * Watch out for races here between the receive process and the * poll process. The key assertion is that, if nextdate equals * current_time, the call is from the poll process; otherwise, * it is from the receive process. * * First, bracket the poll interval according to the type of * association and options. If a fixed interval is configured, * use minpoll. This primarily is for reference clocks, but * works for any association. */ if (peer->flags & FLAG_FIXPOLL) { hpoll = peer->minpoll; /* * The ordinary case; clamp the poll interval between minpoll * and maxpoll. */ } else { hpoll = max(min(peer->maxpoll, mpoll), peer->minpoll); }#ifdef OPENSSL /* * Bit of crass arrogance at this point. If the poll interval * has changed and we have a keylist, the lifetimes in the * keylist are probably bogus. In this case purge the keylist * and regenerate it later. */ if (hpoll != peer->hpoll) key_expire(peer);#endif /* OPENSSL */ peer->hpoll = hpoll; /* * Now we figure out if there is an override. If during the * crypto protocol and a message is pending, make it wait not * more than two seconds. */#ifdef OPENSSL if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC || peer->crypto)) { peer->nextdate = current_time + RESP_DELAY; /* * If we get called from the receive routine while a burst is * pending, just slink away. If from the poll routine and a * reference clock or a pending crypto response, delay for one * second. If this is the first sent in a burst, wait for the * modem to come up. For others in the burst, delay two seconds. */ } else if (peer->burst > 0) {#else /* OPENSSL */ if (peer->burst > 0) {#endif /* OPENSSL */ if (peer->nextdate != current_time) return;#ifdef REFCLOCK else if (peer->flags & FLAG_REFCLOCK) peer->nextdate += RESP_DELAY;#endif /* REFCLOCK */ else if (peer->flags & (FLAG_IBURST | FLAG_BURST) && peer->burst == NTP_BURST) peer->nextdate += sys_calldelay; else peer->nextdate += BURST_DELAY; /* * The ordinary case; use the minimum of the host and peer * intervals, but not less than minpoll. In other words, * oversampling is okay but understampling is evil. */ } else { peer->nextdate = peer->outdate + RANDPOLL(max(min(peer->ppoll, hpoll), peer->minpoll)); } /* * If the time for the next poll has already happened, bring it * up to the next second after this one. This way the only way * to get nexdate == current time is from the poll routine. */ if (peer->nextdate <= current_time) peer->nextdate = current_time + 1;#ifdef DEBUG if (debug > 1) printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n", current_time, ntoa(&peer->srcadr), peer->flags, peer->hpoll, peer->burst, peer->outdate, peer->nextdate);#endif}/* * peer_clear - clear peer filter registers. See Section 3.4.8 of the spec. */voidpeer_clear( struct peer *peer, /* peer structure */ char *ident /* tally lights */ ){ int i; /* * If cryptographic credentials have been acquired, toss them to * Valhalla. Note that autokeys are ephemeral, in that they are * tossed immediately upon use. Therefore, the keylist can be * purged anytime without needing to preserve random keys. Note * that, if the peer is purged, the cryptographic variables are * purged, too. This makes it much harder to sneak in some * unauthenticated data in the clock filter. */#ifdef OPENSSL key_expire(peer); if (peer->pkey != NULL) EVP_PKEY_free(peer->pkey); if (peer->ident_pkey != NULL) EVP_PKEY_free(peer->ident_pkey); if (peer->subject != NULL) free(peer->subject); if (peer->issuer != NULL) free(peer->issuer); if (peer->iffval != NULL) BN_free(peer->iffval); if (peer->grpkey != NULL) BN_free(peer->grpkey); if (peer->cmmd != NULL) { free(peer->cmmd); peer->cmmd = NULL; } value_free(&peer->cookval); value_free(&peer->recval); value_free(&peer->encrypt); value_free(&peer->sndval);#endif /* OPENSSL */ if (peer == sys_peer) sys_peer = NULL; /* * Wipe the association clean and initialize the nonzero values. */ memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); peer->estbdelay = sys_bdelay; peer->ppoll = peer->maxpoll; peer->hpoll = peer->minpoll; peer->disp = MAXDISPERSE; peer->jitter = LOGTOD(sys_precision); for (i = 0; i < NTP_SHIFT; i++) { peer->filter_order[i] = i; peer->filter_disp[i] = MAXDISPERSE; }#ifdef REFCLOCK if (!(peer->flags & FLAG_REFCLOCK)) { peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_UNSPEC; memcpy(&peer->refid, ident, 4); }#else peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_UNSPEC; memcpy(&peer->refid, ident, 4);#endif /* REFCLOCK */ /* * During initialization use the association count to spread out * the polls at one-second intervals. Othersie, randomize over * the minimum poll interval in order to avoid broadcast * implosion. */ peer->nextdate = peer->update = peer->outdate = current_time; if (initializing) peer->nextdate += peer_associations; else if (peer->hmode == MODE_PASSIVE) peer->nextdate += RESP_DELAY; else peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) - 1));#ifdef DEBUG if (debug) printf("peer_clear: at %ld next %ld assoc ID %d refid %s\n", current_time, peer->nextdate, peer->associd, ident);#endif}/* * clock_filter - add incoming clock sample to filter register and run * the filter procedure to find the best sample. */voidclock_filter( struct peer *peer, /* peer structure pointer */ double sample_offset, /* clock offset */ double sample_delay, /* roundtrip delay */ double sample_disp /* dispersion */ ){ double dst[NTP_SHIFT]; /* distance vector */ int ord[NTP_SHIFT]; /* index vector */ int i, j, k, m; double dtemp, etemp; /* * Shift the new sample into the register and discard the oldest * one. The new offset and delay come directly from the * timestamp calculations. The dispersion grows from the last * outbound packet or reference clock update to the present time * and increased by the sum of the peer precision and the system * precision. The delay can sometimes swing negative due to * frequency skew, so it is clamped non-negative. */ j = peer->filter_nextpt; peer->filter_offset[j] = sample_offset; peer->filter_delay[j] = max(0, sample_delay); peer->filter_disp[j] = sample_disp; peer->filter_epoch[j] = current_time; j = (j + 1) % NTP_SHIFT; peer->filter_nextpt = j; /* * Update dispersions since the last update and at the same * time initialize the distance and index lists. The distance * list uses a compound metric. If the sample is valid and * younger than the minimum Allan intercept, use delay; * otherwise, use biased dispersion. */ dtemp = clock_phi * (current_time - peer->update); peer->update = current_time; for (i = NTP_SHIFT - 1; i >= 0; i--) { if (i != 0) peer->filter_disp[j] += dtemp; if (peer->filter_disp[j] >= MAXDISPERSE) peer->filter_disp[j] = MAXDISPERSE; if (peer->filter_disp[j] >= MAXDISPERSE) dst[i] = MAXDISPERSE; else if (peer->update - peer->filter_epoch[j] > allan_xpt) dst[i] = sys_maxdist + peer->filter_disp[j]; else dst[i] = peer->filter_delay[j]; ord[i] = j; j++; j %= NTP_SHIFT; } /* * Sort the samples in both lists by distance. Note, we do not * displace a higher distance sample by a lower distance one * unless lower by at least the precision. */ for (i = 1; i < NTP_SHIFT; i++) { for (j = 0; j < i; j++) { if (dst[j] > dst[i] + LOGTOD(sys_precision)) { k = ord[j]; ord[j] = ord[i]; ord[i] = k; etemp = dst[j]; dst[j] = dst[i]; dst[i] = etemp; } } } /* * Copy the index list to the association structure so ntpq * can see it later. Prune the distance list to samples less * than max distance, but keep at least two valid samples for * jitter calculation. */ m = 0; for (i = 0; i < NTP_SHIFT; i++) { peer->filter_order[i] = (u_char) ord[i]; if (dst[i] >= MAXDISPERSE || (m >= 2 && dst[i] >= sys_maxdist)) continue; m++; } /* * Compute the dispersion and jitter. The dispersion is weighted * exponentially by NTP_FWEIGHT (0.5) so it is normalized close * to 1.0. The jitter is the RMS differences relative to the * lowest delay sample. If no acceptable samples remain in the * shift register, quietly tiptoe home leaving only the * dispersion. */ peer->disp = peer->jitter = 0; k = ord[0]; for (i = NTP_SHIFT - 1; i >= 0; i--) { j = ord[i]; peer->disp = NTP_FWEIGHT * (peer->disp + peer->filter_disp[j]); if (i < m) peer->jitter += DIFF(peer->filter_offset[j], peer->filter_offset[k]); } /* * If no acceptable samples remain in the shift register, * quietly tiptoe home leaving only the dispersion. Otherwise, * save the offset, delay and jitter. Note the jitter must not * be less than the precision. */ if (m == 0) return; etemp = fabs(peer->offset - peer->filter_offset[k]); peer->offset = peer->filter_offset[k]; peer->delay = peer->filter_delay[k]; if (m > 1) peer->jitter /= m - 1; peer->jitter = max(SQRT(peer->jitter), LOGTOD(sys_precision)); /* * A new sample is useful only if it is younger than the last * one used, but only if the sucker has been synchronized. */ if (peer->filter_epoch[k] <= peer->epoch && sys_leap != LEAP_NOTINSYNC) {#ifdef DEBUG if (debug) printf("clock_filter: discard %lu\n", peer->epoch - peer->filter_epoch[k]);#endif return; } /* * If the difference between the last offset and the current one * exceeds the jitter by CLOCK_SGATE and the interval since the * last update is less than twice the system poll interval, * consider the update a popcorn spike and ignore it. */ if (etemp > CLOCK_SGATE * peer->jitter && m > 1 && peer->filter_epoch[k] - peer->epoch < 2. * ULOGTOD(sys_poll)) {#ifdef DEBUG if (debug) printf("clock_filter: popcorn %.6f %.6f\n", etemp, dtemp);#endif return; } /* * The mitigated sample statistics are saved for later * processing. If not in a burst, tickle the select. */ peer->epoch = peer->filter_epoch[k];#ifdef DEBUG if (debug) printf( "clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f, age %lu\n", m, peer->offset, peer->delay, peer->disp, peer->jitter, current_time - peer->epoch);#endif if (peer->burst == 0 || sys_leap == LEAP_NOTINSYNC) clock_select();}/* * clock_select - find the pick-of-the-litter clock * * LOCKCLOCK: If the local clock is the prefer peer, it will always be * enabled, even if declared falseticker, (2) only the prefer peer can * be selected as the system peer, (3) if the external source is down, * the system leap bits are set to 11 and the stratum set to infinity. */voidclock_select(void){ struct peer *peer; int i, j, k, n; int nlist, nl3; int allow, osurv; double d, e, f, g; double high, low; double synch[NTP_MAXASSOC], error[NTP_MAXASSOC]; struct peer *osys_peer; struct peer *typeacts = NULL; struct peer *typelocal = NULL; struct peer *typesystem = NULL; static int list_alloc = 0; static struct endpoint *endpoint = NULL; static int *indx = NULL; static struct peer **peer_list = NULL; static u_int endpoint_size = 0; static u_int indx_size = 0; static u_int peer_list_size = 0; /* * Initialize and create endpoint, index and peer lists big * enough to handle all associations. */ osys_peer = sys_peer; sys_peer = NULL; sys_pps = NULL; sys_prefer = NULL; osurv = sys_survivors; sys_survivors = 0;#ifdef LOCKCLOCK sys_leap = LEAP_NOTINSYNC; sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "DOWN", 4);#endif /* LOCKCLOCK */ nlist = 0; for (n = 0; n < NTP_HASH_SIZE; n++) nlist += peer_hash_count[n]; if (nlist > list_alloc) { if (list_alloc > 0) { free(endpoint); free(indx); free(peer_list); } while (list_alloc < nlist) { list_alloc += 5; endpoint_size += 5 * 3 * sizeof(*endpoint); indx_size += 5 * 3 * sizeof(*indx); peer_list_size += 5 * sizeof(*peer_list); } endpoint = (struct endpoint *)emalloc(endpoint_size); indx = (int *)emalloc(indx_size); peer_list = (struct peer **)emalloc(peer_list_size); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -