in mini-sntp/src/lib.rs [155:218]
fn parse_server_response(
buf: [u8; 48],
request_transmit_timestamp: chrono::DateTime<chrono::Utc>,
) -> Result<SntpTimeQueryResult, Error> {
let sntp_epoch = sntp_epoch();
let destination_timestamp = chrono::Utc::now();
#[cfg(test)]
let destination_timestamp = destination_timestamp - chrono::Duration::seconds(30); // simulate unsynced local clock
let packet = Packet::parse(buf, sntp_epoch);
#[cfg(test)]
let packet = dbg!(packet);
match packet.leap_indicator {
0..=2 => (),
leap_indicator => {
return Err(Error::BadServerResponse(
BadServerResponseReason::LeapIndicator(leap_indicator),
));
}
};
// RFC 2030 says:
//
// >Version 4 servers are required to
// >reply in the same version as the request, so the VN field of the
// >request also specifies the version of the reply.
//
// But at least one pool.ntp.org server does not respect this and responds with VN=4
// even though our client requests have VN=3.
//
// So allow both VN=3 and VN=4 in the server response. The response body format is identical for both anyway.
if packet.version_number != 3 && packet.version_number != 4 {
return Err(Error::BadServerResponse(
BadServerResponseReason::VersionNumber(packet.version_number),
));
}
if packet.mode != 4 {
return Err(Error::BadServerResponse(BadServerResponseReason::Mode(
packet.mode,
)));
}
if packet.originate_timestamp != request_transmit_timestamp {
return Err(Error::BadServerResponse(
BadServerResponseReason::OriginateTimestamp {
expected: request_transmit_timestamp,
actual: packet.originate_timestamp,
},
));
}
Ok(SntpTimeQueryResult {
local_clock_offset: ((packet.receive_timestamp - request_transmit_timestamp)
+ (packet.transmit_timestamp - destination_timestamp))
/ 2,
round_trip_delay: (destination_timestamp - request_transmit_timestamp)
- (packet.receive_timestamp - packet.transmit_timestamp),
})
}