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§

util

Structs§

AcceptedTcpState
An accept()ed TCP state. This is used to ensure that the caller uses finalize to update the state’s Dependencies since the state is no longer owned by the listening socket.
Ipv4Header
Payload
A packet payload containing a list of byte chunks.
PollState
TcpConfig
TcpFlags
TcpHeader
TcpState

Enums§

AcceptError
CloseError
ConnectError
ListenError
PopPacketError
PushPacketError
RecvError
SendError
Shutdown
ShutdownError
TcpError
TimerRegisteredBy
Specifies whether the callback is meant to run on the parent state or a child state.

Traits§

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