use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use super::{CaptureSource, pcap_ts_us};
pub struct StdinSource {
cap: pcap::Capture<pcap::Offline>,
linktype: u32,
stop: Option<Arc<AtomicBool>>,
}
impl StdinSource {
pub unsafe fn open() -> anyhow::Result<Self> {
let cap = unsafe {
pcap::Capture::from_raw_fd(0)
.map_err(|e| anyhow::anyhow!("open stdin pcap stream: {e}"))?
};
let linktype = cap.get_datalink().0 as u32;
Ok(Self {
cap,
linktype,
stop: None,
})
}
}
impl CaptureSource for StdinSource {
fn set_stop(&mut self, stop: Arc<AtomicBool>) {
self.stop = Some(stop);
}
fn next_frame(&mut self, f: &mut dyn FnMut(u64, u32, &[u8])) -> bool {
loop {
if self
.stop
.as_ref()
.is_some_and(|s| s.load(Ordering::Relaxed))
{
return false;
}
match self.cap.next_packet() {
Ok(pkt) => {
f(pcap_ts_us(pkt.header), self.linktype, pkt.data);
return true;
}
Err(pcap::Error::NoMorePackets) => return false,
Err(pcap::Error::TimeoutExpired) => continue,
Err(e) => {
tracing::warn!(error = %e, "stdin capture error, stopping");
return false;
}
}
}
}
}