ntp_udp/
lib.rs

1//! This crate contains networking and timestamping code for ntpd-rs and is not
2//! intended as a public interface at this time. It follows the same version as the
3//! main ntpd-rs crate, but that version is not intended to give any stability
4//! guarantee. Use at your own risk.
5//!
6//! Please visit the [ntpd-rs](https://github.com/pendulum-project/ntpd-rs) project
7//! for more information.
8#![forbid(unsafe_op_in_unsafe_fn)]
9
10mod interface;
11mod raw_socket;
12mod socket;
13
14#[cfg(target_os = "linux")]
15mod hwtimestamp;
16
17use ntp_proto::NtpTimestamp;
18
19pub use interface::InterfaceName;
20use serde::Deserialize;
21pub use socket::UdpSocket;
22
23/// Enable the given timestamps. This is a hint!
24///
25/// Your OS or hardware might not actually support some timestamping modes.
26/// Unsupported timestamping modes are ignored.
27#[derive(Debug, Clone, Copy, Deserialize)]
28#[serde(rename_all = "kebab-case")]
29pub struct EnableTimestamps {
30    #[serde(default = "bool_true")]
31    pub rx_software: bool,
32    #[serde(default = "bool_true")]
33    pub tx_software: bool,
34    #[serde(default)] // defaults to `false`
35    pub rx_hardware: bool,
36    #[serde(default)] // defaults to `false`
37    pub tx_hardware: bool,
38}
39
40impl Default for EnableTimestamps {
41    fn default() -> Self {
42        Self {
43            rx_software: true,
44            tx_software: false,
45            rx_hardware: false,
46            tx_hardware: false,
47        }
48    }
49}
50
51#[derive(Clone, Copy)]
52pub(crate) enum LibcTimestamp {
53    #[cfg_attr(any(target_os = "macos", target_os = "freebsd"), allow(unused))]
54    TimeSpec {
55        seconds: i64,
56        nanos: i64,
57    },
58    TimeVal {
59        seconds: i64,
60        micros: i64,
61    },
62}
63
64impl LibcTimestamp {
65    #[cfg_attr(any(target_os = "macos", target_os = "freebsd"), allow(unused))]
66    fn from_timespec(timespec: libc::timespec) -> Self {
67        Self::TimeSpec {
68            seconds: timespec.tv_sec as _,
69            nanos: timespec.tv_nsec as _,
70        }
71    }
72
73    #[cfg_attr(target_os = "linux", allow(unused))]
74    fn from_timeval(timespec: libc::timeval) -> Self {
75        Self::TimeVal {
76            seconds: timespec.tv_sec as _,
77            micros: timespec.tv_usec as _,
78        }
79    }
80}
81
82impl LibcTimestamp {
83    pub(crate) fn into_ntp_timestamp(self) -> NtpTimestamp {
84        // Unix uses an epoch located at 1/1/1970-00:00h (UTC) and NTP uses 1/1/1900-00:00h.
85        // This leads to an offset equivalent to 70 years in seconds
86        // there are 17 leap years between the two dates so the offset is
87        const EPOCH_OFFSET: u32 = (70 * 365 + 17) * 86400;
88
89        match self {
90            LibcTimestamp::TimeSpec { seconds, nanos } => {
91                // truncates the higher bits of the i64
92                let seconds = (seconds as u32).wrapping_add(EPOCH_OFFSET);
93
94                // tv_nsec is always within [0, 1e10)
95                let nanos = nanos as u32;
96
97                NtpTimestamp::from_seconds_nanos_since_ntp_era(seconds, nanos)
98            }
99            LibcTimestamp::TimeVal { seconds, micros } => {
100                // truncates the higher bits of the i64
101                let seconds = (seconds as u32).wrapping_add(EPOCH_OFFSET);
102                let nanos = micros as u32 * 1000;
103
104                NtpTimestamp::from_seconds_nanos_since_ntp_era(seconds, nanos)
105            }
106        }
107    }
108}
109
110fn bool_true() -> bool {
111    true
112}