rtc_sctp/association/
timer.rs1use std::time::{Duration, Instant};
2
3pub(crate) const ACK_INTERVAL: u64 = 200;
4const MAX_INIT_RETRANS: usize = 8;
5const PATH_MAX_RETRANS: usize = 5;
6const NO_MAX_RETRANS: usize = usize::MAX;
7const TIMER_COUNT: usize = 6;
8
9#[derive(Debug, Copy, Clone)]
10pub struct TimerConfig {
15 pub max_t1_init_retrans: usize,
17 pub max_t1_cookie_retrans: usize,
19 pub max_t2_shutdown_retrans: usize,
21 pub max_t3_rtx_retrans: usize,
25 pub max_reconfig_retrans: usize,
27 pub max_ack_retrans: usize,
29}
30
31impl Default for TimerConfig {
32 fn default() -> Self {
33 Self {
34 max_t1_init_retrans: MAX_INIT_RETRANS,
35 max_t1_cookie_retrans: MAX_INIT_RETRANS,
36 max_t2_shutdown_retrans: NO_MAX_RETRANS,
37 max_t3_rtx_retrans: PATH_MAX_RETRANS,
38 max_reconfig_retrans: PATH_MAX_RETRANS,
39 max_ack_retrans: PATH_MAX_RETRANS,
40 }
41 }
42}
43
44#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
45pub(crate) enum Timer {
46 T1Init = 0,
47 T1Cookie = 1,
48 T2Shutdown = 2,
49 T3RTX = 3,
50 Reconfig = 4,
51 Ack = 5,
52}
53
54impl Timer {
55 pub(crate) const VALUES: [Self; TIMER_COUNT] = [
56 Timer::T1Init,
57 Timer::T1Cookie,
58 Timer::T2Shutdown,
59 Timer::T3RTX,
60 Timer::Reconfig,
61 Timer::Ack,
62 ];
63}
64
65#[derive(Debug, Copy, Clone, Default)]
67pub(crate) struct TimerTable {
68 data: [Option<Instant>; TIMER_COUNT],
69 retrans: [usize; TIMER_COUNT],
70 max_retrans: [usize; TIMER_COUNT],
71}
72
73impl TimerTable {
74 pub fn new(time_config: TimerConfig) -> Self {
75 TimerTable {
76 max_retrans: [
77 time_config.max_t1_init_retrans, time_config.max_t1_cookie_retrans, time_config.max_t2_shutdown_retrans, time_config.max_t3_rtx_retrans, time_config.max_reconfig_retrans, time_config.max_ack_retrans, ],
84 ..Default::default()
85 }
86 }
87
88 pub fn set(&mut self, timer: Timer, time: Option<Instant>) {
89 self.data[timer as usize] = time;
90 }
91
92 pub fn get(&self, timer: Timer) -> Option<Instant> {
93 self.data[timer as usize]
94 }
95
96 pub fn next_timeout(&self) -> Option<Instant> {
97 self.data.iter().filter_map(|&x| x).min()
98 }
99
100 pub fn start(&mut self, timer: Timer, now: Instant, interval: u64) {
101 let interval = if timer == Timer::Ack {
102 interval
103 } else {
104 calculate_next_timeout(interval, self.retrans[timer as usize])
105 };
106
107 let time = now + Duration::from_millis(interval);
108 self.data[timer as usize] = Some(time);
109 }
110
111 pub fn restart_if_stale(&mut self, timer: Timer, now: Instant, interval: u64) {
113 if let Some(current) = self.data[timer as usize]
114 && current >= now
115 {
116 return;
117 }
118
119 self.start(timer, now, interval);
120 }
121
122 pub fn stop(&mut self, timer: Timer) {
123 self.data[timer as usize] = None;
124 self.retrans[timer as usize] = 0;
125 }
126
127 pub fn is_expired(&mut self, timer: Timer, after: Instant) -> (bool, bool, usize) {
128 let expired = self.data[timer as usize].is_some_and(|x| x <= after);
129 let mut failure = false;
130 if expired {
131 self.retrans[timer as usize] += 1;
132 if self.retrans[timer as usize] > self.max_retrans[timer as usize] {
133 failure = true;
134 }
135 }
136
137 (expired, failure, self.retrans[timer as usize])
138 }
139}
140
141const RTO_INITIAL: u64 = 3000; const RTO_MIN: u64 = 1000; const RTO_MAX: u64 = 60000; const RTO_ALPHA: u64 = 1;
145const RTO_BETA: u64 = 2;
146const RTO_BASE: u64 = 8;
147
148#[derive(Default, Debug)]
151pub(crate) struct RtoManager {
152 pub(crate) srtt: u64,
153 pub(crate) rttvar: f64,
154 pub(crate) rto: u64,
155 pub(crate) no_update: bool,
156}
157
158impl RtoManager {
159 pub(crate) fn new() -> Self {
161 RtoManager {
162 rto: RTO_INITIAL,
163 ..Default::default()
164 }
165 }
166
167 pub(crate) fn set_new_rtt(&mut self, rtt: u64) -> u64 {
169 if self.no_update {
170 return self.srtt;
171 }
172
173 if self.srtt == 0 {
174 self.srtt = rtt;
176 self.rttvar = rtt as f64 / 2.0;
177 } else {
178 self.rttvar = ((RTO_BASE - RTO_BETA) as f64 * self.rttvar
180 + RTO_BETA as f64 * (self.srtt as i64 - rtt as i64).abs() as f64)
181 / RTO_BASE as f64;
182 self.srtt = ((RTO_BASE - RTO_ALPHA) * self.srtt + RTO_ALPHA * rtt) / RTO_BASE;
183 }
184
185 self.rto = (self.srtt + (4.0 * self.rttvar) as u64).clamp(RTO_MIN, RTO_MAX);
186
187 self.srtt
188 }
189
190 pub(crate) fn get_rto(&self) -> u64 {
192 self.rto
193 }
194
195 pub(crate) fn reset(&mut self) {
197 if self.no_update {
198 return;
199 }
200
201 self.srtt = 0;
202 self.rttvar = 0.0;
203 self.rto = RTO_INITIAL;
204 }
205
206 pub(crate) fn set_rto(&mut self, rto: u64, no_update: bool) {
208 self.rto = rto;
209 self.no_update = no_update;
210 }
211}
212
213fn calculate_next_timeout(rto: u64, n_rtos: usize) -> u64 {
214 if n_rtos < 31 {
220 std::cmp::min(rto << n_rtos, RTO_MAX)
221 } else {
222 RTO_MAX
223 }
224}