use std::{hash::Hash, sync::Arc, time::Duration};
use crossbeam_queue::SegQueue;
use super::{
BroadcastSlotHandle,
broadcast::BroadcastInner,
slot::SlotHandle,
typed_slot::{DatagramSlot, ErasedSlot, Order, SessionSlot},
};
use crate::{
PacketView, Timestamp,
dedup::Dedup,
detect::signatures::SignatureFn,
event::{AnomalyKind, EndReason, FlowEvent, FlowSide, FlowState, FlowStats},
extractor::{FlowExtractor, L4Proto, Orientation, TcpInfo},
flow_driver::FlowDriver,
history::HistoryString,
parser_kind::{ParserKind, SlotId},
reassembler::StreamChunks,
segment_reassembler::SegmentBufferReassemblerFactory,
session::{
DatagramParser, DatagramParserFactory, SessionParser, SessionParserFactory,
TemplateFactory,
core::{
Ctx, DEFAULT_PROBE_PACKETS, DatagramCore, Emit, Ports, Selector, SessionCore, Stream,
},
engine::{Dispatch, Engine},
},
tracker::{FlowTracker, FlowTrackerConfig},
};
type IdleTimeoutFn<K> =
Box<dyn Fn(&K, Option<L4Proto>) -> Option<Duration> + Send + Sync + 'static>;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
#[cfg_attr(feature = "serde", serde(bound(serialize = "K: serde::Serialize")))]
#[non_exhaustive]
pub enum Event<K> {
Started {
key: K,
orientation: Orientation,
ts: Timestamp,
l4: Option<L4Proto>,
},
Established {
key: K,
ts: Timestamp,
l4: Option<L4Proto>,
},
StateChange {
key: K,
from: FlowState,
to: FlowState,
ts: Timestamp,
},
#[non_exhaustive]
Packet {
key: K,
side: FlowSide,
orientation: Orientation,
len: usize,
ts: Timestamp,
tcp: Option<TcpInfo>,
source_idx: Option<u32>,
},
Ended {
key: K,
reason: EndReason,
stats: FlowStats,
history: HistoryString,
l4: Option<L4Proto>,
ts: Timestamp,
},
Tick {
key: K,
stats: FlowStats,
ts: Timestamp,
},
#[non_exhaustive]
ParserClosed {
key: K,
slot: SlotId,
parser_kind: ParserKind,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
},
#[non_exhaustive]
ParserSideStopped {
key: K,
slot: SlotId,
parser_kind: ParserKind,
side: FlowSide,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
},
FlowAnomaly {
key: K,
kind: AnomalyKind,
ts: Timestamp,
},
TrackerAnomaly { kind: AnomalyKind, ts: Timestamp },
}
impl<K> Event<K> {
pub fn key(&self) -> Option<&K> {
match self {
Event::Started { key, .. }
| Event::Established { key, .. }
| Event::StateChange { key, .. }
| Event::Packet { key, .. }
| Event::Ended { key, .. }
| Event::Tick { key, .. }
| Event::ParserClosed { key, .. }
| Event::ParserSideStopped { key, .. }
| Event::FlowAnomaly { key, .. } => Some(key),
Event::TrackerAnomaly { .. } => None,
}
}
pub fn tcp(&self) -> Option<&TcpInfo> {
match self {
Event::Packet { tcp, .. } => tcp.as_ref(),
_ => None,
}
}
pub fn timestamp(&self) -> Timestamp {
match self {
Event::Started { ts, .. }
| Event::Established { ts, .. }
| Event::StateChange { ts, .. }
| Event::Packet { ts, .. }
| Event::Ended { ts, .. }
| Event::Tick { ts, .. }
| Event::ParserClosed { ts, .. }
| Event::ParserSideStopped { ts, .. }
| Event::FlowAnomaly { ts, .. }
| Event::TrackerAnomaly { ts, .. } => *ts,
}
}
pub fn into_flow_event(self) -> Option<FlowEvent<K>> {
Some(match self {
Event::Started {
key,
orientation,
ts,
l4,
} => FlowEvent::Started {
key,
side: FlowSide::Initiator,
orientation,
ts,
l4,
},
Event::Established { key, ts, l4 } => FlowEvent::Established { key, ts, l4 },
Event::StateChange { key, from, to, ts } => {
FlowEvent::StateChange { key, from, to, ts }
}
Event::Packet {
key,
side,
orientation,
len,
ts,
tcp: _,
source_idx,
} => FlowEvent::Packet {
key,
side,
orientation,
len,
ts,
source_idx,
},
Event::Ended {
key,
reason,
stats,
history,
l4,
ts: _,
} => FlowEvent::Ended {
key,
reason,
stats,
history,
l4,
},
Event::Tick { key, stats, ts } => FlowEvent::Tick { key, stats, ts },
Event::FlowAnomaly { key, kind, ts } => FlowEvent::FlowAnomaly { key, kind, ts },
Event::TrackerAnomaly { kind, ts } => FlowEvent::TrackerAnomaly { kind, ts },
Event::ParserClosed { .. } | Event::ParserSideStopped { .. } => return None,
})
}
pub fn to_flow_event(&self) -> Option<FlowEvent<K>>
where
K: Clone,
{
self.clone().into_flow_event()
}
}
impl<K> From<FlowEvent<K>> for Event<K> {
fn from(ev: FlowEvent<K>) -> Self {
match ev {
FlowEvent::Started {
key,
side,
orientation,
ts,
l4,
} => Event::Started {
key,
orientation: match side {
FlowSide::Initiator => orientation,
FlowSide::Responder => orientation.flipped(),
},
ts,
l4,
},
FlowEvent::Established { key, ts, l4 } => Event::Established { key, ts, l4 },
FlowEvent::StateChange { key, from, to, ts } => {
Event::StateChange { key, from, to, ts }
}
FlowEvent::Packet {
key,
side,
orientation,
len,
ts,
source_idx,
} => Event::Packet {
key,
side,
orientation,
len,
ts,
tcp: None,
source_idx,
},
FlowEvent::Ended {
key,
reason,
stats,
history,
l4,
} => {
let ts = stats.last_seen;
Event::Ended {
key,
reason,
stats,
history,
l4,
ts,
}
}
FlowEvent::Tick { key, stats, ts } => Event::Tick { key, stats, ts },
FlowEvent::FlowAnomaly { key, kind, ts } => Event::FlowAnomaly { key, kind, ts },
FlowEvent::TrackerAnomaly { kind, ts } => Event::TrackerAnomaly { kind, ts },
}
}
}
struct Slots<K> {
list: Vec<Box<dyn ErasedSlot<K> + Send + Sync>>,
needs_ports: bool,
emit_packet_details: bool,
order: Order,
}
impl<K> Dispatch<K> for Slots<K>
where
K: Hash + Eq + Clone,
{
type Out = Vec<Event<K>>;
fn needs_ports(&self) -> bool {
self.needs_ports
}
fn wants_stream(&self, ports: Ports) -> bool {
self.list.iter().any(|s| s.wants_stream(ports))
}
fn wants_datagram(&self, ports: Ports, l4: Option<crate::L4Proto>) -> bool {
self.list.iter().any(|s| s.wants_datagram(ports, l4))
}
fn on_stream(
&mut self,
cx: &Ctx<'_, K>,
ports: Ports,
chunks: &Stream<'_>,
out: &mut Self::Out,
) {
for slot in &mut self.list {
slot.on_stream(cx, ports, chunks, out, &mut self.order);
}
}
fn streams_done(&self, key: &K, ports: Ports) -> [bool; 2] {
let mut done = [true, true];
for slot in &self.list {
let d = slot.streams_done(key, ports);
done[0] &= d[0];
done[1] &= d[1];
if done == [false, false] {
break;
}
}
done
}
fn on_datagram(&mut self, cx: &Ctx<'_, K>, ports: Ports, payload: &[u8], out: &mut Self::Out) {
for slot in &mut self.list {
slot.on_datagram(cx, ports, payload, out, &mut self.order);
}
}
fn on_flow_end(
&mut self,
key: &K,
reason: EndReason,
stats: &FlowStats,
finals: [&StreamChunks; 2],
ports: Ports,
emit: Emit,
out: &mut Self::Out,
) {
for slot in &mut self.list {
slot.on_flow_end(
key,
reason,
stats,
finals,
ports,
emit,
out,
&mut self.order,
);
}
}
fn on_tick(
&mut self,
now: Timestamp,
stamp: Timestamp,
orientation_of: &dyn Fn(&K) -> Orientation,
emit: Emit,
out: &mut Self::Out,
) {
for slot in &mut self.list {
slot.on_tick(now, stamp, orientation_of, emit, out, &mut self.order);
}
}
fn retain(&mut self, alive: &dyn Fn(&K) -> bool) {
for slot in &mut self.list {
slot.retain(alive);
}
}
fn lifecycle(&mut self, ev: FlowEvent<K>, tcp: Option<TcpInfo>, out: &mut Self::Out) {
let tcp = if self.emit_packet_details { tcp } else { None };
if let Some(ev) = map_flow_event(ev, tcp) {
out.push(ev);
}
}
}
pub struct Driver<E>
where
E: FlowExtractor,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
engine: Engine<E>,
slots: Slots<E::Key>,
lifecycle_seq: u64,
}
impl<E> Driver<E>
where
E: FlowExtractor + Clone + Send + 'static,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
pub fn builder(extractor: E) -> DriverBuilder<E> {
DriverBuilder {
extractor,
config: FlowTrackerConfig::default(),
monotonic_timestamps: false,
emit_anomalies: false,
emit_packet_details: false,
emit_packet_source_idx: None,
dedup: None,
idle_timeout_fn: None,
slots: Vec::new(),
}
}
pub fn track<'v>(&mut self, view: impl Into<PacketView<'v>>) -> Vec<Event<E::Key>> {
let mut out = Vec::new();
self.track_into(view, &mut out);
out
}
pub fn track_into<'v>(
&mut self,
view: impl Into<PacketView<'v>>,
out: &mut Vec<Event<E::Key>>,
) {
let start = self.begin(out);
self.engine.track(view, &mut self.slots, out);
self.end(out, start);
}
pub fn lifecycle_seq(&self) -> u64 {
self.lifecycle_seq
}
fn begin(&mut self, out: &[Event<E::Key>]) -> usize {
self.slots.order.base = self.lifecycle_seq;
self.slots.order.start = out.len();
out.len()
}
fn end(&mut self, out: &[Event<E::Key>], start: usize) {
self.lifecycle_seq += (out.len() - start) as u64;
}
pub fn sweep(&mut self, now: Timestamp) -> Vec<Event<E::Key>> {
let mut out = Vec::new();
self.sweep_into(now, &mut out);
out
}
pub fn sweep_into(&mut self, now: Timestamp, out: &mut Vec<Event<E::Key>>) {
let start = self.begin(out);
self.engine.sweep(now, &mut self.slots, out);
self.end(out, start);
}
pub fn finish(&mut self) -> Vec<Event<E::Key>> {
let mut out = Vec::new();
self.finish_into(&mut out);
out
}
pub fn finish_into(&mut self, out: &mut Vec<Event<E::Key>>) {
let start = self.begin(out);
self.engine.finish(&mut self.slots, out);
self.end(out, start);
}
#[cfg(feature = "pcap")]
pub fn run_pcap<P: AsRef<std::path::Path>>(self, path: P) -> crate::Result<RunPcap<E>> {
let source = crate::pcap::PcapFlowSource::open(path)?;
Ok(RunPcap {
driver: self,
views: source.views(),
buf: Vec::with_capacity(32),
cursor: 0,
finished: false,
})
}
pub fn force_close(&mut self, key: &E::Key, now: Timestamp) -> Vec<Event<E::Key>> {
let mut out = Vec::new();
self.force_close_into(key, now, &mut out);
out
}
pub fn force_close_into(&mut self, key: &E::Key, now: Timestamp, out: &mut Vec<Event<E::Key>>) {
let start = self.begin(out);
self.engine.force_close(key, now, &mut self.slots, out);
self.end(out, start);
}
pub fn tracker(&self) -> &FlowTracker<E, ()> {
self.engine.flow.tracker()
}
pub fn set_idle_timeout_fn<G>(&mut self, f: G)
where
G: Fn(&E::Key, Option<L4Proto>) -> Option<std::time::Duration> + Send + Sync + 'static,
{
self.engine.flow.tracker_mut().set_idle_timeout_fn(f);
}
pub fn set_config(&mut self, config: FlowTrackerConfig) {
self.engine.flow.set_config(config);
}
pub fn dedup(&self) -> Option<&Dedup> {
self.engine.flow.dedup()
}
pub fn set_dedup(&mut self, dedup: Option<Dedup>) {
self.engine.flow.set_dedup(dedup);
}
pub fn pause_events(&mut self) {
self.engine.flow.pause_events();
}
pub fn resume_events(&mut self) {
self.engine.flow.resume_events();
}
pub fn flow_driver(&self) -> &FlowDriver<E, SegmentBufferReassemblerFactory, ()> {
&self.engine.flow
}
pub fn snapshot_flow_stats(&self) -> impl Iterator<Item = (E::Key, FlowStats)> + '_ {
self.engine.flow.snapshot_flow_stats()
}
}
#[must_use = "a DriverBuilder does nothing until you register parsers and call `.build()`"]
pub struct DriverBuilder<E>
where
E: FlowExtractor,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
extractor: E,
config: FlowTrackerConfig,
monotonic_timestamps: bool,
emit_anomalies: bool,
emit_packet_details: bool,
emit_packet_source_idx: Option<bool>,
dedup: Option<Dedup>,
idle_timeout_fn: Option<IdleTimeoutFn<E::Key>>,
slots: Vec<Box<dyn ErasedSlot<E::Key> + Send + Sync>>,
}
impl<E> DriverBuilder<E>
where
E: FlowExtractor + Clone + Send + 'static,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
pub fn config(&mut self, c: FlowTrackerConfig) -> &mut Self {
self.config = c;
self
}
pub fn monotonic_timestamps(&mut self, on: bool) -> &mut Self {
self.monotonic_timestamps = on;
self
}
pub fn emit_packet_details(&mut self, on: bool) -> &mut Self {
self.emit_packet_details = on;
self
}
pub fn emit_packet_source_idx(&mut self, on: bool) -> &mut Self {
self.emit_packet_source_idx = Some(on);
self
}
pub fn emit_anomalies(&mut self, on: bool) -> &mut Self {
self.emit_anomalies = on;
self
}
pub fn dedup(&mut self, dedup: Dedup) -> &mut Self {
self.dedup = Some(dedup);
self
}
pub fn idle_timeout_fn<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&E::Key, Option<L4Proto>) -> Option<Duration> + Send + Sync + 'static,
{
self.idle_timeout_fn = Some(Box::new(f));
self
}
fn next_slot_id(&self) -> SlotId {
SlotId(self.slots.len() as u32)
}
pub fn session_factory_on_ports<F, I>(
&mut self,
factory: F,
ports: I,
) -> SlotHandle<<F::Parser as SessionParser>::Message, E::Key>
where
F: SessionParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as SessionParser>::Message: Send + Sync + 'static,
I: IntoIterator<Item = u16>,
{
self.add_session_factory(factory, Selector::Ports(ports.into_iter().collect()))
}
pub fn session_factory_broadcast<F>(
&mut self,
factory: F,
) -> SlotHandle<<F::Parser as SessionParser>::Message, E::Key>
where
F: SessionParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as SessionParser>::Message: Send + Sync + 'static,
{
self.add_session_factory(factory, Selector::All)
}
pub fn datagram_factory_on_ports<F, I>(
&mut self,
factory: F,
ports: I,
) -> SlotHandle<<F::Parser as DatagramParser>::Message, E::Key>
where
F: DatagramParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as DatagramParser>::Message: Send + Sync + 'static,
I: IntoIterator<Item = u16>,
{
self.add_datagram_factory(factory, Selector::Ports(ports.into_iter().collect()))
}
pub fn datagram_factory_broadcast<F>(
&mut self,
factory: F,
) -> SlotHandle<<F::Parser as DatagramParser>::Message, E::Key>
where
F: DatagramParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as DatagramParser>::Message: Send + Sync + 'static,
{
self.add_datagram_factory(factory, Selector::All)
}
fn add_session_factory<F>(
&mut self,
factory: F,
selector: Selector,
) -> SlotHandle<<F::Parser as SessionParser>::Message, E::Key>
where
F: SessionParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as SessionParser>::Message: Send + Sync + 'static,
{
let id = self.next_slot_id();
let queue = Arc::new(SegQueue::new());
self.slots.push(Box::new(SessionSlot {
core: SessionCore::new(factory, selector),
sink: Arc::clone(&queue),
id,
}));
SlotHandle {
inner: queue,
parser_kind: ParserKind::Unspecified,
slot: id,
}
}
fn add_datagram_factory<F>(
&mut self,
factory: F,
selector: Selector,
) -> SlotHandle<<F::Parser as DatagramParser>::Message, E::Key>
where
F: DatagramParserFactory<E::Key> + Send + Sync + 'static,
F::Parser: Send + Sync,
<F::Parser as DatagramParser>::Message: Send + Sync + 'static,
{
let id = self.next_slot_id();
let queue = Arc::new(SegQueue::new());
self.slots.push(Box::new(DatagramSlot {
core: DatagramCore::new(factory, selector),
sink: Arc::clone(&queue),
id,
}));
SlotHandle {
inner: queue,
parser_kind: ParserKind::Unspecified,
slot: id,
}
}
fn add_session<P>(&mut self, parser: P, selector: Selector) -> SlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + 'static,
{
let parser_kind = parser.parser_kind();
let id = self.next_slot_id();
let queue = Arc::new(SegQueue::new());
self.slots.push(Box::new(SessionSlot {
core: SessionCore::new(TemplateFactory(parser), selector),
sink: Arc::clone(&queue),
id,
}));
SlotHandle {
inner: queue,
parser_kind,
slot: id,
}
}
fn add_datagram<D>(&mut self, parser: D, selector: Selector) -> SlotHandle<D::Message, E::Key>
where
D: DatagramParser + Clone + Send + Sync + 'static,
D::Message: Send + Sync + 'static,
{
let parser_kind = parser.parser_kind();
let id = self.next_slot_id();
let queue = Arc::new(SegQueue::new());
self.slots.push(Box::new(DatagramSlot {
core: DatagramCore::new(TemplateFactory(parser), selector),
sink: Arc::clone(&queue),
id,
}));
SlotHandle {
inner: queue,
parser_kind,
slot: id,
}
}
pub fn session_on_ports<P, I>(&mut self, parser: P, ports: I) -> SlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + 'static,
I: IntoIterator<Item = u16>,
{
self.add_session(parser, Selector::Ports(ports.into_iter().collect()))
}
pub fn session_on_ports_broadcast_each<P, I>(
&mut self,
parser: P,
ports: I,
) -> BroadcastSlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + Clone + 'static,
E::Key: Send + Sync + Clone + 'static,
I: IntoIterator<Item = u16>,
{
let parser_kind = parser.parser_kind();
let id = self.next_slot_id();
let inner = BroadcastInner::new();
let handle = BroadcastSlotHandle::new(Arc::clone(&inner), parser_kind, id);
self.slots.push(Box::new(SessionSlot {
core: SessionCore::new(
TemplateFactory(parser),
Selector::Ports(ports.into_iter().collect()),
),
sink: inner,
id,
}));
handle
}
pub fn session_broadcast<P>(&mut self, parser: P) -> SlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + 'static,
{
self.add_session(parser, Selector::All)
}
pub fn session_heuristic<P>(
&mut self,
parser: P,
signature: SignatureFn,
) -> SlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + 'static,
{
self.session_heuristic_with_budget(parser, signature, DEFAULT_PROBE_PACKETS)
}
pub fn session_heuristic_with_budget<P>(
&mut self,
parser: P,
signature: SignatureFn,
max_probe_packets: u8,
) -> SlotHandle<P::Message, E::Key>
where
P: SessionParser + Clone + Send + Sync + 'static,
P::Message: Send + Sync + 'static,
{
self.add_session(
parser,
Selector::Signature {
signature,
max_probe_packets,
},
)
}
pub fn datagram_on_ports<D, I>(&mut self, parser: D, ports: I) -> SlotHandle<D::Message, E::Key>
where
D: DatagramParser + Clone + Send + Sync + 'static,
D::Message: Send + Sync + 'static,
I: IntoIterator<Item = u16>,
{
self.add_datagram(parser, Selector::Ports(ports.into_iter().collect()))
}
pub fn datagram_broadcast<D>(&mut self, parser: D) -> SlotHandle<D::Message, E::Key>
where
D: DatagramParser + Clone + Send + Sync + 'static,
D::Message: Send + Sync + 'static,
{
self.add_datagram(parser, Selector::All)
}
pub fn datagram_heuristic<D>(
&mut self,
parser: D,
signature: SignatureFn,
) -> SlotHandle<D::Message, E::Key>
where
D: DatagramParser + Clone + Send + Sync + 'static,
D::Message: Send + Sync + 'static,
{
self.datagram_heuristic_with_budget(parser, signature, DEFAULT_PROBE_PACKETS)
}
pub fn datagram_heuristic_with_budget<D>(
&mut self,
parser: D,
signature: SignatureFn,
max_probe_packets: u8,
) -> SlotHandle<D::Message, E::Key>
where
D: DatagramParser + Clone + Send + Sync + 'static,
D::Message: Send + Sync + 'static,
{
self.add_datagram(
parser,
Selector::Signature {
signature,
max_probe_packets,
},
)
}
pub fn build(mut self) -> Driver<E> {
if let Some(on) = self.emit_packet_source_idx {
self.config.emit_packet_source_idx = on;
}
let mut engine = Engine::new(self.extractor, self.config);
engine.flow.set_emit_anomalies(self.emit_anomalies);
engine
.flow
.set_monotonic_timestamps(self.monotonic_timestamps);
engine.flow.set_dedup(self.dedup);
if let Some(f) = self.idle_timeout_fn {
engine
.flow
.tracker_mut()
.set_idle_timeout_fn(move |k, l4| f(k, l4));
}
let needs_ports = self.slots.iter().any(|s| s.needs_ports());
Driver {
engine,
slots: Slots {
list: self.slots,
needs_ports,
emit_packet_details: self.emit_packet_details,
order: Order::default(),
},
lifecycle_seq: 0,
}
}
}
fn map_flow_event<K>(ev: FlowEvent<K>, tcp: Option<TcpInfo>) -> Option<Event<K>> {
if matches!(ev, FlowEvent::StateChange { .. }) {
return None;
}
let mut event = Event::from(ev);
if let Event::Packet { tcp: slot, .. } = &mut event {
*slot = tcp;
}
Some(event)
}
#[cfg(feature = "pcap")]
#[must_use = "RunPcap is a lazy iterator — it replays no packets until consumed (e.g. in a `for` loop)"]
pub struct RunPcap<E>
where
E: FlowExtractor + Clone + Send + 'static,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
driver: Driver<E>,
views: crate::pcap::ViewIter<std::io::BufReader<std::fs::File>>,
buf: Vec<Event<E::Key>>,
cursor: usize,
finished: bool,
}
#[cfg(feature = "pcap")]
impl<E> Iterator for RunPcap<E>
where
E: FlowExtractor + Clone + Send + 'static,
E::Key: Hash + Eq + Clone + Send + Sync + 'static,
{
type Item = crate::Result<Event<E::Key>>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.cursor < self.buf.len() {
let ev = self.buf[self.cursor].clone();
self.cursor += 1;
return Some(Ok(ev));
}
self.buf.clear();
self.cursor = 0;
match self.views.next() {
Some(Ok(view)) => {
self.driver.track_into(&view, &mut self.buf);
}
Some(Err(e)) => return Some(Err(e)),
None => {
if self.finished {
return None;
}
self.finished = true;
self.driver.finish_into(&mut self.buf);
}
}
}
}
}