riptun 0.1.4

riptun is a cross platform library for creating, managing, and leveraging both sync and async TUN/TAP devices.
Documentation
// (c) Copyright 2021 Christian Saide
// SPDX-License-Identifier: MIT

use riptun::{Result, TokioTun};

use std::io::ErrorKind;
use std::sync::Arc;

const NUM_QUEUES: usize = 5;

#[tokio::main]
pub async fn main() -> Result<()> {
    // Create a new async Tun using the TokioTun implementation, named `rip%d` with
    // NUM_QUEUES internal queues.
    let async_dev = TokioTun::new("rip%d", NUM_QUEUES)?;

    // Print out the OS given name of this device.
    println!("[INFO] => Created new virtual device: {}", async_dev.name());

    // Create a Vec to store the Futures in to eventually join on.
    let mut handles = Vec::with_capacity(NUM_QUEUES);

    // Since we need to clone the TokioTun across thread boundries lets wrap it in a Arc.
    let async_dev = Arc::new(async_dev);

    // Createa a new Future for each queue and have that Future execute forever reading packets
    // off its configured queue.
    for queue in 0..NUM_QUEUES {
        // Clone our TokioTun instance so that we can move it to the new thread.
        let handle_dev = async_dev.clone();

        // Spawn a new Future to execute for this queue.
        let handle = tokio::spawn(async move {
            // Each Future gets its own buffer the same size as the MTU of the device, which by default
            // is 1500 bytes.
            let mut buffer: [u8; 1500] = [0x00; 1500];

            // Loop forever reading packets off the queue.
            loop {
                // Read the next packet off the specified queue and into the buffer using the async/await
                // syntax to execute the future returned by recv_via.
                let read = match handle_dev.recv_via(queue, &mut buffer).await {
                    Ok(read) => read,
                    // If its a WouldBlock simply short circuit, and re-poll the AsyncStdQueue.
                    Err(err) if err.kind() == ErrorKind::WouldBlock => continue,
                    Err(err) => {
                        // If we error simply log the issue, and continue on business as usual.
                        println!("[ERROR][Queue: {:?}] => {}", queue, err);
                        continue;
                    }
                };

                // Print the packet data as a byte slice, noting its size and which queue the
                // packet came from.
                println!(
                    "[INFO][Queue: {}] => Packet data ({}B): {:?}",
                    queue,
                    read,
                    &buffer[..read]
                );
            }
        });

        // Store the future in our Vec.
        handles.push(handle);
    }

    // Now execute all of the Futures we generated above and await for them to finish. Note that in this program
    // this line will never return.
    futures_util::future::join_all(handles).await;

    Ok(())
}