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§
- An accept()ed TCP state. This is used to ensure that the caller uses
finalize
to update the state’sDependencies
since the state is no longer owned by the listening socket. - A packet payload containing a list of byte chunks.
Enums§
- Specifies whether the callback is meant to run on the parent state or a child state.
Traits§
- A collection of methods that allow the TCP state to interact with the external system.