Crate tcp

source ·
Expand description

A TCP implementation with a somewhat-BSD-like socket API. It is written as a “sans-I/O” library meaning it doesn’t do any networking I/O itself, it just accepts bytes and provides bytes. A dependencies object must be be provided to support setting timers and getting the current time. The TCP state object should probably be used with a reference-counting wrapper so that a reference to the state object can be stored in the timer callbacks.

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
struct TcpDependencies {
    // a reference to the tcp state
    state: Weak<RefCell<tcp::TcpState<Self>>>,
}

impl tcp::Dependencies for TcpDependencies {
    type Instant = std::time::Instant;
    type Duration = std::time::Duration;

    fn register_timer(
        &self,
        time: Self::Instant,
        f: impl FnOnce(&mut tcp::TcpState<Self>, tcp::TimerRegisteredBy) + Send + Sync + 'static,
    ) {
        let tcp_state = self.state.upgrade().unwrap();

        // TODO: To register timers, you would likely want to involve an async
        // runtime. A simple example would create a new task for each timer. The
        // task would sleep for some duration and then run the callback.
    }

    fn current_time(&self) -> Self::Instant {
        std::time::Instant::now()
    }

    fn fork(&self) -> Self {
        // TODO: the implementation here would depend on the implementation
        // of `register_timer`
        todo!();
    }
}

// create the TCP state object
let tcp_state = Rc::new_cyclic(|weak| {
    let dependencies = TcpDependencies {
        state: weak.clone(),
    };
    RefCell::new(tcp::TcpState::new(dependencies, tcp::TcpConfig::default()))
});

let mut tcp_state = tcp_state.borrow_mut();

// connect to port 80
let dst_addr = "127.0.0.1:80".parse().unwrap();
tcp_state.connect(dst_addr, || {
    // here we would ask the network interface for an unused port (implicit bind),
    // or where we would use the port assigned to a raw IP socket
    let bind_addr = "127.0.0.1:2532".parse().unwrap();
    Ok::<_, ()>((bind_addr, ()))
}).unwrap();

// get the SYN packet from the connect
let (header, _payload) = tcp_state.pop_packet().unwrap();
assert!(header.flags.contains(tcp::TcpFlags::SYN));
assert_eq!(header.dst(), dst_addr);

Modules§

Structs§

Enums§

Traits§

  • A collection of methods that allow the TCP state to interact with the external system.