pub struct AsyncCapture<S: PacketSource + AsRawFd> { /* private fields */ }Expand description
Async wrapper around any PacketSource using tokio’s AsyncFd.
Three reception entry points (in order of recommended use):
§Guarded zero-copy
let mut cap = AsyncCapture::new(Capture::open("lo")?)?;
loop {
let mut guard = cap.readable().await?;
if let Some(batch) = guard.next_batch() {
for pkt in &batch {
println!("{} bytes", pkt.len());
}
}
}§Single-call zero-copy
let mut cap = AsyncCapture::new(Capture::open("lo")?)?;
let batch = cap.try_recv_batch().await?;
for pkt in &batch {
println!("{} bytes", pkt.len());
}§Owned (use when the future must be Send, e.g. tokio::spawn)
let mut cap = AsyncCapture::new(Capture::open("lo")?)?;
let packets = cap.recv().await?;
for pkt in &packets {
println!("{} bytes", pkt.data.len());
}Implementations§
Source§impl<S: PacketSource + AsRawFd> AsyncCapture<S>
impl<S: PacketSource + AsRawFd> AsyncCapture<S>
Source§impl AsyncCapture<Capture>
impl AsyncCapture<Capture>
Sourcepub fn open(interface: &str) -> Result<Self, Error>
pub fn open(interface: &str) -> Result<Self, Error>
Open an async AF_PACKET capture on interface with default settings.
One-liner shortcut for AsyncCapture::new(Capture::open(interface)?).
For configured captures, use AsyncCapture::new(Capture::builder()...build()?).
§Examples
let mut cap = netring::AsyncCapture::open("eth0")?;
let mut guard = cap.readable().await?;
if let Some(batch) = guard.next_batch() {
for pkt in &batch {
println!("{} bytes", pkt.len());
}
}Source§impl<S: PacketSource + AsRawFd> AsyncCapture<S>
impl<S: PacketSource + AsRawFd> AsyncCapture<S>
Sourcepub async fn readable(&mut self) -> Result<ReadableGuard<'_, S>, Error>
pub async fn readable(&mut self) -> Result<ReadableGuard<'_, S>, Error>
Wait until readable and return a guard for zero-copy batch retrieval.
The guard borrows &mut self and exposes a single
next_batch() entry that returns the
batch as a zero-copy view. If next_batch returns None, the guard
also clears tokio’s readiness flag so the next readable() call
re-arms via epoll.
§Cancel safety
This method is cancel-safe. Dropping the future before it resolves
abandons the readiness wait but does not lose data — tokio’s reactor
re-arms on the next call. Once the future resolves and a guard is
returned, the kernel ring is unaffected; if you then drop the guard
without calling next_batch, no data is consumed.
§Examples
let rx = CaptureBuilder::default().interface("lo").build()?;
let mut cap = AsyncCapture::new(rx)?;
loop {
let mut guard = cap.readable().await?;
if let Some(batch) = guard.next_batch() {
for pkt in &batch {
let _ = pkt.len();
}
}
}Sourcepub async fn try_recv_batch(&mut self) -> Result<PacketBatch<'_>, Error>
pub async fn try_recv_batch(&mut self) -> Result<PacketBatch<'_>, Error>
Wait until readable and return the next batch as a zero-copy view.
Sugar over self.readable().await?.next_batch() plus a spurious-
wakeup retry loop. Equivalent to:
loop {
let mut guard = self.readable().await?;
if let Some(batch) = guard.next_batch() {
return Ok(batch);
}
}Borrows &mut self for the lifetime of the returned batch — same
“one batch live at a time” rule as PacketSource::next_batch.
§Cancel safety
Cancel-safe between iterations: if cancelled while awaiting
readability, no data is consumed; if cancelled while holding a
resolved guard but before extracting the batch, the guard drops
without consuming. Once next_batch() returns Some(batch), the
borrow is committed — drop the batch normally to release it.
Sourcepub async fn recv(&mut self) -> Result<Vec<OwnedPacket>, Error>
pub async fn recv(&mut self) -> Result<Vec<OwnedPacket>, Error>
Receive the next batch of packets as owned copies.
Waits for the socket to become readable, then returns all packets
from the next retired block as OwnedPackets. The block is
returned to the kernel before this method returns.
Internally retries on spurious wakeups (the inner next_batch()
may return None even after readability fires; we re-arm and
re-wait). For zero-copy access without the per-packet Vec<u8>
copy, use try_recv_batch instead.
§When to use this vs try_recv_batch
recv returns Vec<OwnedPacket> (Send + 'static), so the future
it produces is Send. Use this when you want to:
tokio::spawnthe await, or- cross await points that involve sending packets through a
tokio::sync::mpsc::Sender(or any otherSend-requiring sink).
try_recv_batch yields PacketBatch<'_>,
which is !Send because it borrows from the mmap ring (whose
NonNull<u8> base is not Sync). That makes the surrounding
future !Send and incompatible with tokio::spawn. Use
try_recv_batch only when staying on a single task / runtime
thread (or when using LocalSet / tokio::task::spawn_local).
Sourcepub fn get_mut(&mut self) -> &mut S
pub fn get_mut(&mut self) -> &mut S
Mutable access to the inner source.
Borrow the inner source mutably (e.g. for stats accessors). Most
users want readable() to
call next_batch() for zero-copy access.
Sourcepub fn into_inner(self) -> S
pub fn into_inner(self) -> S
Unwrap into the inner source.
Sourcepub fn into_stream(self) -> PacketStream<S>
pub fn into_stream(self) -> PacketStream<S>
Convert this capture into a Stream.
Yields one Vec<OwnedPacket> per retired block — see
PacketStream for the Stream::Item type and cancel-safety
details. Equivalent to PacketStream::new(self) but reads more
fluently in builder-style chains:
use netring::{AsyncCapture, Capture};
let stream = AsyncCapture::new(Capture::open("eth0")?)?.into_stream();Sourcepub fn stats(&self) -> Result<CaptureStats, Error>
pub fn stats(&self) -> Result<CaptureStats, Error>
Capture statistics — passthrough to PacketSource::stats.
Saves use netring::PacketSource; at the call site. Resets kernel
counters on each read — see PacketSource::stats for the full
contract or cumulative_stats for monotonic
totals.
Sourcepub fn cumulative_stats(&self) -> Result<CaptureStats, Error>
pub fn cumulative_stats(&self) -> Result<CaptureStats, Error>
Accumulated statistics since the source was created — passthrough to
PacketSource::cumulative_stats.
Source§impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
Sourcepub fn flow_conversations<E>(self, extractor: E) -> ConversationStream<S, E>
pub fn flow_conversations<E>(self, extractor: E) -> ConversationStream<S, E>
Shortcut for cap.flow_stream(extractor).into_conversations().
Source§impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
Sourcepub fn dedup_stream(self, dedup: Dedup) -> DedupStream<S>
pub fn dedup_stream(self, dedup: Dedup) -> DedupStream<S>
Convert this capture into a stream of OwnedPackets with
duplicates filtered out by dedup.
Consumes the capture. Yields OwnedPacket (not Packet<'_>)
because the underlying batch is processed inside poll_next.
Users who need zero-copy should use the manual loop:
use netring::{AsyncCapture, Dedup};
let mut cap = AsyncCapture::open("lo")?;
let mut dedup = Dedup::loopback();
loop {
let mut g = cap.readable().await?;
if let Some(batch) = g.next_batch() {
for pkt in &batch {
if dedup.keep(&pkt) {
// process pkt
}
}
}
}Source§impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
impl<S> AsyncCapture<S>where
S: PacketSource + AsRawFd,
Sourcepub fn flow_stream<E>(self, extractor: E) -> FlowStream<S, E, (), NoReassembler>where
E: FlowExtractor,
pub fn flow_stream<E>(self, extractor: E) -> FlowStream<S, E, (), NoReassembler>where
E: FlowExtractor,
Convert this capture into a stream of FlowEvents.
Consumes the capture. The returned FlowStream uses
default tracker config and () for per-flow user state.
Chain .with_state(...), .with_config(...), and
.with_async_reassembler(...) to customize.