rvoip_dialog_core/api/server/mod.rs
1//! Dialog Server API
2//!
3//! This module provides a comprehensive server interface for SIP dialog management,
4//! designed for building robust SIP servers, proxies, and application servers that
5//! handle incoming calls, dialog state management, and advanced SIP operations.
6//!
7//! ## Overview
8//!
9//! The DialogServer is the primary interface for server-side SIP operations, providing
10//! a modular, scalable architecture that handles the complexities of SIP dialog management
11//! while offering powerful features for call handling, media coordination, and protocol
12//! extensions.
13//!
14//! ### Key Features
15//!
16//! - **Call Handling**: Accept, reject, and manage incoming calls with full control
17//! - **Dialog Management**: Complete SIP dialog lifecycle for server scenarios
18//! - **Session Integration**: Built-in coordination with session-core for media management
19//! - **Request/Response Handling**: Process incoming requests and generate compliant responses
20//! - **Auto-Response Modes**: Automatic handling of OPTIONS, REGISTER, and other methods
21//! - **Statistics & Monitoring**: Real-time metrics and performance tracking
22//! - **Modular Architecture**: Clean separation of concerns across focused submodules
23//!
24//! ## Architecture Overview
25//!
26//! The DialogServer is organized into focused submodules for maintainability:
27//!
28//! ```text
29//! ┌─────────────────────────────────────────┐
30//! │ DialogServer │
31//! ├─────────────────────────────────────────┤
32//! │ Core │ Server struct & config │ ← [`core`]
33//! │ Call Ops │ Call lifecycle mgmt │ ← [`call_operations`]
34//! │ Dialog Ops │ Dialog management │ ← [`dialog_operations`]
35//! │ Response │ Response building │ ← [`response_builder`]
36//! │ SIP Methods │ Specialized handlers │ ← [`sip_methods`]
37//! ├─────────────────────────────────────────┤
38//! │ DialogManager (shared) │
39//! ├─────────────────────────────────────────┤
40//! │ TransactionManager │
41//! ├─────────────────────────────────────────┤
42//! │ TransportManager │
43//! └─────────────────────────────────────────┘
44//! ```
45//!
46//! ## Quick Start
47//!
48//! ### Basic SIP Server
49//!
50//! ```rust,no_run
51//! use rvoip_dialog_core::api::{DialogServer, DialogApi, ServerConfig};
52//! use rvoip_dialog_core::events::SessionCoordinationEvent;
53//! use rvoip_transaction_core::TransactionManager;
54//! use tokio::sync::mpsc;
55//! use std::sync::Arc;
56//!
57//! #[tokio::main]
58//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
59//! // Set up dependencies (transport setup omitted for brevity)
60//! # let transport = unimplemented!(); // Mock transport
61//! let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
62//! let config = ServerConfig::new("0.0.0.0:5060".parse()?)
63//! .with_domain("sip.company.com")
64//! .with_auto_options()
65//! .with_auto_register();
66//!
67//! // Create and configure server
68//! let server = DialogServer::with_dependencies(tx_mgr, config).await?;
69//!
70//! // Set up session coordination for call handling
71//! let (session_tx, mut session_rx) = mpsc::channel(100);
72//! server.set_session_coordinator(session_tx).await?;
73//!
74//! // Start the server
75//! server.start().await?;
76//! println!("✅ SIP server listening on 0.0.0.0:5060");
77//!
78//! // Handle incoming calls
79//! tokio::spawn(async move {
80//! while let Some(event) = session_rx.recv().await {
81//! match event {
82//! SessionCoordinationEvent::IncomingCall { dialog_id, request, .. } => {
83//! println!("📞 Incoming call: {} from {}",
84//! dialog_id, request.from().unwrap().uri());
85//! // Handle call - see examples below
86//! },
87//! _ => {}
88//! }
89//! }
90//! });
91//!
92//! // Keep server running
93//! tokio::signal::ctrl_c().await?;
94//! server.stop().await?;
95//! println!("✅ Server stopped gracefully");
96//!
97//! Ok(())
98//! }
99//! ```
100//!
101//! ## Usage Patterns
102//!
103//! ### Pattern 1: Simple Call Server
104//!
105//! For basic call handling with automatic responses:
106//!
107//! ```rust,no_run
108//! use rvoip_dialog_core::api::{DialogServer, DialogApi, ServerConfig};
109//! use rvoip_dialog_core::events::SessionCoordinationEvent;
110//! use rvoip_sip_core::StatusCode;
111//! use tokio::sync::mpsc;
112//!
113//! # async fn simple_server() -> Result<(), Box<dyn std::error::Error>> {
114//! # let (tx_mgr, config) = setup_dependencies().await?;
115//! let server = DialogServer::with_dependencies(tx_mgr, config).await?;
116//!
117//! // Set up call handling
118//! let (session_tx, mut session_rx) = mpsc::channel(100);
119//! server.set_session_coordinator(session_tx).await?;
120//! server.start().await?;
121//!
122//! // Simple call handler
123//! tokio::spawn(async move {
124//! while let Some(event) = session_rx.recv().await {
125//! match event {
126//! SessionCoordinationEvent::IncomingCall { dialog_id, request, .. } => {
127//! // Accept calls using handle_invite with the actual request
128//! if let Ok(call) = server.handle_invite(request, "127.0.0.1:5060".parse().unwrap()).await {
129//! call.answer(Some("SDP answer".to_string())).await.ok();
130//! println!("Call {} auto-accepted", dialog_id);
131//! }
132//! },
133//! SessionCoordinationEvent::CallTerminated { dialog_id, .. } => {
134//! println!("Call {} ended", dialog_id);
135//! },
136//! _ => {}
137//! }
138//! }
139//! });
140//! # Ok(())
141//! # }
142//! # async fn setup_dependencies() -> Result<(std::sync::Arc<rvoip_transaction_core::TransactionManager>, rvoip_dialog_core::api::ServerConfig), std::io::Error> { unimplemented!() }
143//! ```
144//!
145//! ### Pattern 2: Advanced Call Processing
146//!
147//! For sophisticated call routing and processing:
148//!
149//! ```rust,no_run
150//! use rvoip_dialog_core::api::{DialogServer, DialogApi};
151//! use rvoip_dialog_core::events::SessionCoordinationEvent;
152//! use rvoip_sip_core::{StatusCode, Request};
153//! use std::collections::HashMap;
154//!
155//! # async fn advanced_server(server: DialogServer) -> Result<(), Box<dyn std::error::Error>> {
156//! let (session_tx, mut session_rx) = mpsc::channel(100);
157//! server.set_session_coordinator(session_tx).await?;
158//! server.start().await?;
159//!
160//! // Advanced call processing with routing logic
161//! tokio::spawn(async move {
162//! let mut active_calls = HashMap::new();
163//!
164//! while let Some(event) = session_rx.recv().await {
165//! match event {
166//! SessionCoordinationEvent::IncomingCall { dialog_id, request, .. } => {
167//! let to_uri = request.to().unwrap().uri().to_string();
168//!
169//! // Route based on destination
170//! match route_call(&to_uri).await {
171//! CallRoute::Accept(sdp_answer) => {
172//! if let Ok(call) = server.handle_invite(request, "127.0.0.1:5060".parse().unwrap()).await {
173//! call.answer(Some(sdp_answer)).await.ok();
174//! active_calls.insert(dialog_id.clone(), CallInfo::new(to_uri));
175//! println!("✅ Call {} accepted and routed", dialog_id);
176//! }
177//! },
178//! CallRoute::Redirect(_new_target) => {
179//! // Handle redirect (simplified for doc test)
180//! println!("↪️ Call {} would be redirected", dialog_id);
181//! },
182//! CallRoute::Reject(_reason) => {
183//! // Handle rejection (simplified for doc test)
184//! println!("❌ Call {} would be rejected", dialog_id);
185//! }
186//! }
187//! },
188//! SessionCoordinationEvent::CallTerminated { dialog_id, .. } => {
189//! active_calls.remove(&dialog_id);
190//! println!("📞 Call {} terminated", dialog_id);
191//! },
192//! _ => {}
193//! }
194//! }
195//! });
196//! # Ok(())
197//! # }
198//! # enum CallRoute { Accept(String), Redirect(String), Reject(String) }
199//! # async fn route_call(to_uri: &str) -> CallRoute { CallRoute::Accept("SDP".to_string()) }
200//! # struct CallInfo;
201//! # impl CallInfo { fn new(uri: String) -> Self { Self } }
202//! # use tokio::sync::mpsc;
203//! ```
204//!
205//! ### Pattern 3: Protocol Extension Server
206//!
207//! For servers implementing custom SIP extensions:
208//!
209//! ```rust,no_run
210//! use rvoip_dialog_core::api::DialogServer;
211//! use rvoip_sip_core::{Method, StatusCode};
212//! use rvoip_dialog_core::dialog::DialogId;
213//!
214//! # async fn protocol_server(server: DialogServer) -> Result<(), Box<dyn std::error::Error>> {
215//! // Handle custom SIP methods and extensions
216//!
217//! // Custom NOTIFY handler for presence
218//! async fn handle_notify(server: &DialogServer, dialog_id: &DialogId, body: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
219//! if let Some(presence_data) = body {
220//! println!("📍 Presence update: {}", presence_data);
221//!
222//! // Process presence information
223//! let presence_status = parse_presence(&presence_data)?;
224//! update_presence_database(&dialog_id, presence_status).await?;
225//!
226//! // Acknowledgment would be sent via proper transaction handling
227//! println!("✅ Presence processed for dialog {}", dialog_id);
228//! }
229//! Ok(())
230//! }
231//!
232//! // Custom INFO handler for application data
233//! async fn handle_info(server: &DialogServer, dialog_id: &DialogId, body: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
234//! if let Some(app_data) = body {
235//! println!("📱 Application data: {}", app_data);
236//!
237//! // Process application-specific information
238//! match parse_app_data(&app_data)? {
239//! AppData::ScreenShare { session_id } => {
240//! setup_screen_share(dialog_id, &session_id).await?;
241//! println!("🖥️ Screen share initiated for {}", dialog_id);
242//! },
243//! AppData::FileTransfer { file_id, size } => {
244//! initiate_file_transfer(dialog_id, &file_id, size).await?;
245//! println!("📁 File transfer started for {}", dialog_id);
246//! },
247//! _ => {
248//! println!("❓ Unknown app data type for {}", dialog_id);
249//! }
250//! }
251//! }
252//! Ok(())
253//! }
254//! # Ok(())
255//! # }
256//! # fn parse_presence(data: &str) -> Result<String, Box<dyn std::error::Error>> { Ok("online".to_string()) }
257//! # async fn update_presence_database(dialog_id: &DialogId, status: String) -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
258//! # enum AppData { ScreenShare { session_id: String }, FileTransfer { file_id: String, size: u64 } }
259//! # fn parse_app_data(data: &str) -> Result<AppData, Box<dyn std::error::Error>> { Ok(AppData::ScreenShare { session_id: "123".to_string() }) }
260//! # async fn setup_screen_share(dialog_id: &DialogId, session_id: &str) -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
261//! # async fn initiate_file_transfer(dialog_id: &DialogId, file_id: &str, size: u64) -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
262//! ```
263//!
264//! ## Configuration Patterns
265//!
266//! ### Production Server Configuration
267//!
268//! ```rust
269//! use rvoip_dialog_core::api::ServerConfig;
270//! use std::time::Duration;
271//!
272//! let config = ServerConfig::new("0.0.0.0:5060".parse().unwrap())
273//! .with_domain("sip.production.com")
274//! .with_auto_options()
275//! .with_auto_register();
276//!
277//! // Customize for high-load production
278//! let mut prod_config = config;
279//! prod_config.dialog = prod_config.dialog
280//! .with_timeout(Duration::from_secs(300))
281//! .with_max_dialogs(100000)
282//! .with_user_agent("ProductionSIP/1.0")
283//! .without_auto_cleanup(); // Manual control for performance
284//! ```
285//!
286//! ### Development Server Configuration
287//!
288//! ```rust
289//! use rvoip_dialog_core::api::ServerConfig;
290//! use std::time::Duration;
291//!
292//! let dev_config = ServerConfig::new("127.0.0.1:5060".parse().unwrap())
293//! .with_domain("localhost")
294//! .with_auto_options();
295//!
296//! // Fast timeouts for development
297//! let mut test_config = dev_config;
298//! test_config.dialog = test_config.dialog
299//! .with_timeout(Duration::from_secs(30))
300//! .with_user_agent("DevSIP/1.0");
301//! ```
302//!
303//! ## Error Handling Strategies
304//!
305//! ```rust,no_run
306//! use rvoip_dialog_core::api::{DialogServer, ApiError};
307//! use rvoip_sip_core::StatusCode;
308//! use rvoip_dialog_core::dialog::DialogId;
309//!
310//! async fn robust_call_handler(server: &DialogServer, dialog_id: &DialogId) -> Result<(), Box<dyn std::error::Error>> {
311//! // This example shows error handling patterns, but actual implementation would need proper request/transaction context
312//! println!("🔄 Processing call for dialog {}", dialog_id);
313//!
314//! // In a real implementation, you would:
315//! // 1. Get the original INVITE request from transaction context
316//! // 2. Use handle_invite() with the actual request
317//! // 3. Use proper transaction keys for responses
318//!
319//! match server.get_dialog_info(dialog_id).await {
320//! Ok(dialog_info) => {
321//! println!("✅ Dialog {} found: {} -> {}", dialog_id, dialog_info.local_uri, dialog_info.remote_uri);
322//! // Handle successful dialog case
323//! },
324//! Err(ApiError::Dialog { message }) => {
325//! eprintln!("Dialog error for {}: {}", dialog_id, message);
326//! // Dialog not found - would send 481 Call/Transaction Does Not Exist in real scenario
327//! },
328//! Err(ApiError::Protocol { message }) => {
329//! eprintln!("Protocol error for {}: {}", dialog_id, message);
330//! // Protocol error - would send 400 Bad Request in real scenario
331//! },
332//! Err(e) => {
333//! eprintln!("Internal error for {}: {}", dialog_id, e);
334//! // Internal error - would send 500 Server Internal Error in real scenario
335//! }
336//! }
337//! Ok(())
338//! }
339//! ```
340//!
341//! ## Integration Examples
342//!
343//! ### Media Server Integration
344//!
345//! ```rust,no_run
346//! use rvoip_dialog_core::api::{DialogServer, DialogApi};
347//! use rvoip_dialog_core::events::SessionCoordinationEvent;
348//! use tokio::sync::mpsc;
349//!
350//! # async fn media_integration() -> Result<(), Box<dyn std::error::Error>> {
351//! # let (tx_mgr, config) = setup_dependencies().await?;
352//! let server = DialogServer::with_dependencies(tx_mgr, config).await?;
353//! let (session_tx, mut session_rx) = mpsc::channel(100);
354//! server.set_session_coordinator(session_tx).await?;
355//! server.start().await?;
356//!
357//! tokio::spawn(async move {
358//! while let Some(event) = session_rx.recv().await {
359//! match event {
360//! SessionCoordinationEvent::IncomingCall { dialog_id, request, .. } => {
361//! // Extract SDP offer from incoming INVITE
362//! if let Some(offer_sdp) = extract_sdp_from_request(&request) {
363//! // Set up media session
364//! match setup_media_session(offer_sdp).await {
365//! Ok(answer_sdp) => {
366//! // Accept call with SDP answer
367//! if let Ok(call) = server.handle_invite(request, "127.0.0.1:5060".parse().unwrap()).await {
368//! call.answer(Some(answer_sdp)).await.ok();
369//! println!("🎵 Media session established for {}", dialog_id);
370//! }
371//! },
372//! Err(e) => {
373//! eprintln!("❌ Media setup failed: {}", e);
374//! // Would reject call in real scenario with proper transaction handling
375//! }
376//! }
377//! }
378//! },
379//! SessionCoordinationEvent::CallTerminated { dialog_id, .. } => {
380//! // Clean up media resources
381//! cleanup_media_session(&dialog_id).await.ok();
382//! println!("🔇 Media session cleaned up for {}", dialog_id);
383//! },
384//! _ => {}
385//! }
386//! }
387//! });
388//! # Ok(())
389//! # }
390//! # use rvoip_sip_core::Request;
391//! # fn extract_sdp_from_request(request: &Request) -> Option<String> { Some("SDP".to_string()) }
392//! # async fn setup_media_session(offer: String) -> Result<String, Box<dyn std::error::Error + Send + Sync>> { Ok("answer".to_string()) }
393//! # async fn cleanup_media_session(dialog_id: &rvoip_dialog_core::dialog::DialogId) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { Ok(()) }
394//! # async fn setup_dependencies() -> Result<(std::sync::Arc<rvoip_transaction_core::TransactionManager>, rvoip_dialog_core::api::ServerConfig), std::io::Error> { unimplemented!() }
395//! ```
396//!
397//! ### Load Balancer Integration
398//!
399//! ```rust,no_run
400//! use rvoip_dialog_core::api::{DialogServer, DialogApi};
401//! use rvoip_sip_core::StatusCode;
402//! use std::sync::atomic::{AtomicU64, Ordering};
403//! use std::sync::Arc;
404//!
405//! # async fn load_balancer_integration() -> Result<(), Box<dyn std::error::Error>> {
406//! # let (tx_mgr, config) = setup_dependencies().await?;
407//! let server = DialogServer::with_dependencies(tx_mgr, config).await?;
408//! let call_counter = Arc::new(AtomicU64::new(0));
409//! let max_calls = 1000; // Server capacity limit
410//!
411//! let (session_tx, mut session_rx) = tokio::sync::mpsc::channel(100);
412//! server.set_session_coordinator(session_tx).await?;
413//! server.start().await?;
414//!
415//! let counter_clone = call_counter.clone();
416//! tokio::spawn(async move {
417//! while let Some(event) = session_rx.recv().await {
418//! match event {
419//! rvoip_dialog_core::events::SessionCoordinationEvent::IncomingCall { dialog_id, .. } => {
420//! let current_calls = counter_clone.load(Ordering::Relaxed);
421//!
422//! if current_calls >= max_calls {
423//! // Server at capacity - redirect to another server
424//! println!("📊 Server at capacity, would redirect call {}", dialog_id);
425//! } else {
426//! // Accept the call (simplified for doc test)
427//! println!("📞 Call {} would be accepted ({}/{})", dialog_id, current_calls + 1, max_calls);
428//! counter_clone.fetch_add(1, Ordering::Relaxed);
429//! }
430//! },
431//! rvoip_dialog_core::events::SessionCoordinationEvent::CallTerminated { dialog_id, .. } => {
432//! counter_clone.fetch_sub(1, Ordering::Relaxed);
433//! let remaining = counter_clone.load(Ordering::Relaxed);
434//! println!("📞 Call {} ended ({}/{})", dialog_id, remaining, max_calls);
435//! },
436//! _ => {}
437//! }
438//! }
439//! });
440//! # Ok(())
441//! # }
442//! # async fn setup_dependencies() -> Result<(std::sync::Arc<rvoip_transaction_core::TransactionManager>, rvoip_dialog_core::api::ServerConfig), std::io::Error> { unimplemented!() }
443//! ```
444//!
445//! ## Monitoring & Statistics
446//!
447//! ```rust,no_run
448//! use rvoip_dialog_core::api::{DialogServer, DialogApi};
449//! use tokio::time::{interval, Duration};
450//!
451//! # async fn monitoring_example(server: DialogServer) -> Result<(), Box<dyn std::error::Error>> {
452//! // Set up periodic monitoring
453//! let mut monitor_interval = interval(Duration::from_secs(60));
454//!
455//! tokio::spawn(async move {
456//! loop {
457//! monitor_interval.tick().await;
458//!
459//! let stats = server.get_stats().await;
460//! println!("=== Server Statistics ===");
461//! println!("Active dialogs: {}", stats.active_dialogs);
462//! println!("Total dialogs: {}", stats.total_dialogs);
463//! println!("Success rate: {:.1}%",
464//! 100.0 * stats.successful_calls as f64 / (stats.successful_calls + stats.failed_calls) as f64);
465//! println!("Average call duration: {:.1}s", stats.avg_call_duration);
466//!
467//! // Health check
468//! if stats.active_dialogs > 5000 {
469//! println!("⚠️ High dialog count - consider scaling");
470//! }
471//!
472//! // List active dialogs for debugging
473//! let active_dialogs = server.list_active_dialogs().await;
474//! if active_dialogs.len() > 100 {
475//! println!("📋 {} active dialogs (showing first 5):", active_dialogs.len());
476//! for dialog_id in active_dialogs.iter().take(5) {
477//! if let Ok(info) = server.get_dialog_info(dialog_id).await {
478//! println!(" Dialog {}: {} -> {} ({})",
479//! dialog_id, info.local_uri, info.remote_uri, info.state);
480//! }
481//! }
482//! }
483//! }
484//! });
485//! # Ok(())
486//! # }
487//! ```
488//!
489//! ## Best Practices
490//!
491//! 1. **Use Session Coordination**: Always set up session event handling for robust call management
492//! 2. **Configure Auto-Responses**: Enable auto-OPTIONS and auto-REGISTER for standard compliance
493//! 3. **Implement Proper Error Handling**: Use specific error types and appropriate SIP status codes
494//! 4. **Monitor Server Health**: Track statistics and implement alerting for high loads
495//! 5. **Scale Horizontally**: Use load balancing and capacity limits for production deployments
496//! 6. **Validate Configuration**: Always call `validate()` on configurations before use
497//! 7. **Clean Shutdown**: Implement graceful shutdown with proper resource cleanup
498//! 8. **Security Considerations**: Implement authentication, authorization, and rate limiting
499//!
500//! ## Thread Safety
501//!
502//! DialogServer is designed to be thread-safe and can handle concurrent operations:
503//!
504//! ```rust,no_run
505//! use rvoip_dialog_core::api::DialogServer;
506//! use std::sync::Arc;
507//!
508//! # async fn thread_safety(server: DialogServer) -> Result<(), Box<dyn std::error::Error>> {
509//! let server = Arc::new(server);
510//!
511//! // Spawn multiple tasks handling different aspects
512//! let server1 = server.clone();
513//! let call_handler = tokio::spawn(async move {
514//! // Handle incoming calls
515//! });
516//!
517//! let server2 = server.clone();
518//! let monitoring_task = tokio::spawn(async move {
519//! // Monitor server statistics
520//! });
521//!
522//! let server3 = server.clone();
523//! let protocol_handler = tokio::spawn(async move {
524//! // Handle custom protocol extensions
525//! });
526//!
527//! // All tasks can safely use the server concurrently
528//! tokio::try_join!(call_handler, monitoring_task, protocol_handler)?;
529//! # Ok(())
530//! # }
531//! ```
532//!
533//! ## Submodules
534//!
535//! - [`core`]: Core server struct, constructors, and configuration management
536//! - [`call_operations`]: Call lifecycle management (handle, accept, reject, terminate)
537//! - [`dialog_operations`]: Dialog management operations (create, query, list, terminate)
538//! - [`response_builder`]: Response building and sending functionality with SIP compliance
539//! - [`sip_methods`]: Specialized SIP method handlers (BYE, REFER, NOTIFY, UPDATE, INFO)
540
541pub mod core;
542pub mod call_operations;
543pub mod dialog_operations;
544pub mod response_builder;
545pub mod sip_methods;
546
547// Re-export the main types for external use
548pub use core::{DialogServer, ServerStats};