#[cfg(windows)]
mod windowsonly {
use bitflags::bitflags;
use std::{
sync::{
atomic::{AtomicU32, Ordering},
Arc,
},
thread::{sleep, spawn, JoinHandle},
time::Duration,
};
use windows_sys::Win32::{Foundation::HANDLE, System::Threading::SetEvent};
bitflags! {
pub(crate) struct CmdFlags: u32 {
const KILL = 0b00000001;
const SHOW_STATS = 0b00000010;
const ALL = {
Self::KILL.bits() | Self::SHOW_STATS.bits()
};
}
}
struct Controller {
jh: Option<JoinHandle<()>>,
cmdreq: Arc<AtomicU32>,
hev_wakeup: HANDLE,
}
impl Controller {
fn kill(mut self) {
self.cmdreq
.fetch_or(CmdFlags::KILL.bits(), Ordering::SeqCst);
unsafe {
if SetEvent(self.hev_wakeup) == 0 {
panic!("Unable to signal event");
}
}
if let Some(jh) = self.jh.take() {
let _ = jh.join();
}
}
fn show_stats(&self) {
self.cmdreq
.fetch_or(CmdFlags::SHOW_STATS.bits(), Ordering::SeqCst);
unsafe {
if SetEvent(self.hev_wakeup) == 0 {
panic!("Unable to signal event");
}
}
}
}
fn run_cap_loop(devname: &str) -> Controller {
let cap = pcap::Capture::from_device(devname).unwrap();
let mut cap = cap.open().unwrap();
let hev_wakeup = unsafe { cap.get_event() };
let cmdreq = AtomicU32::new(0);
let cmdreq = Arc::new(cmdreq);
let mut ctrl = Controller {
jh: None,
cmdreq: cmdreq.clone(),
hev_wakeup,
};
let jh = spawn(move || {
let mut pkt_count: u64 = 0;
let mut pkt_size: u64 = 0;
loop {
let res = cap.next_packet();
let cmd = cmdreq.fetch_and(0, Ordering::SeqCst);
if cmd & CmdFlags::KILL.bits() != 0 {
break;
}
if cmd & CmdFlags::SHOW_STATS.bits() != 0 {
println!("packet count: {pkt_count}");
println!("total packet size: {pkt_size}");
}
match res {
Ok(pkt) => {
println!("Got a packet!");
pkt_count += 1;
pkt_size += pkt.len() as u64;
}
Err(pcap::Error::TimeoutExpired) => {
continue;
}
Err(e) => {
eprintln!("{e}");
break;
}
}
}
});
ctrl.jh = Some(jh);
ctrl
}
pub fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let ctrl = run_cap_loop(&args[0]);
println!("Waiting 1 second ..");
sleep(Duration::from_secs(1));
println!("Tell capture thread to show stats ..");
ctrl.show_stats();
println!("Waiting 1 second ..");
sleep(Duration::from_secs(1));
println!("Tell capture thread to show stats ..");
ctrl.show_stats();
println!("Waiting 1 second ..");
sleep(Duration::from_secs(1));
println!("Tell capture thread to terminate ..");
ctrl.kill();
println!("Done -- bye");
}
}
fn main() {
#[cfg(windows)]
windowsonly::main();
#[cfg(not(windows))]
println!("winevt example is for Windows platforms only");
}