use async_trait::async_trait; use chimemon::{ChimemonMessage, ChimemonTarget, ChimemonTargetChannel, ChronySockConfig}; use libc::{c_double, c_int, timeval}; use log::debug; use std::mem; use std::os::unix::net::UnixDatagram; use std::path::PathBuf; const CHRONY_MAGIC: c_int = 0x534f434b; pub struct ChronySockServer { sock_path: PathBuf, } #[repr(C)] #[derive(Debug)] pub struct ChronyTimeReport { tv: timeval, offset: c_double, pulse: c_int, leap: c_int, _pad: c_int, magic: c_int, } impl ChronySockServer { pub fn new(config: ChronySockConfig) -> Self { ChronySockServer { sock_path: config.sock.into(), } } } #[async_trait] impl ChimemonTarget for ChronySockServer { async fn run(mut self, mut chan: ChimemonTargetChannel) { loop { let msg = chan.recv().await.unwrap(); match msg { ChimemonMessage::TimeReport(tr) => { if tr.valid { { let frame = ChronyTimeReport { tv: timeval { tv_sec: tr.system_time.timestamp(), tv_usec: tr.system_time.timestamp(), }, offset: tr.offset.num_nanoseconds().unwrap() as f64 / 1e9, leap: if tr.leap_flag { 1 } else { 0 }, pulse: 0, _pad: 0, magic: CHRONY_MAGIC, }; let bs = unsafe { std::slice::from_raw_parts( (&frame as *const ChronyTimeReport) as *const u8, mem::size_of::(), ) }; debug!("Sending to chrony sock {:#?}", frame); let sock = UnixDatagram::unbound().unwrap(); sock.send_to(bs, &self.sock_path).unwrap(); } } } _ => continue, } } } }