use std::collections::{HashMap, VecDeque};
use std::time::{Duration, Instant};
const DEFAULT_INITIAL_RTO: Duration = Duration::from_millis(1000);
const MIN_RTO: Duration = Duration::from_millis(200);
const MAX_RTO: Duration = Duration::from_secs(2);
const DEFAULT_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(15);
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
const MAX_RETRANSMIT_ATTEMPTS: u32 = 5;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TimerType {
ConnectTimeout,
Retransmit(u16),
Keepalive,
IdleTimeout,
}
impl std::fmt::Display for TimerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TimerType::ConnectTimeout => write!(f, "ConnectTimeout"),
TimerType::Retransmit(seq) => write!(f, "Retransmit(seq={})", seq),
TimerType::Keepalive => write!(f, "Keepalive"),
TimerType::IdleTimeout => write!(f, "IdleTimeout"),
}
}
}
#[derive(Debug, Clone)]
struct TimerEntry {
timer_type: TimerType,
#[allow(dead_code)]
conn_id: u16,
expires_at: Instant,
duration: Duration,
fire_count: u32,
}
impl TimerEntry {
fn new(conn_id: u16, timer_type: TimerType, duration: Duration) -> Self {
Self {
timer_type,
conn_id,
expires_at: Instant::now() + duration,
duration,
fire_count: 0,
}
}
#[allow(dead_code)] fn is_expired(&self) -> bool {
Instant::now() >= self.expires_at
}
fn remaining(&self) -> Duration {
let now = Instant::now();
if now >= self.expires_at {
Duration::ZERO
} else {
self.expires_at - now
}
}
fn reset(&mut self, duration: Duration) {
self.expires_at = Instant::now() + duration;
self.duration = duration;
self.fire_count += 1;
}
fn is_max_attempts_reached(&self) -> bool {
matches!(self.timer_type, TimerType::Retransmit(_))
&& self.fire_count >= MAX_RETRANSMIT_ATTEMPTS
}
}
#[derive(Debug)]
pub struct TimerManager {
timers: HashMap<(u16, TimerType), TimerEntry>,
timer_queue: VecDeque<(u16, TimerType)>,
default_connect_timeout: Duration,
default_idle_timeout: Duration,
default_keepalive_interval: Duration,
backoff_multiplier: f64,
max_backoff: f64,
}
impl Default for TimerManager {
fn default() -> Self {
Self::new()
}
}
impl TimerManager {
pub fn new() -> Self {
Self {
timers: HashMap::new(),
timer_queue: VecDeque::new(),
default_connect_timeout: DEFAULT_CONNECT_TIMEOUT,
default_idle_timeout: DEFAULT_IDLE_TIMEOUT,
default_keepalive_interval: DEFAULT_KEEPALIVE_INTERVAL,
backoff_multiplier: 2.0,
max_backoff: 64.0,
}
}
pub fn with_defaults(
connect_timeout: Duration,
idle_timeout: Duration,
keepalive_interval: Duration,
) -> Self {
Self {
timers: HashMap::new(),
timer_queue: VecDeque::new(),
default_connect_timeout: connect_timeout,
default_idle_timeout: idle_timeout,
default_keepalive_interval: keepalive_interval,
backoff_multiplier: 2.0,
max_backoff: 64.0,
}
}
pub fn set_timer(&mut self, conn_id: u16, timer_type: TimerType, duration: Duration) {
let key = (conn_id, timer_type);
let entry = TimerEntry::new(conn_id, timer_type, duration);
self.timers.insert(key, entry);
self.timer_queue.retain(|k| *k != key);
self.timer_queue.push_back(key);
}
pub fn cancel_timer(&mut self, conn_id: u16, timer_type: TimerType) {
let key = (conn_id, timer_type);
self.timers.remove(&key);
self.timer_queue.retain(|k| *k != key);
}
pub fn cancel_all_timers(&mut self, conn_id: u16) {
let timer_types: Vec<TimerType> = self
.timers
.keys()
.filter(|(id, _)| *id == conn_id)
.map(|(_, t)| *t)
.collect();
for timer_type in timer_types {
self.cancel_timer(conn_id, timer_type);
}
}
pub fn get_expired_timers(&mut self) -> Vec<(u16, TimerType)> {
let mut expired = Vec::new();
let now = Instant::now();
let expired_keys: Vec<(u16, TimerType)> = self
.timers
.iter()
.filter(|(_, entry)| entry.expires_at <= now)
.map(|(key, _)| *key)
.collect();
for key in expired_keys {
expired.push(key);
if let Some(entry) = self.timers.get(&key) {
if matches!(entry.timer_type, TimerType::Retransmit(_)) {
if entry.is_max_attempts_reached() {
self.timers.remove(&key);
self.timer_queue.retain(|k| *k != key);
} else {
let new_duration = self.calculate_backoff(entry.duration, entry.fire_count);
if let Some(new_entry) = self.timers.get_mut(&key) {
new_entry.reset(new_duration);
}
}
} else {
self.timers.remove(&key);
self.timer_queue.retain(|k| *k != key);
}
}
}
expired
}
fn calculate_backoff(&self, base_duration: Duration, fire_count: u32) -> Duration {
let backoff = self.backoff_multiplier.powi(fire_count as i32);
let clamped_backoff = backoff.min(self.max_backoff);
let new_duration_us = (base_duration.as_micros() as f64 * clamped_backoff) as u64;
Duration::from_micros(new_duration_us).clamp(MIN_RTO, MAX_RTO)
}
pub fn has_timer(&self, conn_id: u16, timer_type: TimerType) -> bool {
self.timers.contains_key(&(conn_id, timer_type))
}
pub fn remaining_time(&self, conn_id: u16, timer_type: TimerType) -> Option<Duration> {
self.timers
.get(&(conn_id, timer_type))
.map(|e| e.remaining())
}
pub fn next_timer(&self) -> Option<(u16, TimerType, Duration)> {
self.timer_queue.front().and_then(|key| {
self.timers
.get(key)
.map(|entry| (key.0, key.1, entry.remaining()))
})
}
pub fn timer_count(&self) -> usize {
self.timers.len()
}
pub fn connection_timer_count(&self, conn_id: u16) -> usize {
self.timers.keys().filter(|(id, _)| *id == conn_id).count()
}
pub fn clear(&mut self) {
self.timers.clear();
self.timer_queue.clear();
}
pub fn default_connect_timeout(&self) -> Duration {
self.default_connect_timeout
}
pub fn default_idle_timeout(&self) -> Duration {
self.default_idle_timeout
}
pub fn default_keepalive_interval(&self) -> Duration {
self.default_keepalive_interval
}
pub fn set_default_connect_timeout(&mut self, timeout: Duration) {
self.default_connect_timeout = timeout;
}
pub fn set_default_idle_timeout(&mut self, timeout: Duration) {
self.default_idle_timeout = timeout;
}
pub fn set_default_keepalive_interval(&mut self, interval: Duration) {
self.default_keepalive_interval = interval;
}
pub fn retransmit_count(&self, conn_id: u16, seq_nr: u16) -> Option<u32> {
self.timers
.get(&(conn_id, TimerType::Retransmit(seq_nr)))
.map(|e| e.fire_count)
}
pub fn is_retransmit_max_attempts(&self, conn_id: u16, seq_nr: u16) -> bool {
self.timers
.get(&(conn_id, TimerType::Retransmit(seq_nr)))
.map(|e| e.is_max_attempts_reached())
.unwrap_or(false)
}
}
#[derive(Debug, Clone)]
pub struct RetransmitScheduler {
base_rto: Duration,
current_rto: Duration,
timeout_count: u32,
max_attempts: u32,
backoff_multiplier: f64,
max_backoff: f64,
}
impl Default for RetransmitScheduler {
fn default() -> Self {
Self::new()
}
}
impl RetransmitScheduler {
pub fn new() -> Self {
Self {
base_rto: DEFAULT_INITIAL_RTO,
current_rto: DEFAULT_INITIAL_RTO,
timeout_count: 0,
max_attempts: MAX_RETRANSMIT_ATTEMPTS,
backoff_multiplier: 2.0,
max_backoff: 64.0,
}
}
pub fn with_rto(rto: Duration) -> Self {
Self {
base_rto: rto,
current_rto: rto,
..Self::new()
}
}
pub fn rto(&self) -> Duration {
self.current_rto
}
pub fn base_rto(&self) -> Duration {
self.base_rto
}
pub fn timeout_count(&self) -> u32 {
self.timeout_count
}
pub fn is_max_attempts_reached(&self) -> bool {
self.timeout_count >= self.max_attempts
}
pub fn on_timeout(&mut self) {
self.timeout_count += 1;
let backoff = self.backoff_multiplier.powi(self.timeout_count as i32);
let clamped_backoff = backoff.min(self.max_backoff);
let new_rto_us = (self.base_rto.as_micros() as f64 * clamped_backoff) as u64;
self.current_rto = Duration::from_micros(new_rto_us).clamp(MIN_RTO, MAX_RTO);
}
pub fn on_ack_received(&mut self) {
self.timeout_count = 0;
self.current_rto = self.base_rto;
}
pub fn update_rto(&mut self, srtt: Duration, rttvar: Duration) {
let new_rto = srtt + 4 * rttvar;
self.base_rto = new_rto.clamp(MIN_RTO, MAX_RTO);
if self.timeout_count == 0 {
self.current_rto = self.base_rto;
}
}
pub fn set_max_attempts(&mut self, max: u32) {
self.max_attempts = max;
}
pub fn reset(&mut self) {
self.current_rto = self.base_rto;
self.timeout_count = 0;
}
}
#[derive(Debug, Clone)]
pub struct KeepaliveManager {
interval: Duration,
last_keepalive: Option<Instant>,
last_activity: Option<Instant>,
enabled: bool,
}
impl Default for KeepaliveManager {
fn default() -> Self {
Self::new()
}
}
impl KeepaliveManager {
pub fn new() -> Self {
Self {
interval: DEFAULT_KEEPALIVE_INTERVAL,
last_keepalive: None,
last_activity: None,
enabled: true,
}
}
pub fn with_interval(interval: Duration) -> Self {
Self {
interval,
..Self::new()
}
}
pub fn interval(&self) -> Duration {
self.interval
}
pub fn set_interval(&mut self, interval: Duration) {
self.interval = interval;
}
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn record_activity(&mut self) {
self.last_activity = Some(Instant::now());
}
pub fn record_keepalive_sent(&mut self) {
self.last_keepalive = Some(Instant::now());
}
pub fn should_send_keepalive(&self) -> bool {
if !self.enabled {
return false;
}
let now = Instant::now();
if let Some(last_activity) = self.last_activity
&& now.duration_since(last_activity) >= self.interval
{
return true;
}
if let Some(last_keepalive) = self.last_keepalive {
if now.duration_since(last_keepalive) >= self.interval {
return true;
}
} else {
if self.last_activity.is_none() {
return true;
}
}
false
}
pub fn next_keepalive(&self) -> Option<Duration> {
if !self.enabled {
return None;
}
let now = Instant::now();
let idle_time = self
.last_activity
.map_or(Duration::ZERO, |t| now.duration_since(t));
if idle_time >= self.interval {
Some(Duration::ZERO)
} else {
Some(self.interval - idle_time)
}
}
pub fn reset(&mut self) {
self.last_keepalive = None;
self.last_activity = None;
}
}
#[derive(Debug, Clone)]
pub struct IdleTimeoutDetector {
timeout: Duration,
last_activity: Option<Instant>,
enabled: bool,
}
impl Default for IdleTimeoutDetector {
fn default() -> Self {
Self::new()
}
}
impl IdleTimeoutDetector {
pub fn new() -> Self {
Self {
timeout: DEFAULT_IDLE_TIMEOUT,
last_activity: None,
enabled: true,
}
}
pub fn with_timeout(timeout: Duration) -> Self {
Self {
timeout,
..Self::new()
}
}
pub fn timeout(&self) -> Duration {
self.timeout
}
pub fn set_timeout(&mut self, timeout: Duration) {
self.timeout = timeout;
}
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn record_activity(&mut self) {
self.last_activity = Some(Instant::now());
}
pub fn is_timeout(&self) -> bool {
if !self.enabled {
return false;
}
if let Some(last_activity) = self.last_activity {
last_activity.elapsed() >= self.timeout
} else {
true
}
}
pub fn idle_time(&self) -> Duration {
self.last_activity.map_or(Duration::ZERO, |t| t.elapsed())
}
pub fn remaining_time(&self) -> Option<Duration> {
if !self.enabled {
return None;
}
let idle = self.idle_time();
if idle >= self.timeout {
Some(Duration::ZERO)
} else {
Some(self.timeout - idle)
}
}
pub fn reset(&mut self) {
self.last_activity = Some(Instant::now());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_timer_type_display() {
assert_eq!(TimerType::ConnectTimeout.to_string(), "ConnectTimeout");
assert_eq!(TimerType::Retransmit(42).to_string(), "Retransmit(seq=42)");
assert_eq!(TimerType::Keepalive.to_string(), "Keepalive");
assert_eq!(TimerType::IdleTimeout.to_string(), "IdleTimeout");
}
#[test]
fn test_timer_manager_new() {
let manager = TimerManager::new();
assert_eq!(manager.timer_count(), 0);
assert!(manager.next_timer().is_none());
}
#[test]
fn test_timer_manager_set_timer() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::ConnectTimeout, Duration::from_secs(5));
assert_eq!(manager.timer_count(), 1);
assert!(manager.has_timer(1, TimerType::ConnectTimeout));
}
#[test]
fn test_timer_manager_cancel_timer() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::ConnectTimeout, Duration::from_secs(5));
assert_eq!(manager.timer_count(), 1);
manager.cancel_timer(1, TimerType::ConnectTimeout);
assert_eq!(manager.timer_count(), 0);
assert!(!manager.has_timer(1, TimerType::ConnectTimeout));
}
#[test]
fn test_timer_manager_cancel_all_timers() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::ConnectTimeout, Duration::from_secs(5));
manager.set_timer(1, TimerType::Keepalive, Duration::from_secs(10));
manager.set_timer(2, TimerType::IdleTimeout, Duration::from_secs(30));
assert_eq!(manager.timer_count(), 3);
assert_eq!(manager.connection_timer_count(1), 2);
manager.cancel_all_timers(1);
assert_eq!(manager.timer_count(), 1);
assert_eq!(manager.connection_timer_count(1), 0);
assert_eq!(manager.connection_timer_count(2), 1);
}
#[test]
fn test_timer_manager_get_expired_timers() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::ConnectTimeout, Duration::from_millis(1));
std::thread::sleep(Duration::from_millis(10));
let expired = manager.get_expired_timers();
assert_eq!(expired.len(), 1);
assert_eq!(expired[0], (1, TimerType::ConnectTimeout));
assert_eq!(manager.timer_count(), 0);
}
#[test]
fn test_timer_manager_remaining_time() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::Keepalive, Duration::from_secs(10));
let remaining = manager.remaining_time(1, TimerType::Keepalive);
assert!(remaining.is_some());
let rem = remaining.unwrap();
assert!(rem <= Duration::from_secs(10));
assert!(rem > Duration::from_secs(8));
}
#[test]
fn test_timer_manager_clear() {
let mut manager = TimerManager::new();
manager.set_timer(1, TimerType::ConnectTimeout, Duration::from_secs(5));
manager.set_timer(2, TimerType::Keepalive, Duration::from_secs(10));
manager.clear();
assert_eq!(manager.timer_count(), 0);
}
#[test]
fn test_timer_manager_defaults() {
let manager = TimerManager::new();
assert_eq!(manager.default_connect_timeout(), DEFAULT_CONNECT_TIMEOUT);
assert_eq!(manager.default_idle_timeout(), DEFAULT_IDLE_TIMEOUT);
assert_eq!(
manager.default_keepalive_interval(),
DEFAULT_KEEPALIVE_INTERVAL
);
}
#[test]
fn test_retransmit_scheduler_new() {
let scheduler = RetransmitScheduler::new();
assert_eq!(scheduler.rto(), DEFAULT_INITIAL_RTO);
assert_eq!(scheduler.timeout_count(), 0);
assert!(!scheduler.is_max_attempts_reached());
}
#[test]
fn test_retransmit_scheduler_timeout() {
let mut scheduler = RetransmitScheduler::new();
let initial_rto = scheduler.rto();
scheduler.on_timeout();
assert_eq!(scheduler.timeout_count(), 1);
assert!(scheduler.rto() > initial_rto);
}
#[test]
fn test_retransmit_scheduler_ack_received() {
let mut scheduler = RetransmitScheduler::new();
scheduler.on_timeout();
scheduler.on_timeout();
assert_eq!(scheduler.timeout_count(), 2);
scheduler.on_ack_received();
assert_eq!(scheduler.timeout_count(), 0);
assert_eq!(scheduler.rto(), scheduler.base_rto());
}
#[test]
fn test_keepalive_manager_new() {
let manager = KeepaliveManager::new();
assert_eq!(manager.interval(), DEFAULT_KEEPALIVE_INTERVAL);
assert!(manager.is_enabled());
}
#[test]
fn test_keepalive_manager_should_send() {
let mut manager = KeepaliveManager::new();
assert!(manager.should_send_keepalive());
manager.record_activity();
assert!(!manager.should_send_keepalive());
}
#[test]
fn test_idle_timeout_detector_new() {
let detector = IdleTimeoutDetector::new();
assert_eq!(detector.timeout(), DEFAULT_IDLE_TIMEOUT);
assert!(detector.is_enabled());
}
#[test]
fn test_idle_timeout_detector_is_timeout() {
let mut detector = IdleTimeoutDetector::with_timeout(Duration::from_millis(100));
detector.record_activity();
assert!(!detector.is_timeout());
std::thread::sleep(Duration::from_millis(150));
assert!(detector.is_timeout());
}
}