From 2087f93bb7ebf47c471f531176b82a7487ee4f79 Mon Sep 17 00:00:00 2001 From: Jakub Pisarek <99591440+sgfn@users.noreply.github.com> Date: Fri, 29 May 2026 17:06:24 +0200 Subject: [PATCH] Fix compile warnings, bump deps+CI --- .github/workflows/ci.yml | 10 +- lib/ex_ice/ice_agent.ex | 2 +- lib/ex_ice/priv/candidate_pair.ex | 10 +- lib/ex_ice/priv/checklist.ex | 4 +- .../priv/conn_check_handler/controlled.ex | 34 +-- .../priv/conn_check_handler/controlling.ex | 22 +- lib/ex_ice/priv/gatherer.ex | 7 +- lib/ex_ice/priv/ice_agent.ex | 264 ++++++++++-------- lib/ex_ice/priv/transport/tcp.ex | 2 - mix.exs | 4 +- mix.lock | 22 +- test/integration/p2p_test.exs | 4 +- test/priv/ice_agent_test.exs | 16 +- 13 files changed, 219 insertions(+), 182 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a57845..5898782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,8 @@ jobs: name: lint OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} strategy: matrix: - otp: ['26'] - elixir: ['1.15'] + otp: ['29'] + elixir: ['1.20'] steps: - uses: actions/checkout@v2 - uses: erlef/setup-beam@v1 @@ -24,8 +24,8 @@ jobs: name: test OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} strategy: matrix: - otp: ['26'] - elixir: ['1.15'] + otp: ['29'] + elixir: ['1.20'] env: MIX_ENV: test GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -39,4 +39,4 @@ jobs: - run: mix coveralls.json - uses: codecov/codecov-action@v4 with: - token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/lib/ex_ice/ice_agent.ex b/lib/ex_ice/ice_agent.ex index b4820b8..e905d8a 100644 --- a/lib/ex_ice/ice_agent.ex +++ b/lib/ex_ice/ice_agent.ex @@ -164,7 +164,7 @@ defmodule ExICE.ICEAgent do @doc """ Gets agent's role. """ - @spec get_role(pid()) :: ExICE.Agent.t() | nil + @spec get_role(pid()) :: role() | nil def get_role(ice_agent) do GenServer.call(ice_agent, :get_role) end diff --git a/lib/ex_ice/priv/candidate_pair.ex b/lib/ex_ice/priv/candidate_pair.ex index 96e490e..7e5e4fe 100644 --- a/lib/ex_ice/priv/candidate_pair.ex +++ b/lib/ex_ice/priv/candidate_pair.ex @@ -1,6 +1,5 @@ defmodule ExICE.Priv.CandidatePair do @moduledoc false - require Logger alias ExICE.Priv.{Candidate, Utils} @@ -62,8 +61,9 @@ defmodule ExICE.Priv.CandidatePair do ] @doc false - @spec new(Candidate.t(), Candidate.t(), ExICE.ICEAgent.role(), state(), valid?: boolean()) :: - t() + @spec new(Candidate.t(), Candidate.t(), ExICE.ICEAgent.role(), state(), [ + {:valid?, boolean()} | {:last_seen, integer()} + ]) :: t() def new(local_cand, remote_cand, agent_role, state, opts \\ []) do priority = priority(agent_role, local_cand.base.priority, remote_cand.priority) @@ -94,8 +94,8 @@ defmodule ExICE.Priv.CandidatePair do @doc false @spec recompute_priority(t(), integer(), integer(), ExICE.ICEAgent.role()) :: t() - def recompute_priority(pair, local_cand_prio, remote_cand_prio, role) do - %__MODULE__{pair | priority: priority(role, local_cand_prio, remote_cand_prio)} + def recompute_priority(%__MODULE__{} = pair, local_cand_prio, remote_cand_prio, role) do + %{pair | priority: priority(role, local_cand_prio, remote_cand_prio)} end @doc false diff --git a/lib/ex_ice/priv/checklist.ex b/lib/ex_ice/priv/checklist.ex index 522427d..d1ff955 100644 --- a/lib/ex_ice/priv/checklist.ex +++ b/lib/ex_ice/priv/checklist.ex @@ -96,9 +96,9 @@ defmodule ExICE.Priv.Checklist do @spec timeout_pairs(t(), [integer()]) :: t() def timeout_pairs(checklist, ids) do - for {_id, pair} <- checklist, into: %{} do + for {_id, %CandidatePair{} = pair} <- checklist, into: %{} do if pair.id in ids do - {pair.id, %CandidatePair{pair | valid?: false, state: :failed}} + {pair.id, %{pair | valid?: false, state: :failed}} else {pair.id, pair} end diff --git a/lib/ex_ice/priv/conn_check_handler/controlled.ex b/lib/ex_ice/priv/conn_check_handler/controlled.ex index ac9eb8a..73767a5 100644 --- a/lib/ex_ice/priv/conn_check_handler/controlled.ex +++ b/lib/ex_ice/priv/conn_check_handler/controlled.ex @@ -24,9 +24,9 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do nil when ice_agent.state in [:new, :checking, :connected] -> Logger.debug("Adding new candidate pair: #{inspect(pair)}") - pair = %CandidatePair{pair | requests_received: 1} + pair = %{pair | requests_received: 1} checklist = Map.put(ice_agent.checklist, pair.id, pair) - ice_agent = %ICEAgent{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} ICEAgent.send_binding_success_response(ice_agent, pair, msg) %CandidatePair{} = checklist_pair -> @@ -34,7 +34,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do ice_agent.state == :failed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -45,7 +45,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do checklist_pair.state == :failed and ice_agent.state == :completed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -56,7 +56,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do checklist_pair.state == :failed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | state: :waiting, last_seen: pair.last_seen, @@ -69,7 +69,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do true -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -98,16 +98,16 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do successful conn check: #{inspect(pair.id)}\ """) - pair = %CandidatePair{pair | nominate?: true, requests_received: 1} + pair = %{pair | nominate?: true, requests_received: 1} checklist = Map.put(ice_agent.checklist, pair.id, pair) - ice_agent = %ICEAgent{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} ICEAgent.send_binding_success_response(ice_agent, pair, msg) %CandidatePair{state: :succeeded} = checklist_pair when ice_agent.state != :failed -> discovered_pair = Map.fetch!(ice_agent.checklist, checklist_pair.discovered_pair_id) - discovered_pair = %CandidatePair{ + discovered_pair = %{ discovered_pair | last_seen: pair.last_seen, requests_received: discovered_pair.requests_received + 1 @@ -133,7 +133,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do Pair: #{inspect(pair.id)} """) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | nominate?: true, last_seen: pair.last_seen, @@ -151,7 +151,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do Pair: #{inspect(checklist_pair.id)} """) - checklist_pair = %CandidatePair{ + checklist_pair = %{ checklist_pair | nominate?: true, last_seen: pair.last_seen, @@ -164,7 +164,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do %CandidatePair{} = checklist_pair -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -182,22 +182,22 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do Logger.debug("Nomination succeeded, pair: #{pair_id}") pair = Map.fetch!(ice_agent.checklist, pair_id) - pair = %CandidatePair{pair | nominate?: false, nominated?: true} + pair = %{pair | nominate?: false, nominated?: true} checklist = Map.put(ice_agent.checklist, pair.id, pair) - ice_agent = %ICEAgent{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} cond do ice_agent.selected_pair_id == nil -> Logger.debug("Selecting pair: #{pair_id}") - %ICEAgent{ + %{ ice_agent | selected_pair_id: pair.id, selected_candidate_pair_changes: ice_agent.selected_candidate_pair_changes + 1 } - ice_agent.selected_pair_id != nil and pair.id != ice_agent.selected_pair_id -> + pair.id != ice_agent.selected_pair_id -> selected_pair = Map.fetch!(ice_agent.checklist, ice_agent.selected_pair_id) if pair.priority >= selected_pair.priority do @@ -206,7 +206,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlled do New pair: #{pair_id}, old pair: #{ice_agent.selected_pair_id}.\ """) - %ICEAgent{ + %{ ice_agent | selected_pair_id: pair.id, selected_candidate_pair_changes: ice_agent.selected_candidate_pair_changes + 1 diff --git a/lib/ex_ice/priv/conn_check_handler/controlling.ex b/lib/ex_ice/priv/conn_check_handler/controlling.ex index 75653be..4d301ce 100644 --- a/lib/ex_ice/priv/conn_check_handler/controlling.ex +++ b/lib/ex_ice/priv/conn_check_handler/controlling.ex @@ -36,9 +36,9 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do nil when ice_agent.state in [:new, :checking, :connected] -> Logger.debug("Adding new candidate pair: #{inspect(pair)}") - pair = %CandidatePair{pair | requests_received: 1} + pair = %{pair | requests_received: 1} checklist = Map.put(ice_agent.checklist, pair.id, pair) - ice_agent = %ICEAgent{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} ICEAgent.send_binding_success_response(ice_agent, pair, msg) %CandidatePair{} = checklist_pair -> @@ -46,7 +46,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do ice_agent.state == :failed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -57,7 +57,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do checklist_pair.state == :failed and ice_agent.state == :completed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -68,7 +68,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do checklist_pair.state == :failed -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | state: :waiting, last_seen: pair.last_seen, @@ -81,7 +81,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do true -> r_pair = resolve_pair(ice_agent, checklist_pair) - r_pair = %CandidatePair{ + r_pair = %{ r_pair | last_seen: pair.last_seen, requests_received: r_pair.requests_received + 1 @@ -106,7 +106,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do Logger.debug("Nomination succeeded. Selecting pair: #{inspect(pair_id)}") pair = Map.fetch!(ice_agent.checklist, pair_id) - pair = %CandidatePair{pair | nominate?: false, nominated?: true} + pair = %{pair | nominate?: false, nominated?: true} ice_agent = put_in(ice_agent.checklist[pair.id], pair) ice_agent = @@ -114,13 +114,13 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do ice_agent.selected_pair_id == nil -> Logger.debug("Selecting pair: #{pair_id}") - %ICEAgent{ + %{ ice_agent | selected_pair_id: pair.id, selected_candidate_pair_changes: ice_agent.selected_candidate_pair_changes + 1 } - ice_agent.selected_pair_id != nil and pair.id != ice_agent.selected_pair_id -> + pair.id != ice_agent.selected_pair_id -> selected_pair = Map.fetch!(ice_agent.checklist, ice_agent.selected_pair_id) if pair.priority >= selected_pair.priority do @@ -129,7 +129,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do New pair: #{pair_id}, old pair: #{ice_agent.selected_pair_id}.\ """) - %ICEAgent{ + %{ ice_agent | selected_pair_id: pair.id, selected_candidate_pair_changes: ice_agent.selected_candidate_pair_changes + 1 @@ -150,7 +150,7 @@ defmodule ExICE.Priv.ConnCheckHandler.Controlling do Logger.warning("Nomination succeeded but checklist hasn't finished.") end - %ICEAgent{ice_agent | nominating?: {false, nil}} + %{ice_agent | nominating?: {false, nil}} end defp resolve_pair(ice_agent, pair) do diff --git a/lib/ex_ice/priv/gatherer.ex b/lib/ex_ice/priv/gatherer.ex index 9b937b7..acee92b 100644 --- a/lib/ex_ice/priv/gatherer.ex +++ b/lib/ex_ice/priv/gatherer.ex @@ -10,6 +10,8 @@ defmodule ExICE.Priv.Gatherer do require Logger + @type local_preferences :: %{:inet.ip_address() => non_neg_integer()} + @type t() :: %__MODULE__{ if_discovery_module: module(), transport_module: module(), @@ -95,9 +97,8 @@ defmodule ExICE.Priv.Gatherer do end) end - @spec gather_host_candidates(t(), %{:inet.ip_address() => non_neg_integer()}, [ - {Transport.socket(), map()} - ]) :: [Candidate.t()] + @spec gather_host_candidates(t(), local_preferences(), [{Transport.socket(), map()}]) :: + {local_preferences(), [Candidate.t()]} def gather_host_candidates(gatherer, local_preferences, sockets) do {local_preferences, cands} = Enum.reduce(sockets, {local_preferences, []}, fn socket, {local_preferences, cands} -> diff --git a/lib/ex_ice/priv/ice_agent.ex b/lib/ex_ice/priv/ice_agent.ex index b4d0844..f0c51a9 100644 --- a/lib/ex_ice/priv/ice_agent.ex +++ b/lib/ex_ice/priv/ice_agent.ex @@ -19,6 +19,9 @@ defmodule ExICE.Priv.ICEAgent do alias ExSTUN.Message.Type alias ExSTUN.Message.Attribute.{ErrorCode, Username, XORMappedAddress} + # dialyzer falsely complains about ExTURN.Client.new never matching {:ok, client} + @dialyzer {:no_match, create_relay_gathering_transactions: 3} + # Ta timeout in ms. @ta_timeout 50 @@ -110,21 +113,22 @@ defmodule ExICE.Priv.ICEAgent do end end - defp resolve_address(remote_cand) when is_binary(remote_cand.address) do - Logger.debug("Trying to resolve addr: #{remote_cand.address}") + defp resolve_address(%ExICE.Candidate{address: address} = remote_cand) + when is_binary(address) do + Logger.debug("Trying to resolve addr: #{address}") with pid when is_pid(pid) <- Process.whereis(ExICE.Priv.MDNS.Resolver), - {:ok, addr} <- ExICE.Priv.MDNS.Resolver.gethostbyname(remote_cand.address) do - Logger.debug("Successfully resolved #{remote_cand.address} to #{inspect(addr)}") - remote_cand = %ExICE.Candidate{remote_cand | address: addr} + {:ok, addr} <- ExICE.Priv.MDNS.Resolver.gethostbyname(address) do + Logger.debug("Successfully resolved #{address} to #{inspect(addr)}") + remote_cand = %{remote_cand | address: addr} {:ok, remote_cand} else {:error, reason} = err -> - Logger.debug("Couldn't resolve #{remote_cand.address}, reason: #{reason}") + Logger.debug("Couldn't resolve #{address}, reason: #{reason}") err nil -> - Logger.debug("Couldn't resolve #{remote_cand.address}, reason: MDNS reslover not alive.") + Logger.debug("Couldn't resolve #{address}, reason: MDNS reslover not alive.") {:error, :mdns_resolver_not_alive} end end @@ -170,26 +174,26 @@ defmodule ExICE.Priv.ICEAgent do end @spec on_gathering_state_change(t(), pid() | nil) :: t() - def on_gathering_state_change(ice_agent, send_to) do - %__MODULE__{ice_agent | on_gathering_state_change: send_to} + def on_gathering_state_change(%__MODULE__{} = ice_agent, send_to) do + %{ice_agent | on_gathering_state_change: send_to} end @spec on_connection_state_change(t(), pid() | nil) :: t() - def on_connection_state_change(ice_agent, send_to) do - %__MODULE__{ice_agent | on_connection_state_change: send_to} + def on_connection_state_change(%__MODULE__{} = ice_agent, send_to) do + %{ice_agent | on_connection_state_change: send_to} end @spec on_data(t(), pid() | nil) :: t() - def on_data(ice_agent, send_to) do - %__MODULE__{ice_agent | on_data: send_to} + def on_data(%__MODULE__{} = ice_agent, send_to) do + %{ice_agent | on_data: send_to} end @spec on_new_candidate(t(), pid() | nil) :: t() - def on_new_candidate(ice_agent, send_to) do - %__MODULE__{ice_agent | on_new_candidate: send_to} + def on_new_candidate(%__MODULE__{} = ice_agent, send_to) do + %{ice_agent | on_new_candidate: send_to} end - @spec get_role(t()) :: ExICE.Agent.role() | nil + @spec get_role(t()) :: ExICE.ICEAgent.role() | nil def get_role(ice_agent), do: ice_agent.role @spec get_local_credentials(t()) :: {binary(), binary()} @@ -246,7 +250,7 @@ defmodule ExICE.Priv.ICEAgent do end def set_role(%__MODULE__{role: nil} = ice_agent, role) do - %__MODULE__{ice_agent | role: role} + %{ice_agent | role: role} end def set_role(%__MODULE__{} = ice_agent, _role) do @@ -270,7 +274,7 @@ defmodule ExICE.Priv.ICEAgent do # This is very loosely based on RFC 8863, sec. 4. # We can start eoc timer after sending and receiving ICE credentials. # In our case, we do this just after receiving remote credentials. - %__MODULE__{ice_agent | remote_ufrag: ufrag, remote_pwd: pwd} + %{ice_agent | remote_ufrag: ufrag, remote_pwd: pwd} |> start_eoc_timer() # check if timer does not need to be started |> update_ta_timer() @@ -285,10 +289,10 @@ defmodule ExICE.Priv.ICEAgent do ice_agent end - def set_remote_credentials(ice_agent, ufrag, pwd) do + def set_remote_credentials(%__MODULE__{} = ice_agent, ufrag, pwd) do Logger.debug("New remote credentials different than the current ones. Restarting ICE") ice_agent = do_restart(ice_agent) - %__MODULE__{ice_agent | remote_ufrag: ufrag, remote_pwd: pwd} + %{ice_agent | remote_ufrag: ufrag, remote_pwd: pwd} end @spec gather_candidates(t()) :: t() @@ -322,7 +326,7 @@ defmodule ExICE.Priv.ICEAgent do {local_preferences, host_cands} = Gatherer.gather_host_candidates(ice_agent.gatherer, ice_agent.local_preferences, sockets) - ice_agent = %__MODULE__{ice_agent | local_preferences: local_preferences} + ice_agent = %{ice_agent | local_preferences: local_preferences} srflx_cands = Gatherer.fabricate_srflx_candidates( @@ -422,7 +426,7 @@ defmodule ExICE.Priv.ICEAgent do ice_agent end - def add_remote_candidate(ice_agent, remote_cand) do + def add_remote_candidate(%__MODULE__{} = ice_agent, remote_cand) do Logger.debug("Trying to add a new remote candidate: #{inspect(remote_cand)}") found_cand = @@ -445,10 +449,10 @@ defmodule ExICE.Priv.ICEAgent do "Remote candidate already discovered as prflx. Updating its type and priority. Recomputing pair prios." ) - found_cand = %ExICE.Candidate{found_cand | type: :host, priority: remote_cand.priority} + found_cand = %{found_cand | type: :host, priority: remote_cand.priority} ice_agent = put_in(ice_agent.remote_cands[found_cand.id], found_cand) checklist = recompute_pair_prios(ice_agent) - ice_agent = %__MODULE__{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} if ice_agent.selected_pair_id != nil do %CandidatePair{} = best_valid_pair = Checklist.get_valid_pair(ice_agent.checklist) @@ -456,7 +460,7 @@ defmodule ExICE.Priv.ICEAgent do if best_valid_pair.id != ice_agent.selected_pair_id do Logger.debug("New best valid pair: #{best_valid_pair.id}. Selecting.") - %__MODULE__{ + %{ ice_agent | selected_pair_id: best_valid_pair.id, selected_candidate_pair_changes: ice_agent.selected_candidate_pair_changes + 1 @@ -521,7 +525,7 @@ defmodule ExICE.Priv.ICEAgent do {:ok, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_sent: pair.packets_sent + 1, bytes_sent: pair.bytes_sent + data_size @@ -539,7 +543,7 @@ defmodule ExICE.Priv.ICEAgent do {:error, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_discarded_on_send: pair.packets_discarded_on_send + 1, bytes_discarded_on_send: pair.bytes_discarded_on_send + data_size @@ -652,7 +656,7 @@ defmodule ExICE.Priv.ICEAgent do defp execute_transaction(ice_agent, :conn_check, pair) do Logger.debug("Sending conn check on pair: #{inspect(pair.id)}") - pair = %CandidatePair{pair | last_seen: now()} + pair = %{pair | last_seen: now()} send_conn_check(ice_agent, pair) end @@ -708,7 +712,7 @@ defmodule ExICE.Priv.ICEAgent do {:error, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_discarded_on_send: pair.packets_discarded_on_send + 1, bytes_discarded_on_send: pair.bytes_discarded_on_send + byte_size(conn_check.raw_req) @@ -847,7 +851,7 @@ defmodule ExICE.Priv.ICEAgent do # if pair was selected, send keepalives only on that pair s_pair = Map.fetch!(ice_agent.checklist, id) pair = CandidatePair.schedule_keepalive(s_pair) - ice_agent = %__MODULE__{ice_agent | checklist: Map.put(ice_agent.checklist, id, pair)} + ice_agent = %{ice_agent | checklist: Map.put(ice_agent.checklist, id, pair)} send_keepalive(ice_agent, ice_agent.checklist[id]) end @@ -859,14 +863,14 @@ defmodule ExICE.Priv.ICEAgent do ice_agent end - def handle_keepalive_timeout(ice_agent, id) do + def handle_keepalive_timeout(%__MODULE__{} = ice_agent, id) do # TODO: keepalives should be sent only if no data has been sent for @tr_timeout # atm, we send keepalives anyways, also it might be better to pace them with ta_timer # TODO: candidates not in a valid pair also should be kept alive (RFC 8445, sect 5.1.1.4) case Map.fetch(ice_agent.checklist, id) do {:ok, %CandidatePair{state: :succeeded, valid?: true} = pair} -> pair = CandidatePair.schedule_keepalive(pair) - ice_agent = %__MODULE__{ice_agent | checklist: Map.put(ice_agent.checklist, id, pair)} + ice_agent = %{ice_agent | checklist: Map.put(ice_agent.checklist, id, pair)} send_keepalive(ice_agent, pair) {:ok, _pair} -> @@ -1076,16 +1080,17 @@ defmodule ExICE.Priv.ICEAgent do |> Map.new() end - defp do_add_remote_candidate(ice_agent, remote_cand) when ice_agent.local_cands == %{} do + defp do_add_remote_candidate(%__MODULE__{local_cands: local_cands} = ice_agent, remote_cand) + when local_cands == %{} do Logger.debug("Not adding any new pairs as we don't have any local candidates.") - %__MODULE__{ + %{ ice_agent | remote_cands: Map.put(ice_agent.remote_cands, remote_cand.id, remote_cand) } end - defp do_add_remote_candidate(ice_agent, remote_cand) do + defp do_add_remote_candidate(%__MODULE__{} = ice_agent, remote_cand) do local_cands = get_matching_candidates_remote(Map.values(ice_agent.local_cands), remote_cand) checklist_foundations = get_foundations(ice_agent) @@ -1114,7 +1119,7 @@ defmodule ExICE.Priv.ICEAgent do Logger.debug("New candidate pairs: #{inspect(added_pairs)}") end - %__MODULE__{ + %{ ice_agent | checklist: checklist, remote_cands: Map.put(ice_agent.remote_cands, remote_cand.id, remote_cand) @@ -1125,7 +1130,7 @@ defmodule ExICE.Priv.ICEAgent do Enum.find(ice_agent.gathering_transactions, fn {_t_id, t} -> t.state == :waiting end) end - defp execute_gathering_transaction(ice_agent, %{stun_server: stun_server} = tr) do + defp execute_gathering_transaction(%__MODULE__{} = ice_agent, %{stun_server: stun_server} = tr) do {:ok, {sock_ip, sock_port}} = ice_agent.transport_module.sockname(tr.socket) Logger.debug(""" @@ -1138,7 +1143,7 @@ defmodule ExICE.Priv.ICEAgent do :ok -> tr = %{tr | state: :in_progress, send_time: now()} gathering_transactions = Map.put(ice_agent.gathering_transactions, tr.t_id, tr) - ice_agent = %__MODULE__{ice_agent | gathering_transactions: gathering_transactions} + ice_agent = %{ice_agent | gathering_transactions: gathering_transactions} {:ok, ice_agent} {:error, reason} -> @@ -1186,7 +1191,7 @@ defmodule ExICE.Priv.ICEAgent do timeout_conn_checks(ice_agent, now) end - defp timeout_conn_checks(ice_agent, now) do + defp timeout_conn_checks(%__MODULE__{} = ice_agent, now) do {stale_cc, cc} = Enum.split_with(ice_agent.conn_checks, fn {_id, %{send_time: send_time}} -> now - send_time >= @hto @@ -1204,10 +1209,10 @@ defmodule ExICE.Priv.ICEAgent do ice_agent.checklist end - %__MODULE__{ice_agent | checklist: checklist, conn_checks: cc} + %{ice_agent | checklist: checklist, conn_checks: cc} end - defp timeout_gathering_transactions(ice_agent, now) do + defp timeout_gathering_transactions(%__MODULE__{} = ice_agent, now) do {stale_gath_trans, gath_trans} = Enum.split_with(ice_agent.gathering_transactions, fn {_id, tr} -> tr.state == :in_progress and now - tr.send_time >= @hto @@ -1220,7 +1225,7 @@ defmodule ExICE.Priv.ICEAgent do Logger.debug("Gathering transactions timed out: #{inspect(ids)}") end - %__MODULE__{ice_agent | gathering_transactions: gath_trans} + %{ice_agent | gathering_transactions: gath_trans} end defp from_turn?(ice_agent, src_ip, src_port), @@ -1427,10 +1432,10 @@ defmodule ExICE.Priv.ICEAgent do do_handle_data_message(ice_agent, pair, packet) end - defp do_handle_data_message(ice_agent, pair, packet) do + defp do_handle_data_message(ice_agent, %CandidatePair{} = pair, packet) do data_size = byte_size(packet) - pair = %CandidatePair{ + pair = %{ pair | last_seen: now(), packets_received: pair.packets_received + 1, @@ -1448,7 +1453,7 @@ defmodule ExICE.Priv.ICEAgent do } end - defp add_local_cand(ice_agent, local_cand) do + defp add_local_cand(%__MODULE__{} = ice_agent, local_cand) do ice_agent = put_in(ice_agent.local_cands[local_cand.base.id], local_cand) remote_cands = get_matching_candidates_local(Map.values(ice_agent.remote_cands), local_cand) @@ -1474,7 +1479,7 @@ defmodule ExICE.Priv.ICEAgent do Logger.debug("New candidate pairs: #{inspect(added_pairs)}") end - %__MODULE__{ice_agent | checklist: checklist} + %{ice_agent | checklist: checklist} end defp do_handle_stun_message(ice_agent, local_cand, src_ip, src_port, %Message{} = msg) do @@ -1552,12 +1557,14 @@ defmodule ExICE.Priv.ICEAgent do ## BINDING INDICATION HANDLING ## defp handle_binding_indication(ice_agent, local_cand, src_ip, src_port) do remote_cand = find_remote_cand(Map.values(ice_agent.remote_cands), src_ip, src_port) - pair = Checklist.find_pair(ice_agent.checklist, local_cand.base.id, remote_cand.id) + + %CandidatePair{} = + pair = Checklist.find_pair(ice_agent.checklist, local_cand.base.id, remote_cand.id) case pair.state do :succeeded -> pair = Map.fetch!(ice_agent.checklist, pair.discovered_pair_id) - pair = %CandidatePair{pair | last_seen: now()} + pair = %{pair | last_seen: now()} put_in(ice_agent.checklist[pair.id], pair) :failed -> @@ -1574,13 +1581,13 @@ defmodule ExICE.Priv.ICEAgent do # The `last_seen` field will be overritten when sending conn-check, # but we update it for consistency, the same way we update it when # receiving normal data. - pair = %CandidatePair{pair | last_seen: now()} + pair = %{pair | last_seen: now()} put_in(ice_agent.checklist[pair.id], pair) end end ## BINDING REQUEST HANDLING ## - defp handle_binding_request(ice_agent, local_cand, src_ip, src_port, msg) do + defp handle_binding_request(%__MODULE__{} = ice_agent, local_cand, src_ip, src_port, msg) do with :ok <- check_username(msg, ice_agent.local_ufrag), :ok <- authenticate_msg(msg, ice_agent.local_pwd), {:ok, prio_attr} <- get_prio_attribute(msg), @@ -1604,7 +1611,7 @@ defmodule ExICE.Priv.ICEAgent do |> update_ta_timer() else error -> - ice_agent = %__MODULE__{ice_agent | unmatched_requests: ice_agent.unmatched_requests + 1} + ice_agent = %{ice_agent | unmatched_requests: ice_agent.unmatched_requests + 1} handle_binding_request_error(ice_agent, local_cand, src_ip, src_port, msg, error) end end @@ -1704,7 +1711,7 @@ defmodule ExICE.Priv.ICEAgent do Peer's tiebreaker: #{tiebreaker}\ """) - ice_agent = %__MODULE__{ice_agent | role: :controlled} + ice_agent = %{ice_agent | role: :controlled} checklist = recompute_pair_prios(ice_agent) @@ -1722,11 +1729,11 @@ defmodule ExICE.Priv.ICEAgent do Peer's tiebreaker: #{tiebreaker}\ """) - ice_agent = %__MODULE__{ice_agent | role: :controlling} + ice_agent = %{ice_agent | role: :controlling} checklist = recompute_pair_prios(ice_agent) - {:ok, %__MODULE__{ice_agent | checklist: checklist}} + {:ok, %{ice_agent | checklist: checklist}} end defp check_req_role_conflict(%__MODULE__{role: :controlled}, %ICEControlled{ @@ -1754,13 +1761,13 @@ defmodule ExICE.Priv.ICEAgent do end ## BINDING RESPONSE HANDLING ## - defp handle_conn_check_response(ice_agent, local_cand, src_ip, src_port, msg) do + defp handle_conn_check_response(%__MODULE__{} = ice_agent, local_cand, src_ip, src_port, msg) do {%{pair_id: pair_id, raw_req: raw_req}, conn_checks} = Map.pop!(ice_agent.conn_checks, msg.transaction_id) {:ok, req} = Message.decode(raw_req) - ice_agent = %__MODULE__{ice_agent | conn_checks: conn_checks} - conn_check_pair = Map.fetch!(ice_agent.checklist, pair_id) + ice_agent = %{ice_agent | conn_checks: conn_checks} + %CandidatePair{} = conn_check_pair = Map.fetch!(ice_agent.checklist, pair_id) # This shouldn't happen as we clear conn checks when a pair times out. if conn_check_pair.state == :failed do @@ -1790,7 +1797,7 @@ defmodule ExICE.Priv.ICEAgent do Pair failed: #{conn_check_pair.id}\ """) - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | state: :failed, valid?: false, @@ -1801,7 +1808,11 @@ defmodule ExICE.Priv.ICEAgent do end end - defp handle_conn_check_success_response(ice_agent, conn_check_pair, msg) do + defp handle_conn_check_success_response( + %__MODULE__{} = ice_agent, + %CandidatePair{} = conn_check_pair, + msg + ) do with :ok <- authenticate_msg(msg, ice_agent.remote_pwd), {:ok, xor_addr} <- Message.get_attribute(msg, XORMappedAddress) do {local_cand, ice_agent} = get_or_create_local_cand(ice_agent, xor_addr, conn_check_pair) @@ -1817,7 +1828,7 @@ defmodule ExICE.Priv.ICEAgent do pair = CandidatePair.schedule_keepalive(ice_agent.checklist[pair_id]) - pair = %CandidatePair{ + pair = %{ pair | last_seen: now(), responses_received: pair.responses_received + 1 @@ -1827,11 +1838,11 @@ defmodule ExICE.Priv.ICEAgent do # get new conn check pair as it will have updated # discovered and succeeded pair fields - conn_check_pair = Map.fetch!(ice_agent.checklist, conn_check_pair.id) + %CandidatePair{} = conn_check_pair = Map.fetch!(ice_agent.checklist, conn_check_pair.id) nominate? = conn_check_pair.nominate? - conn_check_pair = %CandidatePair{conn_check_pair | nominate?: false} + conn_check_pair = %{conn_check_pair | nominate?: false} checklist = Map.put(ice_agent.checklist, conn_check_pair.id, conn_check_pair) - ice_agent = %__MODULE__{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} @conn_check_handler[ice_agent.role].update_nominated_flag(ice_agent, pair_id, nominate?) else {:error, reason} -> @@ -1841,7 +1852,7 @@ defmodule ExICE.Priv.ICEAgent do Conn check pair: #{inspect(conn_check_pair.id)}.\ """) - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | responses_received: conn_check_pair.responses_received + 1 } @@ -1850,7 +1861,12 @@ defmodule ExICE.Priv.ICEAgent do end end - defp handle_conn_check_error_response(ice_agent, conn_check_pair, req, resp) do + defp handle_conn_check_error_response( + %__MODULE__{} = ice_agent, + %CandidatePair{} = conn_check_pair, + req, + resp + ) do # We only authenticate role conflict as it changes our state. # We don't add message-integrity to bad request and unauthenticated errors # so we also don't expect to receive it. @@ -1864,7 +1880,7 @@ defmodule ExICE.Priv.ICEAgent do "Conn check failed due to error response from the peer, error: #{inspect(other)}" ) - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | state: :failed, valid?: false, @@ -1872,11 +1888,16 @@ defmodule ExICE.Priv.ICEAgent do } checklist = Map.put(ice_agent.checklist, conn_check_pair.id, conn_check_pair) - %__MODULE__{ice_agent | checklist: checklist} + %{ice_agent | checklist: checklist} end end - defp handle_role_conflict_error_response(ice_agent, conn_check_pair, req, resp) do + defp handle_role_conflict_error_response( + %__MODULE__{} = ice_agent, + %CandidatePair{} = conn_check_pair, + req, + resp + ) do case authenticate_msg(resp, ice_agent.remote_pwd) do :ok -> {:ok, role} = get_role_attribute(req) @@ -1902,7 +1923,7 @@ defmodule ExICE.Priv.ICEAgent do tiebreaker = generate_tiebreaker() checklist = recompute_pair_prios(ice_agent) - %__MODULE__{ + %{ ice_agent | role: new_role, checklist: checklist, @@ -1910,7 +1931,7 @@ defmodule ExICE.Priv.ICEAgent do } end - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | state: :waiting, responses_received: conn_check_pair.responses_received + 1 @@ -1918,7 +1939,7 @@ defmodule ExICE.Priv.ICEAgent do checklist = Map.replace!(ice_agent.checklist, conn_check_pair.id, conn_check_pair) - %__MODULE__{ice_agent | checklist: checklist} + %{ice_agent | checklist: checklist} {:error, reason} -> Logger.debug( @@ -2006,13 +2027,13 @@ defmodule ExICE.Priv.ICEAgent do %Message{type: %Type{class: :success_response}} = msg ) do {pair_id, ice_agent} = pop_in(ice_agent.keepalives[msg.transaction_id]) - pair = Map.fetch!(ice_agent.checklist, pair_id) + %CandidatePair{} = pair = Map.fetch!(ice_agent.checklist, pair_id) with true <- symmetric?(ice_agent, local_cand.base.socket, {src_ip, src_port}, pair), :ok <- authenticate_msg(msg, ice_agent.remote_pwd) do Logger.debug("Received keepalive success response on: #{pair_info(ice_agent, pair)}") - pair = %CandidatePair{ + pair = %{ pair | last_seen: now(), responses_received: pair.responses_received + 1 @@ -2060,8 +2081,8 @@ defmodule ExICE.Priv.ICEAgent do %Message{type: %Type{class: :error_response}} = msg ) do {pair_id, ice_agent} = pop_in(ice_agent.keepalives[msg.transaction_id]) - pair = Map.fetch!(ice_agent.checklist, pair_id) - pair = %CandidatePair{pair | responses_received: pair.responses_received + 1} + %CandidatePair{} = pair = Map.fetch!(ice_agent.checklist, pair_id) + pair = %{pair | responses_received: pair.responses_received + 1} ice_agent = put_in(ice_agent.checklist[pair.id], pair) Logger.debug(""" @@ -2082,14 +2103,19 @@ defmodule ExICE.Priv.ICEAgent do # Check against valid_pair == conn_check_pair before # checking against valid_pair == checklist_pair as # the second condition is always true if the first one is - defp add_valid_pair(ice_agent, valid_pair, conn_check_pair, _) + defp add_valid_pair( + %__MODULE__{} = ice_agent, + %CandidatePair{} = valid_pair, + %CandidatePair{} = conn_check_pair, + _ + ) when are_pairs_equal(valid_pair, conn_check_pair) do Logger.debug(""" New valid pair: #{conn_check_pair.id} \ resulted from conn check on pair: #{conn_check_pair.id}\ """) - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | succeeded_pair_id: conn_check_pair.id, discovered_pair_id: conn_check_pair.id, @@ -2099,25 +2125,30 @@ defmodule ExICE.Priv.ICEAgent do checklist = Map.replace!(ice_agent.checklist, conn_check_pair.id, conn_check_pair) - ice_agent = %__MODULE__{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} {conn_check_pair.id, ice_agent} end - defp add_valid_pair(ice_agent, valid_pair, conn_check_pair, checklist_pair) + defp add_valid_pair( + %__MODULE__{} = ice_agent, + %CandidatePair{} = valid_pair, + %CandidatePair{} = conn_check_pair, + %CandidatePair{} = checklist_pair + ) when are_pairs_equal(valid_pair, checklist_pair) do Logger.debug(""" New valid pair: #{checklist_pair.id} \ resulted from conn check on pair: #{conn_check_pair.id}\ """) - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | discovered_pair_id: checklist_pair.id, succeeded_pair_id: conn_check_pair.id, state: :succeeded } - checklist_pair = %CandidatePair{ + checklist_pair = %{ checklist_pair | discovered_pair_id: checklist_pair.id, succeeded_pair_id: conn_check_pair.id, @@ -2130,11 +2161,16 @@ defmodule ExICE.Priv.ICEAgent do |> Map.replace!(conn_check_pair.id, conn_check_pair) |> Map.replace!(checklist_pair.id, checklist_pair) - ice_agent = %__MODULE__{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} {checklist_pair.id, ice_agent} end - defp add_valid_pair(ice_agent, valid_pair, conn_check_pair, nil) do + defp add_valid_pair( + %__MODULE__{} = ice_agent, + %CandidatePair{} = valid_pair, + %CandidatePair{} = conn_check_pair, + nil + ) do # TODO compute priority according to sec 7.2.5.3.2 Logger.debug(""" Adding new candidate pair resulted from conn check \ @@ -2143,14 +2179,14 @@ defmodule ExICE.Priv.ICEAgent do Logger.debug("New valid pair: #{valid_pair.id}") - conn_check_pair = %CandidatePair{ + conn_check_pair = %{ conn_check_pair | discovered_pair_id: valid_pair.id, succeeded_pair_id: conn_check_pair.id, state: :succeeded } - valid_pair = %CandidatePair{ + valid_pair = %{ valid_pair | discovered_pair_id: valid_pair.id, succeeded_pair_id: conn_check_pair.id @@ -2161,13 +2197,13 @@ defmodule ExICE.Priv.ICEAgent do |> Map.replace!(conn_check_pair.id, conn_check_pair) |> Map.put(valid_pair.id, valid_pair) - ice_agent = %__MODULE__{ice_agent | checklist: checklist} + ice_agent = %{ice_agent | checklist: checklist} {valid_pair.id, ice_agent} end @doc false @spec send_binding_success_response(t(), CandidatePair.t(), Message.t()) :: t() - def send_binding_success_response(ice_agent, pair, req) do + def send_binding_success_response(ice_agent, %CandidatePair{} = pair, req) do local_cand = Map.fetch!(ice_agent.local_cands, pair.local_cand_id) remote_cand = Map.fetch!(ice_agent.remote_cands, pair.remote_cand_id) @@ -2184,13 +2220,13 @@ defmodule ExICE.Priv.ICEAgent do case do_send(ice_agent, local_cand, {src_ip, src_port}, resp) do {:ok, ice_agent} -> - pair = %CandidatePair{pair | responses_sent: pair.responses_sent + 1} + pair = %{pair | responses_sent: pair.responses_sent + 1} put_in(ice_agent.checklist[pair.id], pair) {:error, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_discarded_on_send: pair.packets_discarded_on_send + 1, bytes_discarded_on_send: pair.bytes_discarded_on_send + byte_size(resp) @@ -2278,7 +2314,7 @@ defmodule ExICE.Priv.ICEAgent do if f in checklist_foundations, do: :frozen, else: :waiting end - defp get_or_create_local_cand(ice_agent, xor_addr, conn_check_pair) do + defp get_or_create_local_cand(%__MODULE__{} = ice_agent, xor_addr, conn_check_pair) do conn_check_local_cand = Map.fetch!(ice_agent.local_cands, conn_check_pair.local_cand_id) local_cand = @@ -2343,7 +2379,7 @@ defmodule ExICE.Priv.ICEAgent do Logger.debug("Adding new local prflx candidate: #{inspect(cand)}") - ice_agent = %__MODULE__{ + ice_agent = %{ ice_agent | local_cands: Map.put(ice_agent.local_cands, cand.base.id, cand) } @@ -2539,15 +2575,15 @@ defmodule ExICE.Priv.ICEAgent do defp time_to_nominate?(_ice_agent), do: false - defp try_nominate(ice_agent) do + defp try_nominate(%__MODULE__{} = ice_agent) do case Checklist.get_pair_for_nomination(ice_agent.checklist) do %CandidatePair{} = pair -> Logger.debug("Trying to nominate pair: #{inspect(pair.id)}") - pair = %CandidatePair{pair | nominate?: true} + pair = %{pair | nominate?: true} checklist = Map.put(ice_agent.checklist, pair.id, pair) - ice_agent = %__MODULE__{ice_agent | checklist: checklist, nominating?: {true, pair.id}} + ice_agent = %{ice_agent | checklist: checklist, nominating?: {true, pair.id}} pair = Map.fetch!(ice_agent.checklist, pair.succeeded_pair_id) - pair = %CandidatePair{pair | state: :waiting, nominate?: true} + pair = %{pair | state: :waiting, nominate?: true} send_conn_check(ice_agent, pair) nil -> @@ -2561,7 +2597,7 @@ defmodule ExICE.Priv.ICEAgent do end end - defp do_restart(ice_agent) do + defp do_restart(%__MODULE__{} = ice_agent) do Enum.each(ice_agent.sockets, fn socket -> case ice_agent.transport_module.sockname(socket) do {:ok, {ip, port}} -> @@ -2596,7 +2632,7 @@ defmodule ExICE.Priv.ICEAgent do pair_changes_diff = if ice_agent.selected_pair_id != nil, do: 1, else: 0 - %__MODULE__{ + %{ ice_agent | sockets: [], gathering_transactions: %{}, @@ -2679,10 +2715,12 @@ defmodule ExICE.Priv.ICEAgent do |> List.wrap() |> Enum.map(fn url -> case ExSTUN.URI.parse(url) do - {:ok, url} -> - ice_server - |> Map.delete(:urls) - |> Map.put(:url, url) + {:ok, parsed_url} -> + %{ + url: parsed_url, + username: ice_server[:username], + credential: ice_server[:credential] + } :error -> Logger.warning("Couldn't parse URL: #{inspect(url)}. Ignoring.") @@ -2725,14 +2763,14 @@ defmodule ExICE.Priv.ICEAgent do end end - defp change_gathering_state(ice_agent, new_gathering_state, opts \\ []) do + defp change_gathering_state(%__MODULE__{} = ice_agent, new_gathering_state, opts \\ []) do Logger.debug("Gathering state change: #{ice_agent.gathering_state} -> #{new_gathering_state}") if opts[:notify] != false do notify(ice_agent.on_gathering_state_change, {:gathering_state_change, new_gathering_state}) end - %__MODULE__{ice_agent | gathering_state: new_gathering_state} + %{ice_agent | gathering_state: new_gathering_state} end defp update_gathering_state(%{gathering_state: :complete} = ice_agent), do: ice_agent @@ -2847,14 +2885,14 @@ defmodule ExICE.Priv.ICEAgent do do_change_connection_state(ice_agent, new_conn_state, opts) end - defp do_change_connection_state(ice_agent, new_conn_state, opts) do + defp do_change_connection_state(%__MODULE__{} = ice_agent, new_conn_state, opts) do Logger.debug("Connection state change: #{ice_agent.state} -> #{new_conn_state}") if opts[:notify] != false do notify(ice_agent.on_connection_state_change, {:connection_state_change, new_conn_state}) end - %__MODULE__{ice_agent | state: new_conn_state} + %{ice_agent | state: new_conn_state} end defp update_connection_state(%__MODULE__{state: :new} = ice_agent) do @@ -3069,7 +3107,7 @@ defmodule ExICE.Priv.ICEAgent do %{ice_agent | ta_timer: nil} end - defp send_keepalive(ice_agent, pair) do + defp send_keepalive(%__MODULE__{} = ice_agent, %CandidatePair{} = pair) do Logger.debug("Sending keepalive on #{pair_info(ice_agent, pair)}") local_cand = Map.fetch!(ice_agent.local_cands, pair.local_cand_id) remote_cand = Map.fetch!(ice_agent.remote_cands, pair.remote_cand_id) @@ -3081,15 +3119,15 @@ defmodule ExICE.Priv.ICEAgent do case do_send(ice_agent, local_cand, dst, raw_req) do {:ok, ice_agent} -> - pair = %CandidatePair{pair | requests_sent: pair.requests_sent + 1} + pair = %{pair | requests_sent: pair.requests_sent + 1} ice_agent = put_in(ice_agent.checklist[pair.id], pair) keepalives = Map.put(ice_agent.keepalives, req.transaction_id, pair.id) - %__MODULE__{ice_agent | keepalives: keepalives} + %{ice_agent | keepalives: keepalives} {:error, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_discarded_on_send: pair.packets_discarded_on_send + 1, bytes_discarded_on_send: pair.bytes_discarded_on_send + byte_size(raw_req) @@ -3099,7 +3137,7 @@ defmodule ExICE.Priv.ICEAgent do end end - defp send_conn_check(ice_agent, pair) do + defp send_conn_check(%__MODULE__{} = ice_agent, %CandidatePair{} = pair) do local_cand = Map.fetch!(ice_agent.local_cands, pair.local_cand_id) remote_cand = Map.fetch!(ice_agent.remote_cands, pair.remote_cand_id) @@ -3110,7 +3148,7 @@ defmodule ExICE.Priv.ICEAgent do # set nominate? flag in case we are running aggressive nomination # but don't override it if we are controlled agent and it was already set to true - pair = %CandidatePair{pair | nominate?: pair.nominate? || nominate} + pair = %{pair | nominate?: pair.nominate? || nominate} ice_agent = put_in(ice_agent.checklist[pair.id], pair) req = binding_request(ice_agent, local_cand, nominate) @@ -3133,12 +3171,12 @@ defmodule ExICE.Priv.ICEAgent do conn_checks = Map.put(ice_agent.conn_checks, req.transaction_id, conn_check) checklist = Map.put(ice_agent.checklist, pair.id, pair) - %__MODULE__{ice_agent | conn_checks: conn_checks, checklist: checklist} + %{ice_agent | conn_checks: conn_checks, checklist: checklist} {:error, ice_agent} -> pair = Map.fetch!(ice_agent.checklist, pair.id) - pair = %CandidatePair{ + pair = %{ pair | packets_discarded_on_send: pair.packets_discarded_on_send + 1, bytes_discarded_on_send: pair.bytes_discarded_on_send + byte_size(raw_req), diff --git a/lib/ex_ice/priv/transport/tcp.ex b/lib/ex_ice/priv/transport/tcp.ex index 80beb48..77ae10f 100644 --- a/lib/ex_ice/priv/transport/tcp.ex +++ b/lib/ex_ice/priv/transport/tcp.ex @@ -2,8 +2,6 @@ defmodule ExICE.Priv.Transport.TCP do @moduledoc false @behaviour ExICE.Priv.Transport - require Logger - alias ExICE.Priv.Transport.TCP.Client @impl true diff --git a/mix.exs b/mix.exs index 6e7df83..7801057 100644 --- a/mix.exs +++ b/mix.exs @@ -55,8 +55,8 @@ defmodule ExICE.MixProject do defp deps do [ - {:ex_stun, "~> 0.2.0"}, - {:ex_turn, "~> 0.2.2"}, + {:ex_stun, "~> 0.2.1"}, + {:ex_turn, "~> 0.2.3"}, {:elixir_uuid, "~> 1.0"}, {:excoveralls, "~> 0.15", only: :test, runtime: false}, {:ex_doc, "~> 0.27", only: :dev, runtime: false}, diff --git a/mix.lock b/mix.lock index 6691970..8809458 100644 --- a/mix.lock +++ b/mix.lock @@ -1,18 +1,18 @@ %{ "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "credo": {:hex, :credo, "1.7.17", "f92b6aa5b26301eaa5a35e4d48ebf5aa1e7094ac00ae38f87086c562caf8a22f", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1eb5645c835f0b6c9b5410f94b5a185057bcf6d62a9c2b476da971cde8749645"}, + "credo": {:hex, :credo, "1.7.19", "cc52129665fc7c15143d47838fda0f9cd6dac9ceced7bf4da6f85fcbfe64b12a", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2d8bc95d5a7bb99dd2613621d4f08c6a3575c3fd4b62e6a2b48a100352a557b8"}, "dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, - "erlex": {:hex, :erlex, "0.2.8", "cd8116f20f3c0afe376d1e8d1f0ae2452337729f68be016ea544a72f767d9c12", [:mix], [], "hexpm", "9d66ff9fedf69e49dc3fd12831e12a8a37b76f8651dd21cd45fcf5561a8a7590"}, - "ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"}, - "ex_stun": {:hex, :ex_stun, "0.2.0", "feb1fc7db0356406655b2a617805e6c712b93308c8ea2bf0ba1197b1f0866deb", [:mix], [], "hexpm", "1e01ba8290082ccbf37acaa5190d1f69b51edd6de2026a8d6d51368b29d115d0"}, - "ex_turn": {:hex, :ex_turn, "0.2.2", "b9dd1a66a657a34f320caf0e22cc116575ea3503fdcec66a9a541a76fe919ac8", [:mix], [{:ex_stun, "~> 0.2.0", [hex: :ex_stun, repo: "hexpm", optional: false]}], "hexpm", "00f5380b593c5a8bfc80511e53cb1fdb0b8ad7577f61da3dd2612f7fda1ef0e6"}, - "excoveralls": {:hex, :excoveralls, "0.18.3", "bca47a24d69a3179951f51f1db6d3ed63bca9017f476fe520eb78602d45f7756", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "746f404fcd09d5029f1b211739afb8fb8575d775b21f6a3908e7ce3e640724c6"}, + "erlex": {:hex, :erlex, "0.2.9", "7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], "hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"}, + "ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"}, + "ex_stun": {:hex, :ex_stun, "0.2.1", "f8273f16687c4a052583b91307783763675c3ee208d7746e9072eab1d7fe5318", [:mix], [], "hexpm", "df711db3610302d4161ce362321f98862fad858de48a75c135fd0b343f18e817"}, + "ex_turn": {:hex, :ex_turn, "0.2.3", "7d10ce9c784c4a01dfb9adf42d94e52000db014b4557287067cd344b2939e0b6", [:mix], [{:ex_stun, "~> 0.2.1", [hex: :ex_stun, repo: "hexpm", optional: false]}], "hexpm", "f94874c6d240a162ba610deca0e3a42a6dbc2721c37310ec1ab6063ac1e677c0"}, + "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, - "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "jason": {:hex, :jason, "1.4.5", "2e3a008590b0b8d7388c20293e9dcc9cf3e5d642fd2a114e4cbbb52e595d940a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b0c823996102bcd0239b3c2444eb00409b72f6a140c1950bc8b457d836b30684"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, - "makeup_elixir": {:hex, :makeup_elixir, "1.0.0", "74bb8348c9b3a51d5c589bf5aebb0466a84b33274150e3b6ece1da45584afc82", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49159b7d7d999e836bedaf09dcf35ca18b312230cf901b725a64f3f42e407983"}, - "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.1.0", "835f7e60792e08824cda445639555d7bf1bbbddb1b60b306e33cb6f6db24dc74", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "1cd6780fb1dd1a03979abaed0fe82712b0625118fd5257d3ebbf73f960c73c3c"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, } diff --git a/test/integration/p2p_test.exs b/test/integration/p2p_test.exs index 9ae4ca8..621325b 100644 --- a/test/integration/p2p_test.exs +++ b/test/integration/p2p_test.exs @@ -242,7 +242,7 @@ defmodule ExICE.Integration.P2PTest do Logger.info("Sending file...") Task.start(fn -> - File.stream!("./test/fixtures/lotr.txt", [], 1000) + File.stream!("./test/fixtures/lotr.txt", 1000, []) |> Stream.each(fn chunk -> ICEAgent.send_data(agent1, chunk) end) |> Stream.run() @@ -280,7 +280,7 @@ defmodule ExICE.Integration.P2PTest do Logger.info("Sending file...") Task.start(fn -> - File.stream!("./test/fixtures/lotr.txt", [], 1000) + File.stream!("./test/fixtures/lotr.txt", 1000, []) |> Stream.each(fn chunk -> ICEAgent.send_data(agent2, chunk) end) |> Stream.run() diff --git a/test/priv/ice_agent_test.exs b/test/priv/ice_agent_test.exs index ea4a49c..cd7a74a 100644 --- a/test/priv/ice_agent_test.exs +++ b/test/priv/ice_agent_test.exs @@ -178,7 +178,7 @@ defmodule ExICE.Priv.ICEAgentTest do assert [prflx_cand] = Map.values(ice_agent.remote_cands) assert [prflx_pair] = Map.values(ice_agent.checklist) assert prflx_cand.type == :prflx - prflx_pair = %CandidatePair{prflx_pair | state: :succeeded, valid?: true} + prflx_pair = %{prflx_pair | state: :succeeded, valid?: true} ice_agent = put_in(ice_agent.checklist[prflx_pair.id], prflx_pair) # add another remote candidate that will result in higher pair priority @@ -190,9 +190,9 @@ defmodule ExICE.Priv.ICEAgentTest do end) assert host_pair.priority > prflx_pair.priority - host_pair = %CandidatePair{host_pair | state: :succeeded, valid?: true} + host_pair = %{host_pair | state: :succeeded, valid?: true} ice_agent = put_in(ice_agent.checklist[host_pair.id], host_pair) - ice_agent = %ICEAgent{ice_agent | selected_pair_id: host_pair.id} + ice_agent = %{ice_agent | selected_pair_id: host_pair.id} # try to add host candidate that is the same as prflx candidate ice_agent = ICEAgent.add_remote_candidate(ice_agent, remote_cand1) @@ -388,9 +388,9 @@ defmodule ExICE.Priv.ICEAgentTest do # check stats stats = ICEAgent.get_stats(ice_agent) - assert stats.local_candidates != %{} - assert stats.remote_candidates != %{} - assert stats.candidate_pairs != %{} + assert stats.local_candidates != [] + assert stats.remote_candidates != [] + assert stats.candidate_pairs != [] assert stats.state == :closed refute_received {:ex_ice, _pid, {:connection_state_change, :closed}} @@ -1051,7 +1051,7 @@ defmodule ExICE.Priv.ICEAgentTest do |> Message.encode() # modify last byte to make fingerprint incorrect - <> = request + <> = request request = <> _ice_agent = @@ -1220,7 +1220,7 @@ defmodule ExICE.Priv.ICEAgentTest do # mark pair as failed [pair_before] = Map.values(ice_agent.checklist) - pair_before = %CandidatePair{pair_before | state: :failed, valid?: false} + pair_before = %{pair_before | state: :failed, valid?: false} ice_agent = put_in(ice_agent.checklist[pair_before.id], pair_before) # wait so that there is a change in last_seen in case of