sipx_sip/transaction/
timing.rs1use std::time::Duration;
4
5use crate::transaction::Reliability;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Timer {
14 A,
16 B,
18 D,
20 E,
22 F,
24 G,
26 H,
28 I,
30 J,
32 K,
34 L,
36 M,
38 Trying100,
43}
44
45impl Timer {
46 pub const ALL: [Self; 13] = [
49 Self::A,
50 Self::B,
51 Self::D,
52 Self::E,
53 Self::F,
54 Self::G,
55 Self::H,
56 Self::I,
57 Self::J,
58 Self::K,
59 Self::L,
60 Self::M,
61 Self::Trying100,
62 ];
63}
64
65#[derive(Debug, Clone, Copy)]
67pub struct Timers {
68 pub t1: Duration,
70 pub t2: Duration,
72 pub t4: Duration,
74}
75
76impl Default for Timers {
77 fn default() -> Self {
78 Self {
79 t1: Duration::from_millis(500),
80 t2: Duration::from_secs(4),
81 t4: Duration::from_secs(5),
82 }
83 }
84}
85
86impl Timers {
87 #[must_use]
89 pub fn timeout(&self) -> Duration {
90 self.t1 * 64
91 }
92
93 #[must_use]
98 pub fn timer_d(&self, reliability: Reliability) -> Duration {
99 if reliability.is_reliable() {
100 Duration::ZERO
101 } else {
102 Duration::from_secs(32).max(self.timeout())
103 }
104 }
105
106 #[must_use]
108 pub fn absorb(&self, reliability: Reliability) -> Duration {
109 if reliability.is_reliable() {
110 Duration::ZERO
111 } else {
112 self.t4
113 }
114 }
115
116 #[must_use]
118 pub fn timer_j(&self, reliability: Reliability) -> Duration {
119 if reliability.is_reliable() {
120 Duration::ZERO
121 } else {
122 self.timeout()
123 }
124 }
125
126 #[must_use]
128 pub fn double(&self, current: Duration) -> Duration {
129 current.saturating_mul(2)
130 }
131
132 #[must_use]
134 pub fn double_capped(&self, current: Duration) -> Duration {
135 current.saturating_mul(2).min(self.t2)
136 }
137
138 #[must_use]
140 pub fn trying_100(&self) -> Duration {
141 Duration::from_millis(200)
142 }
143}
144
145#[cfg(test)]
146#[allow(
147 clippy::unwrap_used,
148 clippy::expect_used,
149 clippy::panic,
150 clippy::indexing_slicing
151)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn defaults_match_rfc3261_table_4() {
157 let t = Timers::default();
158 assert_eq!(t.t1, Duration::from_millis(500));
159 assert_eq!(t.t2, Duration::from_secs(4));
160 assert_eq!(t.t4, Duration::from_secs(5));
161 assert_eq!(t.timeout(), Duration::from_secs(32));
162 }
163
164 #[test]
165 fn backoff_doubles_and_timer_e_stops_at_t2() {
166 let t = Timers::default();
167 assert_eq!(t.double(t.t1), Duration::from_secs(1));
169 assert_eq!(t.double(Duration::from_secs(4)), Duration::from_secs(8));
170 assert_eq!(t.double_capped(Duration::from_secs(4)), t.t2);
172 assert_eq!(t.double_capped(Duration::from_secs(8)), t.t2);
173 }
174
175 #[test]
176 fn reliable_transports_collapse_the_absorption_timers() {
177 let t = Timers::default();
178 assert_eq!(t.absorb(Reliability::Reliable), Duration::ZERO);
179 assert_eq!(t.timer_j(Reliability::Reliable), Duration::ZERO);
180 assert_eq!(t.timer_d(Reliability::Reliable), Duration::ZERO);
181
182 assert_eq!(t.absorb(Reliability::Unreliable), t.t4);
183 assert_eq!(t.timer_j(Reliability::Unreliable), t.timeout());
184 assert_eq!(t.timer_d(Reliability::Unreliable), Duration::from_secs(32));
185 }
186
187 #[test]
190 fn timer_d_outlasts_the_transaction_even_with_a_large_t1() {
191 let t = Timers {
192 t1: Duration::from_secs(2),
193 ..Timers::default()
194 };
195 assert_eq!(t.timeout(), Duration::from_secs(128));
196 assert_eq!(t.timer_d(Reliability::Unreliable), Duration::from_secs(128));
197 }
198}