Rsip

A common general purpose library for SIP. It can parse and generate all SIP structures.

Like HTTP, this crate is a general purpose library for common types found when working with the SIP protocol. You’ll find the SipMessage and its Request and Response variant types for working as either a client or a server as well as all of their components, like Method, Version, a very flexible Uri, StatusCode etc.

Rsip is capable of parsing messages from bytes, &str or String using nom parser and can also generate SIP messages using helpful structs.

You will notably not find an implementation of sending requests or spinning up a SIP server in this crate. SIP servers, by nature of SIP protocol, are very complex usually and will sit at different crates/libs. Rsip is intended to be the de-facto SIP base library for Rust. It was built to be used inside viska initially but then was split to a different crate.

It was inspired by libsip but has taken a bit different path regarding parsing, flexibility & safety.

Features

Examples

For instance, generating the Register request found in section 2.1 of RFC3665

REGISTER sips:ss2.biloxi.example.com SIP/2.0 Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 Max-Forwards: 70 From: Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl To: Bob <sips:bob@biloxi.example.com> Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com CSeq: 1 REGISTER Contact: <sips:bob@client.biloxi.example.com> Content-Length: 0

can be done like that:

```rust fn generateregisterrequest() -> rsip::SipMessage { let mut headers: rsip::Headers = Default::default();

let base_uri = rsip::Uri {
    schema: Some(rsip::Schema::Sips),
    auth: Some(("bob", Option::<String>::None).into()),
    host_with_port: rsip::Domain::from("biloxi.example.com").into(),
    ..Default::default()
};

headers.push(
    rsip::typed::Via {
        version: rsip::Version::V2,
        transport: rsip::Transport::Tls,
        uri: rsip::Uri {
            host_with_port: (rsip::Domain::from("client.biloxi.example.com"), 5060).into(),
            ..Default::default()
        },
        params: vec![rsip::Param::Branch(rsip::param::Branch::new(
            "z9hG4bKnashds7",
        ))],
    }
    .into(),
);
headers.push(rsip::headers::MaxForwards::default().into());
headers.push(
    rsip::typed::From {
        display_name: Some("Bob".into()),
        uri: base_uri.clone(),
        params: vec![rsip::Param::Tag(rsip::param::Tag::new("a73kszlfl"))],
    }
    .into(),
);
headers.push(
    rsip::typed::To {
        display_name: Some("Bob".into()),
        uri: base_uri.clone(),
        params: Default::default(),
    }
    .into(),
);
headers.push(rsip::headers::CallId::default().into());
headers.push(
    rsip::typed::CSeq {
        seq: 1,
        method: rsip::Method::Register,
    }
    .into(),
);
headers.push(
    rsip::typed::Contact {
        display_name: None,
        uri: base_uri,
        params: Default::default(),
    }
    .into(),
);
headers.push(rsip::headers::ContentLength::default().into());

rsip::Request {
    method: rsip::Method::Register,
    uri: rsip::Uri {
        schema: Some(rsip::Schema::Sips),
        host_with_port: rsip::Domain::from("ss2.biloxi.example.com").into(),
        ..Default::default()
    },
    version: rsip::Version::V2,
    headers: headers,
    body: Default::default(),
}
.into()

} ```

And the response similarly can be generated:

```rust pub fn createunauthorizedfrom(request: rsip::Request) -> Result { //imports helpful header traits use rsip::prelude::*;

let mut headers: rsip::Headers = Default::default();
headers.push(request.via_header()?.clone().into());
headers.push(request.from_header()?.clone().into());
let mut to = request.to_header()?.typed()?;
to.with_tag("1410948204".into());
headers.push(to.into());
headers.push(request.call_id_header()?.clone().into());
headers.push(request.cseq_header()?.clone().into());
headers.push(rsip::Header::ContentLength(Default::default()));
headers.push(rsip::Header::Server(Default::default()));

headers.push(
    rsip::typed::WwwAuthenticate {
        realm: "atlanta.example.com".into(),
        nonce: "ea9c8e88df84f1cec4341ae6cbe5a359".into(),
        algorithm: Some(rsip::headers::auth::Algorithm::Md5),
        qop: Some(rsip::headers::auth::Qop::Auth),
        stale: Some("FALSE".into()),
        opaque: Some("".into()),
        ..Default::default()
    }
    .into(),
);

Ok(rsip::Response {
    status_code: 401.into(),
    headers,
    version: rsip::Version::V2,
    body: Default::default()
}
.into())

} ```

which generates the following:

SIP/2.0 401 Unauthorized Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 ;received=192.0.2.201 From: Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl To: Bob <sips:bob@biloxi.example.com>;tag=1410948204 Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com CSeq: 1 REGISTER WWW-Authenticate: Digest realm="atlanta.example.com", qop="auth", nonce="ea9c8e88df84f1cec4341ae6cbe5a359", opaque="", stale=FALSE, algorithm=MD5 Content-Length: 0

To Do