Packages
sippet
0.6.3
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/transactions/client/invite.ex
defmodule Sippet.Transactions.Client.Invite do
@moduledoc false
use Sippet.Transactions.Client, initial_state: :calling
alias Sippet.Message, as: Message
alias Sippet.Message.StatusLine, as: StatusLine
alias Sippet.Transactions.Client.State, as: State
@timer_a 600 # optimization: transaction ends in 37.8s
@timer_b 64 * @timer_a
@timer_d 32_000 # timer D should be > 32s
defp retry({past_wait, passed_time}, %State{request: request} = data) do
send_request(request, data)
new_delay = past_wait * 2
{:keep_state_and_data, [{:state_timeout, new_delay,
{new_delay, passed_time + new_delay}}]}
end
defp build_ack(request, last_response) do
ack =
:ack
|> Message.build_request(request.start_line.request_uri)
|> Message.put_header(:via, Message.get_header(request, :via))
|> Message.put_header(:max_forwards, 70)
|> Message.put_header(:from, Message.get_header(request, :from))
|> Message.put_header(:to, Message.get_header(request, :to))
|> Message.put_header(:call_id, Message.get_header(request, :call_id))
{sequence, _method} = request.headers.cseq
ack = ack |> Message.put_header(:cseq, {sequence, :ack})
ack =
if Message.has_header?(request, :route) do
ack |> Message.put_header(:route, Message.get_header(request, :route))
else
ack
end
ack =
case last_response.headers.to do
{_, _, %{"tag" => to_tag}} ->
ack |> Message.update_header(:to, nil,
fn {display_name, uri, params} ->
{display_name, uri, params |> Map.put("tag", to_tag)}
end)
_otherwise ->
ack
end
if request |> Message.has_header?(:route) do
ack |> Message.put_header(:route, request.headers.route)
else
ack
end
end
def calling(:enter, _old_state, %State{request: request} = data) do
send_request(request, data)
actions =
if reliable?(request) do
[{:state_timeout, @timer_b, {@timer_b, @timer_b}}]
else
[{:state_timeout, @timer_a, {@timer_a, @timer_a}}]
end
{:keep_state_and_data, actions}
end
def calling(:state_timeout, {_past_wait, passed_time} = time_event, data) do
if passed_time >= @timer_b do
timeout(data)
else
retry(time_event, data)
end
end
def calling(:cast, {:incoming_response, response}, data) do
receive_response(response, data)
case StatusLine.status_code_class(response.start_line) do
1 -> {:next_state, :proceeding, data}
2 -> {:stop, :normal, data}
_ ->
extras = data.extras |> Map.put(:last_response, response)
{:next_state, :completed, Map.put(data, :extras, extras)}
end
end
def calling(:cast, {:error, reason}, data),
do: shutdown(reason, data)
def calling(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
def proceeding(:enter, _old_state, _data),
do: :keep_state_and_data
def proceeding(:cast, {:incoming_response, response}, data) do
receive_response(response, data)
case StatusLine.status_code_class(response.start_line) do
1 -> {:keep_state, data}
2 -> {:stop, :normal, data}
_ ->
extras = data.extras |> Map.put(:last_response, response)
{:next_state, :completed, Map.put(data, :extras, extras)}
end
end
def proceeding(:cast, {:error, reason}, data),
do: shutdown(reason, data)
def proceeding(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
def completed(:enter, _old_state,
%State{request: request, extras: extras} = data) do
ack = build_ack(request, extras.last_response)
send_request(ack, data)
data = %State{extras: extras |> Map.put(:ack, ack)}
if reliable?(request) do
{:stop, :normal, data}
else
{:keep_state, data, [{:state_timeout, @timer_d, nil}]}
end
end
def completed(:state_timeout, _nil, data),
do: {:stop, :normal, data}
def completed(:cast, {:incoming_response, response},
%State{extras: %{ack: ack}} = data) do
if StatusLine.status_code_class(response.start_line) >= 3 do
send_request(ack, data)
end
:keep_state_and_data
end
def completed(:cast, {:error, _reason}, _data),
do: :keep_state_and_data
def completed(event_type, event_content, data),
do: unhandled_event(event_type, event_content, data)
end