Skip to main content

sipx_sip/transaction/
timing.rs

1//! Transaction timers (RFC 3261 §17, Table 4).
2
3use std::time::Duration;
4
5use crate::transaction::Reliability;
6
7/// The timers of RFC 3261 §17.
8///
9/// Named by letter because that is what the RFC calls them and what every packet capture and
10/// every mailing-list thread will call them. Renaming them to something friendlier would only
11/// make the code harder to check against the specification.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Timer {
14    /// INVITE request retransmission. Unreliable transports only.
15    A,
16    /// INVITE client transaction timeout.
17    B,
18    /// Wait for response retransmissions after a non-2xx final response.
19    D,
20    /// Non-INVITE request retransmission. Unreliable transports only.
21    E,
22    /// Non-INVITE client transaction timeout.
23    F,
24    /// INVITE response retransmission. Unreliable transports only.
25    G,
26    /// Wait for an ACK.
27    H,
28    /// Wait for ACK retransmissions.
29    I,
30    /// Wait for non-INVITE request retransmissions.
31    J,
32    /// Wait for response retransmissions, non-INVITE client.
33    K,
34    /// RFC 6026: wait for an ACK to a 2xx.
35    L,
36    /// RFC 6026: wait for retransmissions of a 2xx.
37    M,
38    /// The 200 ms after which a server transaction sends 100 Trying by itself.
39    ///
40    /// Not lettered in the RFC — §17.2.1 states it as a plain duration — but it is a timer and
41    /// the machine needs a name for it.
42    Trying100,
43}
44
45impl Timer {
46    /// Every transaction timer, for drivers that terminate one transaction and must discard its
47    /// whole bounded timer set without scanning timers belonging to other transactions.
48    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/// The three constants everything else is derived from.
66#[derive(Debug, Clone, Copy)]
67pub struct Timers {
68    /// Round-trip estimate. The base of every backoff.
69    pub t1: Duration,
70    /// Ceiling for retransmission intervals.
71    pub t2: Duration,
72    /// Longest a message can linger in the network.
73    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    /// 64·T1 — how long a transaction waits before giving up.
88    #[must_use]
89    pub fn timeout(&self) -> Duration {
90        self.t1 * 64
91    }
92
93    /// Timer D: at least 32 s on an unreliable transport, nothing on a reliable one.
94    ///
95    /// The RFC gives 32 s rather than a multiple of T1 because the purpose is to outlast
96    /// response retransmissions from the *other* end, whose T1 we do not know.
97    #[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    /// Timer I and Timer K: T4 unreliable, zero reliable.
107    #[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    /// Timer J: 64·T1 unreliable, zero reliable.
117    #[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    /// The next retransmission interval, doubling without a ceiling — Timer A.
127    #[must_use]
128    pub fn double(&self, current: Duration) -> Duration {
129        current.saturating_mul(2)
130    }
131
132    /// The next retransmission interval, doubling but capped at T2 — Timers E and G.
133    #[must_use]
134    pub fn double_capped(&self, current: Duration) -> Duration {
135        current.saturating_mul(2).min(self.t2)
136    }
137
138    /// How long a server transaction waits before sending 100 Trying on its own initiative.
139    #[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        // Timer A doubles without a ceiling: 500ms, 1s, 2s, 4s, 8s…
168        assert_eq!(t.double(t.t1), Duration::from_secs(1));
169        assert_eq!(t.double(Duration::from_secs(4)), Duration::from_secs(8));
170        // Timer E is capped at T2.
171        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    /// With a large T1, Timer D must still outlast the transaction, so it is the larger of
188    /// 32 s and 64·T1 rather than a flat 32 s.
189    #[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}