Skip to content

Commit 130f07f

Browse files
committed
fix/timesync: Ensure that auto-update waits for time sync
- Added check to not attempt auto update if time sync is needed and not yet successful (delays 30 second to recheck). - Added resync of time when DHCP or link state changes if online - Added conditional* fallback from configured* NTP servers to the IP-named NTP servers, and then to the DNS named ones if that fails - Added conditional* fallback from the configured* HTTP servers to the default DNS named ones. - Uses the configuration* option for how many queries to run in parallel - Added known static IPs for time servers (in case DNS resolution isn't up yet) - Added time.cloudflare.com to fall-back NTP servers * Note: The UI for configuring many of these things doesn't exist yet, but the defaults are reasonable
1 parent 7725278 commit 130f07f

File tree

6 files changed

+74
-22
lines changed

6 files changed

+74
-22
lines changed

internal/network/netif.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type NetworkInterfaceOptions struct {
4747
DefaultHostname string
4848
OnStateChange func(state *NetworkInterfaceState)
4949
OnInitialCheck func(state *NetworkInterfaceState)
50-
OnDhcpLeaseChange func(lease *udhcpc.Lease)
50+
OnDhcpLeaseChange func(lease *udhcpc.Lease, state *NetworkInterfaceState)
5151
OnConfigChange func(config *NetworkConfig)
5252
NetworkConfig *NetworkConfig
5353
}
@@ -92,7 +92,7 @@ func NewNetworkInterfaceState(opts *NetworkInterfaceOptions) (*NetworkInterfaceS
9292

9393
_ = s.setHostnameIfNotSame()
9494

95-
opts.OnDhcpLeaseChange(lease)
95+
opts.OnDhcpLeaseChange(lease, s)
9696
},
9797
})
9898

internal/timesync/http.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ var defaultHTTPUrls = []string{
1919
// "http://www.msftconnecttest.com/connecttest.txt",
2020
}
2121

22-
func (t *TimeSync) queryAllHttpTime() (now *time.Time) {
22+
func (t *TimeSync) queryAllHttpTime(httpUrls []string) (now *time.Time) {
2323
chunkSize := 4
24-
httpUrls := t.httpUrls
24+
if t.networkConfig.TimeSyncParallel.Valid {
25+
chunkSize = int(t.networkConfig.TimeSyncParallel.Int64)
26+
}
2527

2628
// shuffle the http urls to avoid always querying the same servers
2729
rand.Shuffle(len(httpUrls), func(i, j int) { httpUrls[i], httpUrls[j] = httpUrls[j], httpUrls[i] })

internal/timesync/ntp.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,39 @@ import (
88
"github.com/beevik/ntp"
99
)
1010

11-
var defaultNTPServers = []string{
11+
var defaultNTPServerIPs = []string{
12+
// These servers are known by static IP and as such don't need DNS lookups
13+
// These are from Google and Cloudflare since if they're down, the internet
14+
// is broken anyway
15+
"162.159.200.1", // time.cloudflare.com IPv4
16+
"162.159.200.123", // time.cloudflare.com IPv4
17+
"2606:4700:f1::1", // time.cloudflare.com IPv6
18+
"2606:4700:f1::123", // time.cloudflare.com IPv6
19+
"216.239.35.0", // time.google.com IPv4
20+
"216.239.35.4", // time.google.com IPv4
21+
"216.239.35.8", // time.google.com IPv4
22+
"216.239.35.12", // time.google.com IPv4
23+
"2001:4860:4806::", // time.google.com IPv6
24+
"2001:4860:4806:4::", // time.google.com IPv6
25+
"2001:4860:4806:8::", // time.google.com IPv6
26+
"2001:4860:4806:c::", // time.google.com IPv6
27+
}
28+
29+
var defaultNTPServerHostnames = []string{
30+
// should use something from https://github.com/jauderho/public-ntp-servers
1231
"time.apple.com",
1332
"time.aws.com",
1433
"time.windows.com",
1534
"time.google.com",
16-
"162.159.200.123", // time.cloudflare.com IPv4
17-
"2606:4700:f1::123", // time.cloudflare.com IPv6
18-
"0.pool.ntp.org",
19-
"1.pool.ntp.org",
20-
"2.pool.ntp.org",
21-
"3.pool.ntp.org",
35+
"time.cloudflare.com",
36+
"pool.ntp.org",
2237
}
2338

24-
func (t *TimeSync) queryNetworkTime() (now *time.Time, offset *time.Duration) {
39+
func (t *TimeSync) queryNetworkTime(ntpServers []string) (now *time.Time, offset *time.Duration) {
2540
chunkSize := 4
26-
ntpServers := t.ntpServers
41+
if t.networkConfig.TimeSyncParallel.Valid {
42+
chunkSize = int(t.networkConfig.TimeSyncParallel.Int64)
43+
}
2744

2845
// shuffle the ntp servers to avoid always querying the same servers
2946
rand.Shuffle(len(ntpServers), func(i, j int) { ntpServers[i], ntpServers[j] = ntpServers[j], ntpServers[i] })

internal/timesync/timesync.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func NewTimeSync(opts *TimeSyncOptions) *TimeSync {
6969
rtcDevicePath: rtcDevice,
7070
rtcLock: &sync.Mutex{},
7171
preCheckFunc: opts.PreCheckFunc,
72-
ntpServers: defaultNTPServers,
72+
ntpServers: defaultNTPServerIPs,
7373
httpUrls: defaultHTTPUrls,
7474
networkConfig: opts.NetworkConfig,
7575
}
@@ -159,11 +159,28 @@ func (t *TimeSync) Sync() error {
159159
metricTimeSyncCount.Inc()
160160

161161
if syncMode.Ntp {
162-
now, offset = t.queryNetworkTime()
162+
// try the configured servers first
163+
now, offset = t.queryNetworkTime(t.ntpServers)
164+
165+
if syncMode.NtpUseFallback && now == nil {
166+
// now try the default hard-coded IP servers in case DNS is down
167+
now, offset = t.queryNetworkTime(defaultNTPServerIPs)
168+
169+
if now == nil {
170+
// unlikely to arrive here, but fall-back to DNS names default servers
171+
now, offset = t.queryNetworkTime(defaultNTPServerHostnames)
172+
}
173+
}
163174
}
164175

165176
if syncMode.Http && now == nil {
166-
now = t.queryAllHttpTime()
177+
// try the configured servers first
178+
now = t.queryAllHttpTime(t.httpUrls)
179+
180+
if syncMode.HttpUseFallback && now == nil {
181+
// unlikely to arrive here, but fall-back to DNS names default servers
182+
now = t.queryAllHttpTime(defaultHTTPUrls)
183+
}
167184
}
168185

169186
if now == nil {

main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,25 @@ func Main() {
9696
if !config.AutoUpdateEnabled {
9797
return
9898
}
99+
100+
if isTimeSyncNeeded() && !timeSync.IsSyncSuccess() {
101+
logger.Debug().Msg("system time is not synced, will retry in 30 seconds")
102+
time.Sleep(30 * time.Second)
103+
continue
104+
}
105+
99106
if currentSession != nil {
100107
logger.Debug().Msg("skipping update since a session is active")
101108
time.Sleep(1 * time.Minute)
102109
continue
103110
}
111+
104112
includePreRelease := config.IncludePreRelease
105113
err = TryUpdate(context.Background(), GetDeviceID(), includePreRelease)
106114
if err != nil {
107115
logger.Warn().Err(err).Msg("failed to auto update")
108116
}
117+
109118
time.Sleep(1 * time.Hour)
110119
}
111120
}()

network.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var (
1515
networkState *network.NetworkInterfaceState
1616
)
1717

18-
func networkStateChanged() {
18+
func networkStateChanged(isOnline bool) {
1919
// do not block the main thread
2020
go waitCtrlAndRequestDisplayUpdate(true)
2121

@@ -26,6 +26,13 @@ func networkStateChanged() {
2626
networkState.GetFQDN(),
2727
}, true)
2828
}
29+
30+
// if the network is now online, trigger an NTP sync if still needed
31+
if isOnline && timeSync != nil && (isTimeSyncNeeded() || !timeSync.IsSyncSuccess()) {
32+
if err := timeSync.Sync(); err != nil {
33+
logger.Warn().Str("error", err.Error()).Msg("unable to sync time on network state change")
34+
}
35+
}
2936
}
3037

3138
func initNetwork() error {
@@ -37,13 +44,13 @@ func initNetwork() error {
3744
NetworkConfig: config.NetworkConfig,
3845
Logger: networkLogger,
3946
OnStateChange: func(state *network.NetworkInterfaceState) {
40-
networkStateChanged()
47+
networkStateChanged(state.IsOnline())
4148
},
4249
OnInitialCheck: func(state *network.NetworkInterfaceState) {
43-
networkStateChanged()
50+
networkStateChanged(state.IsOnline())
4451
},
45-
OnDhcpLeaseChange: func(lease *udhcpc.Lease) {
46-
networkStateChanged()
52+
OnDhcpLeaseChange: func(lease *udhcpc.Lease, state *network.NetworkInterfaceState) {
53+
networkStateChanged(state.IsOnline())
4754

4855
if currentSession == nil {
4956
return
@@ -53,7 +60,7 @@ func initNetwork() error {
5360
},
5461
OnConfigChange: func(networkConfig *network.NetworkConfig) {
5562
config.NetworkConfig = networkConfig
56-
networkStateChanged()
63+
networkStateChanged(false)
5764

5865
if mDNS != nil {
5966
_ = mDNS.SetListenOptions(networkConfig.GetMDNSMode())

0 commit comments

Comments
 (0)