use flowscope::extract::FiveTuple;
use flowscope::pcap::PcapFlowSource;
use flowscope::reassembler::BufferedReassemblerFactory;
use flowscope::tracker::FlowTrackerConfig;
use flowscope::{
AnomalyKind, EndReason, FlowDriver, FlowEvent, MemcapPolicy, OverflowPolicy, Timestamp,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = std::env::args()
.nth(1)
.unwrap_or_else(|| "tests/data/mixed_short.pcap".to_string());
println!("=== Scenario A — DropFlow per-reassembler ===");
run(
&path,
"drop_flow",
FlowTrackerConfig::default(),
BufferedReassemblerFactory::default()
.with_max_buffer(16 * 1024)
.with_overflow_policy(OverflowPolicy::DropFlow),
)?;
println!();
println!("=== Scenario B — SlidingWindow per-reassembler ===");
run(
&path,
"sliding_window",
FlowTrackerConfig::default(),
BufferedReassemblerFactory::default()
.with_max_buffer(16 * 1024)
.with_overflow_policy(OverflowPolicy::SlidingWindow),
)?;
println!();
println!("=== Scenario C — Cross-flow memcap, DropFlow ===");
let mut cfg = FlowTrackerConfig::default();
cfg.reassembly_memcap = Some(64 * 1024);
cfg.reassembly_memcap_policy = MemcapPolicy::DropFlow;
run(
&path,
"memcap_drop_flow",
cfg,
BufferedReassemblerFactory::default(),
)?;
Ok(())
}
fn run(
path: &str,
label: &str,
cfg: FlowTrackerConfig,
factory: BufferedReassemblerFactory,
) -> Result<(), Box<dyn std::error::Error>> {
let mut driver =
FlowDriver::with_config(FiveTuple::bidirectional(), factory, cfg).with_emit_anomalies(true);
let mut last_ts = Timestamp { sec: 0, nsec: 0 };
let mut overflow_endings = 0u64;
let mut memcap_hits = 0u64;
let mut total_ended = 0u64;
let mut total_packets = 0u64;
for view in PcapFlowSource::open(path)?.views() {
let view = view?;
total_packets += 1;
last_ts = view.timestamp;
for ev in driver.track(&view) {
classify(
&ev,
&mut overflow_endings,
&mut memcap_hits,
&mut total_ended,
);
}
}
for ev in driver.sweep(last_ts) {
classify(
&ev,
&mut overflow_endings,
&mut memcap_hits,
&mut total_ended,
);
}
println!(
"[{label}] packets={total_packets} ended={total_ended} buffer_overflow={overflow_endings} \
memcap_hits={memcap_hits}"
);
Ok(())
}
fn classify<K>(
ev: &FlowEvent<K>,
overflow_endings: &mut u64,
memcap_hits: &mut u64,
total_ended: &mut u64,
) {
match ev {
FlowEvent::Ended {
reason: EndReason::BufferOverflow,
..
} => {
*overflow_endings += 1;
*total_ended += 1;
}
FlowEvent::Ended { .. } => *total_ended += 1,
FlowEvent::TrackerAnomaly {
kind: AnomalyKind::GlobalMemcapHit { .. },
..
} => {
*memcap_hits += 1;
}
_ => {}
}
}