rvoip_transaction_core/server/
mod.rs

1/// # Server Transaction Module
2///
3/// This module implements the server-side transaction state machines according to 
4/// [RFC 3261 Section 17.2](https://datatracker.ietf.org/doc/html/rfc3261#section-17.2).
5/// 
6/// ## SIP Server Transactions
7///
8/// Server transactions are created when a SIP element receives a request from a client.
9/// They ensure proper handling of requests, responses, and retransmissions according
10/// to the SIP protocol specifications.
11///
12/// ## Transaction Types
13///
14/// RFC 3261 defines two types of server transactions with different state machines:
15///
16/// 1. **INVITE Server Transactions** (Section 17.2.1): Used for handling session establishment requests.
17///    - More complex due to the three-way handshake (INVITE, response, ACK)
18///    - Uses a four-state machine: Proceeding, Completed, Confirmed, and Terminated
19///    - Uses timers G, H, and I for retransmission and timeout management
20///    - Must handle ACK specially in the Completed state
21///
22/// 2. **Non-INVITE Server Transactions** (Section 17.2.2): Used for all other request types.
23///    - Simpler state machine with three states: Trying, Proceeding, and Completed
24///    - Uses timer J for state management
25///    - No special handling for ACK required
26///
27/// ## Implementation Details
28///
29/// Both transaction types share common infrastructure but implement different state machines:
30///
31/// - `ServerInviteTransaction`: Implements the INVITE server transaction state machine
32/// - `ServerNonInviteTransaction`: Implements the non-INVITE server transaction state machine
33/// - `ServerTransactionData`: Shared data structure for both transaction types
34/// - `CommonServerTransaction`: Common behavior for server transactions
35/// - `ServerTransaction`: Interface for all server transactions
36///
37/// ## Usage
38///
39/// Server transactions are typically created by the `TransactionManager` when it receives
40/// a request from the network. It routes incoming messages to the appropriate transaction
41/// and provides a clean API for the Transaction User (TU) to send responses.
42
43mod common;
44mod invite;
45mod non_invite;
46mod data;
47pub mod builders;
48
49pub use common::*;
50pub use invite::ServerInviteTransaction;
51pub use non_invite::ServerNonInviteTransaction;
52pub use data::{ServerTransactionData, CommandSender, CommandReceiver, CommonServerTransaction};
53
54use async_trait::async_trait;
55use std::net::SocketAddr;
56use std::future::Future;
57use std::pin::Pin;
58use std::sync::Arc;
59
60use crate::error::Result;
61use crate::transaction::{Transaction, TransactionState, TransactionKey, TransactionAsync};
62use rvoip_sip_core::prelude::*;
63use rvoip_sip_core::json::ext::SipMessageJson;
64
65/// Common interface for server transactions, implementing the behavior defined in RFC 3261 Section 17.2.
66///
67/// This trait defines operations that both INVITE and non-INVITE server transactions must support.
68/// It encapsulates the functionality required to process requests, send responses, and track state
69/// according to the SIP specification.
70#[async_trait]
71pub trait ServerTransaction: Transaction + TransactionAsync + Send + Sync + 'static {
72    /// Processes an incoming request associated with this transaction.
73    ///
74    /// This handles various types of requests that may arrive for this transaction:
75    /// - For INVITE server transactions: ACK requests or CANCEL requests
76    /// - For non-INVITE server transactions: Retransmissions of the original request
77    ///
78    /// # Arguments
79    ///
80    /// * `request` - The SIP request to process
81    ///
82    /// # Returns
83    ///
84    /// A Future that resolves to Ok(()) if the request was processed successfully,
85    /// or an Error if there was a problem.
86    fn process_request(&self, request: Request) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>>;
87
88    /// Sends a response for this transaction, triggering appropriate state transitions.
89    ///
90    /// According to RFC 3261 Sections 17.2.1 and 17.2.2, sending responses triggers 
91    /// specific state transitions based on the response status code:
92    ///
93    /// - For INVITE server transactions:
94    ///   - 1xx responses keep the transaction in Proceeding state
95    ///   - 2xx responses cause transition to Terminated state
96    ///   - 3xx-6xx responses cause transition to Completed state
97    ///
98    /// - For non-INVITE server transactions:
99    ///   - In Trying state, 1xx responses cause transition to Proceeding state
100    ///   - In Trying or Proceeding state, final responses cause transition to Completed state
101    ///
102    /// # Arguments
103    ///
104    /// * `response` - The SIP response to send
105    ///
106    /// # Returns
107    ///
108    /// A Future that resolves to Ok(()) if the response was sent successfully,
109    /// or an Error if there was a problem.
110    fn send_response(&self, response: Response) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>>;
111
112    /// Returns the last response sent by this transaction.
113    ///
114    /// This can be used to handle retransmissions of requests, where the server
115    /// should resend the last response without passing the request to the TU.
116    ///
117    /// # Returns
118    ///
119    /// The last SIP response sent by this transaction, or None if no response has been sent.
120    fn last_response(&self) -> Option<Response>;
121    
122    /// Gets the Call-ID from the original request that created this transaction.
123    ///
124    /// Call-ID is a critical dialog identifier used to match ACK with its INVITE.
125    /// According to RFC 3261 section 8.1.1.4, Call-ID must be identical for all
126    /// requests and responses in a dialog, including the ACK for a final response.
127    ///
128    /// # Returns
129    /// 
130    /// Some(call_id) if the transaction has an original request with a Call-ID header,
131    /// None otherwise.
132    fn original_request_call_id(&self) -> Option<String> {
133        if let Some(req) = self.original_request_sync() {
134            req.call_id().map(|hdr| hdr.value().to_string())
135        } else {
136            None
137        }
138    }
139    
140    /// Gets the From tag from the original request that created this transaction.
141    ///
142    /// From tag is part of the dialog identifiers used to match ACK with its INVITE.
143    /// According to RFC 3261 section 8.1.1.7, the From tag must be identical for all
144    /// requests and responses in a dialog (including ACK and CANCEL).
145    ///
146    /// # Returns
147    /// 
148    /// Some(from_tag) if the transaction has an original request with a From tag,
149    /// None otherwise.
150    fn original_request_from_tag(&self) -> Option<String> {
151        if let Some(req) = self.original_request_sync() {
152            req.from_tag()
153        } else {
154            None
155        }
156    }
157    
158    /// Gets the To tag from the original request that created this transaction.
159    ///
160    /// To tag may be part of the dialog identifiers used to match ACK with its INVITE.
161    /// In early dialogs, the original INVITE may not have a To tag, but subsequent
162    /// ACKs for final responses will include the To tag from the response.
163    ///
164    /// # Returns
165    /// 
166    /// Some(to_tag) if the transaction has an original request with a To tag,
167    /// None otherwise.
168    fn original_request_to_tag(&self) -> Option<String> {
169        if let Some(req) = self.original_request_sync() {
170            req.to_tag()
171        } else {
172            None
173        }
174    }
175    
176    /// Synchronous accessor for the original request if it's available without async operations.
177    /// This is an internal helper method that should be implemented by transaction types
178    /// that can provide synchronous access to the original request.
179    ///
180    /// # Returns
181    /// 
182    /// Some(Request) if the transaction has cached the original request,
183    /// None if it would require an async operation to retrieve.
184    fn original_request_sync(&self) -> Option<Request> {
185        None
186    }
187}
188
189/// Extension trait for Transaction to safely downcast to ServerTransaction.
190///
191/// This trait provides a convenience method for downcasting any Transaction object
192/// to a ServerTransaction reference, making it easier to work with transaction-specific
193/// functionality without unsafe code.
194pub trait TransactionExt {
195    /// Attempts to downcast to a ServerTransaction reference.
196    ///
197    /// # Returns
198    ///
199    /// Some(&dyn ServerTransaction) if the transaction is a server transaction,
200    /// None otherwise.
201    fn as_server_transaction(&self) -> Option<&dyn ServerTransaction>;
202}
203
204impl<T: Transaction + ?Sized> TransactionExt for T {
205    fn as_server_transaction(&self) -> Option<&dyn ServerTransaction> {
206        use crate::transaction::TransactionKind;
207        
208        match self.kind() {
209            TransactionKind::InviteServer | TransactionKind::NonInviteServer => {
210                // Get the Any representation and try downcasting
211                self.as_any().downcast_ref::<Box<dyn ServerTransaction>>()
212                    .map(|boxed| boxed.as_ref())
213                    .or_else(|| {
214                        // Try with specific implementations
215                        use crate::server::{ServerInviteTransaction, ServerNonInviteTransaction};
216                        
217                        if let Some(tx) = self.as_any().downcast_ref::<ServerInviteTransaction>() {
218                            Some(tx as &dyn ServerTransaction)
219                        } else if let Some(tx) = self.as_any().downcast_ref::<ServerNonInviteTransaction>() {
220                            Some(tx as &dyn ServerTransaction)
221                        } else {
222                            None
223                        }
224                    })
225            },
226            _ => None,
227        }
228    }
229}