github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/p2p/discover/ntp.go (about) 1 package discover 2 3 import ( 4 "fmt" 5 "net" 6 "sort" 7 "time" 8 9 "github.com/neatlab/neatio/chain/log" 10 ) 11 12 const ( 13 ntpPool = "pool.ntp.org" 14 ntpChecks = 3 15 ) 16 17 type durationSlice []time.Duration 18 19 func (s durationSlice) Len() int { return len(s) } 20 func (s durationSlice) Less(i, j int) bool { return s[i] < s[j] } 21 func (s durationSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 22 23 func checkClockDrift() { 24 drift, err := sntpDrift(ntpChecks) 25 if err != nil { 26 return 27 } 28 if drift < -driftThreshold || drift > driftThreshold { 29 log.Warn(fmt.Sprintf("System clock seems off by %v, which can prevent network connectivity", drift)) 30 log.Warn("Please enable network time synchronisation in system settings.") 31 } else { 32 log.Debug("NTP sanity check done", "drift", drift) 33 } 34 } 35 36 func sntpDrift(measurements int) (time.Duration, error) { 37 addr, err := net.ResolveUDPAddr("udp", ntpPool+":123") 38 if err != nil { 39 return 0, err 40 } 41 request := make([]byte, 48) 42 request[0] = 3<<3 | 3 43 44 drifts := []time.Duration{} 45 for i := 0; i < measurements+2; i++ { 46 conn, err := net.DialUDP("udp", nil, addr) 47 if err != nil { 48 return 0, err 49 } 50 defer conn.Close() 51 52 sent := time.Now() 53 if _, err = conn.Write(request); err != nil { 54 return 0, err 55 } 56 conn.SetDeadline(time.Now().Add(5 * time.Second)) 57 58 reply := make([]byte, 48) 59 if _, err = conn.Read(reply); err != nil { 60 return 0, err 61 } 62 elapsed := time.Since(sent) 63 64 sec := uint64(reply[43]) | uint64(reply[42])<<8 | uint64(reply[41])<<16 | uint64(reply[40])<<24 65 frac := uint64(reply[47]) | uint64(reply[46])<<8 | uint64(reply[45])<<16 | uint64(reply[44])<<24 66 67 nanosec := sec*1e9 + (frac*1e9)>>32 68 69 t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nanosec)).Local() 70 71 drifts = append(drifts, sent.Sub(t)+elapsed/2) 72 } 73 sort.Sort(durationSlice(drifts)) 74 75 drift := time.Duration(0) 76 for i := 1; i < len(drifts)-1; i++ { 77 drift += drifts[i] 78 } 79 return drift / time.Duration(measurements), nil 80 }