Skip to content

Commit fa4c5c3

Browse files
committed
Add close/1
1 parent 7552d06 commit fa4c5c3

File tree

2 files changed

+94
-23
lines changed

2 files changed

+94
-23
lines changed

lib/ex_ice/ice_agent.ex

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule ExICE.ICEAgent do
3030
For exact meaning refer to the W3C WebRTC standard, sec. 5.6.4.
3131
"""
3232
@type connection_state_change() ::
33-
{:connection_state_change, :checking | :connected | :completed | :failed}
33+
{:connection_state_change, :checking | :connected | :completed | :failed | :closed}
3434

3535
@typedoc """
3636
Messages sent by the ExICE.
@@ -276,6 +276,16 @@ defmodule ExICE.ICEAgent do
276276
GenServer.cast(ice_agent, :restart)
277277
end
278278

279+
@doc """
280+
Irreversibly closes ICE agent but does not terminate its process.
281+
282+
To terminate ICE agent process, see `stop/1`.
283+
"""
284+
@spec close(pid()) :: :ok
285+
def close(ice_agent) do
286+
GenServer.cast(ice_agent, :close)
287+
end
288+
279289
@doc """
280290
Stops ICE agent and all of its sockets.
281291
"""
@@ -346,6 +356,12 @@ defmodule ExICE.ICEAgent do
346356
{:reply, stats, state}
347357
end
348358

359+
@impl true
360+
def handle_call(:close, _from, state) do
361+
ice_agent = ExICE.Priv.ICEAgent.close(state.ice_agent)
362+
{:reply, :ok, %{state | ice_agent: ice_agent}}
363+
end
364+
349365
@impl true
350366
def handle_cast({:set_role, role}, state) do
351367
ice_agent = ExICE.Priv.ICEAgent.set_role(state.ice_agent, role)

lib/ex_ice/priv/ice_agent.ex

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,9 @@ defmodule ExICE.Priv.ICEAgent do
250250
end
251251

252252
@spec set_remote_credentials(t(), binary(), binary()) :: t()
253-
def set_remote_credentials(%__MODULE__{state: :failed} = ice_agent, _, _) do
254-
Logger.debug("Tried to set remote credentials in failed state. ICE restart needed. Ignoring.")
253+
def set_remote_credentials(%__MODULE__{state: state} = ice_agent, _, _)
254+
when state in [:failed, :closed] do
255+
Logger.debug("Tried to set remote credentials in state #{state}. Ignoring.")
255256
ice_agent
256257
end
257258

@@ -286,8 +287,8 @@ defmodule ExICE.Priv.ICEAgent do
286287
end
287288

288289
@spec gather_candidates(t()) :: t()
289-
def gather_candidates(%__MODULE__{state: :failed} = ice_agent) do
290-
Logger.warning("Can't gather candidates in state failed. ICE restart needed. Ignoring.")
290+
def gather_candidates(%__MODULE__{state: state} = ice_agent) when state in [:failed, :closed] do
291+
Logger.warning("Can't gather candidates in state #{state}. Ignoring.")
291292
ice_agent
292293
end
293294

@@ -364,9 +365,10 @@ defmodule ExICE.Priv.ICEAgent do
364365
end
365366

366367
@spec add_remote_candidate(t(), Candidate.t()) :: t()
367-
def add_remote_candidate(%__MODULE__{state: :failed} = ice_agent, _) do
368+
def add_remote_candidate(%__MODULE__{state: state} = ice_agent, _)
369+
when state in [:failed, :closed] do
368370
# Completed state will be caught by the next clause
369-
Logger.debug("Can't add remote candidate in state failed. ICE restart needed. Ignoring.")
371+
Logger.debug("Can't add remote candidate in state #{state}. Ignoring.")
370372
ice_agent
371373
end
372374

@@ -455,7 +457,7 @@ defmodule ExICE.Priv.ICEAgent do
455457
end
456458

457459
@spec end_of_candidates(t()) :: t()
458-
def end_of_candidates(%__MODULE__{state: :failed} = ice_agent) do
460+
def end_of_candidates(%__MODULE__{state: state} = ice_agent) when state in [:failed, :closed] do
459461
Logger.debug("Can't set end-of-candidates flag in state failed. Ignoring.")
460462
ice_agent
461463
end
@@ -537,12 +539,22 @@ defmodule ExICE.Priv.ICEAgent do
537539
end
538540

539541
@spec restart(t()) :: t()
542+
def restart(%__MODULE__{state: :closed} = ice_agent) do
543+
Logger.debug("Can't restart ICE in state closed. Ignoring.")
544+
ice_agent
545+
end
546+
540547
def restart(ice_agent) do
541548
Logger.debug("Restarting ICE")
542549
do_restart(ice_agent)
543550
end
544551

545552
@spec handle_ta_timeout(t()) :: t()
553+
def handle_ta_timeout(%__MODULE__{state: :closed} = ice_agent) do
554+
Logger.debug("Ta timer fired in closed state. Ignoring.")
555+
ice_agent
556+
end
557+
546558
def handle_ta_timeout(%__MODULE__{state: state} = ice_agent)
547559
when state in [:completed, :failed] do
548560
Logger.warning("""
@@ -694,6 +706,11 @@ defmodule ExICE.Priv.ICEAgent do
694706
end
695707

696708
@spec handle_tr_rtx_timeout(t(), integer()) :: t()
709+
def handle_tr_rtx_timeout(%__MODULE__{state: :closed} = ice_agent, _) do
710+
Logger.debug("Transaction rtx timer fired in state closed. Ignoring.")
711+
ice_agent
712+
end
713+
697714
def handle_tr_rtx_timeout(ice_agent, t_id) when is_map_key(ice_agent.conn_checks, t_id) do
698715
# Mark transaction id as ready to be retransmitted.
699716
# We will do this in handle_ta_timeout as it has to be paced.
@@ -725,8 +742,9 @@ defmodule ExICE.Priv.ICEAgent do
725742
end
726743

727744
@spec handle_eoc_timeout(t()) :: t()
728-
def handle_eoc_timeout(%__MODULE__{state: :failed} = ice_agent) do
729-
Logger.debug("EOC timer fired but we are in the failed state. Ignoring.")
745+
def handle_eoc_timeout(%__MODULE__{state: state} = ice_agent)
746+
when state in [:failed, :closed] do
747+
Logger.debug("EOC timer fired but we are in the #{state} state. Ignoring.")
730748
%{ice_agent | eoc_timer: nil}
731749
end
732750

@@ -742,6 +760,11 @@ defmodule ExICE.Priv.ICEAgent do
742760
end
743761

744762
@spec handle_pair_timeout(t()) :: t()
763+
def handle_pair_timeout(%__MODULE__{state: :closed} = ice_agent) do
764+
Logger.debug("Pair timer fired in closed state. Ignoring.")
765+
ice_agent
766+
end
767+
745768
def handle_pair_timeout(ice_agent) do
746769
start_pair_timer()
747770

@@ -792,6 +815,11 @@ defmodule ExICE.Priv.ICEAgent do
792815
end
793816

794817
@spec handle_keepalive_timeout(t(), integer()) :: t()
818+
def handle_keepalive_timeout(%__MODULE__{state: :closed} = ice_agent, _) do
819+
Logger.debug("Keepalive timer fired in closed state. Ignoring.")
820+
ice_agent
821+
end
822+
795823
def handle_keepalive_timeout(%__MODULE__{selected_pair_id: id} = ice_agent, id) do
796824
# if pair was selected, send keepalives only on that pair
797825
s_pair = Map.fetch!(ice_agent.checklist, id)
@@ -842,7 +870,8 @@ defmodule ExICE.Priv.ICEAgent do
842870
:inet.port_number(),
843871
binary()
844872
) :: t()
845-
def handle_udp(%{state: :failed} = ice_agent, _socket, _src_ip, _src_port, _packet) do
873+
def handle_udp(%{state: state} = ice_agent, _socket, _src_ip, _src_port, _packet)
874+
when state in [:failed, :closed] do
846875
ice_agent
847876
end
848877

@@ -868,6 +897,11 @@ defmodule ExICE.Priv.ICEAgent do
868897
end
869898

870899
@spec handle_ex_turn_msg(t(), reference(), ExTURN.Client.notification_message()) :: t()
900+
def handle_ex_turn_msg(%__MODULE__{state: :closed} = ice_agent, _, _) do
901+
Logger.debug("Received ex_turn message in closed state. Ignoring.")
902+
ice_agent
903+
end
904+
871905
def handle_ex_turn_msg(ice_agent, client_ref, msg) do
872906
tr_id_tr = find_gathering_transaction(ice_agent.gathering_transactions, client_ref)
873907

@@ -919,6 +953,18 @@ defmodule ExICE.Priv.ICEAgent do
919953
end
920954
end
921955

956+
@spec close(t()) :: t()
957+
def close(%__MODULE__{state: :closed} = ice_agent) do
958+
ice_agent
959+
end
960+
961+
def close(%__MODULE__{} = ice_agent) do
962+
ice_agent.sockets
963+
|> Enum.reduce(ice_agent, fn socket, ice_agent -> close_socket(ice_agent, socket) end)
964+
|> change_gathering_state(:complete, notify: false)
965+
|> change_connection_state(:closed, notify: false)
966+
end
967+
922968
## PRIV API
923969

924970
defp create_srflx_gathering_transactions(stun_servers, sockets) do
@@ -2497,7 +2543,6 @@ defmodule ExICE.Priv.ICEAgent do
24972543
end
24982544

24992545
defp generate_credentials() do
2500-
# TODO am I using Base.encode64 correctly?
25012546
ufrag = :crypto.strong_rand_bytes(3) |> Base.encode64()
25022547
pwd = :crypto.strong_rand_bytes(16) |> Base.encode64()
25032548
{ufrag, pwd}
@@ -2523,9 +2568,13 @@ defmodule ExICE.Priv.ICEAgent do
25232568
end
25242569
end
25252570

2526-
defp change_gathering_state(ice_agent, new_gathering_state) do
2527-
Logger.debug("Gathering state change: #{ice_agent.gathering_state} -> #{new_gathering_state}")
2528-
notify(ice_agent.on_gathering_state_change, {:gathering_state_change, new_gathering_state})
2571+
defp change_gathering_state(ice_agent, new_gathering_state, opts \\ []) do
2572+
Logger.debug("Gatering state change: #{ice_agent.gathering_state} -> #{new_gathering_state}")
2573+
2574+
if opts[:notify] != false do
2575+
notify(ice_agent.on_gathering_state_change, {:gathering_state_change, new_gathering_state})
2576+
end
2577+
25292578
%__MODULE__{ice_agent | gathering_state: new_gathering_state}
25302579
end
25312580

@@ -2551,7 +2600,9 @@ defmodule ExICE.Priv.ICEAgent do
25512600

25522601
@doc false
25532602
@spec change_connection_state(t(), atom()) :: t()
2554-
def change_connection_state(ice_agent, :failed) do
2603+
def change_connection_state(ice_agent, new_state, opts \\ [])
2604+
2605+
def change_connection_state(ice_agent, :failed, opts) do
25552606
ice_agent =
25562607
Enum.reduce(ice_agent.sockets, ice_agent, fn socket, ice_agent ->
25572608
close_socket(ice_agent, socket)
@@ -2599,10 +2650,10 @@ defmodule ExICE.Priv.ICEAgent do
25992650
nominating?: {false, nil}
26002651
}
26012652
|> disable_timer()
2602-
|> do_change_connection_state(:failed)
2653+
|> do_change_connection_state(:failed, opts)
26032654
end
26042655

2605-
def change_connection_state(ice_agent, :completed) do
2656+
def change_connection_state(ice_agent, :completed, opts) do
26062657
selected_pair = Map.fetch!(ice_agent.checklist, ice_agent.selected_pair_id)
26072658
succeeded_pair = Map.fetch!(ice_agent.checklist, selected_pair.succeeded_pair_id)
26082659

@@ -2632,16 +2683,20 @@ defmodule ExICE.Priv.ICEAgent do
26322683
end
26332684
end)
26342685

2635-
do_change_connection_state(ice_agent, :completed)
2686+
do_change_connection_state(ice_agent, :completed, opts)
26362687
end
26372688

2638-
def change_connection_state(ice_agent, new_conn_state) do
2639-
do_change_connection_state(ice_agent, new_conn_state)
2689+
def change_connection_state(ice_agent, new_conn_state, opts) do
2690+
do_change_connection_state(ice_agent, new_conn_state, opts)
26402691
end
26412692

2642-
defp do_change_connection_state(ice_agent, new_conn_state) do
2693+
defp do_change_connection_state(ice_agent, new_conn_state, opts) do
26432694
Logger.debug("Connection state change: #{ice_agent.state} -> #{new_conn_state}")
2644-
notify(ice_agent.on_connection_state_change, {:connection_state_change, new_conn_state})
2695+
2696+
if opts[:notify] != false do
2697+
notify(ice_agent.on_connection_state_change, {:connection_state_change, new_conn_state})
2698+
end
2699+
26452700
%__MODULE__{ice_agent | state: new_conn_state}
26462701
end
26472702

0 commit comments

Comments
 (0)