Skip to main content

Crate rsipstack

Crate rsipstack 

Source
Expand description

§RSIPStack - A SIP Stack Implementation in Rust

RSIPStack is a comprehensive Session Initiation Protocol (SIP) implementation written in Rust. It provides a complete SIP stack with support for multiple transport protocols, transaction management, dialog handling, and more.

§Features

  • Complete SIP Implementation - Full RFC 3261 compliance
  • Multiple Transports - UDP, TCP, TLS, WebSocket support
  • Transaction Layer - Automatic retransmissions and timer management
  • Dialog Management - Full dialog state machine implementation
  • Async/Await Support - Built on Tokio for high performance
  • Type Safety - Leverages Rust’s type system for protocol correctness
  • Extensible - Modular design for easy customization

§Architecture

The stack is organized into several layers following the SIP specification:

┌─────────────────────────────────────┐
│           Application Layer         │
├─────────────────────────────────────┤
│           Dialog Layer              │
├─────────────────────────────────────┤
│         Transaction Layer           │
├─────────────────────────────────────┤
│          Transport Layer            │
└─────────────────────────────────────┘

§Quick Start

§Creating a SIP Endpoint

use rsipstack::EndpointBuilder;
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a SIP endpoint
    let endpoint = EndpointBuilder::new()
        .with_user_agent("MyApp/1.0")
        .build();

    // Get incoming transactions
    let mut incoming = endpoint.incoming_transactions().expect("incoming_transactions");

    // Start the endpoint (in production, you'd run this in a separate task)
    // let endpoint_inner = endpoint.inner.clone();
    // tokio::spawn(async move {
    //     endpoint_inner.serve().await.ok();
    // });

    // Process incoming requests
    while let Some(transaction) = incoming.recv().await {
        // Handle the transaction
        println!("Received: {}", transaction.original.method);
        break; // Exit for example
    }

    Ok(())
}

§Sending SIP Requests

use rsipstack::dialog::dialog_layer::DialogLayer;
use rsipstack::dialog::invitation::InviteOption;
use rsipstack::transaction::endpoint::EndpointInner;
use std::sync::Arc;

// Create a dialog layer
let dialog_layer = DialogLayer::new(endpoint.clone());

// Send an INVITE
let invite_option = InviteOption {
    caller: rsipstack::sip::Uri::try_from("sip:alice@example.com")?,
    callee: rsipstack::sip::Uri::try_from("sip:bob@example.com")?,
    contact: rsipstack::sip::Uri::try_from("sip:alice@myhost.com:5060")?,
    content_type: Some("application/sdp".to_string()),
    offer: Some(sdp_body),
    ..Default::default()
};

let (dialog, response) = dialog_layer.do_invite(invite_option, state_sender).await?;

§Core Components

§Transport Layer

The transport layer handles network communication across different protocols:

§Transaction Layer

The transaction layer provides reliable message delivery:

§Dialog Layer

The dialog layer manages SIP dialogs and sessions:

§Error Handling

The stack uses a comprehensive error type that covers all layers:

use rsipstack::{Result, Error};

fn handle_sip_error(error: Error) {
    match error {
        Error::TransportLayerError(msg, addr) => {
            eprintln!("Transport error at {msg}: {addr}");
        },
        Error::TransactionError(msg, key) => {
            eprintln!("Transaction error {msg}: {key}");
        },
        Error::DialogError(msg, id, code) => {
            eprintln!("Dialog error {msg}: {id} (Status code: {code})");
        },
        _ => eprintln!("Other error: {}", error),
    }
}

§Configuration

The stack can be configured for different use cases:

§Basic UDP Server

use rsipstack::EndpointBuilder;
use rsipstack::transport::{TransportLayer, udp::UdpConnection};
use tokio_util::sync::CancellationToken;

let transport_layer = TransportLayer::new(cancel_token.child_token());
let udp_conn = UdpConnection::create_connection("0.0.0.0:5060".parse()?, None, Some(cancel_token.child_token())).await?;
transport_layer.add_transport(udp_conn.into());

let endpoint = EndpointBuilder::new()
    .with_transport_layer(transport_layer)
    .build();

§Secure TLS Server

#[cfg(feature = "rustls")]
use rsipstack::transport::tls::{TlsConnection, TlsConfig};
use rsipstack::transport::TransportLayer;

// Configure TLS transport
let tls_config = TlsConfig {
    cert: Some(cert_pem),
    key: Some(key_pem),
    ..Default::default()
};

// TLS connections would be created using the TLS configuration
// let tls_conn = TlsConnection::serve_listener(...).await?;

§Standards Compliance

RSIPStack implements the following RFCs:

  • RFC 3261 - SIP: Session Initiation Protocol (core specification)
  • RFC 3581 - Symmetric Response Routing (rport)
  • RFC 6026 - Correct Transaction Handling for 2xx Responses to INVITE. Server Accepted state + Timer L (§7.1); client Accepted state + Timer M (§7.2). Two documented deviations keep the rsipstack 0.5.x wire behavior inside the new state machine. Client deviation: the transaction auto-ACKs a 2xx (and re-ACKs every retransmitted/forked 2xx) while parked in Accepted; strict §7.2 + RFC 3261 §17.1.1.3 place that responsibility on the TU — set EndpointOption::auto_ack_2xx = false for strict TU-owned ACKs (proxy mode: the 2xx then terminates the transaction at once). Server deviation: the transaction keeps Timer G (T1, doubling to T2, RFC 3261 §13.3.1.4) while in Accepted and stops it when the ACK arrives, because the rsipstack dialog layer does not retransmit 2xx itself. Dialog users must keep receiving the client transaction until Timer M ends it (DialogLayer::do_invite/do_invite_async do this); the absorption window delivers every retransmitted/forked 2xx to the TU.

§Performance

The stack is designed for high performance:

  • Zero-copy parsing where possible
  • Async I/O with Tokio for scalability
  • Efficient timer management for large numbers of transactions
  • Memory-safe with Rust’s ownership system

§Testing

Comprehensive test suite covering:

  • Unit tests for all components
  • Integration tests for protocol compliance
  • Performance benchmarks
  • Interoperability testing

§Examples

See the examples/ directory for complete working examples:

  • Simple SIP client
  • SIP proxy server
  • WebSocket SIP gateway
  • Load testing tools

Re-exports§

pub use crate::error::Error;
pub use transaction::EndpointBuilder;
pub use sip as rsip;

Modules§

dialog
error
platform
Platform abstraction layer — multi-backend (WP0→WP3).
prelude
Crate-internal prelude: fills the no_std gaps with alloc/core items. In std builds the std prelude already provides most of these; the glob import here is harmless (same types) and only activates under no_std.
resolver
sip
transaction
transport

Macros§

sip_all_headers
sip_header
sip_header_opt
sip_header_pop

Constants§

VERSION

Type Aliases§

Result