Skip to content

Commit 3dfba1d

Browse files
chriscederbeevik
authored andcommitted
Add GetSystemTime query option
GetSystemTime is a callback used to override the default method of obtaining the local system time during time synchronization.
1 parent 9dfcbd9 commit 3dfba1d

File tree

2 files changed

+54
-5
lines changed

2 files changed

+54
-5
lines changed

ntp.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ type QueryOptions struct {
249249
// DEPRECATED. Use Dialer instead.
250250
Dial func(laddr string, lport int, raddr string, rport int) (net.Conn, error)
251251

252+
// GetSystemTime is a callback used to override the default method of
253+
// obtaining the local system time during time synchronization. If not
254+
// specified, time.Now is used.
255+
GetSystemTime func() time.Time
256+
252257
// Port indicates the port used to reach the remote NTP server.
253258
//
254259
// DEPRECATED. Embed the port number in the query address string instead.
@@ -495,6 +500,9 @@ func getTime(address string, opt *QueryOptions) (*header, ntpTime, error) {
495500
if opt.Dialer == nil {
496501
opt.Dialer = defaultDialer
497502
}
503+
if opt.GetSystemTime == nil {
504+
opt.GetSystemTime = time.Now
505+
}
498506

499507
// Compose a conforming host:port remote address string if the address
500508
// string doesn't already contain a port.
@@ -566,7 +574,7 @@ func getTime(address string, opt *QueryOptions) (*header, ntpTime, error) {
566574
appendMAC(&xmitBuf, opt.Auth, authKey)
567575

568576
// Transmit the query and keep track of when it was transmitted.
569-
xmitTime := time.Now()
577+
xmitTime := opt.GetSystemTime()
570578
_, err = con.Write(xmitBuf.Bytes())
571579
if err != nil {
572580
return nil, 0, err
@@ -581,11 +589,10 @@ func getTime(address string, opt *QueryOptions) (*header, ntpTime, error) {
581589
// Keep track of the time the response was received. As of go 1.9, the
582590
// time package uses a monotonic clock, so delta will never be less than
583591
// zero for go version 1.9 or higher.
584-
delta := time.Since(xmitTime)
585-
if delta < 0 {
586-
delta = 0
592+
recvTime := opt.GetSystemTime()
593+
if recvTime.Sub(xmitTime) < 0 {
594+
recvTime = xmitTime
587595
}
588-
recvTime := xmitTime.Add(delta)
589596

590597
// Parse the response header.
591598
recvBuf = recvBuf[:recvBytes]

ntp_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net"
1010
"os"
1111
"strings"
12+
"sync/atomic"
1213
"testing"
1314
"time"
1415

@@ -154,6 +155,47 @@ func TestOnlineTTL(t *testing.T) {
154155
assert.NotNil(t, err)
155156
}
156157

158+
func TestOnlineCustomGetSystemTime(t *testing.T) {
159+
if host == "localhost" {
160+
t.Skip("Timeout test not available with localhost NTP server.")
161+
return
162+
}
163+
164+
var simuTime atomic.Value
165+
simuTime.Store(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC))
166+
167+
const timerInterval = 1 * time.Millisecond
168+
ctx := t.Context()
169+
170+
// Start a simulated clock independent of the system wall clock,
171+
// initialized at 2020-01-01T00:00:00, advancing in 1 ms increments.
172+
go func() {
173+
ticker := time.NewTicker(timerInterval)
174+
defer ticker.Stop()
175+
176+
for {
177+
select {
178+
case <-ctx.Done():
179+
return
180+
case <-ticker.C:
181+
current := simuTime.Load().(time.Time)
182+
simuTime.Store(current.Add(timerInterval))
183+
}
184+
}
185+
}()
186+
187+
r, err := QueryWithOptions(host, QueryOptions{
188+
GetSystemTime: func() time.Time { return simuTime.Load().(time.Time) },
189+
})
190+
if isNil(t, host, err) {
191+
tm := simuTime.Load().(time.Time)
192+
trueTime := tm.Add(r.ClockOffset)
193+
t.Logf(" Custom Time: %s\n", tm.Format(timeFormat))
194+
t.Logf(" ~True Time: %s\n", trueTime.Format(timeFormat))
195+
t.Logf("~ClockOffset: %v\n", trueTime.Sub(tm))
196+
}
197+
}
198+
157199
func TestOfflineConvertLong(t *testing.T) {
158200
ts := []ntpTime{0x0, 0xff800000, 0x1ff800000, 0x80000000ff800000, 0xffffffffff800000}
159201
for _, v := range ts {

0 commit comments

Comments
 (0)