pub mod tcp;
pub mod udp;
pub mod quic;
pub mod quic_socket;
pub mod websocket;
#[cfg(test)]
mod tests;
use std::time::Duration;
use tokio::net::TcpStream;
use crate::network::PeerAddr;
#[allow(async_fn_in_trait)]
pub trait StreamTransport: Send + Sync {
type Stream: FramedStream;
async fn connect(&self, addr: &PeerAddr) -> Result<Self::Stream, TransportError>;
async fn listen(&self) -> Result<StreamListener<Self::Stream>, TransportError>;
}
#[allow(async_fn_in_trait)]
pub trait FramedStream: Send + Sync + 'static {
async fn send(&mut self, data: &[u8]) -> Result<(), TransportError>;
async fn recv(&mut self) -> Result<Option<Vec<u8>>, TransportError>;
async fn close(&mut self) -> Result<(), TransportError>;
fn peer_addr(&self) -> String;
}
#[allow(async_fn_in_trait)]
pub trait RawTransport: Send + Sync {
async fn open(&self, addr: &PeerAddr, port: u16) -> Result<TcpStream, TransportError>;
async fn listen(&self, port: u16) -> Result<RawListener, TransportError>;
}
#[allow(async_fn_in_trait)]
pub trait DatagramTransport: Send + Sync {
async fn bind(&self, port: u16) -> Result<DatagramSocket, TransportError>;
}
pub struct StreamListener<S: FramedStream> {
rx: tokio::sync::mpsc::Receiver<S>,
pub port: u16,
}
impl<S: FramedStream> StreamListener<S> {
pub fn new(rx: tokio::sync::mpsc::Receiver<S>, port: u16) -> Self {
Self { rx, port }
}
pub async fn accept(&mut self) -> Option<S> {
self.rx.recv().await
}
}
pub struct RawListener {
rx: tokio::sync::mpsc::Receiver<RawIncoming>,
pub port: u16,
}
impl RawListener {
pub fn new(rx: tokio::sync::mpsc::Receiver<RawIncoming>, port: u16) -> Self {
Self { rx, port }
}
pub async fn accept(&mut self) -> Option<RawIncoming> {
self.rx.recv().await
}
}
pub struct RawIncoming {
pub stream: TcpStream,
pub remote_addr: String,
}
pub enum DatagramSocket {
Direct {
socket: tokio::net::UdpSocket,
},
Network {
socket: crate::network::NetworkUdpSocket,
},
}
impl DatagramSocket {
pub fn direct(socket: tokio::net::UdpSocket) -> Self {
Self::Direct { socket }
}
pub fn network(socket: crate::network::NetworkUdpSocket) -> Self {
Self::Network { socket }
}
pub async fn send_to(&self, data: &[u8], addr: &str) -> Result<usize, TransportError> {
match self {
Self::Direct { socket } => {
socket.send_to(data, addr).await.map_err(TransportError::Io)
}
Self::Network { socket } => {
let sock_addr: std::net::SocketAddr = addr.parse().map_err(|e| {
TransportError::ConnectFailed(format!("invalid address '{addr}': {e}"))
})?;
socket
.send_to(data, sock_addr)
.await
.map_err(|e| TransportError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())))
}
}
}
pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, String), TransportError> {
match self {
Self::Direct { socket } => {
let (n, addr) = socket.recv_from(buf).await.map_err(TransportError::Io)?;
Ok((n, addr.to_string()))
}
Self::Network { socket } => {
let (n, addr) = socket
.recv_from(buf)
.await
.map_err(|e| TransportError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())))?;
Ok((n, addr.to_string()))
}
}
}
pub fn local_addr(&self) -> Result<std::net::SocketAddr, TransportError> {
match self {
Self::Direct { socket } => socket.local_addr().map_err(TransportError::Io),
Self::Network { socket } => socket
.local_addr()
.map_err(|e| TransportError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))),
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
pub struct Handshake {
pub peer_id: String,
pub capabilities: Vec<String>,
pub protocol_version: u32,
}
pub const PROTOCOL_VERSION: u32 = 1;
pub use quic::QuicConfig;
pub use udp::UdpConfig;
#[derive(Debug, Clone)]
pub struct WsConfig {
pub port: u16,
pub ping_interval: Duration,
pub pong_timeout: Duration,
pub max_message_size: usize,
}
impl Default for WsConfig {
fn default() -> Self {
Self {
port: 9417,
ping_interval: Duration::from_secs(10),
pong_timeout: Duration::from_secs(30),
max_message_size: 16 * 1024 * 1024, }
}
}
pub(crate) fn resolve_dial_addr(addr: &PeerAddr) -> String {
if let Some(ip) = &addr.ip {
ip.to_string()
} else if let Some(dns) = &addr.dns_name {
dns.clone()
} else {
addr.hostname.clone()
}
}
#[derive(Debug, thiserror::Error)]
pub enum TransportError {
#[error("not implemented: {0}")]
NotImplemented(String),
#[error("connect failed: {0}")]
ConnectFailed(String),
#[error("listen failed: {0}")]
ListenFailed(String),
#[error("handshake failed: {0}")]
HandshakeFailed(String),
#[error("protocol version mismatch: local={local}, remote={remote}")]
VersionMismatch {
local: u32,
remote: u32,
},
#[error("connection closed: {0}")]
ConnectionClosed(String),
#[error("timeout: {0}")]
Timeout(String),
#[error("heartbeat timeout after {0:?}")]
HeartbeatTimeout(Duration),
#[error("websocket error: {0}")]
WebSocket(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("serialization error: {0}")]
Serialize(String),
#[error("network error: {0}")]
Network(#[from] crate::network::NetworkError),
}