Files
Schedule-ICTIS/Carthage/Checkouts/TrueTime.swift/Sources/NTPResponse.swift
Vladimir Dubovik 5abafda21b Commit
2025-06-13 11:59:16 +03:00

69 lines
2.2 KiB
Swift

//
// NTPResponse.swift
// TrueTime
//
// Created by Michael Sanders on 10/14/16.
// Copyright © 2016 Instacart. All rights reserved.
//
import Foundation
struct NTPResponse {
let packet: ntp_packet_t
let responseTime: Int64
let receiveTime: timeval
init?(packet: ntp_packet_t, responseTime: Int64, receiveTime: timeval = .now()) {
self.packet = packet
self.responseTime = responseTime
self.receiveTime = receiveTime
guard isValidResponse else { return nil }
}
// See https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm
var offset: Int64 {
let T = offsetValues
return ((T[1] - T[0]) + (T[2] - T[3])) / 2
}
var delay: Int64 {
let T = offsetValues
return (T[3] - T[0]) - (T[2] - T[1])
}
var networkDate: Date {
let interval = TimeInterval(milliseconds: responseTime + offset)
return Date(timeIntervalSince1970: interval)
}
}
func bestTime(fromResponses times: [[FrozenNetworkTime]]) -> FrozenNetworkTime? {
let bestTimes = times.map { serverTimes -> FrozenNetworkTime? in
serverTimes.min { $0.serverResponse.delay < $1.serverResponse.delay }
}.compactMap { $0 }.sorted { $0.serverResponse.offset < $1.serverResponse.offset }
return bestTimes.isEmpty ? nil : bestTimes[bestTimes.count / 2]
}
private extension NTPResponse {
var isValidResponse: Bool {
return packet.stratum > 0 && packet.stratum < 16 &&
packet.root_delay.durationInMilliseconds < maxRootDispersion &&
packet.root_dispersion.durationInMilliseconds < maxRootDispersion &&
packet.client_mode == ntpModeServer &&
packet.leap_indicator != leapIndicatorUnknown &&
abs(receiveTime.milliseconds - packet.originate_time.milliseconds - delay) < maxDelayDelta
}
var offsetValues: [Int64] {
return [packet.originate_time.milliseconds,
packet.receive_time.milliseconds,
packet.transmit_time.milliseconds,
responseTime]
}
}
private let maxRootDispersion: Int64 = 100
private let maxDelayDelta: Int64 = 100
private let ntpModeServer: UInt8 = 4
private let leapIndicatorUnknown: UInt8 = 3