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, Tun};

use std::sync::Arc;
use std::thread;

const NUM_QUEUES: usize = 5;

pub fn main() -> Result<()> {
    // Create a new synchronous Tun named `rip%d` with NUM_QUEUES internal queues.
    let sync = Tun::new("rip%d", NUM_QUEUES)?;

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

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

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

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

        // Spawn a new thread to execute for this queue.
        let handle = thread::spawn(move || {
            // Each thread 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 blocking until data
                // is available to read.
                let read = match handle_dev.recv_via(queue, &mut buffer) {
                    Ok(read) => read,
                    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 JoinHandle in our Vec.
        handles.push(handle);
    }

    // Loop over all handles Joining and noting any errors that come up.
    for handle in handles {
        if let Err(err) = handle.join() {
            println!("[ERROR] => {:?}", err);
        }
    }
    Ok(())
}