ftth_rsipstack/transaction/
mod.rs

1use crate::transport::{SipAddr, SipConnection};
2use key::TransactionKey;
3use std::time::Duration;
4use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
5use transaction::Transaction;
6
7use crate::rsip;
8
9pub mod endpoint;
10pub mod key;
11pub mod message;
12mod timer;
13pub mod transaction;
14pub use endpoint::Endpoint;
15pub use endpoint::EndpointBuilder;
16#[cfg(test)]
17mod tests;
18
19pub const TO_TAG_LEN: usize = 8;
20pub const BRANCH_LEN: usize = 12;
21pub const CNONCE_LEN: usize = 8;
22pub const CALL_ID_LEN: usize = 22;
23pub struct IncomingRequest {
24    pub request: rsip::Request,
25    pub connection: SipConnection,
26    pub from: SipAddr,
27}
28
29pub type TransactionReceiver = UnboundedReceiver<Transaction>;
30pub type TransactionSender = UnboundedSender<Transaction>;
31
32/// SIP Transaction State
33///
34/// `TransactionState` represents the various states a SIP transaction can be in
35/// during its lifecycle. These states implement the transaction state machines
36/// defined in RFC 3261 for both client and server transactions.
37///
38/// # States
39///
40/// * `Nothing` - Initial state for client transactions created
41/// * `Calling` - Initial state for client transactions when request is sent or received
42/// * `Trying` - Request has been sent/received, waiting for response/processing
43/// * `Proceeding` - Provisional response received/sent (1xx except 100 Trying)
44/// * `Completed` - Final response received/sent, waiting for ACK (INVITE) or cleanup
45/// * `Confirmed` - ACK received/sent for INVITE transactions
46/// * `Terminated` - Transaction has completed and is being cleaned up
47///
48/// # State Transitions
49///
50/// ## Client Non-INVITE Transaction
51/// ```text
52/// Nothing → Calling → Trying → Proceeding → Completed → Terminated
53/// ```
54///
55/// ## Client INVITE Transaction  
56/// ```text
57/// Nothing → Calling → Trying → Proceeding → Completed → Terminated
58///                                      ↓
59///                                   Confirmed → Terminated
60/// ```
61///
62/// ## Server Transactions
63/// ```text
64/// Calling → Trying → Proceeding → Completed → Terminated
65///                           ↓
66///                         Confirmed → Terminated (INVITE only)
67/// ```
68///
69/// # Examples
70///
71/// ```rust
72/// use ftth_rsipstack::transaction::TransactionState;
73///
74/// let state = TransactionState::Proceeding;
75/// match state {
76///     TransactionState::Nothing => println!("Transaction starting"),
77///     TransactionState::Calling => println!("Request sent"),
78///     TransactionState::Trying => println!("Request sent/received"),
79///     TransactionState::Proceeding => println!("Provisional response"),
80///     TransactionState::Completed => println!("Final response"),
81///     TransactionState::Confirmed => println!("ACK received/sent"),
82///     TransactionState::Terminated => println!("Transaction complete"),
83/// }
84/// ```
85#[derive(Debug, Clone, PartialEq)]
86pub enum TransactionState {
87    Nothing,
88    Calling,
89    Trying,
90    Proceeding,
91    Completed,
92    Confirmed,
93    Terminated,
94}
95
96impl std::fmt::Display for TransactionState {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match self {
99            TransactionState::Nothing => write!(f, "Nothing"),
100            TransactionState::Calling => write!(f, "Calling"),
101            TransactionState::Trying => write!(f, "Trying"),
102            TransactionState::Proceeding => write!(f, "Proceeding"),
103            TransactionState::Completed => write!(f, "Completed"),
104            TransactionState::Confirmed => write!(f, "Confirmed"),
105            TransactionState::Terminated => write!(f, "Terminated"),
106        }
107    }
108}
109/// SIP Transaction Type
110///
111/// `TransactionType` distinguishes between the four types of SIP transactions
112/// as defined in RFC 3261. Each type has different behavior for retransmissions,
113/// timers, and state transitions.
114///
115/// # Types
116///
117/// * `ClientInvite` - Client-side INVITE transaction (UAC INVITE)
118/// * `ClientNonInvite` - Client-side non-INVITE transaction (UAC non-INVITE)
119/// * `ServerInvite` - Server-side INVITE transaction (UAS INVITE)
120/// * `ServerNonInvite` - Server-side non-INVITE transaction (UAS non-INVITE)
121///
122/// # Characteristics
123///
124/// ## Client INVITE
125/// * Longer timeouts due to human interaction
126/// * ACK handling for 2xx responses
127/// * CANCEL support for early termination
128///
129/// ## Client Non-INVITE
130/// * Shorter timeouts for automated responses
131/// * No ACK required
132/// * Simpler state machine
133///
134/// ## Server INVITE
135/// * Must handle ACK for final responses
136/// * Supports provisional responses
137/// * Complex retransmission rules
138///
139/// ## Server Non-INVITE
140/// * Simple request/response pattern
141/// * No ACK handling
142/// * Faster completion
143///
144/// # Examples
145///
146/// ```rust
147/// use ftth_rsipstack::transaction::TransactionType;
148/// use rsip::Method;
149///
150/// fn get_transaction_type(method: &Method, is_client: bool) -> TransactionType {
151///     match (method, is_client) {
152///         (Method::Invite, true) => TransactionType::ClientInvite,
153///         (Method::Invite, false) => TransactionType::ServerInvite,
154///         (_, true) => TransactionType::ClientNonInvite,
155///         (_, false) => TransactionType::ServerNonInvite,
156///     }
157/// }
158/// ```
159#[derive(Debug, PartialEq)]
160pub enum TransactionType {
161    ClientInvite,
162    ClientNonInvite,
163    ServerInvite,
164    ServerNonInvite,
165}
166impl std::fmt::Display for TransactionType {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        match self {
169            TransactionType::ClientInvite => write!(f, "ClientInvite"),
170            TransactionType::ClientNonInvite => write!(f, "ClientNonInvite"),
171            TransactionType::ServerInvite => write!(f, "ServerInvite"),
172            TransactionType::ServerNonInvite => write!(f, "ServerNonInvite"),
173        }
174    }
175}
176/// SIP Transaction Timers
177///
178/// `TransactionTimer` represents the various timers used in SIP transactions
179/// as defined in RFC 3261. These timers ensure reliable message delivery
180/// and proper transaction cleanup.
181///
182/// # Timer Types
183///
184/// * `TimerA` - Retransmission timer for client transactions (unreliable transport)
185/// * `TimerB` - Transaction timeout timer for client transactions
186/// * `TimerD` - Wait timer for response retransmissions (client)
187/// * `TimerE` - Retransmission timer for non-INVITE server transactions
188/// * `TimerF` - Transaction timeout timer for non-INVITE server transactions
189/// * `TimerK` - Wait timer for ACK (server INVITE transactions)
190/// * `TimerG` - Retransmission timer for INVITE server transactions
191/// * `TimerCleanup` - Internal cleanup timer for transaction removal
192///
193/// # Timer Values (RFC 3261)
194///
195/// * T1 = 500ms (RTT estimate)
196/// * T2 = 4s (maximum retransmit interval)
197/// * T4 = 5s (maximum duration a message will remain in the network)
198///
199/// ## Timer Calculations
200/// * Timer A: starts at T1, doubles each retransmission up to T2
201/// * Timer B: 64*T1 (32 seconds)
202/// * Timer D: 32 seconds for unreliable, 0 for reliable transports
203/// * Timer E: starts at T1, doubles up to T2
204/// * Timer F: 64*T1 (32 seconds)
205/// * Timer G: starts at T1, doubles up to T2
206/// * Timer K: T4 for unreliable, 0 for reliable transports
207///
208/// # Examples
209///
210/// ```rust
211/// use ftth_rsipstack::transaction::{TransactionTimer, key::{TransactionKey, TransactionRole}};
212/// use std::time::Duration;
213///
214/// # fn example() -> ftth_rsipstack::Result<()> {
215/// // Create a mock request to generate a transaction key
216/// let request = rsip::Request {
217///     method: rsip::Method::Register,
218///     uri: rsip::Uri::try_from("sip:example.com")?,
219///     headers: vec![
220///         rsip::Header::Via("SIP/2.0/UDP example.com:5060;branch=z9hG4bKnashds".into()),
221///         rsip::Header::CSeq("1 REGISTER".into()),
222///         rsip::Header::From("Alice <sip:alice@example.com>;tag=1928301774".into()),
223///         rsip::Header::CallId("a84b4c76e66710@pc33.atlanta.com".into()),
224///     ].into(),
225///     version: rsip::Version::V2,
226///     body: Default::default(),
227/// };
228/// let key = TransactionKey::from_request(&request, TransactionRole::Client)?;
229///
230/// let timer = TransactionTimer::TimerA(key.clone(), Duration::from_millis(500));
231/// match timer {
232///     TransactionTimer::TimerA(key, duration) => {
233///         println!("Timer A fired for transaction {}", key);
234///     },
235///     TransactionTimer::TimerB(key) => {
236///         println!("Transaction {} timed out", key);
237///     },
238///     _ => {}
239/// }
240/// # Ok(())
241/// # }
242/// ```
243///
244/// # Usage
245///
246/// Timers are automatically managed by the transaction layer:
247/// * Started when entering appropriate states
248/// * Cancelled when leaving states or receiving responses
249/// * Fire events that drive state machine transitions
250/// * Handle retransmissions and timeouts
251pub enum TransactionTimer {
252    TimerA(TransactionKey, Duration),
253    TimerB(TransactionKey),
254    TimerC(TransactionKey),
255    TimerD(TransactionKey),
256    TimerK(TransactionKey),
257    TimerG(TransactionKey, Duration),
258    TimerCleanup(TransactionKey),
259}
260
261impl TransactionTimer {
262    pub fn key(&self) -> &TransactionKey {
263        match self {
264            TransactionTimer::TimerA(key, _) => key,
265            TransactionTimer::TimerB(key) => key,
266            TransactionTimer::TimerC(key) => key,
267            TransactionTimer::TimerD(key) => key,
268            TransactionTimer::TimerG(key, _) => key,
269            TransactionTimer::TimerK(key) => key,
270            TransactionTimer::TimerCleanup(key) => key,
271        }
272    }
273}
274
275impl std::fmt::Display for TransactionTimer {
276    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277        match self {
278            TransactionTimer::TimerA(key, duration) => {
279                write!(f, "TimerA: {} {}", key, duration.as_millis())
280            }
281            TransactionTimer::TimerB(key) => write!(f, "TimerB: {}", key),
282            TransactionTimer::TimerC(key) => write!(f, "TimerC: {}", key),
283            TransactionTimer::TimerD(key) => write!(f, "TimerD: {}", key),
284            TransactionTimer::TimerG(key, duration) => {
285                write!(f, "TimerG: {} {}", key, duration.as_millis())
286            }
287            TransactionTimer::TimerK(key) => write!(f, "TimerK: {}", key),
288            TransactionTimer::TimerCleanup(key) => write!(f, "TimerCleanup: {}", key),
289        }
290    }
291}
292
293pub fn make_via_branch() -> rsip::Param {
294    rsip::Param::Branch(format!("z9hG4bK{}", random_text(BRANCH_LEN)).into())
295}
296
297pub fn make_call_id(domain: Option<&str>) -> rsip::headers::CallId {
298    format!(
299        "{}@{}",
300        random_text(CALL_ID_LEN),
301        domain.unwrap_or("restsend.com")
302    )
303    .into()
304}
305
306pub fn make_tag() -> rsip::param::Tag {
307    random_text(TO_TAG_LEN).into()
308}
309
310pub fn random_text(count: usize) -> String {
311    use rand::Rng;
312    rand::rng()
313        .sample_iter(rand::distr::Alphanumeric)
314        .take(count)
315        .map(char::from)
316        .collect::<String>()
317}