{"id":13508978,"url":"https://github.com/balena/elixir-sippet","last_synced_at":"2025-04-06T12:09:15.558Z","repository":{"id":44908961,"uuid":"68231981","full_name":"balena/elixir-sippet","owner":"balena","description":"An Elixir library designed to be used as SIP protocol middleware.","archived":false,"fork":false,"pushed_at":"2024-03-01T07:24:58.000Z","size":471,"stargazers_count":78,"open_issues_count":1,"forks_count":24,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-30T10:09:34.764Z","etag":null,"topics":["datagram","elixir-library","hex","middleware","protocol","sip-library","transport-protocols"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/balena.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-14T18:25:01.000Z","updated_at":"2025-01-17T02:14:30.000Z","dependencies_parsed_at":"2024-05-01T17:21:11.656Z","dependency_job_id":"2f8e63b2-b805-4854-b529-c680320a5aec","html_url":"https://github.com/balena/elixir-sippet","commit_stats":{"total_commits":302,"total_committers":6,"mean_commits":"50.333333333333336","dds":"0.16887417218543044","last_synced_commit":"e441de7896d89657dff75fec84061f31c41f9383"},"previous_names":[],"tags_count":70,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena%2Felixir-sippet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena%2Felixir-sippet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena%2Felixir-sippet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena%2Felixir-sippet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/balena","download_url":"https://codeload.github.com/balena/elixir-sippet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247478323,"owners_count":20945266,"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","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":["datagram","elixir-library","hex","middleware","protocol","sip-library","transport-protocols"],"created_at":"2024-08-01T02:01:01.255Z","updated_at":"2025-04-06T12:09:15.532Z","avatar_url":"https://github.com/balena.png","language":"Elixir","readme":"![Sippet](http://sippet.github.io/sippet/public/apple-touch-icon-144-precomposed.png)\n=========\n\n[![Build Status](https://travis-ci.org/balena/elixir-sippet.svg)](https://travis-ci.org/balena/elixir-sippet)\n[![Coverage Status](https://coveralls.io/repos/github/balena/elixir-sippet/badge.svg?branch=master)](https://coveralls.io/github/balena/elixir-sippet?branch=master)\n[![Docs Status](https://inch-ci.org/github/balena/elixir-sippet.svg?branch=master)](http://inch-ci.org/github/balena/elixir-sippet)\n[![Hex version](https://img.shields.io/hexpm/v/sippet.svg \"Hex version\")](https://hex.pm/packages/sippet)\n[![Hex.pm](https://img.shields.io/hexpm/l/sippet.svg \"BSD Licensed\")](https://github.com/balena/elixir-sippet/blob/master/LICENSE)\n[![Code Triagers Badge](https://www.codetriage.com/balena/elixir-sippet/badges/users.svg)](https://www.codetriage.com/balena/elixir-sippet)\n\nAn Elixir library designed to write Session Initiation Protocol middleware.\n\n\n# Introduction\n\n[SIP](https://tools.ietf.org/html/rfc3261) is a very flexible protocol that has\ngreat depth. It was designed to be a general-purpose way to set up real-time\nmultimedia sessions between groups of participants. It is a text-based protocol\nmodeled on the request/response model used in HTTP. This makes it easy to debug\nbecause the messages are relatively easy to construct and easy to see.\n\nSippet is designed as a simple SIP middleware library, aiming the developer to\nwrite any kind of function required to register users, get their availability,\ncheck capabilities, setup and manage sessions. On the other hand, Sippet does\nnot intend to provide any feature available in a fully functional SIP UAC/UAS,\nproxy server, B2BUA, SBC or application; instead, it has only the essential\nbuilding blocks to build any kind of SIP middleware.\n\n\n## Overview\n\nOne of the most central parts of Sippet is the `Sippet.Message`. Instead of\nmany headers that you end up having to parse by yourself, there's an internal\nparser written in C++ (an Erlang NIF) that does all the hard work for you. This\nway, the `Sippet.Message.headers` is a key-value simple `Map` where the key is\nthe header name, and the value varies accordingly the header type. For\ninstance, the header `:cseq` has the form `{sequence :: integer, method}` where\nthe `method` is an atom with the method name (like `:invite`).\n\nMessage routing is performed just manipulating `Sippet.Message` headers;\neverything else is performed by these layers in a very standard way. That means\nyou may not be able to build some non-standard behaviors, like routing the\nmessage to a given host that wasn't correctly added to the topmost Via header.\n\nAs Sippet is a simple SIP library, the developer has to understand the protocol\nvery well before writing a middleware. This design decision came up because all\nattempts to hide any inherent SIP complexity by other frameworks have failed.\n\nThere is no support for plugins or hooks, these case be implemented easily with\nElixir behaviors and macros, and the developer may custom as he likes. Incoming\nmessages and transport errors are directed to a `Sippet.Core` module behavior.\n\nFinally, there is no support for many different transport protocols; a simple\n`Sippet.Transports.UDP` implementation is provided, which is enough for general\npurpose SIP middleware. Transport protocols can be implemented quite easily\nusing the same logic of `Sippet.Transport.UDP`.\n\n\n## Installation\n\nThe package can be installed from [Hex](https://hex.pm/docs/publish) as:\n\n  1. Add `sippet` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [{:sippet, \"~\u003e 1.0\"}]\nend\n```\n\n  2. Give a name to your stack and build it:\n\n```elixir\n# Creates a :mystack Sippet instance\nSippet.start_link(name: :mystack)\n\n# The below will create a default UDP transport listening on 0.0.0.0:5060/udp\nSippet.Transports.UDP.start_link(name: :mystack)\n```\n\n  4. Create a `Sippet.Core` and register it:\n\n```elixir\ndefmodule MyCore do\n  use Sippet.Core\n\n  def receive_request(incoming_request, server_key) do\n    # route the request to your UA or proxy process\n  end\n\n  def receive_response(incoming_response, client_key) do\n    # route the response to your UA or proxy process\n  end\n\n  def receive_error(reason, client_or_server_key) do\n    # route the error to your UA or proxy process\n  end\nend\n\nSippet.register_core(:mystack, MyCore)\n```\n\nVoilà! The SIP stack will be listening on the indicated address and port, and\nyour `MyCore` module will receive callbacks from it whenever a SIP message\narrives on it.\n\nYou may send messages this way:\n\n```elixir\nrequest = %Message{\n  start_line: RequestLine.new(:options, \"sip:sip.example.com\"),\n  headers: %{\n    via: [\n      {{2, 0}, :udp, {\"localhost\", 5060}, %{\"branch\" =\u003e Message.create_branch()}}\n    ],\n    from: {\"\", URI.parse!(\"sip:localhost\"), %{\"tag\" =\u003e Message.create_tag()}},\n    to: {\"\", URI.parse!(\"sip:sip.example.com\"), %{}},\n    cseq: {1, :options},\n    user_agent: \"Sippet/1.0\",\n    call_id: Message.create_call_id()\n  }\n}\n\nSippet.send(:sippet, request)\n```\n\nIf you prefer to specify messages directly in wire format, here you go:\n\n```elixir\nrequest =\n  \"\"\"\n  OPTIONS sip:sip.example.com SIP/2.0\n  Via: SIP/2.0/UDP localhost:5060;branch=#{Message.create_branch()}\n  From: sip:localhost;tag=#{Message.create_tag()}\n  To: sip:sip.example.com\n  CSeq: 1 OPTIONS\n  User-Agent: Sippet/1.0\n  Call-ID: #{Message.create_call_id()}\n  \"\"\" |\u003e Message.parse!()\n\nSippet.send(:sippet, request)\n```\n\nFurther documentation can found at\n[https://hexdocs.pm/sippet](https://hexdocs.pm/sippet).\n\n\n## Headers format\n\n```elixir\n# Definitions\n# ======================================================================================\n@type type :: String.t\n@type subtype :: String.t\n@type token :: String.t\n@type name :: String.t\n@type scheme :: String.t\n@type parameters :: %{String.t =\u003e String.t}\n@type uri :: Sippet.URI.t\n@type major :: integer\n@type minor :: integer\n@type display_name :: String.t\n@type string :: String.t\n@type timestamp :: double\n@type delay :: double\n@type protocol :: atom | String.t\n@type method :: atom | String.t\n\n\n# Header Name             Type\n# ======================================================================================\n@type headers :: %{\n  :accept              =\u003e [{{type, subtype}, parameters}, ...],\n  :accept_encoding     =\u003e [{token, parameters}, ...],\n  :accept_language     =\u003e [{token, parameters}, ...],\n  :alert_info          =\u003e [{uri, parameters}, ...],\n  :allow               =\u003e [token, ...],\n  :authentication_info =\u003e %{name =\u003e value},\n  :authorization       =\u003e [{scheme, parameters}, ...],\n  :call_id             =\u003e token,\n  :call_info           =\u003e [{uri, parameters}, ...],\n  :contact             =\u003e \"*\" | [{display_name, uri, parameters}, ...],\n  :content_disposition =\u003e {token, parameters},\n  :content_encoding    =\u003e [token, ...],\n  :content_language    =\u003e [token, ...],\n  :content_length      =\u003e integer,\n  :content_type        =\u003e {{type, subtype}, parameters},\n  :cseq                =\u003e {integer, method},\n  :date                =\u003e NaiveDateTime.t,\n  :error_info          =\u003e [{uri, parameters}, ...],\n  :expires             =\u003e integer,\n  :from                =\u003e {display_name, uri, parameters},\n  :in_reply_to         =\u003e [token, ...],\n  :max_forwards        =\u003e integer,\n  :mime_version        =\u003e {major, minor},\n  :min_expires         =\u003e integer,\n  :organization        =\u003e string,\n  :p_asserted_identity =\u003e [{display_name, uri, parameters}, ...],\n  :priority            =\u003e token,\n  :proxy_authenticate  =\u003e [{scheme, parameters}, ...],\n  :proxy_authorization =\u003e [{scheme, parameters}, ...],\n  :proxy_require       =\u003e [token, ...],\n  :reason              =\u003e [{token, parameters}, ...],\n  :record_route        =\u003e [{display_name, uri, parameters}, ...],\n  :reply_to            =\u003e {display_name, uri, parameters},\n  :require             =\u003e [token, ...],\n  :retry_after         =\u003e {integer, comment, parameters},\n  :route               =\u003e [{display_name, uri, parameters}, ...],\n  :server              =\u003e string,\n  :subject             =\u003e string,\n  :supported           =\u003e [token, ...],\n  :timestamp           =\u003e {timestamp, delay},\n  :to                  =\u003e {display_name, uri, parameters},\n  :unsupported         =\u003e [token, ...],\n  :user_agent          =\u003e string,\n  :via                 =\u003e [{{major, minor}, protocol, {address, port}, parameters}, ...],\n  :warning             =\u003e [{integer, agent, text}, ...],\n  :www_authenticate    =\u003e [{scheme, parameters}, ...],\n  String.t             =\u003e [String.t, ...]\n}\n```\n\n\n## Copyright\n\nCopyright (c) 2016-2020 Guilherme Balena Versiani. See [LICENSE](LICENSE) for\nfurther details.\n","funding_links":[],"categories":["Protocols"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbalena%2Felixir-sippet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbalena%2Felixir-sippet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbalena%2Felixir-sippet/lists"}