use serde::{Deserialize, Serialize};
use crate::types::{SessionId, TrafficStats};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum MessageType {
ClientHello = 0,
ServerHello = 1,
ClientAuth = 2,
ServerAuthOk = 3,
ServerAuthFail = 4,
Data = 10,
DataAck = 11,
DataNack = 12,
Ping = 20,
Pong = 21,
PathProbe = 22,
PathProbeAck = 23,
SessionUpdate = 30,
UplinkAdd = 31,
UplinkRemove = 32,
UplinkStatus = 33,
Close = 40,
CloseAck = 41,
Error = 42,
QualityReport = 50,
BandwidthEstimate = 51,
}
impl MessageType {
pub fn from_u8(v: u8) -> Option<Self> {
match v {
0 => Some(Self::ClientHello),
1 => Some(Self::ServerHello),
2 => Some(Self::ClientAuth),
3 => Some(Self::ServerAuthOk),
4 => Some(Self::ServerAuthFail),
10 => Some(Self::Data),
11 => Some(Self::DataAck),
12 => Some(Self::DataNack),
20 => Some(Self::Ping),
21 => Some(Self::Pong),
22 => Some(Self::PathProbe),
23 => Some(Self::PathProbeAck),
30 => Some(Self::SessionUpdate),
31 => Some(Self::UplinkAdd),
32 => Some(Self::UplinkRemove),
33 => Some(Self::UplinkStatus),
40 => Some(Self::Close),
41 => Some(Self::CloseAck),
42 => Some(Self::Error),
50 => Some(Self::QualityReport),
51 => Some(Self::BandwidthEstimate),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Message {
ClientHello(ClientHelloMessage),
ServerHello(ServerHelloMessage),
ClientAuth(ClientAuthMessage),
ServerAuthOk(ServerAuthOkMessage),
ServerAuthFail(ServerAuthFailMessage),
Data(DataMessage),
DataAck(DataAckMessage),
DataNack(DataNackMessage),
Control(ControlMessage),
UplinkStatus(UplinkStatusMessage),
Close(CloseMessage),
Error(ErrorMessage),
}
impl Message {
pub fn message_type(&self) -> MessageType {
match self {
Self::ClientHello(_) => MessageType::ClientHello,
Self::ServerHello(_) => MessageType::ServerHello,
Self::ClientAuth(_) => MessageType::ClientAuth,
Self::ServerAuthOk(_) => MessageType::ServerAuthOk,
Self::ServerAuthFail(_) => MessageType::ServerAuthFail,
Self::Data(_) => MessageType::Data,
Self::DataAck(_) => MessageType::DataAck,
Self::DataNack(_) => MessageType::DataNack,
Self::Control(c) => match c {
ControlMessage::Ping { .. } => MessageType::Ping,
ControlMessage::Pong { .. } => MessageType::Pong,
ControlMessage::PathProbe { .. } => MessageType::PathProbe,
ControlMessage::PathProbeAck { .. } => MessageType::PathProbeAck,
ControlMessage::QualityReport(_) => MessageType::QualityReport,
},
Self::UplinkStatus(_) => MessageType::UplinkStatus,
Self::Close(_) => MessageType::Close,
Self::Error(_) => MessageType::Error,
}
}
pub fn to_bytes(&self) -> Result<Vec<u8>, crate::error::ProtocolError> {
bincode::serialize(self)
.map_err(|e| crate::error::ProtocolError::Serialization(e.to_string()))
}
pub fn from_bytes(data: &[u8]) -> Result<Self, crate::error::ProtocolError> {
bincode::deserialize(data)
.map_err(|e| crate::error::ProtocolError::Deserialization(e.to_string()))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientHelloMessage {
pub ephemeral_public: [u8; 32],
pub session_id: SessionId,
pub capabilities: ClientCapabilities,
pub uplink_count: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerHelloMessage {
pub ephemeral_public: [u8; 32],
pub session_id: SessionId,
pub capabilities: ServerCapabilities,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientAuthMessage {
pub auth_token: [u8; 32],
pub handshake_payload: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerAuthOkMessage {
pub confirmation: [u8; 32],
pub uplink_endpoints: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerAuthFailMessage {
pub error_code: u32,
pub message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataMessage {
pub stream_id: u32,
pub offset: u64,
pub payload: Vec<u8>,
pub fin: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataAckMessage {
pub acked: Vec<u64>,
pub sack_ranges: Vec<(u64, u64)>,
pub window: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataNackMessage {
pub missing: Vec<u64>,
pub reason: NackReason,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NackReason {
PacketLoss,
Timeout,
IntegrityFailure,
DecryptionFailure,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ControlMessage {
Ping {
timestamp: u64,
uplink_id: u16,
},
Pong {
ping_timestamp: u64,
uplink_id: u16,
},
PathProbe {
probe_id: u64,
uplink_id: u16,
size: u16,
},
PathProbeAck {
probe_id: u64,
uplink_id: u16,
received_size: u16,
},
QualityReport(QualityReportMessage),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QualityReportMessage {
pub uplink_stats: Vec<UplinkQualityStats>,
pub aggregate: TrafficStats,
pub timestamp: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UplinkQualityStats {
pub uplink_id: u16,
pub rtt_us: u32,
pub rtt_var_us: u32,
pub loss_ratio: f32,
pub bandwidth_bps: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
pub packets_sent: u64,
pub packets_dropped: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UplinkStatusMessage {
pub uplink_id: u16,
pub status: UplinkStatusType,
pub details: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum UplinkStatusType {
Active,
Degraded,
Down,
Adding,
Removing,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloseMessage {
pub code: u32,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorMessage {
pub code: u32,
pub message: String,
pub severity: ErrorSeverity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ErrorSeverity {
Info,
Warning,
Error,
Fatal,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientCapabilities {
pub max_uplinks: u8,
pub compression: bool,
pub fast_path: bool,
pub tcp_fallback: bool,
pub ipv6: bool,
pub extensions: Vec<String>,
}
impl Default for ClientCapabilities {
fn default() -> Self {
Self {
max_uplinks: 8,
compression: true,
fast_path: true,
tcp_fallback: true,
ipv6: true,
extensions: vec![],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerCapabilities {
pub max_uplinks: u8,
pub compression: bool,
pub fast_path: bool,
pub tcp_fallback: bool,
pub version: String,
pub extensions: Vec<String>,
}
impl Default for ServerCapabilities {
fn default() -> Self {
Self {
max_uplinks: 16,
compression: true,
fast_path: true,
tcp_fallback: true,
version: env!("CARGO_PKG_VERSION").to_string(),
extensions: vec![],
}
}
}