Skip to main content

rvoip_sip_core/
lib.rs

1//! # rvoip-sip-core
2//!
3//! Core SIP protocol implementation for the rvoip VoIP stack.
4//!
5//! This crate provides a complete, RFC-compliant implementation of the Session Initiation Protocol (SIP),
6//! including message parsing, serialization, and manipulation. It serves as the foundation for building
7//! SIP-based communication systems like VoIP clients, proxies, and servers.
8//!
9//! ## Overview
10//!
11//! The crate is structured around the following key components:
12//!
13//! - **Message Types**: Core SIP message abstractions ([`Request`], [`Response`], [`Message`])
14//! - **Header Types**: Strongly-typed SIP headers with parsing and serialization
15//! - **URI Handling**: Comprehensive SIP URI parsing and manipulation
16//! - **SDP Support**: Session Description Protocol integration
17//! - **Parsing**: Robust, efficient, and RFC-compliant message parsing
18//! - **Builder Patterns**: Fluent APIs for constructing SIP and SDP messages
19//! - **Macros**: Convenient macros for creating SIP requests and responses
20//!
21//! ## Getting Started
22//!
23//! ### Creating SIP Messages
24//!
25//! The recommended way to create SIP messages is to use either the builder pattern or macros:
26//!
27//! #### Using the Builder Pattern (recommended for complex messages)
28//!
29//! ```rust
30//! use rvoip_sip_core::prelude::*;
31//!
32//! // Create a SIP request with the RequestBuilder
33//! let request = RequestBuilder::new(Method::Invite, "sip:bob@example.com").unwrap()
34//!     .from("Alice", "sip:alice@example.com", Some("1928301774"))
35//!     .to("Bob", "sip:bob@example.com", None)
36//!     .call_id("a84b4c76e66710@pc33.atlanta.com")
37//!     .cseq(314159)
38//!     .via("pc33.atlanta.com", "UDP", Some("z9hG4bK776asdhds"))
39//!     .max_forwards(70)
40//!     .contact("sip:alice@pc33.atlanta.com", None)
41//!     .content_type("application/sdp")
42//!     .body("v=0\r\no=alice 123 456 IN IP4 127.0.0.1\r\ns=A call\r\nt=0 0\r\n")
43//!     .build();
44//!
45//! // Create a SIP response with the ResponseBuilder
46//! let response = ResponseBuilder::new(StatusCode::Ok, Some("OK"))
47//!     .from("Alice", "sip:alice@example.com", Some("1928301774"))
48//!     .to("Bob", "sip:bob@example.com", Some("a6c85cf"))
49//!     .call_id("a84b4c76e66710@pc33.atlanta.com")
50//!     .cseq(1, Method::Invite)
51//!     .via("pc33.atlanta.com", "UDP", Some("z9hG4bK776asdhds"))
52//!     .contact("sip:bob@192.168.1.2", None)
53//!     .content_type("application/sdp")
54//!     .body("v=0\r\no=bob 123 456 IN IP4 192.168.1.2\r\ns=A call\r\nt=0 0\r\n")
55//!     .build();
56//! ```
57//!
58//! #### Using Macros (recommended for simple messages)
59//!
60//! ```ignore
61//! use rvoip_sip_core::prelude::*;
62//! use rvoip_sip_core::{sip_request, sip_response};
63//!
64//! // Create a SIP request with the sip_request! macro 
65//! let request = sip_request! {
66//!     method: Method::Invite,
67//!     uri: "sip:bob@example.com",
68//!     from_name: "Alice", 
69//!     from_uri: "sip:alice@example.com",
70//!     from_tag: "1928301774",
71//!     call_id: "a84b4c76e66710",
72//!     cseq: 1
73//! };
74//!
75//! // Create a SIP response with the sip_response! macro
76//! let response = sip_response! {
77//!     status: StatusCode::Ok,
78//!     reason: "OK",
79//!     from_name: "Alice", 
80//!     from_uri: "sip:alice@example.com", 
81//!     to_name: "Bob", 
82//!     to_uri: "sip:bob@example.com",
83//!     call_id: "a84b4c76e66710",
84//!     cseq: 1, 
85//!     cseq_method: Method::Invite
86//! };
87//! ```
88//!
89//! ### Creating SDP Messages
90//!
91//! For SDP messages, you can use either the SdpBuilder (for programmatic creation) or the sdp! macro (for declarative creation):
92//!
93//! #### Using the SdpBuilder Pattern
94//!
95//! ```rust
96//! use rvoip_sip_core::sdp_prelude::*;
97//!
98//! // Create an SDP session with the SdpBuilder
99//! let sdp = SdpBuilder::new("My Session")
100//!     .origin("-", "1234567890", "2", "IN", "IP4", "127.0.0.1")
101//!     .time("0", "0")  // Time 0-0 means permanent session
102//!     .media_audio(49170, "RTP/AVP")
103//!         .formats(&["0", "8"])
104//!         .direction(MediaDirection::SendRecv)
105//!         .rtpmap("0", "PCMU/8000")
106//!         .rtpmap("8", "PCMA/8000")
107//!         .done()
108//!     .build();
109//! ```
110//!
111//! #### Using the sdp! Macro (recommended for simple messages)
112//!
113//! ```rust
114//! use rvoip_sip_core::sdp;
115//! use rvoip_sip_core::sdp_prelude::*;
116//!
117//! // Create an SDP session with the sdp! macro
118//! let sdp_result = sdp! {
119//!     origin: ("-", "1234567890", "2", "IN", "IP4", "192.168.1.100"),
120//!     session_name: "Audio Call",
121//!     connection: ("IN", "IP4", "192.168.1.100"),
122//!     time: ("0", "0"),
123//!     media: {
124//!         type: "audio",
125//!         port: 49170,
126//!         protocol: "RTP/AVP",
127//!         formats: ["0", "8"],
128//!         rtpmap: ("0", "PCMU/8000"),
129//!         rtpmap: ("8", "PCMA/8000"),
130//!         direction: "sendrecv"
131//!     }
132//! };
133//!
134//! let sdp = sdp_result.expect("Valid SDP");
135//! ```
136//!
137//! ### Parsing SIP Messages
138//!
139//! The library provides robust parsing for SIP messages:
140//!
141//! ```rust
142//! use rvoip_sip_core::prelude::*;
143//! use bytes::Bytes;
144//!
145//! // Parse a SIP message from bytes
146//! let data = Bytes::from(
147//!     "INVITE sip:bob@example.com SIP/2.0\r\n\
148//!      Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
149//!      Max-Forwards: 70\r\n\
150//!      To: Bob <sip:bob@example.com>\r\n\
151//!      From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
152//!      Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
153//!      CSeq: 314159 INVITE\r\n\
154//!      Contact: <sip:alice@pc33.atlanta.com>\r\n\
155//!      Content-Type: application/sdp\r\n\
156//!      Content-Length: 0\r\n\r\n"
157//! );
158//!
159//! let message = parse_message(&data).expect("Valid SIP message");
160//!
161//! // Access message components
162//! if let Message::Request(request) = message {
163//!     assert_eq!(request.method(), Method::Invite);
164//!     assert_eq!(request.uri().to_string(), "sip:bob@example.com");
165//!     
166//!     // Get headers and display them
167//!     if let Some(from_header) = request.header(&HeaderName::From) {
168//!         println!("From: {}", from_header);
169//!     }
170//!     if let Some(to_header) = request.header(&HeaderName::To) {
171//!         println!("To: {}", to_header);
172//!     }
173//! }
174//! ```
175//!
176//! ## Parsing Modes
177//!
178//! The library supports different parsing modes to handle various levels of RFC compliance:
179//!
180//! ```rust
181//! use rvoip_sip_core::prelude::*;
182//! use bytes::Bytes;
183//!
184//! let data = Bytes::from("SIP message data...");
185//!
186//! // Standard parsing mode
187//! let message = parse_message(&data);
188//!
189//! // Custom parsing mode
190//! let strict_message = parse_message_with_mode(&data, ParseMode::Strict);
191//! ```
192//!
193//! ## Feature Flags
194//!
195//! - `lenient_parsing` - Enables more lenient parsing mode for torture tests and handling of non-compliant messages
196
197// Re-export core types and parsers
198
199// Declare modules
200pub mod error;
201pub mod types;
202pub mod builder;
203pub mod parser;
204pub mod macros;
205#[cfg(feature = "sdp")]
206pub mod sdp;
207/// JSON representation and access layer for SIP types
208pub mod json;
209/// Prelude module that exports commonly used types and traits
210pub mod prelude;
211/// SDP prelude module that exports SDP-related types and traits
212#[cfg(feature = "sdp")]
213pub mod sdp_prelude;
214
215// Re-export key public items
216pub use error::{Error, Result};
217pub use types::header::{Header, HeaderValue, TypedHeader, TypedHeaderTrait};
218pub use types::headers::HeaderName;
219pub use types::Method;
220pub use parser::parse_message;
221pub use parser::message::parse_message_with_mode;
222pub use parser::message::ParseMode;
223pub use types::StatusCode;
224pub use types::{
225    Address, 
226    CallId, 
227    Contact, 
228    ContentDisposition, 
229    ContentLength, 
230    ContentType, 
231    CSeq, 
232    Expires, 
233    From, 
234    MaxForwards, 
235    MediaType, 
236    sip_message::Message,
237    sip_request::Request,
238    sip_response::Response,
239    sdp::SdpSession,
240    Via,  // Changed from via::Via
241    Warning,
242    warning::{WarnAgent, WarningValue},
243    sdp::MediaDescription,
244    sdp::Origin,
245    sdp::ConnectionData,
246    sdp::TimeDescription,
247    auth::*,
248    sdp::ParsedAttribute,
249    sdp::RtpMapAttribute,
250    sdp::FmtpAttribute,
251    sdp::CandidateAttribute,
252    sdp::SsrcAttribute,
253    sdp::RepeatTime,
254    Version,
255    Allow,
256    Accept,
257    Subject,
258    CallInfo,
259};
260pub use types::uri::{Uri, Host};
261#[cfg(feature = "sdp")]
262pub use sdp::attributes::MediaDirection;
263#[cfg(feature = "sdp")]
264pub use sdp::parser::{
265    validate_sdp,
266    validate_network_type,
267    validate_address_type,
268    is_valid_address,
269    is_valid_ipv4,
270    is_valid_ipv6,
271    is_valid_hostname,
272    parse_bandwidth_line,
273    parse_sdp
274};
275pub use builder::{SimpleRequestBuilder as RequestBuilder, SimpleResponseBuilder as ResponseBuilder};
276pub use macros::*;
277
278#[cfg(test)]
279mod tests {
280    #[test]
281    fn it_works() {
282        let result = 2 + 2;
283        assert_eq!(result, 4);
284    }
285}