From 8cb724fe0dbdee59ad5bd2e6666638c253f1953f Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 30 Mar 2025 13:46:51 -0600 Subject: [PATCH] Added the TCP medium + Split impl for Server/Clients + Working, but slow I think it's time to look at performance --- Cargo.toml | 2 +- src/medium/mod.rs | 12 ++++- src/medium/tcp.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 src/medium/tcp.rs diff --git a/Cargo.toml b/Cargo.toml index 2662888..4c015c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ pretty-hex = "0.4.1" env_logger = "0.11.6" clap = { version = "4.5.34", features = ["derive"] } config = "0.15.11" -serde = { version = "1.0.219", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } \ No newline at end of file diff --git a/src/medium/mod.rs b/src/medium/mod.rs index 0cda170..b84be17 100644 --- a/src/medium/mod.rs +++ b/src/medium/mod.rs @@ -1,7 +1,9 @@ pub mod logger; +mod tcp; pub mod udp; use crate::medium::logger::Logger; +use crate::medium::tcp::{TCPClientMedium, TCPServerMedium}; use crate::medium::udp::UdpMedium; use log::info; use serde::Deserialize; @@ -12,7 +14,7 @@ pub trait ReadMedium: Read + Send {} pub trait WriteMedium: Write + Send {} -pub trait Medium: Read + Write + Send { +pub trait Medium: Send { fn split(&self) -> (Box, Box); fn name(&self) -> String; @@ -31,6 +33,12 @@ pub enum Mediums { remote_addr: SocketAddr, }, Logger, + TcpClient { + remote_addr: SocketAddr, + }, + TcpServer { + local_addr: SocketAddr, + }, } impl Mediums { @@ -41,6 +49,8 @@ impl Mediums { remote_addr, } => Box::new(UdpMedium::new(*local_addr, *remote_addr)), Mediums::Logger => Box::new(Logger), + Mediums::TcpClient { remote_addr } => Box::new(TCPClientMedium::new(*remote_addr)), + Mediums::TcpServer { local_addr } => Box::new(TCPServerMedium::new(*local_addr)), } } } diff --git a/src/medium/tcp.rs b/src/medium/tcp.rs new file mode 100644 index 0000000..3713c91 --- /dev/null +++ b/src/medium/tcp.rs @@ -0,0 +1,125 @@ +use crate::medium::{Medium, ReadMedium, WriteMedium}; +use log::info; +use std::fmt::{Display, Formatter}; +use std::io::{Error, ErrorKind}; +use std::net::{SocketAddr, TcpListener, TcpStream}; + +pub enum TCPType { + Client, + Server, +} + +impl Display for TCPType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let type_name = match self { + TCPType::Client => "Client", + TCPType::Server => "Server", + }; + + write!(f, "{}", type_name) + } +} + +pub trait TCPMedium: Send { + fn medium_type() -> TCPType; + + fn handle_init(&mut self) -> Result<(), std::io::Error>; + + fn tcp_stream(&self) -> Result<&TcpStream, std::io::Error>; +} + +impl Medium for T { + fn split(&self) -> (Box, Box) { + let read_stream = self.tcp_stream().unwrap().try_clone().unwrap(); + let write_stream = self.tcp_stream().unwrap().try_clone().unwrap(); + + (Box::new(read_stream), Box::new(write_stream)) + } + + fn name(&self) -> String { + format!("TCP {}", Self::medium_type()) + } + + fn init(&mut self) -> Result<(), Error> { + self.handle_init() + } +} + +pub struct TCPClientMedium { + dest_addr: SocketAddr, + tcp_stream: Option, +} + +impl TCPClientMedium { + pub fn new(dest_addr: SocketAddr) -> Self { + Self { + dest_addr, + tcp_stream: None, + } + } +} + +impl TCPMedium for TCPClientMedium { + fn medium_type() -> TCPType { + TCPType::Client + } + + fn handle_init(&mut self) -> Result<(), Error> { + info!("Connecting to TCP server at {}...", self.dest_addr); + self.tcp_stream = Some(TcpStream::connect(self.dest_addr)?); + info!("Connected to TCP server."); + + Ok(()) + } + + fn tcp_stream(&self) -> Result<&TcpStream, Error> { + self.tcp_stream + .as_ref() + .ok_or(Error::from(ErrorKind::NotConnected)) + } +} + +pub struct TCPServerMedium { + server_addr: SocketAddr, + tcp_stream: Option, +} + +impl TCPServerMedium { + pub fn new(server_addr: SocketAddr) -> Self { + Self { + server_addr, + tcp_stream: None, + } + } +} + +impl TCPMedium for TCPServerMedium { + fn medium_type() -> TCPType { + TCPType::Server + } + + fn handle_init(&mut self) -> Result<(), Error> { + info!( + "Waiting for connections to TCP server @ {}...", + self.server_addr + ); + let listener = TcpListener::bind(self.server_addr)?; + + let (stream, addr) = listener.accept()?; + + info!("Got connection from {}", addr); + self.tcp_stream = Some(stream); + + Ok(()) + } + + fn tcp_stream(&self) -> Result<&TcpStream, Error> { + self.tcp_stream + .as_ref() + .ok_or(Error::from(ErrorKind::NotConnected)) + } +} + +impl ReadMedium for TcpStream {} + +impl WriteMedium for TcpStream {}