87 lines
3.2 KiB
Rust
87 lines
3.2 KiB
Rust
use std::mem;
|
|
use std::os::unix::net::UnixDatagram;
|
|
use std::path::PathBuf;
|
|
|
|
use async_trait::async_trait;
|
|
use libc::{c_double, c_int, timeval};
|
|
use tokio::select;
|
|
use tokio_util::sync::CancellationToken;
|
|
use tracing::{debug, info, warn};
|
|
|
|
use crate::{ChimemonMessage, ChimemonTarget, ChimemonTargetChannel, config::ChronySockConfig};
|
|
|
|
const CHRONY_MAGIC: c_int = 0x534f434b;
|
|
|
|
pub struct ChronySockServer {
|
|
name: String,
|
|
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 {}
|
|
|
|
#[async_trait]
|
|
impl ChimemonTarget for ChronySockServer {
|
|
type Config = ChronySockConfig;
|
|
fn new(name: &str, config: ChronySockConfig) -> Self {
|
|
ChronySockServer {
|
|
name: name.to_owned(),
|
|
sock_path: config.sock.into(),
|
|
}
|
|
}
|
|
async fn run(mut self, mut chan: ChimemonTargetChannel, cancel: CancellationToken) {
|
|
info!("Chrony refclock task started");
|
|
loop {
|
|
select! {
|
|
_ = cancel.cancelled() => { return }
|
|
msg = chan.recv() => {
|
|
match msg {
|
|
Ok(ChimemonMessage::TimeReport(tr)) => {
|
|
if tr.valid {
|
|
{
|
|
let frame = ChronyTimeReport {
|
|
tv: timeval {
|
|
tv_sec: TryInto::<libc::time_t>::try_into(
|
|
tr.system_time.timestamp(),
|
|
)
|
|
.unwrap(),
|
|
tv_usec: tr.system_time.timestamp_subsec_micros()
|
|
as libc::suseconds_t,
|
|
},
|
|
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::<ChronyTimeReport>(),
|
|
)
|
|
};
|
|
debug!("Sending to chrony sock {:#?}", frame);
|
|
let sock = UnixDatagram::unbound().unwrap();
|
|
sock.send_to(bs, &self.sock_path).unwrap();
|
|
}
|
|
}
|
|
},
|
|
Err(e) => warn!("Error receiving from channel: {}", e.to_string()),
|
|
_ => continue,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|