use std::time::Instant;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionState {
Idle,
SynSent,
SynRecv,
Connected,
FinSent,
Closing,
Closed,
Reset,
TimedOut,
}
impl ConnectionState {
pub fn can_send_data(&self) -> bool {
matches!(self, Self::Connected | Self::FinSent)
}
pub fn can_receive_data(&self) -> bool {
matches!(
self,
Self::Connected | Self::SynRecv | Self::FinSent | Self::Closing
)
}
pub fn is_closed(&self) -> bool {
matches!(self, Self::Closed | Self::Reset | Self::TimedOut)
}
pub fn is_active(&self) -> bool {
matches!(
self,
Self::SynSent | Self::SynRecv | Self::Connected | Self::FinSent | Self::Closing
)
}
}
impl std::fmt::Display for ConnectionState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Idle => write!(f, "IDLE"),
Self::SynSent => write!(f, "SYN_SENT"),
Self::SynRecv => write!(f, "SYN_RECV"),
Self::Connected => write!(f, "CONNECTED"),
Self::FinSent => write!(f, "FIN_SENT"),
Self::Closing => write!(f, "CLOSING"),
Self::Closed => write!(f, "CLOSED"),
Self::Reset => write!(f, "RESET"),
Self::TimedOut => write!(f, "TIMED_OUT"),
}
}
}
#[derive(Debug, Clone)]
pub struct PendingPacket {
pub seq_nr: u16,
pub data: Vec<u8>,
pub payload: Vec<u8>,
pub first_sent: Instant,
pub last_sent: Instant,
pub retransmits: u32,
pub size: u32,
}
impl PendingPacket {
pub fn new(seq_nr: u16, data: Vec<u8>, payload: Vec<u8>) -> Self {
let now = Instant::now();
let size = data.len() as u32;
Self {
seq_nr,
data,
payload,
first_sent: now,
last_sent: now,
retransmits: 0,
size,
}
}
pub fn mark_retransmit(&mut self) {
self.last_sent = Instant::now();
self.retransmits += 1;
}
}
#[derive(Debug, Default, Clone)]
pub struct ConnectionStats {
pub packets_sent: u64,
pub packets_received: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
pub retransmits: u64,
pub duplicate_acks: u64,
pub timeouts: u64,
pub packets_lost: u64,
}
impl ConnectionStats {
pub fn new() -> Self {
Self::default()
}
pub fn record_sent(&mut self, bytes: u64) {
self.packets_sent += 1;
self.bytes_sent += bytes;
}
pub fn record_received(&mut self, bytes: u64) {
self.packets_received += 1;
self.bytes_received += bytes;
}
pub fn record_retransmit(&mut self) {
self.retransmits += 1;
}
pub fn record_timeout(&mut self) {
self.timeouts += 1;
}
pub fn record_duplicate_ack(&mut self) {
self.duplicate_acks += 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_connection_state_transitions() {
let state = ConnectionState::Idle;
assert!(!state.can_send_data());
assert!(!state.is_closed());
let state = ConnectionState::SynSent;
assert!(!state.can_send_data());
assert!(state.is_active());
let state = ConnectionState::Connected;
assert!(state.can_send_data());
assert!(state.can_receive_data());
assert!(state.is_active());
let state = ConnectionState::Closed;
assert!(!state.can_send_data());
assert!(state.is_closed());
}
#[test]
fn test_pending_packet() {
let pkt = PendingPacket::new(100, vec![1, 2, 3], vec![1]);
assert_eq!(pkt.seq_nr, 100);
assert_eq!(pkt.retransmits, 0);
}
#[test]
fn test_connection_stats() {
let mut stats = ConnectionStats::new();
stats.record_sent(100);
stats.record_received(200);
assert_eq!(stats.packets_sent, 1);
assert_eq!(stats.bytes_sent, 100);
assert_eq!(stats.packets_received, 1);
assert_eq!(stats.bytes_received, 200);
}
}