1use byteorder::{BE, ReadBytesExt, WriteBytesExt};
2use std::io;
3
4#[cfg(feature = "ntpv5")]
5use super::ntpv5::{NtpV5Flags, PacketV5, Time32, Timescale};
6use super::{
7 DateFormat, KissOfDeath, LeapIndicator, Mode, Packet, PrimarySource, ReadBytes, ReadFromBytes,
8 ReferenceIdentifier, ShortFormat, Stratum, TimestampFormat, Version, WriteBytes, WriteToBytes,
9 be_u32_to_bytes,
10};
11
12impl<W> WriteBytes for W
15where
16 W: WriteBytesExt,
17{
18 fn write_bytes<P: WriteToBytes>(&mut self, protocol: P) -> io::Result<()> {
19 protocol.write_to_bytes(self)
20 }
21}
22
23impl<P> WriteToBytes for &P
24where
25 P: WriteToBytes,
26{
27 fn write_to_bytes<W: WriteBytesExt>(&self, writer: W) -> io::Result<()> {
28 (*self).write_to_bytes(writer)
29 }
30}
31
32impl WriteToBytes for ShortFormat {
33 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
34 writer.write_u16::<BE>(self.seconds)?;
35 writer.write_u16::<BE>(self.fraction)?;
36 Ok(())
37 }
38}
39
40impl WriteToBytes for TimestampFormat {
41 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
42 writer.write_u32::<BE>(self.seconds)?;
43 writer.write_u32::<BE>(self.fraction)?;
44 Ok(())
45 }
46}
47
48impl WriteToBytes for DateFormat {
49 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
50 writer.write_i32::<BE>(self.era_number)?;
51 writer.write_u32::<BE>(self.era_offset)?;
52 writer.write_u64::<BE>(self.fraction)?;
53 Ok(())
54 }
55}
56
57impl WriteToBytes for Stratum {
58 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
59 writer.write_u8(self.0)?;
60 Ok(())
61 }
62}
63
64impl WriteToBytes for ReferenceIdentifier {
65 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
66 match *self {
67 ReferenceIdentifier::KissOfDeath(kod) => {
68 writer.write_u32::<BE>(kod as u32)?;
69 }
70 ReferenceIdentifier::PrimarySource(src) => {
71 writer.write_u32::<BE>(src as u32)?;
72 }
73 ReferenceIdentifier::SecondaryOrClient(arr) => {
74 writer.write_u32::<BE>(code_to_u32!(&arr))?;
75 }
76 ReferenceIdentifier::Unknown(arr) => {
77 writer.write_u32::<BE>(code_to_u32!(&arr))?;
78 }
79 }
80 Ok(())
81 }
82}
83
84impl WriteToBytes for (LeapIndicator, Version, Mode) {
85 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
86 let (li, vn, mode) = *self;
87 let mut li_vn_mode = 0;
88 li_vn_mode |= (li as u8) << 6;
89 li_vn_mode |= vn.0 << 3;
90 li_vn_mode |= mode as u8;
91 writer.write_u8(li_vn_mode)?;
92 Ok(())
93 }
94}
95
96impl WriteToBytes for Packet {
97 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
98 let li_vn_mode = (self.leap_indicator, self.version, self.mode);
99 writer.write_bytes(li_vn_mode)?;
100 writer.write_bytes(self.stratum)?;
101 writer.write_i8(self.poll)?;
102 writer.write_i8(self.precision)?;
103 writer.write_bytes(self.root_delay)?;
104 writer.write_bytes(self.root_dispersion)?;
105 writer.write_bytes(self.reference_id)?;
106 writer.write_bytes(self.reference_timestamp)?;
107 writer.write_bytes(self.origin_timestamp)?;
108 writer.write_bytes(self.receive_timestamp)?;
109 writer.write_bytes(self.transmit_timestamp)?;
110 Ok(())
111 }
112}
113
114impl<R> ReadBytes for R
117where
118 R: ReadBytesExt,
119{
120 fn read_bytes<P: ReadFromBytes>(&mut self) -> io::Result<P> {
121 P::read_from_bytes(self)
122 }
123}
124
125impl ReadFromBytes for ShortFormat {
126 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
127 let seconds = reader.read_u16::<BE>()?;
128 let fraction = reader.read_u16::<BE>()?;
129 let short_format = ShortFormat { seconds, fraction };
130 Ok(short_format)
131 }
132}
133
134impl ReadFromBytes for TimestampFormat {
135 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
136 let seconds = reader.read_u32::<BE>()?;
137 let fraction = reader.read_u32::<BE>()?;
138 let timestamp_format = TimestampFormat { seconds, fraction };
139 Ok(timestamp_format)
140 }
141}
142
143impl ReadFromBytes for DateFormat {
144 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
145 let era_number = reader.read_i32::<BE>()?;
146 let era_offset = reader.read_u32::<BE>()?;
147 let fraction = reader.read_u64::<BE>()?;
148 let date_format = DateFormat {
149 era_number,
150 era_offset,
151 fraction,
152 };
153 Ok(date_format)
154 }
155}
156
157impl ReadFromBytes for Stratum {
158 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
159 let stratum = Stratum(reader.read_u8()?);
160 Ok(stratum)
161 }
162}
163
164impl ReadFromBytes for (LeapIndicator, Version, Mode) {
165 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
166 let li_vn_mode = reader.read_u8()?;
167 let li_u8 = li_vn_mode >> 6;
168 let vn_u8 = (li_vn_mode >> 3) & 0b111;
169 let mode_u8 = li_vn_mode & 0b111;
170 let li = match LeapIndicator::try_from(li_u8).ok() {
171 Some(li) => li,
172 None => {
173 let err_msg = "unknown leap indicator";
174 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
175 }
176 };
177 let vn = Version(vn_u8);
178 let mode = match Mode::try_from(mode_u8).ok() {
179 Some(mode) => mode,
180 None => {
181 let err_msg = "unknown association mode";
182 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
183 }
184 };
185 Ok((li, vn, mode))
186 }
187}
188
189impl ReadFromBytes for Packet {
190 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
191 let (leap_indicator, version, mode) = reader.read_bytes()?;
192 let stratum = reader.read_bytes::<Stratum>()?;
193 let poll = reader.read_i8()?;
194 let precision = reader.read_i8()?;
195 let root_delay = reader.read_bytes()?;
196 let root_dispersion = reader.read_bytes()?;
197 let reference_id = {
198 let u = reader.read_u32::<BE>()?;
199 let raw_bytes = be_u32_to_bytes(u);
200 if stratum == Stratum::UNSPECIFIED {
201 match KissOfDeath::try_from(u) {
203 Ok(kod) => ReferenceIdentifier::KissOfDeath(kod),
204 Err(_) => ReferenceIdentifier::Unknown(raw_bytes),
205 }
206 } else if stratum == Stratum::PRIMARY {
207 match PrimarySource::try_from(u) {
209 Ok(src) => ReferenceIdentifier::PrimarySource(src),
210 Err(_) => ReferenceIdentifier::Unknown(raw_bytes),
211 }
212 } else if stratum.is_secondary() {
213 ReferenceIdentifier::SecondaryOrClient(raw_bytes)
215 } else {
216 ReferenceIdentifier::Unknown(raw_bytes)
218 }
219 };
220 let reference_timestamp = reader.read_bytes()?;
221 let origin_timestamp = reader.read_bytes()?;
222 let receive_timestamp = reader.read_bytes()?;
223 let transmit_timestamp = reader.read_bytes()?;
224 Ok(Packet {
225 leap_indicator,
226 version,
227 mode,
228 stratum,
229 poll,
230 precision,
231 root_delay,
232 root_dispersion,
233 reference_id,
234 reference_timestamp,
235 origin_timestamp,
236 receive_timestamp,
237 transmit_timestamp,
238 })
239 }
240}
241
242#[cfg(feature = "ntpv5")]
247impl WriteToBytes for Time32 {
248 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
249 writer.write_u32::<BE>(self.0)?;
250 Ok(())
251 }
252}
253
254#[cfg(feature = "ntpv5")]
255impl ReadFromBytes for Time32 {
256 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
257 let raw = reader.read_u32::<BE>()?;
258 Ok(Time32(raw))
259 }
260}
261
262#[cfg(feature = "ntpv5")]
263impl WriteToBytes for Timescale {
264 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
265 writer.write_u8(*self as u8)?;
266 Ok(())
267 }
268}
269
270#[cfg(feature = "ntpv5")]
271impl ReadFromBytes for Timescale {
272 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
273 let raw = reader.read_u8()?;
274 Timescale::try_from(raw)
275 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "unknown timescale value"))
276 }
277}
278
279#[cfg(feature = "ntpv5")]
280impl WriteToBytes for NtpV5Flags {
281 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
282 writer.write_u16::<BE>(self.0)?;
283 Ok(())
284 }
285}
286
287#[cfg(feature = "ntpv5")]
288impl ReadFromBytes for NtpV5Flags {
289 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
290 let raw = reader.read_u16::<BE>()?;
291 Ok(NtpV5Flags(raw))
292 }
293}
294
295#[cfg(feature = "ntpv5")]
296impl WriteToBytes for PacketV5 {
297 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
298 let li_vn_mode = (self.leap_indicator, self.version, self.mode);
299 writer.write_bytes(li_vn_mode)?;
300 writer.write_bytes(self.stratum)?;
301 writer.write_i8(self.poll)?;
302 writer.write_i8(self.precision)?;
303 writer.write_bytes(self.root_delay)?;
304 writer.write_bytes(self.root_dispersion)?;
305 writer.write_bytes(self.timescale)?;
306 writer.write_u8(self.era)?;
307 writer.write_bytes(self.flags)?;
308 writer.write_u64::<BE>(self.server_cookie)?;
309 writer.write_u64::<BE>(self.client_cookie)?;
310 writer.write_bytes(self.receive_timestamp)?;
311 writer.write_bytes(self.transmit_timestamp)?;
312 Ok(())
313 }
314}
315
316#[cfg(feature = "ntpv5")]
317impl ReadFromBytes for PacketV5 {
318 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
319 let (leap_indicator, version, mode) = reader.read_bytes()?;
320 let stratum = reader.read_bytes::<Stratum>()?;
321 let poll = reader.read_i8()?;
322 let precision = reader.read_i8()?;
323 let root_delay = reader.read_bytes::<Time32>()?;
324 let root_dispersion = reader.read_bytes::<Time32>()?;
325 let timescale = reader.read_bytes::<Timescale>()?;
326 let era = reader.read_u8()?;
327 let flags = reader.read_bytes::<NtpV5Flags>()?;
328 let server_cookie = reader.read_u64::<BE>()?;
329 let client_cookie = reader.read_u64::<BE>()?;
330 let receive_timestamp = reader.read_bytes()?;
331 let transmit_timestamp = reader.read_bytes()?;
332 Ok(PacketV5 {
333 leap_indicator,
334 version,
335 mode,
336 stratum,
337 poll,
338 precision,
339 root_delay,
340 root_dispersion,
341 timescale,
342 era,
343 flags,
344 server_cookie,
345 client_cookie,
346 receive_timestamp,
347 transmit_timestamp,
348 })
349 }
350}