Skip to main content

AsyncCapture

Struct AsyncCapture 

Source
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>

Source

pub fn new(source: S) -> Result<Self, Error>

Wrap a packet source in an async adapter.

Registers the source’s fd with tokio’s reactor for POLLIN readiness.

§Errors

Returns Error::Io if AsyncFd registration fails.

Source§

impl AsyncCapture<Capture>

Source

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>

Source

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();
        }
    }
}
Source

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.

Source

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::spawn the await, or
  • cross await points that involve sending packets through a tokio::sync::mpsc::Sender (or any other Send-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).

Source

pub fn get_ref(&self) -> &S

Shared access to the inner source.

Source

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.

Source

pub fn into_inner(self) -> S

Unwrap into the inner source.

Source

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();
Source

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.

Source

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,

Source

pub fn flow_conversations<E>(self, extractor: E) -> ConversationStream<S, E>
where E: FlowExtractor, E::Key: Eq + Hash + Clone + Send + Sync + 'static,

Shortcut for cap.flow_stream(extractor).into_conversations().

Source§

impl<S> AsyncCapture<S>
where S: PacketSource + AsRawFd,

Source

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,

Source

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.

Trait Implementations§

Source§

impl<S: PacketSource + AsRawFd> AsFd for AsyncCapture<S>

Source§

fn as_fd(&self) -> BorrowedFd<'_>

Borrows the file descriptor. Read more
Source§

impl<S: PacketSource + AsRawFd + Send> AsyncPacketSource for AsyncCapture<S>

Source§

fn next_batch( &mut self, ) -> impl Future<Output = Result<PacketBatch<'_>, Error>> + Send

Await the next packet batch. Read more

Auto Trait Implementations§

§

impl<S> Freeze for AsyncCapture<S>
where S: Freeze,

§

impl<S> !RefUnwindSafe for AsyncCapture<S>

§

impl<S> Send for AsyncCapture<S>
where S: Send,

§

impl<S> Sync for AsyncCapture<S>
where S: Sync,

§

impl<S> Unpin for AsyncCapture<S>
where S: Unpin,

§

impl<S> UnsafeUnpin for AsyncCapture<S>
where S: UnsafeUnpin,

§

impl<S> !UnwindSafe for AsyncCapture<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more