Packages
sippet
1.0.9
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
An Elixir Session Initiation Protocol (SIP) stack.
Current section
Files
Jump to
Current section
Files
lib/sippet/message/status_line.ex
defmodule Sippet.Message.StatusLine do
@moduledoc """
A SIP Status-Line struct, composed by the SIP-Version, Status-Code and the
Reason-Phrase.
The `start_line` of responses are represented by this struct. The RFC 3261
represents the Status-Line as:
Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
The above `SIP-Version` is represented by a `{major, minor}` tuple, which
assumes the value `{2, 0}` in standard implementations.
The `Status-Code` is a 3-digit integer in the interval 100-699 indicating the
outcome of an attempt to understand and satisfy a request.
The `Reason-Phrase` is a binary representing a short textual description of
the `Status-Code`.
The `Status-Code` is intended for use by automata, whereas the
`Reason-Phrase` is intended for the human user.
"""
defstruct [
status_code: nil,
reason_phrase: nil,
version: nil
]
@type status_code :: 100..699
@type version :: {integer, integer}
@type t :: %__MODULE__{
status_code: status_code,
reason_phrase: binary,
version: version
}
@default_status_codes %{
100 => "Trying",
180 => "Ringing",
181 => "Call Is Being Forwarded",
182 => "Queued",
183 => "Session Progress",
199 => "Early Dialog Terminated",
200 => "OK",
202 => "Accepted",
204 => "No Notification",
300 => "Multiple Choices",
301 => "Moved Permanently",
302 => "Moved Temporarily",
305 => "Use Proxy",
380 => "Alternative Service",
400 => "Bad Request",
401 => "Unauthorized",
402 => "Payment Required",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
406 => "Not Acceptable",
407 => "Proxy Authentication Required",
408 => "Request Timeout",
410 => "Gone",
412 => "Conditional Request Failed",
413 => "Request Entity Too Large",
414 => "Request-URI Too Long",
415 => "Unsupported Media Type",
416 => "Unsupported URI Scheme",
417 => "Unknown Resource-Priority",
420 => "Bad Extension",
421 => "Extension Required",
422 => "Session Interval Too Small",
423 => "Interval Too Brief",
424 => "Bad Location Information",
428 => "Use Identity Header",
429 => "Provide Referrer Identity",
430 => "Flow Failed",
433 => "Anonymity Disallowed",
436 => "Bad Identity-Info",
437 => "Unsupported Certificate",
438 => "Invalid Identity Header",
439 => "First Hop Lacks Outbound Support",
440 => "Max-Breadth Exceeded",
469 => "Bad Info Package",
470 => "Consent Needed",
480 => "Temporarily Unavailable",
481 => "Call/Transaction Does Not Exist",
482 => "Loop Detected",
483 => "Too Many Hops",
484 => "Address Incomplete",
485 => "Ambiguous",
486 => "Busy Here",
487 => "Request Terminated",
488 => "Not Acceptable Here",
489 => "Bad Event",
491 => "Request Pending",
493 => "Undecipherable",
494 => "Security Agreement Required",
500 => "Server Internal Error",
501 => "Not Implemented",
502 => "Bad Gateway",
503 => "Service Unavailable",
504 => "Server Time-out",
505 => "Version Not Supported",
513 => "Message Too Large",
580 => "Precondition Failure",
600 => "Busy Everywhere",
603 => "Decline",
604 => "Does Not Exist Anywhere",
606 => "Not Acceptable"
}
@doc """
Returns a Status-Line struct.
The `reason_phrase` is obtained from default values.
The function will throw an exception if the `status_code` is not in the valid
range `100..699` or if the `status_code` does not have a default reason
phrase.
The version will assume the default value `{2, 0}`.
## Examples
iex> Sippet.Message.StatusLine.new(400)
%Sippet.Message.StatusLine{reason_phrase: "Bad Request", status_code: 400,
version: {2, 0}}
"""
@spec new(status_code) :: t | no_return
def new(status_code) when is_integer(status_code),
do: new(status_code, default_reason!(status_code))
@doc """
Creates a Status-Line struct using a given reason phrase.
In this function, the `reason_phrase` can be anything the application wants.
The function will throw an exception if the `status_code` is not in the valid
range `100..699`.
The version will assume the default value `{2, 0}`.
## Examples
iex> Sippet.Message.StatusLine.new(499, "Foobar")
%Sippet.Message.StatusLine{reason_phrase: "Foobar", status_code: 499,
version: {2, 0}}
"""
@spec new(status_code, reason_phrase :: binary) :: t
def new(status_code, reason_phrase)
when is_integer(status_code) and is_binary(reason_phrase) do
%__MODULE__{
status_code: do_raise_if_invalid(status_code),
reason_phrase: reason_phrase,
version: {2, 0}
}
end
defp do_raise_if_invalid(status_code) do
if status_code < 100 || status_code >= 700 do
raise "invalid status code, got: #{inspect(status_code)}"
else
status_code
end
end
@doc """
Returns an integer representing the status code class in the range `[1, 6]`.
## Examples
iex> alias Sippet.Message.StatusLine
iex> StatusLine.new(202) |> StatusLine.status_code_class()
2
"""
@spec status_code_class(t) :: 1..6
def status_code_class(%__MODULE__{status_code: status_code}) do
div(status_code, 100)
end
@doc """
Returns a binary representing the default reason phrase for the given
`status_code`.
If the `status_code` does not have a corresponding default reason phrase,
returns `nil`.
## Examples
iex> Sippet.Message.StatusLine.default_reason(202)
"Accepted"
iex> Sippet.Message.StatusLine.default_reason(499)
nil
"""
@spec default_reason(status_code) :: binary | nil
def default_reason(status_code) do
defaults = @default_status_codes
if defaults |> Map.has_key?(status_code) do
defaults[status_code]
else
nil
end
end
@doc """
Returns a binary representing the default reason phrase for the given
`status_code`.
If the `status_code` does not have a corresponding default reason phrase,
throws an exception.
## Examples
iex> Sippet.Message.StatusLine.default_reason!(202)
"Accepted"
iex> Sippet.Message.StatusLine.default_reason!(499)
** (ArgumentError) status code 499 does not have a default reason phrase
"""
@spec default_reason!(status_code) :: binary | no_return
def default_reason!(status_code) do
case status_code |> do_raise_if_invalid() |> default_reason() do
nil ->
raise ArgumentError, "status code #{inspect status_code} " <>
"does not have a default reason phrase"
reason_phrase ->
reason_phrase
end
end
@doc """
Returns a binary which corresponds to the text representation of the given
Status-Line.
It does not includes an ending line CRLF.
## Examples
iex> alias Sippet.StatusLine
iex> StatusLine.new(202) |> StatusLine.to_string
"SIP/2.0 202 Accepted"
"""
@spec to_string(t) :: binary
defdelegate to_string(value), to: String.Chars.Sippet.Message.StatusLine
@doc """
Returns an iodata which corresponds to the text representation of the given
Status-Line.
It does not includes an ending line CRLF.
## Examples
iex> alias Sippet.StatusLine
iex> StatusLine.new(202) |> StatusLine.to_iodata
["SIP/", "2", ".", "0", " ", "202", " ", "Accepted"]
"""
@spec to_iodata(t) :: iodata
def to_iodata(%Sippet.Message.StatusLine{version: {major, minor},
status_code: status_code, reason_phrase: reason_phrase}) do
["SIP/", Integer.to_string(major), ".", Integer.to_string(minor),
" ", Integer.to_string(status_code),
" ", reason_phrase]
end
end
defimpl String.Chars, for: Sippet.Message.StatusLine do
alias Sippet.Message.StatusLine, as: StatusLine
def to_string(%StatusLine{} = status_line) do
status_line
|> StatusLine.to_iodata()
|> IO.iodata_to_binary
end
end