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