{"id":15968828,"url":"https://github.com/televiska/rsip","last_synced_at":"2025-08-16T21:32:11.205Z","repository":{"id":42482310,"uuid":"351889128","full_name":"Televiska/rsip","owner":"Televiska","description":"SIP Rust library (generator \u0026 parser)","archived":false,"fork":false,"pushed_at":"2024-06-15T06:22:16.000Z","size":327,"stargazers_count":100,"open_issues_count":9,"forks_count":22,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-08-15T06:21:28.919Z","etag":null,"topics":["rust","signaling","sip","voip","webrtc"],"latest_commit_sha":null,"homepage":"https://docs.rs/rsip","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Televiska.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-26T19:20:06.000Z","updated_at":"2025-08-15T06:10:49.000Z","dependencies_parsed_at":"2022-09-16T07:23:35.072Z","dependency_job_id":null,"html_url":"https://github.com/Televiska/rsip","commit_stats":null,"previous_names":["vasilakisfil/rsip"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Televiska/rsip","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Televiska%2Frsip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Televiska%2Frsip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Televiska%2Frsip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Televiska%2Frsip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Televiska","download_url":"https://codeload.github.com/Televiska/rsip/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Televiska%2Frsip/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270775799,"owners_count":24642961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust","signaling","sip","voip","webrtc"],"created_at":"2024-10-07T19:04:12.688Z","updated_at":"2025-08-16T21:32:10.901Z","avatar_url":"https://github.com/Televiska.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rsip\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![Build status](https://github.com/vasilakisfil/rsip/actions/workflows/rust-ci.yml/badge.svg)\n[![Crates.io Version](https://img.shields.io/crates/v/rsip.svg)](https://crates.io/crates/rsip)\n[![Minimum rustc version](https://img.shields.io/badge/rustc-1.44.0+-lightgray.svg)](#rust-version-requirements)\n\nA common general purpose library for SIP. It can parse and generate all SIP\nstructures.\n\nLike [HTTP](https://github.com/hyperium/http), this crate is a general purpose library for common types found when\nworking with the SIP protocol.\nYou’ll find the `SipMessage` and its `Request` and `Response` variant types for working\nas either a client or a server as well as all of their components, like `Method`,\n`Version`, a very flexible `Uri`, `StatusCode` etc.\n\nRsip is capable of parsing messages from bytes, \u0026str or String using [nom](https://github.com/Geal/nom)\nparser and can also generate SIP messages using helpful structs.\n\nYou will notably not find an implementation of sending requests or spinning up a\nSIP server in this crate. SIP servers, by nature of SIP protocol, are very complex\nusually and will sit at different crates/libs. Rsip is intended to be the de-facto\nSIP base library for Rust. It was built to be used inside [viska](https://github.com/vasilakisfil/viska)\ninitially but then was split to a different crate.\n\nIt was inspired by [libsip](https://github.com/ByteHeathen/libsip) but has taken\na bit different path regarding parsing, flexibility \u0026 safety.\n\n\nFor locating SIP servers ([RFC3263](https://datatracker.ietf.org/doc/html/rfc3263)) take a look on [rsip-dns](https://github.com/vasilakisfil/rsip-dns) library.\n\n## Features\n* This thing is _fast_, uses nom for basic message parsing and headers are parsed\n  only when needed, on-demand. Intentions are to make it even faster by providing\n  non-owning variants (`\u0026str` and `\u0026[u8]`)\n* Strong (new)types everywhere. Even if underlying type is String, everything is\n  a NewType for better type safety.\n* Provides typed headers on demand, like `From`, `To`, `Contact`, `Via` etc\n  The reasoning behind on demand strongly typed headers is 2 fold:\n  * perfromance \u0026 memory reasons: headers are parsed only when needed\n  * it enables you to still have a working Rust SIP parser in case a typed header\n  has a bug, the peer has a bug or there is an edge/new case never seen before.\n* While performance is always a goal, user friendliness and usability is the main\n goal. A lot of helpful functions and convertions to make things easy :)\n* Very simple code structure make it super easy to extend and add new typed headers\n  As long as you can do [nom](https://github.com/Geal/nom) stuff, it's straightforward. The goal is to add\n  many typed headers of latest RFCs like [PASSporT](https://datatracker.ietf.org/doc/html/rfc8224), [SHAKEN](https://datatracker.ietf.org/doc/html/rfc8588), [push notifications](https://datatracker.ietf.org/doc/html/rfc8599) etc\n* Provides some extra services like Digest auth generator/validator etc\n  Intention is to add many helper services.\n\n## Architecture\nEach type in rsip has a tokenizer attached.\nThis is not enforced by the type system yet, however very soon this will be the case.\nIn brief, for every rsip type we have: \n* Tokenizing: in the lowest level we have the `Tokenizer` which is capable of tokenizing the input.\nAll common tokenizers accept abstract input, either `\u0026str` or `\u0026[u8]` so it can be reused when\nthe input is plain bytes, or when the input has already been parsed and it's a `String`/`\u0026str`,\nlike the headers.\n* Parsing: once the input has been tokenized, then there are `TryFrom` impls from the relevant type\ntokenizer to the actual type.\nThis is the parsing step where tokens (in the form of `\u0026str` or `\u0026[u8]`) are transformed to\nintegers, strings and rsip types.\n* each rsip type implements the `Display` trait and hence has a representation.\n\n## Examples\nFor instance, generating the Register request found in [section 2.1 of RFC3665](https://datatracker.ietf.org/doc/html/rfc3665#section-2.1)\n\n```\nREGISTER sips:ss2.biloxi.example.com SIP/2.0\nVia: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7\nMax-Forwards: 70\nFrom: Bob \u003csips:bob@biloxi.example.com\u003e;tag=a73kszlfl\nTo: Bob \u003csips:bob@biloxi.example.com\u003e\nCall-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com\nCSeq: 1 REGISTER\nContact: \u003csips:bob@client.biloxi.example.com\u003e\nContent-Length: 0\n```\n\ncan be done like that:\n\n```rust\nfn generate_register_request() -\u003e rsip::SipMessage {\n    let mut headers: rsip::Headers = Default::default();\n\n    let base_uri = rsip::Uri {\n        scheme: Some(rsip::Scheme::Sips),\n        auth: Some((\"bob\", Option::\u003cString\u003e::None).into()),\n        host_with_port: rsip::Domain::from(\"biloxi.example.com\").into(),\n        ..Default::default()\n    };\n\n    headers.push(\n        rsip::typed::Via {\n            version: rsip::Version::V2,\n            transport: rsip::Transport::Tls,\n            uri: rsip::Uri {\n                host_with_port: (rsip::Domain::from(\"client.biloxi.example.com\"), 5060).into(),\n                ..Default::default()\n            },\n            params: vec![rsip::Param::Branch(rsip::param::Branch::new(\n                \"z9hG4bKnashds7\",\n            ))],\n        }\n        .into(),\n    );\n    headers.push(rsip::headers::MaxForwards::default().into());\n    headers.push(\n        rsip::typed::From {\n            display_name: Some(\"Bob\".into()),\n            uri: base_uri.clone(),\n            params: vec![rsip::Param::Tag(rsip::param::Tag::new(\"a73kszlfl\"))],\n        }\n        .into(),\n    );\n    headers.push(\n        rsip::typed::To {\n            display_name: Some(\"Bob\".into()),\n            uri: base_uri.clone(),\n            params: Default::default(),\n        }\n        .into(),\n    );\n    headers.push(rsip::headers::CallId::default().into());\n    headers.push(\n        rsip::typed::CSeq {\n            seq: 1,\n            method: rsip::Method::Register,\n        }\n        .into(),\n    );\n    headers.push(\n        rsip::typed::Contact {\n            display_name: None,\n            uri: base_uri,\n            params: Default::default(),\n        }\n        .into(),\n    );\n    headers.push(rsip::headers::ContentLength::default().into());\n\n    rsip::Request {\n        method: rsip::Method::Register,\n        uri: rsip::Uri {\n            scheme: Some(rsip::Scheme::Sips),\n            host_with_port: rsip::Domain::from(\"ss2.biloxi.example.com\").into(),\n            ..Default::default()\n        },\n        version: rsip::Version::V2,\n        headers: headers,\n        body: Default::default(),\n    }\n    .into()\n}\n```\n\nAnd the response similarly can be generated:\n\n```rust\npub fn create_unauthorized_from(request: rsip::Request) -\u003e Result\u003crsip::SipMessage, crate::Error\u003e {\n    //imports helpful header traits\n    use rsip::prelude::*;\n\n    let mut headers: rsip::Headers = Default::default();\n    headers.push(request.via_header()?.clone().into());\n    headers.push(request.from_header()?.clone().into());\n    let mut to = request.to_header()?.typed()?;\n    to.with_tag(\"1410948204\".into());\n    headers.push(to.into());\n    headers.push(request.call_id_header()?.clone().into());\n    headers.push(request.cseq_header()?.clone().into());\n    headers.push(rsip::Header::ContentLength(Default::default()));\n    headers.push(rsip::Header::Server(Default::default()));\n\n    headers.push(\n        rsip::typed::WwwAuthenticate {\n            realm: \"atlanta.example.com\".into(),\n            nonce: \"ea9c8e88df84f1cec4341ae6cbe5a359\".into(),\n            algorithm: Some(rsip::headers::auth::Algorithm::Md5),\n            qop: Some(rsip::headers::auth::Qop::Auth),\n            stale: Some(\"FALSE\".into()),\n            opaque: Some(\"\".into()),\n            ..Default::default()\n        }\n        .into(),\n    );\n\n    Ok(rsip::Response {\n        status_code: 401.into(),\n        headers,\n        version: rsip::Version::V2,\n        body: Default::default()\n    }\n    .into())\n}\n```\n\nwhich generates the following:\n\n```\nSIP/2.0 401 Unauthorized\nVia: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7\n ;received=192.0.2.201\nFrom: Bob \u003csips:bob@biloxi.example.com\u003e;tag=a73kszlfl\nTo: Bob \u003csips:bob@biloxi.example.com\u003e;tag=1410948204\nCall-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com\nCSeq: 1 REGISTER\nWWW-Authenticate: Digest realm=\"atlanta.example.com\", qop=\"auth\",\n nonce=\"ea9c8e88df84f1cec4341ae6cbe5a359\",\n opaque=\"\", stale=FALSE, algorithm=MD5\nContent-Length: 0\n```\n\n## To Do\n* improve errors\n* write more tests, especially around edge cases\n* Make tokenizer an associated generic type on each type defined in this lib\n* implement more common traits like Hash etc\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteleviska%2Frsip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fteleviska%2Frsip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteleviska%2Frsip/lists"}