diff --git a/README.md b/README.md
index 3cbc2a8..cef2f82 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# NTPal (Network Time Pal) — A Network Time Protocol System
-NTPal is an in-development, incomplete, and rough around the edges implementation of an NTP client/server process. It also supports NTP symmetric mode, like any good friend would.
+NTPal is an in-development, incomplete, and rough around the edges implementation of an NTP client/server process.
## Code Credits
@@ -22,7 +22,7 @@ The server is hosted on [fly.io](https://fly.io/) with a configuration outlined
NTPal uses a configuration format similar to the [standard `ntpd` config](https://docs.ntpsec.org/latest/ntp_conf.html), but with far fewer options. The available commands, with arguments defined in the `ntpd` config docs, are as follows:
-- `server
[key _key_] [burst] [iburst] [version _version_] [prefer] [minpoll _minpoll_] [maxpoll _maxpoll_]`
+- `server [burst] [iburst] [version _version_] [prefer] [minpoll _minpoll_] [maxpoll _maxpoll_]`
- `driftfile `
Some environment variables are also available to configure the application's runtime and logging:
diff --git a/go.mod b/go.mod
index 977c8cf..83aa860 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
require (
github.com/charmbracelet/harmonica v0.2.0 // indirect
- github.com/charmbracelet/lipgloss v0.7.1 // indirect
+ github.com/charmbracelet/lipgloss v0.7.1
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
)
diff --git a/internal/ntp/network.go b/internal/ntp/network.go
index 732c796..705a57f 100644
--- a/internal/ntp/network.go
+++ b/internal/ntp/network.go
@@ -18,8 +18,6 @@ type TransmitPacket struct {
Leap byte /* leap indicator */
Version byte /* version number */
Mode Mode /* mode */
- Keyid int32 /* key ID */
- Dgst Digest /* message digest */
NtpFieldsEncoded
}
diff --git a/internal/ntp/time.go b/internal/ntp/time.go
index b3c11d9..a1d069b 100644
--- a/internal/ntp/time.go
+++ b/internal/ntp/time.go
@@ -8,8 +8,9 @@ import (
)
const (
- EraLength int64 = 4_294_967_296 // 2^32
- UnixEraOffset int64 = 2_208_988_800 // 1970 - 1900 in seconds
+ EraLength int64 = 4_294_967_296 // 2^32
+ UnixEraOffset int64 = 2_208_988_800 // 1970 - 1900 in seconds
+ ShortLength float64 = 65536 // 2^16
)
func UnixToTime(t unix.Timeval) time.Time {
diff --git a/pkg/ntpal/config.go b/pkg/ntpal/config.go
index 472b47c..31c76d0 100644
--- a/pkg/ntpal/config.go
+++ b/pkg/ntpal/config.go
@@ -23,7 +23,6 @@ type serverAssociationConfig struct {
burst bool
iburst bool
prefer bool
- key int
version int
minpoll int
maxpoll int
@@ -64,7 +63,6 @@ func parseConfig(path string) ntpConfig {
burst := optionalArgument("burst", &arguments)
iburst := optionalArgument("iburst", &arguments)
prefer := optionalArgument("prefer", &arguments)
- key := integerArgument("key", -1, &arguments)
version := integerArgument("version", 4, &arguments)
minpoll := integerArgument("minpoll", defaultMinpoll, &arguments)
maxpoll := integerArgument("maxpoll", defaultMaxpoll, &arguments)
@@ -95,7 +93,6 @@ func parseConfig(path string) ntpConfig {
burst: burst,
iburst: iburst,
prefer: prefer,
- key: key,
version: version,
minpoll: minpoll,
maxpoll: maxpoll,
diff --git a/pkg/ntpal/ntpal.go b/pkg/ntpal/ntpal.go
index d3c2700..d264758 100644
--- a/pkg/ntpal/ntpal.go
+++ b/pkg/ntpal/ntpal.go
@@ -19,7 +19,7 @@ import (
const VERSION byte = 4 // NTP version number
const TOLERANCE = 15e-6 //frequency tolerance PHI (s/s)
-const MINPOLL int8 = 3 //minimum poll exponent (64 s)
+const MINPOLL int8 = 3 //minimum poll exponent (8 s)
const MAXPOLL int8 = 17 // maximum poll exponent (36 h)
const MAXDISP float64 = 16 // maximum dispersion (16 s)
const MINDISP = 0.005 // minimum dispersion increment (s)
@@ -27,15 +27,13 @@ const NOSYNC byte = 0x3 // leap unsync
const MAXDIST byte = 1 // distance threshold (1 s)
const MAXSTRAT byte = 16 // maximum stratum number
-const NTPShortLength float64 = 65536 // 2^16
-
const SGATE = 3 /* spike gate (clock Filter */
const BDELAY = .004 /* broadcast delay (s) */
-const PHI = 15e-6 /* % frequency tolerance (15 ppm) */
+const PHI = 15e-6 /* frequency tolerance (15 ppm) */
const NSTAGE = 8 /* clock Register stages */
const NMAX = 50 /* maximum number of peers */
-const NSANE = 1 /* % minimum intersection survivors */
-const NMIN = 3 /* % minimum cluster survivors */
+const NSANE = 1 /* minimum intersection survivors */
+const NMIN = 3 /* minimum cluster survivors */
const NTP_FWEIGHT = 0.5
const UNREACH = 8 /* unreach counter threshold */
const BCOUNT = 8 /* packets in a burst */
@@ -63,11 +61,11 @@ const PRECISION = -18 /* precision (log2 s) */
const STARTUP_OFFSET_MAX = 5e-4
const (
- NSET int = iota /* clock Never set */
- FSET /* frequency set from file */
- SPIK /* spike detected */
- FREQ /* frequency mode */
- SYNC /* clock Synchronized */
+ NSET int = iota
+ FSET
+ SPIK
+ FREQ
+ SYNC
)
type DispatchCode int
@@ -86,24 +84,24 @@ const (
type AssociationStateCode byte
const (
- INIT AssociationStateCode = iota /* initialization */
- STALE /* timeout */
- STEP /* time step */
- ERROR /* authentication error */
- CRYPTO /* crypto-NAK received */
- NKEY /* untrusted key */
+ INIT AssociationStateCode = iota
+ STALE
+ STEP
+ ERROR
+ CRYPTO
+ NKEY
)
type LocalClockReturnCode int
const (
- IGNORE LocalClockReturnCode = iota /* ignore */
- SLEW /* slew adjustment */
- LSTEP /* step adjustment TODO: RENAME THIS BACK TO STEP */
- PANIC /* panic - no adjustment */
+ IGNORE LocalClockReturnCode = iota
+ SLEW
+ LSTEP
+ PANIC
)
-// Index with [associationMode][packetMOde]
+// Index with [associationMode][packetMode]
var dispatchTable = [][]DispatchCode{
{NEWPS, DSCRD, FXMIT, MANY, NEWBC},
{PROC, PROC, DSCRD, DSCRD, DSCRD},
@@ -141,8 +139,7 @@ type NTPalSystem struct {
drift string
config string
- lock sync.Mutex
- wg sync.WaitGroup
+ wg sync.WaitGroup
hold int64
@@ -160,16 +157,9 @@ type Association struct {
hmode ntp.Mode // HOST (Self) mode
ntp.Association
-
- /*
- * Computed data
- */
t float64 /* clock.T of last used sample */
f [NSTAGE]FilterStage /* clock Filter */
- /*
- * Poll process variables
- */
burst int
ttl int
unreach int
@@ -182,10 +172,10 @@ type Association struct {
ephemeral bool
}
-type Chime struct { /* m is for Marzullo */
- association *Association /* peer structure pointer */
- levelType int /* high +1, mid 0, low -1 */
- edge float64 /* correctness interval edge */
+type Chime struct {
+ association *Association
+ levelType int
+ edge float64
}
type Chimers []Chime
@@ -324,7 +314,6 @@ func (system *NTPalSystem) setupAssociations(associationConfigs []serverAssociat
Srcaddr: associationConfig.address,
Dstaddr: system.address,
Version: byte(associationConfig.version),
- Keyid: int32(associationConfig.key),
},
},
},
@@ -389,26 +378,11 @@ func (system *NTPalSystem) setupServer() {
}
func (system *NTPalSystem) clockAdjust() {
- /*
- * Update the process time c.t. Also increase the dispersion
- * since the last update. In contrast to NTPv3, NTPv4 does not
- * declare unsynchronized after one day, since the dispersion
- * threshold serves this function. When the dispersion exceeds
- * MAXDIST (1 s), the server is considered unfit for
- * synchronization.
- */
system.Clock.lock.Lock()
system.Clock.T++
system.Rootdisp += PHI
- /*
- * Implement the phase and frequency adjustments. The gain
- * factor (denominator) is not allowed to increase beyond the
- * Allan intercept. It doesn't make sense to average phase
- * noise beyond this point and it helps to damp residual offset
- * at the longer poll intervals.
- */
dtemp := system.Clock.Offset / (float64(PLL) * ntp.Log2ToDouble(system.poll))
if system.Clock.State != SYNC {
dtemp = 0
@@ -417,11 +391,6 @@ func (system *NTPalSystem) clockAdjust() {
system.hold--
}
- /*
- * This is the kernel adjust time function, usually implemented
- * by the Unix adjtime() system call.
- */
- // TODO: Might need to wrap this in system.hold == 0 ??
system.Clock.Offset -= dtemp
debug("*****ADJUSTING:")
debug("TIME:", system.Clock.T, "SYS OFFSET:", system.Offset, "CLOCK OFFSET:", system.Clock.Offset)
@@ -430,10 +399,6 @@ func (system *NTPalSystem) clockAdjust() {
system.Clock.lock.Unlock()
- /*
- * Peer timer. Call the poll() routine when the poll timer
- * expires.
- */
for _, association := range system.associations {
if system.Clock.T >= ntp.TimestampEncoded(association.nextdate) {
info("sendPoll:", association.Srcaddr.IP)
@@ -498,14 +463,6 @@ func (system *NTPalSystem) clockAdjust() {
}
func (system *NTPalSystem) sendPoll(association *Association) {
- /*
- * This routine is called when the current time c.t catches up
- * to the next poll time p->nextdate. The value p->outdate is
- * the last time this routine was executed. The poll_update()
- * routine determines the next execution time p->nextdate.
- *
- * If broadcasting, just do it, but only if we are synchronized.
- */
hpoll := association.Hpoll
if association.hmode == ntp.BROADCAST_SERVER {
association.outdate = int32(system.Clock.T)
@@ -516,13 +473,6 @@ func (system *NTPalSystem) sendPoll(association *Association) {
return
}
- /*
- * If manycasting, start with ttl = 1. The ttl is increased by
- * one for each poll until MAXCLOCK Servers have been found or
- * ttl reaches TTLMAX. If reaching MAXCLOCK, stop polling until
- * the number of servers falls below MINCLOCK, then start all
- * over.
- */
if association.hmode == ntp.CLIENT && association.isMany {
association.outdate = int32(system.Clock.T)
if association.unreach > BEACON {
@@ -542,27 +492,11 @@ func (system *NTPalSystem) sendPoll(association *Association) {
}
if association.burst == 0 {
- /*
- * We are not in a burst. Shift the reachability
- * register to the left. Hopefully, some time before
- * the next poll a packet Will arrive and set the
- * rightmost bit.
- */
-
association.outdate = int32(system.Clock.T)
association.Reach = association.Reach << 1
- // Unreachable
if association.Reach == 0 {
system.clockFilter(association, 0, 0, MAXDISP)
- /*
- * The server is unreachable, so bump the
- * unreach counter. If the unreach threshold
- * has been reached, double the poll interval
- * to minimize wasted network traffic. Send a
- * burst only if enabled and the unreach
- * threshold has not been reached.
- */
if association.IburstEnabled && association.unreach == 0 {
association.burst = BCOUNT
}
@@ -571,7 +505,7 @@ func (system *NTPalSystem) sendPoll(association *Association) {
association.unreach++
} else {
// Try to get a new IP
- addr, err := net.ResolveUDPAddr("udp", association.Hostname+":123")
+ addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(association.Hostname, ntp.Port))
if err != nil {
log.Fatal("Invalid address: ", association.Hostname)
}
@@ -582,11 +516,6 @@ func (system *NTPalSystem) sendPoll(association *Association) {
association.unreach = 0
}
} else {
- /*
- * The server is reachable. Set the poll
- * interval to the system poll interval. Send a
- * burst only if enabled and the peer is fit.
- */
association.unreach = 0
hpoll = system.poll
if association.BurstEnabled && system.fit(association) {
@@ -594,16 +523,9 @@ func (system *NTPalSystem) sendPoll(association *Association) {
}
}
} else {
- /*
- * If in a burst, count it down. When the reply comes
- * back the clock_Filter() routine will call
- * clock_Select() to process the results of the burst.
- */
association.burst--
}
- /*
- * Do not transmit if in broadcast client mode.
- */
+
if association.hmode != ntp.BROADCAST_CLIENT {
system.pollPeer(association)
}
@@ -637,17 +559,7 @@ func (system *NTPalSystem) receive(packet ntp.ReceivePacket) *ntp.TransmitPacket
switch dispatchTable[hmode][packet.Mode-1] {
case FXMIT:
info("Received request to sync from:", packet.Srcaddr.IP)
- // If the destination address is not a broadcast
- // address
-
- /* not multicast dstaddr */
-
- // ignore auth
- // if (AUTH(p->flags & P_NOTRUST, auth))
return system.reply(packet, ntp.SERVER)
- // else if (auth == A_ERROR)
- // fast_xmit(r, M_SERV, A_CRYPTO);
- // return; /* M_SERV packet Sent */
case NEWPS:
if !isSymmetricEnabled() {
return nil
@@ -694,9 +606,9 @@ func (system *NTPalSystem) receive(packet ntp.ReceivePacket) *ntp.TransmitPacket
}
func (system *NTPalSystem) process(association *Association, packet ntp.ReceivePacket) {
- var offset float64 /* sample offsset */
- var delay float64 /* sample delay */
- var disp float64 /* sample dispersion */
+ var offset float64
+ var delay float64
+ var disp float64
kod := false
@@ -731,8 +643,8 @@ func (system *NTPalSystem) process(association *Association, packet ntp.ReceiveP
association.Stratum = packet.Stratum
}
association.Mode = packet.Mode
- association.Rootdelay = float64(packet.Rootdelay) / NTPShortLength
- association.Rootdisp = float64(packet.Rootdisp) / NTPShortLength
+ association.Rootdelay = float64(packet.Rootdelay) / ntp.ShortLength
+ association.Rootdisp = float64(packet.Rootdisp) / ntp.ShortLength
association.Refid = packet.Refid
association.Reftime = packet.Reftime
@@ -744,28 +656,12 @@ func (system *NTPalSystem) process(association *Association, packet ntp.ReceiveP
if association.Rootdelay/2+association.Rootdisp >= MAXDISP || association.Reftime >
packet.Xmt {
-
- return /* invalid header values */
+ return
}
system.pollUpdate(association, association.Hpoll)
association.Reach |= 1
- /*
- * Calculate offset, delay and dispersion, then pass to the
- * clock Filter. Note carefully the implied processing. The
- * first-order difference is done directly in 64-bit arithmetic,
- * then the result is converted to floating double. All further
- * processing is in floating-double arithmetic with rounding
- * done by the hardware. This is necessary in order to avoid
- * overflow and preserve precision.
- *
- * The delay calculation is a special case. In cases where the
- * server and client clocks are running at different rates and
- * with very fast networks, the delay can appear negative. In
- * order to avoid violating the Principle of Least Astonishment,
- * the delay is clamped not less than the system precision.
- */
if association.Mode == ntp.BROADCAST_SERVER {
offset = ntp.NTPTimestampDifferenceToDouble(int64(packet.Xmt - packet.Dst))
delay = BDELAY
@@ -788,11 +684,9 @@ func (system *NTPalSystem) process(association *Association, packet ntp.ReceiveP
system.clockFilter(association, offset, delay, disp)
}
-// TODO: Add auth
func (system *NTPalSystem) reply(receivePacket ntp.ReceivePacket, mode ntp.Mode) *ntp.TransmitPacket {
- var transmitPacket ntp.TransmitPacket
+ transmitPacket := receivePacket.TransmitPacket
- transmitPacket.Version = receivePacket.Version
transmitPacket.Srcaddr = receivePacket.Dstaddr
transmitPacket.Dstaddr = receivePacket.Srcaddr
transmitPacket.Leap = system.Leap
@@ -802,44 +696,24 @@ func (system *NTPalSystem) reply(receivePacket ntp.ReceivePacket, mode ntp.Mode)
} else {
transmitPacket.Stratum = system.stratum
}
- transmitPacket.Poll = receivePacket.Poll
transmitPacket.Precision = system.precision
- transmitPacket.Rootdelay = ntp.ShortEncoded(system.Rootdelay * NTPShortLength)
- transmitPacket.Rootdisp = ntp.ShortEncoded(system.Rootdisp * NTPShortLength)
+ transmitPacket.Rootdelay = ntp.ShortEncoded(system.Rootdelay * ntp.ShortLength)
+ transmitPacket.Rootdisp = ntp.ShortEncoded(system.Rootdisp * ntp.ShortLength)
transmitPacket.Refid = system.refid
transmitPacket.Reftime = system.reftime
transmitPacket.Org = receivePacket.Xmt
transmitPacket.Rec = receivePacket.Dst
transmitPacket.Xmt = GetSystemTime()
- /*
- * If the authentication code is A.NONE, include only the
- * header; if A.CRYPTO, send a crypto-NAK; if A.OK, send a valid
- * MAC. Use the key ID in the received packet And the key in
- * the local key cache.
- */
- // if (auth != A_NONE) {
- // if (auth == A_CRYPTO) {
- // x.keyid = 0;
- // } else {
- // x.keyid = r->keyid;
- // x.dgst = md5(x.keyid);
- // }
- // }
-
return &transmitPacket
}
func (system *NTPalSystem) pollPeer(association *Association) {
- var transmitPacket ntp.TransmitPacket
+ transmitPacket := association.TransmitPacket
- /*
- * Initialize header and transmit timestamp
- */
transmitPacket.Srcaddr = association.Dstaddr
transmitPacket.Dstaddr = association.Srcaddr
transmitPacket.Leap = system.Leap
- transmitPacket.Version = association.Version
transmitPacket.Mode = association.hmode
if system.stratum == MAXSTRAT {
transmitPacket.Stratum = 0
@@ -848,36 +722,19 @@ func (system *NTPalSystem) pollPeer(association *Association) {
}
transmitPacket.Poll = association.Hpoll
transmitPacket.Precision = system.precision
- transmitPacket.Rootdelay = ntp.ShortEncoded(system.Rootdelay * NTPShortLength)
- transmitPacket.Rootdisp = ntp.ShortEncoded(system.Rootdisp * NTPShortLength)
+ transmitPacket.Rootdelay = ntp.ShortEncoded(system.Rootdelay * ntp.ShortLength)
+ transmitPacket.Rootdisp = ntp.ShortEncoded(system.Rootdisp * ntp.ShortLength)
transmitPacket.Refid = system.refid
transmitPacket.Reftime = system.reftime
transmitPacket.Org = association.Org
transmitPacket.Rec = association.Rec
- // Xmt set lower down
-
- /*
- * If the key ID is nonzero, send a valid MAC using the key ID
- * of the association and the key in the local key cache. If
- * something breaks, like a missing trusted key, don't send the
- * packet; just reset the association and stop until the problem
- * is fixed.
- */
- if association.Keyid != 0 {
- // if (/* p->keyid invalid */ 0) {
- // clear(p, X_NKEY);
- // return;
- // }
- // x.dgst = md5(p->keyid);
- }
-
transmitPacket.Xmt = GetSystemTime()
association.Xmt = transmitPacket.Xmt
_, err := system.conn.WriteTo(ntp.EncodeTransmitPacket(transmitPacket), transmitPacket.Dstaddr)
if err != nil {
- fmt.Println("Error", err)
+ info("Write to error:", err)
}
}
@@ -890,8 +747,6 @@ func (system *NTPalSystem) pollUpdate(association *Association, poll int8) {
association.nextdate += BTIME
}
} else {
- // info("Next date based on poll:", 1< 0; i-- {
@@ -1032,24 +865,12 @@ func (system *NTPalSystem) clockFilter(association *Association, offset float64,
system.filtered <- 0
}
- /*
- * Popcorn spike suppressor. Compare the difference between the
- * last and current offsets to the current jitter. If greater
- * than SGATE (3) and if the interval since the last offset is
- * less than twice the system poll interval, dump the spike.
- * Otherwise, and if not in a burst, shake out the truechimers.
- */
if association.Disp < float64(MAXDIST) && f[0].disp < float64(MAXDIST) && etemp > SGATE*association.Jitter && (float64(f[0].t)-
association.t) < float64(2*ntp.Log2ToDouble(association.Hpoll)) {
info("Popcorn spike suppresor failed, either offset change WAY above jitter or disp too high")
return
}
- /*
- * Prime directive: use a sample only once and never a sample
- * older than the latest one, but anything goes before first
- * synchronized.
- */
if float64(f[0].t) <= association.t && system.Leap != NOSYNC {
return
}
@@ -1061,18 +882,6 @@ func (system *NTPalSystem) clockFilter(association *Association, offset float64,
}
func (system *NTPalSystem) clockSelect() {
- /*
- * We first cull the falsetickers from the server population,
- * leaving only the truechimers. The correctness interval for
- * association p is the interval from offset - root_dist() to
- * offset + root_dist(). The object of the game is to find a
- * majority clique; that is, an intersection of correctness
- * intervals numbering more than half the server population.
- *
- * First, construct the chime list of tuples (p, type, edge) as
- * shown below, then sort the list by edge from lowest to
- * highest.
- */
osys := system.Association
system.updateAssociation(nil)
@@ -1105,21 +914,10 @@ func (system *NTPalSystem) clockSelect() {
sort.Sort(ByEdge{system.m})
- /*
- * Find the largest contiguous intersection of correctness
- * intervals. Allow is the number of allowed falsetickers;
- * found is the number of midpoints. Note that the edge values
- * are limited to the range +-(2 ^ 30) < +-2e9 by the timestamp
- * calculations.
- */
m := len(system.associations)
low := 2e9
high := -2e9
for allow := 0; 2*allow < m; allow++ {
- /*
- * Scan the chime list from lowest to highest to find
- * the lower endpoint.
- */
found := 0
chime := 0
for i := 0; i < n; i++ {
@@ -1133,10 +931,6 @@ func (system *NTPalSystem) clockSelect() {
}
}
- /*
- * Scan the chime list from highest to lowest to find
- * the upper endpoint.
- */
chime = 0
for i := n - 1; i >= 0; i-- {
chime += system.m[i].levelType
@@ -1149,14 +943,6 @@ func (system *NTPalSystem) clockSelect() {
}
}
- /*
- * If the number of midpoints is greater than the number
- * of allowed falsetickers, the intersection contains at
- * least one truechimer with no midpoint. If so,
- * increment the number of allowed falsetickers and go
- * around again. If not and the intersection is
- * non-empty, declare success.
- */
if found > allow {
continue
}
@@ -1170,12 +956,6 @@ func (system *NTPalSystem) clockSelect() {
return
}
- /*
- * Clustering algorithm. Construct a list of survivors (p,
- * metric) from the chime list, where metric is dominated first
- * by stratum and then by root distance. All other things being
- * equal, this is the order of preference.
- */
system.n = 0
system.v = []Survivor{}
for i := 0; i < n; i++ {
@@ -1191,25 +971,12 @@ func (system *NTPalSystem) clockSelect() {
system.n++
}
- /*
- * There must be at least NSANE survivors to satisfy the
- * correctness assertions. Ordinarily, the Byzantine criteria
- * require four survivors, but for the demonstration here, one
- * is acceptable.
- */
if system.n < NSANE {
return
}
sort.Sort(ByMetric{system.v})
- /*
- * For each association p in turn, calculate the selection
- * jitter p->sjitter as the square root of the sum of squares
- * (p->offset - q->offset) over all q associations. The idea is
- * to repeatedly discard the survivor with maximum selection
- * jitter until a termination condition is met.
- */
for {
var sjitterMaxIdx int
var max, min, dtemp float64
@@ -1236,33 +1003,14 @@ func (system *NTPalSystem) clockSelect() {
}
}
- /*
- * If the maximum selection jitter is less than the
- * minimum peer jitter, then tossing out more survivors
- * will not lower the minimum peer jitter, so we might
- * as well stop. To make sure a few survivors are left
- * for the clustering algorithm to chew on, we also stop
- * if the number of survivors is less than or equal to
- * NMIN (3).
- */
if max < min || n <= NMIN {
break
}
- /*
- * Delete survivor with max sjitter from the list and go around
- * again.
- */
removeIndex(&system.v, sjitterMaxIdx)
system.n--
}
- /*
- * Pick the best clock. If the old system peer is on the list
- * and at the same stratum as the first survivor on the list,
- * then don't do a clock Hop. Otherwise, select the first
- * survivor on the list as the new system peer.
- */
if osys != nil && osys.Stratum == system.v[0].association.Stratum && containsAssociation(system.v, osys) {
system.updateAssociation(osys)
} else {
@@ -1274,44 +1022,16 @@ func (system *NTPalSystem) clockSelect() {
}
func (system *NTPalSystem) clockUpdate(association *Association) {
- info("Clock Update**")
- /*
- * If this is an old update, for instance, as the result of a
- * system peer change, avoid it. We never use an old sample or
- * the same sample twice.
- */
if float64(system.t) >= association.t {
return
}
- /*
- * Combine the survivor offsets and update the system clock; the
- * local_clock() routine will tell us the good or bad news.
- */
system.clockCombine()
switch system.localClock(association, system.Offset) {
- /*
- * The offset is too large and probably bogus. Complain to the
- * system log and order the operator to set the clock Manually
- * within PANIC range. The reference implementation includes a
- * command line option to disable this check and to change the
- * panic threshold from the default 1000 s as required.
- */
- // TODO: Above^
case PANIC:
debug("Offset:", system.Offset)
log.Fatal("Offset too large!")
- /*
- * The offset is more than the step threshold (0.125 s by
- * default). After a step, all associations now have
- * inconsistent time values, so they are reset and started
- * fresh. The step threshold can be changed in the reference
- * implementation in order to lessen the chance the clock Might
- * be stepped backwards. However, there may be serious
- * consequences, as noted in the white papers at the NTP project
- * site.
- */
case LSTEP:
info("Discipline STEPPED")
system.t = uint64(association.t)
@@ -1324,14 +1044,6 @@ func (system *NTPalSystem) clockUpdate(association *Association) {
system.Rootdisp = 0
system.Jitter = ntp.Log2ToDouble(system.precision)
- /*
- * The offset was less than the step threshold, which is the
- * normal case. Update the system variables from the peer
- * variables. The lower clamp on the dispersion increase is to
- * avoid timing loops and clockhOpping when highly precise
- * sources are in play. The clamp can be changed from the
- * default .01 s in the reference implementation.
- */
case SLEW:
info("Discipline SLEWED")
// Offset and jitter already set by clockCombine()
@@ -1349,36 +1061,19 @@ func (system *NTPalSystem) clockUpdate(association *Association) {
math.Abs(association.Offset), MINDISP)
system.Rootdisp = dtemp
fmt.Println("Root disp calc:", association.Disp, association.Rootdisp)
- /*
- * Some samples are discarded while, for instance, a direct
- * frequency measurement is being made.
- */
+
case IGNORE:
info("Discipline IGNORED")
}
}
func (system *NTPalSystem) clockCombine() {
- var association *Association
- var x, y, z, w float64
-
- /*
- * Combine the offsets of the clustering algorithm survivors
- * using a weighted average with weight determined by the root
- * distance. Compute the selection jitter as the weighted RMS
- * difference between the first survivor and the remaining
- * survivors. In some cases, the inherent clock Jitter can be
- * reduced by not using this algorithm, especially when frequent
- * clockhOpping is involved. The reference implementation can
- * be configured to avoid this algorithm by designating a
- * preferred peer.
- */
- w = 0
- z = w
- y = z
+ var w float64
+ z := w
+ y := z
for i := 0; i < len(system.v) && system.v[i].association != nil; i++ {
- association = system.v[i].association
- x = system.rootDist(association)
+ association := system.v[i].association
+ x := system.rootDist(association)
y += 1 / x
z += association.Offset / x
w += math.Pow(association.Offset-system.v[0].association.Offset, 2) / x
@@ -1387,44 +1082,25 @@ func (system *NTPalSystem) clockCombine() {
system.Jitter = math.Sqrt(w / y)
}
-func (system *NTPalSystem) localClock(association *Association, offset float64) LocalClockReturnCode {
+func (system *NTPalSystem) localClock(association *Association, offset float64) (rval LocalClockReturnCode) {
system.Clock.lock.Lock()
defer system.Clock.lock.Unlock()
- var freq, mu float64
- var rval LocalClockReturnCode
- var etemp, dtemp float64
-
if math.Abs(offset) > PANICT {
return PANIC
}
- /*
- * Clock State machine transition function. This is where the
- * action is and defines how the system reacts to large time
- * and frequency errors. There are two main regimes: when the
- * offset exceeds the step threshold and when it does not.
- */
rval = SLEW
- mu = association.t - float64(system.t)
- freq = 0
+
+ var freq float64
+ mu := association.t - float64(system.t)
info("Disciplining with offset:", offset)
if math.Abs(offset) > STEPT {
switch system.Clock.State {
- /*
- * In S_SYNC state, we ignore the first outlier and
- * switch to S_SPIK state.
- */
case SYNC:
system.Clock.State = SPIK
- return rval
-
- /*
- * In S_FREQ state, we ignore outliers and inliers. At
- * the first outlier after the stepout threshold,
- * compute the apparent frequency correction and step
- * the time.
- */
+ return
+
case FREQ:
if mu < WATCH {
return IGNORE
@@ -1432,85 +1108,33 @@ func (system *NTPalSystem) localClock(association *Association, offset float64)
freq = (offset - system.Clock.Offset) / mu
fallthrough
-
- /*
- * In S_SPIK state, we ignore succeeding outliers until
- * either an inlier is found or the stepout threshold is
- * exceeded.
- */
case SPIK:
if mu < WATCH {
return IGNORE
}
- /* fall through to default */
fallthrough
-
- /*
- * We get here by default in S_NSET and S_FSET states
- * and from above in S_FREQ state. Step the time and
- * clamp down the poll interval.
- *
- * In S_NSET state, an initial frequency correction is
- * not available, usually because the frequency file has
- * not yet been written. Since the time is outside the
- * capture range, the clock Is stepped. The frequency
- * will be set directly following the stepout interval.
- *
- * In S_FSET state, the initial frequency has been set
- * from the frequency file. Since the time is outside
- * the capture range, the clock Is stepped immediately,
- * rather than after the stepout interval. Guys get
- * nervous if it takes 17 minutes to set the clock For
-
- * the first time.
- *
- * In S_SPIK state, the stepout threshold has expired
- * and the phase is still above the step threshold.
- * Note that a single spike greater than the step
- * threshold is always suppressed, even at the longer
- * poll intervals.
- */
default:
- /*
- * This is the kernel set time function, usually
- * implemented by the Unix settimeofday() system
- * call.
- */
stepTime(offset)
system.Clock.Count = 0
system.poll = association.minpoll
rval = LSTEP
- // Initialize hold timer for training and startup intervals
if system.Clock.State == NSET || system.Clock.State == FSET {
system.hold = WATCH
}
if system.Clock.State == NSET {
system.rstclock(FREQ, association.t, 0)
- return rval
+ return
}
}
system.rstclock(SYNC, association.t, 0)
} else {
- // fmt.Println("OFFSET < STEPT (0.128)", "|STATE:", system.Clock.State, "|OFFSET:", offset)
- /*
- * Compute the clock Jitter as the RMS of exponentially
- * weighted offset differences. This is used by the
- * poll-adjust code.
- */
- etemp = math.Pow(system.Clock.Jitter, 2)
- dtemp = math.Pow(math.Max(math.Abs(offset-system.Clock.Last),
+ etemp := math.Pow(system.Clock.Jitter, 2)
+ dtemp := math.Pow(math.Max(math.Abs(offset-system.Clock.Last),
ntp.Log2ToDouble(system.precision)), 2)
system.Clock.Jitter = math.Sqrt(etemp + (dtemp-etemp)/AVG)
switch system.Clock.State {
-
- /*
- * In S_NSET state, this is the first update received
- * and the frequency has not been initialized. The
- * first thing to do is directly measure the oscillator
- * frequency.
- */
case NSET:
// Perform a step, despite offset < STEPT. The reason for this is that adjustTime
// would mess up the frequency measurement in the next clock State.
@@ -1521,17 +1145,8 @@ func (system *NTPalSystem) localClock(association *Association, offset float64)
system.rstclock(FREQ, association.t, 0)
return LSTEP
- /*
- * In S_FREQ state, ignore updates until the stepout
- * threshold. After that, correct the phase and
- * frequency and switch to S_SYNC state.
- */
case FREQ:
if mu < WATCH {
- // An addition to help better find the initial frequency, since sometimes the step is bad
- // if system.Clock.Offset == 0 {
- // system.Clock.Offset = offset
- // }
return IGNORE
}
@@ -1539,34 +1154,14 @@ func (system *NTPalSystem) localClock(association *Association, offset float64)
freq = (offset - system.Clock.Offset) / mu
fallthrough
-
- /*
- * We get here by default in S_SYNC and S_SPIK states.
- * Here we compute the frequency update due to PLL and
- * FLL contributions.
- */
default:
-
- /*
- * The FLL and PLL frequency gain constants
- * depending on the poll interval and Allan
- * intercept. The FLL is not used below one
- * half the Allan intercept. Above that the
- * loop gain increases in steps to 1 / AVG.
- */
- // TODO: re-add this?
if system.hold == 0 {
if ntp.Log2ToDouble(system.poll) > ALLAN {
+ // FLL
freq += (offset - system.Clock.Offset) / (FLL * math.Max(mu, float64(system.poll)))
info("FREQ update (FLL):", freq)
}
- /*
- * For the PLL the integration interval
- * (numerator) is the minimum of the update
- * interval and poll interval. This allows
- * oversampling, but not undersampling.
- */
// PLL
etemp = math.Min(mu, ALLAN)
@@ -1582,31 +1177,16 @@ func (system *NTPalSystem) localClock(association *Association, offset float64)
system.rstclock(SYNC, association.t, offset)
}
- /*
- * Calculate the new frequency and frequency stability (wander).
- * Compute the clock Wander as the RMS of exponentially weighted
- * frequency differences. This is not used directly, but can,
- * along with the jitter, be a highly useful monitoring and
- * debugging tool.
- */
freq += system.Clock.Freq
system.Clock.Freq = math.Max(math.Min(MAXFREQ, freq), -MAXFREQ)
info("Set FREQ to:", system.Clock.Freq)
- etemp = math.Pow(system.Clock.Wander, 2)
- dtemp = math.Pow(freq, 2)
+ etemp := math.Pow(system.Clock.Wander, 2)
+ dtemp := math.Pow(freq, 2)
system.Clock.Wander = math.Sqrt(etemp + (dtemp-etemp)/AVG)
- /*
- * Here we adjust the poll interval by comparing the current
- * offset with the clock Jitter. If the offset is less than the
- * clock Jitter times a constant, then the averaging interval is
- * increased; otherwise, it is decreased. A bit of hysteresis
- * helps calm the dance. Works best using burst mode.
- */
- // fmt.Println("CLOCK OFFSET:", system.Clock.Offset, "PGATE*system.Clock.Jitter:", PGATE*system.Clock.Jitter)
if system.hold > 0 {
system.Clock.Count = 0
- return rval
+ return
}
if math.Abs(system.Clock.Offset) < PGATE*system.Clock.Jitter {
@@ -1629,56 +1209,30 @@ func (system *NTPalSystem) localClock(association *Association, offset float64)
}
}
}
- return rval
+
+ return
}
func (system *NTPalSystem) rstclock(state int, t, offset float64) {
- /*
- * Enter new state and set state variables. Note, we use the
- * time of the last clock Filter sample, which must be earlier
- * than the current time.
- */
system.Clock.State = state
system.Clock.Last = system.Clock.Offset
system.Clock.Offset = offset
system.t = uint64(t)
}
-/*
- * fit() - test if association p is acceptable for synchronization
- */
func (system *NTPalSystem) fit(association *Association) bool {
- /*
- * A stratum error occurs if (1) the server has never been
- * synchronized, (2) the server stratum is invalid.
- */
if association.Leap == NOSYNC || association.Stratum >= MAXSTRAT {
return false
}
- /*
- * A distance error occurs if the root distance exceeds the
- * distance threshold plus an increment equal to one poll
- * interval.
- */
if system.rootDist(association) > float64(MAXDIST)+PHI*ntp.Log2ToDouble(system.poll) {
- info("Don't fit?:", association.Srcaddr.IP, system.rootDist(association), float64(MAXDIST)+PHI*ntp.Log2ToDouble(system.poll), association.Disp, association.Rootdisp)
return false
}
- /*
- * A loop error occurs if the remote peer is synchronized to the
- * local peer or the remote peer is synchronized to the current
- * system peer. Note this is the behavior for IPv4; for IPv6
- * the MD5 hash is used instead.
- */
if association.Refid == ipToRefID(association.Dstaddr.IP) || association.Refid == system.refid {
return false
}
- /*
- * An unreachable error occurs if the server is unreachable.
- */
if association.Reach == 0 {
return false
}
@@ -1687,12 +1241,6 @@ func (system *NTPalSystem) fit(association *Association) bool {
}
func (system *NTPalSystem) rootDist(association *Association) float64 {
- /*
- * The root synchronization distance is the maximum error due to
- * all causes of the local clock Relative to the primary server.
- * It is defined as half the total delay plus total dispersion
- * plus peer jitter.
- */
return (association.Rootdelay+association.Delay)/2 +
association.Rootdisp + association.Disp + PHI*float64(float64(system.Clock.T)-association.Update) + association.Jitter
}
diff --git a/pkg/ntpal/query.go b/pkg/ntpal/query.go
index 9fc1dd6..f5e994e 100644
--- a/pkg/ntpal/query.go
+++ b/pkg/ntpal/query.go
@@ -40,7 +40,6 @@ func (system *NTPalSystem) Query(address string, messages int) (*QueryResult, er
Srcaddr: addr,
Dstaddr: system.address,
Version: VERSION,
- Keyid: 0,
},
},
},