1use bitflags::bitflags;
9use bytes::{Buf, BufMut};
10use chrony_candm_derive::{ChronyMessage, ChronySerialize};
11use num_enum::{IntoPrimitive, TryFromPrimitive};
12use std::time::{SystemTime, UNIX_EPOCH};
13
14use crate::common::*;
15
16#[repr(u16)]
17#[derive(
18 Debug,
19 Copy,
20 Clone,
21 PartialEq,
22 Eq,
23 Ord,
24 PartialOrd,
25 Hash,
26 IntoPrimitive,
27 TryFromPrimitive,
28 ChronySerialize,
29)]
30pub enum Status {
31 Success,
32 Failed,
33 Unauth,
34 Invalid,
35 NoSuchSource,
36 InvalidTs,
37 NotEnabled,
38 BadSubnet,
39 AccessAllowed,
40 AccessDenied,
41 NoHostAccess,
42 SourceAlreadyKnown,
43 TooManySources,
44 NoRtc,
45 BadRtcFile,
46 Inactive,
47 BadSample,
48 InvalidAf,
49 BadPktVersion,
50 BadPktLength,
51 InvalidName,
52}
53#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
54pub struct NSources {
55 pub n_sources: u32,
56}
57
58#[repr(u16)]
59#[derive(
60 Debug,
61 Copy,
62 Clone,
63 PartialEq,
64 Eq,
65 Ord,
66 PartialOrd,
67 Hash,
68 IntoPrimitive,
69 TryFromPrimitive,
70 ChronySerialize,
71)]
72pub enum SourceMode {
73 Client,
74 Peer,
75 Ref,
76}
77
78#[repr(u16)]
79#[derive(
80 Debug,
81 Copy,
82 Clone,
83 PartialEq,
84 Eq,
85 Ord,
86 PartialOrd,
87 Hash,
88 IntoPrimitive,
89 TryFromPrimitive,
90 ChronySerialize,
91)]
92pub enum SourceState {
93 Selected,
94 NonSelectable,
95 Falseticker,
96 Jittery,
97 Unselected,
98 Selectable,
99}
100
101#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
102pub struct SourceData {
103 pub ip_addr: ChronyAddr,
104 pub poll: i16,
105 pub stratum: u16,
106 pub state: SourceState,
107 pub mode: SourceMode,
108 pub flags: SourceFlags,
109 pub reachability: u16,
110 pub since_sample: u32,
111 pub orig_latest_meas: ChronyFloat,
112 pub latest_meas: ChronyFloat,
113 pub latest_meas_err: ChronyFloat,
114}
115
116#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
117pub struct Tracking {
118 pub ref_id: u32,
119 pub ip_addr: ChronyAddr,
120 pub stratum: u16,
121 pub leap_status: u16,
122 pub ref_time: SystemTime,
123 pub current_correction: ChronyFloat,
124 pub last_offset: ChronyFloat,
125 pub rms_offset: ChronyFloat,
126 pub freq_ppm: ChronyFloat,
127 pub resid_freq_ppm: ChronyFloat,
128 pub skew_ppm: ChronyFloat,
129 pub root_delay: ChronyFloat,
130 pub root_dispersion: ChronyFloat,
131 pub last_update_interval: ChronyFloat,
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
135pub struct SourceStats {
136 pub ref_id: u32,
137 pub ip_addr: ChronyAddr,
138 pub n_samples: u32,
139 pub n_runs: u32,
140 pub span_seconds: u32,
141 pub sd: ChronyFloat,
142 pub resid_freq_ppm: ChronyFloat,
143 pub skew_ppm: ChronyFloat,
144 pub est_offset: ChronyFloat,
145 pub est_offset_err: ChronyFloat,
146}
147
148#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
149pub struct Rtc {
150 pub ref_time: SystemTime,
151 pub n_samples: u16,
152 pub n_runs: u16,
153 pub span_seconds: u32,
154 pub rtc_seconds_fast: ChronyFloat,
155 pub rtc_gain_rate_ppm: ChronyFloat,
156}
157
158#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
159pub struct ManualTimestamp {
160 pub offset: ChronyFloat,
161 pub dfreq_ppm: ChronyFloat,
162 pub new_afreq_ppm: ChronyFloat,
163}
164
165#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize, Default)]
166pub struct ClientAccessesClient {
167 pub ip: ChronyAddr,
168 pub ntp_hits: u32,
169 pub nke_hits: u32,
170 pub cmd_hits: u32,
171 pub ntp_drops: u32,
172 pub nke_drops: u32,
173 pub cmd_drops: u32,
174 pub ntp_interval: u8,
175 pub nke_interval: u8,
176 pub cmd_interval: u8,
177 pub ntp_timeout_interval: u8,
178 pub last_ntp_hit_ago: u32,
179 pub last_nke_hit_ago: u32,
180 pub last_cmd_hit_ago: u32,
181}
182
183#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
184pub struct ClientAccessesByIndex {
185 pub n_indices: u32,
186 pub next_index: u32,
187 pub n_clients: u32,
188 pub clients: [ClientAccessesClient; 8],
189}
190
191#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
192pub struct ServerStats {
193 pub ntp_hits: u32,
194 pub nke_hits: u32,
195 pub cmd_hits: u32,
196 pub ntp_drops: u32,
197 pub nke_drops: u32,
198 pub cmd_drops: u32,
199 pub log_drops: u32,
200 pub ntp_auth_hits: u32,
201}
202
203#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
204pub struct ServerStats4 {
205 pub ntp_hits: u64,
206 pub nke_hits: u64,
207 pub cmd_hits: u64,
208 pub ntp_drops: u64,
209 pub nke_drops: u64,
210 pub cmd_drops: u64,
211 pub log_drops: u64,
212 pub ntp_auth_hits: u64,
213 pub ntp_interleaved_hits: u64,
214 pub ntp_timestamps: u64,
215 pub ntp_span_seconds: u64,
216 pub ntp_daemon_rx_timestamps: u64,
217 pub ntp_daemon_tx_timestamps: u64,
218 pub ntp_kernel_rx_timestamps: u64,
219 pub ntp_kernel_tx_timestamps: u64,
220 pub ntp_hw_rx_timestamps: u64,
221 pub ntp_hw_tx_timestamps: u64,
222 reserved: [u64; 4],
223}
224
225#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
226pub struct ManualListSample {
227 pub when: SystemTime,
228 pub slewed_offset: ChronyFloat,
229 pub orig_offset: ChronyFloat,
230 pub residual: ChronyFloat,
231}
232
233impl Default for ManualListSample {
234 fn default() -> Self {
235 Self {
236 when: UNIX_EPOCH,
237 slewed_offset: Default::default(),
238 orig_offset: Default::default(),
239 residual: Default::default(),
240 }
241 }
242}
243
244#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
245pub struct ManualList {
246 pub n_samples: u32,
247 pub samples: [ManualListSample; 16],
248}
249
250#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
251pub struct Activity {
252 pub online: u32,
253 pub offline: u32,
254 pub burst_online: u32,
255 pub burst_offline: u32,
256 pub unresolved: u32,
257}
258
259bitflags! {
260 #[derive(ChronySerialize)]
261 pub struct SmoothingFlags : u32 {
262 const ACTIVE = 0x1;
263 const LEAPONLY = 0x2;
264 }
265}
266
267#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
268pub struct Smoothing {
269 pub flags: SmoothingFlags,
270 pub offset: ChronyFloat,
271 pub freq_ppm: ChronyFloat,
272 pub wander_ppm: ChronyFloat,
273 pub last_update_ago: ChronyFloat,
274 pub remaining_time: ChronyFloat,
275}
276
277bitflags! {
278 #[derive(ChronySerialize)]
279 pub struct NtpFlags : u16 {
280 const TESTS = 0x3ff;
281 const INTERLEAVED = 0x4000;
282 const AUTHENTICATED = 0x8000;
283 }
284}
285
286#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
287pub struct NtpData {
288 pub remote_addr: ChronyAddr,
289 pub local_addr: ChronyAddr,
290 pub remote_port: u16,
291 pub leap: u8,
292 pub version: u8,
293 pub mode: u8,
294 pub stratum: u8,
295 pub poll: i8,
296 pub precision: i8,
297 pub root_delay: ChronyFloat,
298 pub root_dispersion: ChronyFloat,
299 pub ref_id: u32,
300 pub ref_time: SystemTime,
301 pub offset: ChronyFloat,
302 pub peer_delay: ChronyFloat,
303 pub peer_dispersion: ChronyFloat,
304 pub response_time: ChronyFloat,
305 pub jitter_asymmetry: ChronyFloat,
306 pub flags: NtpFlags,
307 pub tx_tss_char: u8,
308 pub rx_tss_char: u8,
309 pub total_tx_count: u32,
310 pub total_rx_count: u32,
311 #[pad = 16]
312 pub total_valid_count: u32,
313}
314
315#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
316pub struct NtpSourceName {
317 pub name: [u8; 256],
318}
319
320#[repr(u16)]
321#[derive(
322 Debug,
323 Copy,
324 Clone,
325 PartialEq,
326 Eq,
327 Ord,
328 PartialOrd,
329 Hash,
330 IntoPrimitive,
331 TryFromPrimitive,
332 ChronySerialize,
333)]
334pub enum AuthDataMode {
335 None,
336 Symmetric,
337 Nts,
338}
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
341pub struct AuthData {
342 pub mode: AuthDataMode,
343 pub key_type: u16,
344 pub key_id: u32,
345 pub key_length: u16,
346 pub ke_attempts: u16,
347 pub last_ke_ago: u32,
348 pub cookies: u16,
349 pub cookies_length: u16,
350 #[pad = 2]
351 pub nak: u16,
352}
353
354bitflags! {
355 #[derive(ChronySerialize)]
356 pub struct SelectDataOptions : u16 {
357 const NOSELECT = 0x1;
358 const PREFER = 0x2;
359 const TRUST = 0x4;
360 const REQUIRE = 0x8;
361 }
362}
363
364#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
365pub struct SelectData {
366 pub ref_id: u32,
367 pub ip_addr: ChronyAddr,
368 pub state_char: u8,
369 pub authentication: u8,
370 pub leap: u8,
371 pub pad: u8,
372 pub conf_options: SelectDataOptions,
373 pub eff_options: SelectDataOptions,
374 pub last_sample_ago: u32,
375 pub score: ChronyFloat,
376 pub lo_limit: ChronyFloat,
377 pub hi_limit: ChronyFloat,
378}
379
380#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronyMessage)]
381pub enum ReplyBody {
382 #[cmd = 1]
383 Null,
384 NSources(NSources),
385 SourceData(SourceData),
386 ManualTimestamp,
387 Tracking(Tracking),
388 SourceStats(SourceStats),
389 Rtc(Rtc),
390 #[cmd = 12]
391 Activity(Activity),
392 Smoothing(Smoothing),
393 #[cmd = 16]
394 NtpData(NtpData),
395 ManualTimestamp2(ManualTimestamp),
396 ManualList2(ManualList),
397 NtpSourceName(NtpSourceName),
398 AuthData(AuthData),
399 ClientAccessesByIndex3(ClientAccessesByIndex),
400 ServerStats2(ServerStats),
401 SelectData(SelectData),
402 #[cmd = 25]
403 ServerStats4(ServerStats4),
404}
405
406#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
408pub struct Reply {
409 pub status: Status,
411 pub cmd: u16,
413 pub sequence: u32,
415 pub body: ReplyBody,
417}
418
419impl Reply {
420 pub fn length(&self) -> usize {
422 REPLY_HEADER_LENGTH + self.body.body_length()
423 }
424
425 pub fn serialize<B: BufMut>(&self, buf: &mut B) {
429 let reply = self.body.cmd();
430
431 buf.put_u8(6); buf.put_u8(2); buf.put_u8(0); buf.put_u8(0); buf.put_u16(self.cmd); buf.put_u16(reply);
437 self.status.serialize(buf);
438 buf.put_u16(0); buf.put_u16(0); buf.put_u16(0); buf.put_u32(self.sequence);
442 buf.put_u32(0); buf.put_u32(0); self.body.serialize_body(buf);
445 }
446
447 pub fn deserialize<B: Buf>(buf: &mut B) -> Result<Self, DeserializationError> {
449 if buf.remaining() < REPLY_HEADER_LENGTH {
450 return Err(DeserializationError::new("message too short"));
451 }
452 if buf.get_u8() != 6 {
453 return Err(DeserializationError::new("unsupported version"));
455 }
456
457 if buf.get_u8() != 2 {
458 return Err(DeserializationError::new("wrong packet type"));
460 }
461
462 buf.get_u8(); buf.get_u8(); let cmd = buf.get_u16();
465 let reply = buf.get_u16();
466 let status = Status::deserialize_unchecked(buf)?;
467 buf.get_u16(); buf.get_u16(); buf.get_u16(); let sequence = buf.get_u32();
471 buf.get_u32(); buf.get_u32(); let body = ReplyBody::deserialize_body(reply, buf)?;
474 Ok(Self {
475 status,
476 cmd,
477 sequence,
478 body,
479 })
480 }
481}