Parrot.Sip.Message (Parrot Platform v0.0.1-alpha.2)
Represents a SIP message (request or response).
This module provides a struct and functions for working with SIP messages as defined in RFC 3261 and related specifications. It provides a pure functional implementation that models both SIP requests and responses, along with utility functions for manipulation, analysis, and conversion.
References:
- RFC 3261 Section 7: SIP Messages
- RFC 3261 Section 8.1: UAC Behavior
- RFC 3261 Section 8.2: UAS Behavior
- RFC 3261 Section 20: Header Fields
Summary
Functions
Gets all Via headers from a message.
Gets the branch parameter from the top Via header.
Gets the Call-ID header from a message.
Gets the Contact header from a message.
Gets the CSeq header from a message.
Returns the default reason phrase for a given SIP status code.
Gets a dialog ID from a message.
Gets the From header from a message.
Gets a header from the message by name.
Gets all headers of a given name. Returns a list, even if only one header is present.
Determines if a message is within a dialog.
Checks if a response message is a client error (4xx).
Checks if a response message is a failure (4xx, 5xx, or 6xx).
Checks if a response message is a global error (6xx).
Checks if a response message is provisional (1xx).
Checks if a response message is a redirection (3xx).
Check if a message is a request.
Check if a message is a response.
Checks if a response message is a server error (5xx).
Checks if a response message is successful (2xx).
Creates a new request message with the specified method, request URI, and headers.
Creates a new response message with standard reason phrase based on status code.
Creates a new response message with the specified status code, reason phrase, and headers.
Creates a response from a request with standard reason phrase based on status code.
Creates a response from a request, copying necessary headers and setting the status code and reason phrase.
Sets the body of the message and updates the Content-Length header.
Sets a header in the message.
Gets the status class of a response message (1xx, 2xx, etc.).
Gets the To header from a message.
Converts a message to binary format for transmission.
Convert the message to a string representation.
Gets the top Via header from a message.
Types
@type t() :: %Parrot.Sip.Message{ body: String.t(), dialog_id: String.t() | nil, direction: :incoming | :outgoing | nil, headers: map(), method: Parrot.Sip.Method.t() | nil, reason_phrase: String.t() | nil, request_uri: String.t() | nil, source: map() | nil, status_code: integer() | nil, transaction_id: String.t() | nil, type: :request | :response | nil, version: String.t() }
Functions
@spec all_vias(t()) :: [Parrot.Sip.Headers.Via.t()]
Gets all Via headers from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> via = %Parrot.Sip.Headers.Via{host: "example.com", port: 5060}
iex> message = Parrot.Sip.Message.set_header(message, "Via", via)
iex> Parrot.Sip.Message.all_vias(message)
[%Parrot.Sip.Headers.Via{host: "example.com", port: 5060}]
Gets the branch parameter from the top Via header.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> via = %Parrot.Sip.Headers.Via{parameters: %{"branch" => "z9hG4bK123"}}
iex> message = Parrot.Sip.Message.set_header(message, "Via", via)
iex> Parrot.Sip.Message.branch(message)
"z9hG4bK123"
Gets the Call-ID header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> message = Parrot.Sip.Message.set_header(message, "Call-ID", "abc123@example.com")
iex> Parrot.Sip.Message.call_id(message)
"abc123@example.com"
@spec contact(t()) :: Parrot.Sip.Headers.Contact.t() | nil
Gets the Contact header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> contact = %Parrot.Sip.Headers.Contact{uri: "sip:alice@example.com"}
iex> message = Parrot.Sip.Message.set_header(message, "Contact", contact)
iex> Parrot.Sip.Message.contact(message)
%Parrot.Sip.Headers.Contact{uri: "sip:alice@example.com"}
@spec cseq(t()) :: Parrot.Sip.Headers.CSeq.t() | nil
Gets the CSeq header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> cseq = %Parrot.Sip.Headers.CSeq{sequence: 1, method: :invite}
iex> message = Parrot.Sip.Message.set_header(message, "CSeq", cseq)
iex> Parrot.Sip.Message.cseq(message)
%Parrot.Sip.Headers.CSeq{sequence: 1, method: :invite}
Returns the default reason phrase for a given SIP status code.
@spec dialog_id(t()) :: Parrot.Sip.DialogId.t()
Gets a dialog ID from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> from = %Parrot.Sip.Headers.From{parameters: %{"tag" => "123"}}
iex> to = %Parrot.Sip.Headers.To{parameters: %{"tag" => "456"}}
iex> message = message |> Parrot.Sip.Message.set_header("From", from)
iex> message = message |> Parrot.Sip.Message.set_header("To", to)
iex> message = message |> Parrot.Sip.Message.set_header("Call-ID", "abc@example.com")
iex> dialog_id = Parrot.Sip.Message.dialog_id(message)
iex> dialog_id.call_id
"abc@example.com"
@spec from(t()) :: Parrot.Sip.Headers.From.t() | nil
Gets the From header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> from = %Parrot.Sip.Headers.From{uri: "sip:alice@example.com"}
iex> message = Parrot.Sip.Message.set_header(message, "From", from)
iex> Parrot.Sip.Message.from(message)
%Parrot.Sip.Headers.From{uri: "sip:alice@example.com"}
Gets a header from the message by name.
Header names are case-insensitive as per RFC 3261. If the header is a map, it will be converted to the appropriate struct.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> message = Parrot.Sip.Message.set_header(message, "Via", %{protocol: "SIP", version: "2.0", transport: "udp"})
iex> Parrot.Sip.Message.get_header(message, "via")
%Parrot.Sip.Headers.Via{protocol: "SIP", version: "2.0", transport: :udp}
Gets all headers of a given name. Returns a list, even if only one header is present.
Useful for headers that can appear multiple times like Record-Route or Via.
Determines if a message is within a dialog.
A message is within a dialog if it has a To tag and a From tag.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> from = %Parrot.Sip.Headers.From{parameters: %{"tag" => "123"}}
iex> to = %Parrot.Sip.Headers.To{parameters: %{"tag" => "456"}}
iex> message = message |> Parrot.Sip.Message.set_header("From", from)
iex> message = message |> Parrot.Sip.Message.set_header("To", to)
iex> Parrot.Sip.Message.in_dialog?(message)
true
Checks if a response message is a client error (4xx).
Examples
iex> message = Parrot.Sip.Message.new_response(404, "Not Found")
iex> Parrot.Sip.Message.is_client_error?(message)
true
Checks if a response message is a failure (4xx, 5xx, or 6xx).
Examples
iex> message = Parrot.Sip.Message.new_response(404, "Not Found")
iex> Parrot.Sip.Message.is_failure?(message)
true
Checks if a response message is a global error (6xx).
Examples
iex> message = Parrot.Sip.Message.new_response(603, "Decline")
iex> Parrot.Sip.Message.is_global_error?(message)
true
Checks if a response message is provisional (1xx).
Examples
iex> message = Parrot.Sip.Message.new_response(180, "Ringing")
iex> Parrot.Sip.Message.is_provisional?(message)
true
Checks if a response message is a redirection (3xx).
Examples
iex> message = Parrot.Sip.Message.new_response(302, "Moved Temporarily")
iex> Parrot.Sip.Message.is_redirect?(message)
true
Check if a message is a request.
Check if a message is a response.
Checks if a response message is a server error (5xx).
Examples
iex> message = Parrot.Sip.Message.new_response(500, "Server Internal Error")
iex> Parrot.Sip.Message.is_server_error?(message)
true
Checks if a response message is successful (2xx).
Examples
iex> message = Parrot.Sip.Message.new_response(200, "OK")
iex> Parrot.Sip.Message.is_success?(message)
true
@spec new_request(Parrot.Sip.Method.t(), String.t(), map(), keyword()) :: t()
Creates a new request message with the specified method, request URI, and headers.
This function is the main entry point for creating SIP request messages.
Parameters
- method: The SIP method (atom) for the request
- request_uri: The request target URI
- headers: Optional map of initial headers
Examples
iex> Parrot.Sip.Message.new_request(:invite, "sip:alice@example.com")
%Parrot.Sip.Message{
method: :invite,
request_uri: "sip:alice@example.com",
version: "SIP/2.0",
headers: %{},
body: "",
type: :request,
direction: :outgoing
}
Creates a new response message with standard reason phrase based on status code.
If no reason phrase is provided, a standard one will be used based on the status code.
Examples
iex> Parrot.Sip.Message.new_response(200)
%Parrot.Sip.Message{
status_code: 200,
reason_phrase: "OK",
version: "SIP/2.0",
headers: %{},
body: "",
type: :response,
direction: :outgoing
}
Creates a new response message with the specified status code, reason phrase, and headers.
Parameters
- status_code: The SIP response status code (100-699)
- reason_phrase: The reason phrase for the response
- headers: Optional map of initial headers
Examples
iex> Parrot.Sip.Message.new_response(200, "OK")
%Parrot.Sip.Message{
status_code: 200,
reason_phrase: "OK",
version: "SIP/2.0",
headers: %{},
body: "",
type: :response,
direction: :outgoing
}
Creates a response from a request with standard reason phrase based on status code.
Examples
iex> request = Parrot.Sip.Message.new_request(:invite, "sip:alice@example.com")
iex> response = Parrot.Sip.Message.reply(request, 200)
iex> response.reason_phrase
"OK"
Creates a response from a request, copying necessary headers and setting the status code and reason phrase.
This function follows the requirements in RFC 3261 Section 8.2.6 for copying headers from requests to responses.
Parameters
- request: The SIP request message
- status_code: The response status code
- reason_phrase: The reason phrase for the response
Examples
iex> request = Parrot.Sip.Message.new_request(:invite, "sip:alice@example.com")
iex> response = Parrot.Sip.Message.reply(request, 200, "OK")
iex> response.status_code
200
Sets the body of the message and updates the Content-Length header.
This function automatically calculates and sets the Content-Length header based on the body's length.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> message = Parrot.Sip.Message.set_body(message, "Hello, world!")
iex> message.body
"Hello, world!"
iex> message.headers["content-length"]
13
Sets a header in the message.
Header names are converted to lowercase for consistent storage and retrieval.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> from_header = %Parrot.Sip.Headers.From{}
iex> message = Parrot.Sip.Message.set_header(message, "From", from_header)
iex> message.headers["from"] == from_header
true
Gets the status class of a response message (1xx, 2xx, etc.).
Examples
iex> message = Parrot.Sip.Message.new_response(200, "OK")
iex> Parrot.Sip.Message.status_class(message)
2
@spec to(t()) :: Parrot.Sip.Headers.To.t() | nil
Gets the To header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> to = %Parrot.Sip.Headers.To{uri: "sip:bob@example.com"}
iex> message = Parrot.Sip.Message.set_header(message, "To", to)
iex> Parrot.Sip.Message.to(message)
%Parrot.Sip.Headers.To{uri: "sip:bob@example.com"}
Converts a message to binary format for transmission.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> binary = Parrot.Sip.Message.to_binary(message)
iex> String.starts_with?(binary, "INVITE sip:bob@example.com SIP/2.0")
true
Convert the message to a string representation.
@spec top_via(t()) :: Parrot.Sip.Headers.Via.t() | nil
Gets the top Via header from a message.
Examples
iex> message = Parrot.Sip.Message.new_request(:invite, "sip:bob@example.com")
iex> via = %Parrot.Sip.Headers.Via{host: "example.com", port: 5060}
iex> message = Parrot.Sip.Message.set_header(message, "Via", via)
iex> Parrot.Sip.Message.top_via(message)
%Parrot.Sip.Headers.Via{host: "example.com", port: 5060}