ntp/protocol/ntp.go (29 lines of code) (raw):

/* Copyright (c) Facebook, Inc. and its affiliates. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Package protocol implements ntp packet and basic functions to work with. It provides quick and transparent translation between 48 bytes and simply accessible struct in the most efficient way. */ package protocol import ( "time" ) // NanosecondsToUnix is the difference between the start of NTP Era 0 and the Unix epoch in nanoseconds // Jan-1 1900 00:00:00 UTC (start of NTP epoch Era 0) and Jan-1 1970 00:00:00 UTC (start of Unix epoch) // Formula is 70 * (365 + 17) * 86400 (17 leap days) const NanosecondsToUnix = int64(2_208_988_800_000_000_000) // Time is converting Unix time to sec and frac NTP format func Time(t time.Time) (seconds uint32, fracions uint32) { nsec := t.UnixNano() + NanosecondsToUnix sec := nsec / time.Second.Nanoseconds() return uint32(sec), uint32((nsec - sec*time.Second.Nanoseconds()) << 32 / time.Second.Nanoseconds()) } // Unix is converting NTP seconds and fractions into Unix time func Unix(seconds, fractions uint32) time.Time { secs := int64(seconds) - NanosecondsToUnix/time.Second.Nanoseconds() nanos := (int64(fractions) * time.Second.Nanoseconds()) >> 32 // convert fractional to nanos return time.Unix(secs, nanos) } // Offset uses NTP algorithm for clock offset func Offset(originTime, serverReceiveTime, serverTransmitTime, clientReceiveTime time.Time) int64 { outboundClockDelta := serverReceiveTime.Sub(originTime).Nanoseconds() inboundClockDelta := serverTransmitTime.Sub(clientReceiveTime).Nanoseconds() return (outboundClockDelta + inboundClockDelta) / 2 } // RoundTripDelay uses NTP algorithm for roundtrip network delay func RoundTripDelay(originTime, serverReceiveTime, serverTransmitTime, clientReceiveTime time.Time) int64 { totalDelay := clientReceiveTime.Sub(originTime).Nanoseconds() serverDelay := serverTransmitTime.Sub(serverReceiveTime).Nanoseconds() return (totalDelay - serverDelay) } // CorrectTime returns the correct time based on computed offset func CorrectTime(clientReceiveTime time.Time, offset int64) time.Time { correctTime := clientReceiveTime.Add(time.Duration(offset)) return correctTime }