@@ -220,6 +220,11 @@ defmodule ExICE.Priv.ICEAgent do
220220 end
221221
222222 @ spec set_remote_credentials ( t ( ) , binary ( ) , binary ( ) ) :: t ( )
223+ def set_remote_credentials ( % __MODULE__ { state: :failed } = ice_agent , _ , _ ) do
224+ Logger . debug ( "Tried to set remote credentials in failed state. ICE restart needed. Ignoring." )
225+ ice_agent
226+ end
227+
223228 def set_remote_credentials (
224229 % __MODULE__ { remote_ufrag: nil , remote_pwd: nil } = ice_agent ,
225230 ufrag ,
@@ -249,6 +254,11 @@ defmodule ExICE.Priv.ICEAgent do
249254 end
250255
251256 @ spec gather_candidates ( t ( ) ) :: t ( )
257+ def gather_candidates ( % __MODULE__ { state: :failed } = ice_agent ) do
258+ Logger . warning ( "Can't gather candidates in state failed. ICE restart needed. Ignoring." )
259+ ice_agent
260+ end
261+
252262 def gather_candidates ( % __MODULE__ { gathering_state: :gathering } = ice_agent ) do
253263 Logger . warning ( "Can't gather candidates. Gathering already in progress. Ignoring." )
254264 ice_agent
@@ -311,6 +321,12 @@ defmodule ExICE.Priv.ICEAgent do
311321 end
312322
313323 @ spec add_remote_candidate ( t ( ) , Candidate . t ( ) ) :: t ( )
324+ def add_remote_candidate ( % __MODULE__ { state: :failed } = ice_agent , _ ) do
325+ # Completed state will be caught by the next clause
326+ Logger . debug ( "Can't add remote candidate in state failed. ICE restart needed. Ignoring." )
327+ ice_agent
328+ end
329+
314330 def add_remote_candidate ( % __MODULE__ { eoc: true } = ice_agent , remote_cand ) do
315331 Logger . warning ( """
316332 Received remote candidate after end-of-candidates. Ignoring.
@@ -361,6 +377,11 @@ defmodule ExICE.Priv.ICEAgent do
361377 end
362378
363379 @ spec end_of_candidates ( t ( ) ) :: t ( )
380+ def end_of_candidates ( % __MODULE__ { state: :failed } = ice_agent ) do
381+ Logger . debug ( "Can't set end-of-candidates flag in state failed. Ignoring." )
382+ ice_agent
383+ end
384+
364385 def end_of_candidates ( % __MODULE__ { role: :controlled } = ice_agent ) do
365386 Logger . debug ( "Setting end-of-candidates flag." )
366387 ice_agent = % { ice_agent | eoc: true }
@@ -418,7 +439,7 @@ defmodule ExICE.Priv.ICEAgent do
418439
419440 @ spec handle_ta_timeout ( t ( ) ) :: t ( )
420441 def handle_ta_timeout ( % __MODULE__ { state: state } = ice_agent )
421- when state . state in [ :completed , :failed ] do
442+ when state in [ :completed , :failed ] do
422443 Logger . warning ( """
423444 Ta timer fired in unexpected state: #{ state } .
424445 Trying to update gathering and connection states.
@@ -477,6 +498,11 @@ defmodule ExICE.Priv.ICEAgent do
477498 end
478499
479500 @ spec handle_eoc_timeout ( t ( ) ) :: t ( )
501+ def handle_eoc_timeout ( % __MODULE__ { state: :failed } = ice_agent ) do
502+ Logger . debug ( "EOC timer fired but we are in the failed state. Ignoring." )
503+ % { ice_agent | eoc_timer: nil }
504+ end
505+
480506 def handle_eoc_timeout ( % { eoc: true } = ice_agent ) do
481507 Logger . debug ( "EOC timer fired but EOC flag is already set. Ignoring." )
482508 % { ice_agent | eoc_timer: nil }
@@ -564,8 +590,16 @@ defmodule ExICE.Priv.ICEAgent do
564590 { :ok , _pair } ->
565591 ice_agent
566592
593+ :error when ice_agent . state in [ :failed , :completed ] ->
594+ Logger . warning ( """
595+ Received keepalive request for non-existant candidate pair but we are in state: #{ ice_agent . state } . \
596+ Ignoring.\
597+ """ )
598+
599+ ice_agent
600+
567601 :error ->
568- Logger . warning ( "Received keepalive request for non-existant candidate pair" )
602+ Logger . warning ( "Received keepalive request for non-existant candidate pair. Ignoring. " )
569603 ice_agent
570604 end
571605 end
@@ -588,19 +622,58 @@ defmodule ExICE.Priv.ICEAgent do
588622 handle_turn_gathering_transaction_response ( ice_agent , turn_tr_id , turn_tr , packet )
589623
590624 from_turn? ( ice_agent , src_ip , src_port ) ->
591- handle_turn_message ( ice_agent , socket , src_ip , src_port , packet )
625+ local_cands = Map . values ( ice_agent . local_cands )
626+
627+ case find_relay_cand_by_socket ( local_cands , socket ) do
628+ nil ->
629+ Logger . debug ( """
630+ Couldn't find relay candidate for:
631+ socket: #{ inspect ( socket ) }
632+ src address: #{ inspect ( { src_ip , src_port } ) } .
633+ Ignoring incoming TURN message.
634+ """ )
635+
636+ ice_agent
637+
638+ relay_cand ->
639+ handle_turn_message ( ice_agent , relay_cand , src_ip , src_port , packet )
640+ end
592641
593642 ExSTUN . stun? ( packet ) ->
594- handle_stun_message ( ice_agent , socket , src_ip , src_port , packet )
643+ local_cands = Map . values ( ice_agent . local_cands )
644+
645+ case find_host_cand ( local_cands , socket ) do
646+ nil ->
647+ Logger . debug ( """
648+ Couldn't find host candidate for #{ inspect ( src_ip ) } :#{ src_port } . \
649+ Ignoring incoming STUN message.\
650+ """ )
651+
652+ ice_agent
653+
654+ host_cand ->
655+ handle_stun_message ( ice_agent , host_cand , src_ip , src_port , packet )
656+ end
595657
596658 true ->
597- local_cand = find_host_cand ( Map . values ( ice_agent . local_cands ) , socket )
598- remote_cand = find_remote_cand ( Map . values ( ice_agent . remote_cands ) , src_ip , src_port )
659+ with remote_cands <- Map . values ( ice_agent . remote_cands ) ,
660+ % _ { } = local_cand <- find_host_cand ( Map . values ( ice_agent . local_cands ) , socket ) ,
661+ % _ { } = remote_cand <- find_remote_cand ( remote_cands , src_ip , src_port ) do
662+ % CandidatePair { } =
663+ pair = Checklist . find_pair ( ice_agent . checklist , local_cand . base . id , remote_cand . id )
599664
600- % CandidatePair { } =
601- pair = Checklist . find_pair ( ice_agent . checklist , local_cand . base . id , remote_cand . id )
665+ handle_data_message ( ice_agent , pair , packet )
666+ else
667+ _ ->
668+ Logger . debug ( """
669+ Couldn't find host or remote candidate for:
670+ socket: #{ inspect ( socket ) }
671+ src address: #{ inspect ( { src_ip , src_port } ) } .
672+ Ignoring incoming data message.
673+ """ )
602674
603- handle_data_message ( ice_agent , pair , packet )
675+ ice_agent
676+ end
604677 end
605678 end
606679
@@ -900,9 +973,7 @@ defmodule ExICE.Priv.ICEAgent do
900973 end
901974 end
902975
903- defp handle_turn_message ( ice_agent , socket , src_ip , src_port , packet ) do
904- % cand_mod { } = cand = find_relay_cand_by_socket ( Map . values ( ice_agent . local_cands ) , socket )
905-
976+ defp handle_turn_message ( ice_agent , % cand_mod { } = cand , src_ip , src_port , packet ) do
906977 case cand_mod . receive_data ( cand , src_ip , src_port , packet ) do
907978 { :ok , cand } ->
908979 put_in ( ice_agent . local_cands [ cand . base . id ] , cand )
@@ -935,23 +1006,10 @@ defmodule ExICE.Priv.ICEAgent do
9351006 end
9361007 end
9371008
938- defp handle_stun_message ( ice_agent , socket , src_ip , src_port , packet ) do
1009+ defp handle_stun_message ( ice_agent , host_cand , src_ip , src_port , packet ) do
9391010 case ExSTUN.Message . decode ( packet ) do
9401011 { :ok , msg } ->
941- local_cands = Map . values ( ice_agent . local_cands )
942-
943- case find_host_cand ( local_cands , socket ) do
944- nil ->
945- Logger . debug ( """
946- Couldn't find host candidate for #{ inspect ( src_ip ) } :#{ src_port } . \
947- Ignoring incoming STUN message.\
948- """ )
949-
950- ice_agent
951-
952- local_cand ->
953- do_handle_stun_message ( ice_agent , local_cand , src_ip , src_port , msg )
954- end
1012+ do_handle_stun_message ( ice_agent , host_cand , src_ip , src_port , msg )
9551013
9561014 { :error , reason } ->
9571015 Logger . warning ( "Couldn't decode stun message: #{ inspect ( reason ) } " )
@@ -1787,14 +1845,10 @@ defmodule ExICE.Priv.ICEAgent do
17871845 end
17881846
17891847 defp do_restart ( ice_agent ) do
1790- ice_agent . local_cands
1791- |> Enum . uniq_by ( fn { _id , cand } -> cand . base . socket end )
1792- |> Enum . each ( fn { _id , cand } ->
1793- Logger . debug ( """
1794- Closing local candidate's socket: #{ inspect ( cand . base . base_address ) } :#{ cand . base . base_port } .
1795- """ )
1796-
1797- :ok = ice_agent . transport_module . close ( cand . base . socket )
1848+ Enum . each ( ice_agent . sockets , fn socket ->
1849+ { :ok , { ip , port } } = ice_agent . transport_module . sockname ( socket )
1850+ Logger . debug ( "Closing socket: #{ inspect ( ip ) } :#{ port } ." )
1851+ :ok = ice_agent . transport_module . close ( socket )
17981852 end )
17991853
18001854 { ufrag , pwd } = generate_credentials ( )
@@ -1816,7 +1870,8 @@ defmodule ExICE.Priv.ICEAgent do
18161870
18171871 % __MODULE__ {
18181872 ice_agent
1819- | gathering_transactions: % { } ,
1873+ | sockets: [ ] ,
1874+ gathering_transactions: % { } ,
18201875 selected_pair_id: nil ,
18211876 conn_checks: % { } ,
18221877 checklist: % { } ,
@@ -1957,7 +2012,88 @@ defmodule ExICE.Priv.ICEAgent do
19572012
19582013 @ doc false
19592014 @ spec change_connection_state ( t ( ) , atom ( ) ) :: t ( )
2015+ def change_connection_state ( ice_agent , :failed ) do
2016+ Enum . each ( ice_agent . sockets , fn socket ->
2017+ :ok = ice_agent . transport_module . close ( socket )
2018+ end )
2019+
2020+ % {
2021+ ice_agent
2022+ | sockets: [ ] ,
2023+ gathering_transactions: % { } ,
2024+ selected_pair_id: nil ,
2025+ conn_checks: % { } ,
2026+ checklist: % { } ,
2027+ local_cands: % { } ,
2028+ remote_cands: % { } ,
2029+ local_ufrag: nil ,
2030+ local_pwd: nil ,
2031+ remote_ufrag: nil ,
2032+ remote_pwd: nil ,
2033+ eoc: false ,
2034+ nominating?: { false , nil }
2035+ }
2036+ |> disable_timer ( )
2037+ |> do_change_connection_state ( :failed )
2038+ end
2039+
2040+ def change_connection_state ( ice_agent , :completed ) do
2041+ selected_pair = Map . fetch! ( ice_agent . checklist , ice_agent . selected_pair_id )
2042+ succeeded_pair = Map . fetch! ( ice_agent . checklist , selected_pair . succeeded_pair_id )
2043+
2044+ if selected_pair . id != selected_pair . discovered_pair_id do
2045+ raise """
2046+ Selected pair isn't also discovered pair. This should never happen.
2047+ Selected pair: #{ inspect ( selected_pair ) } \
2048+ """
2049+ end
2050+
2051+ local_cand = Map . fetch! ( ice_agent . local_cands , succeeded_pair . local_cand_id )
2052+
2053+ Enum . each ( ice_agent . sockets , fn socket ->
2054+ unless socket == local_cand . base . socket do
2055+ :ok = ice_agent . transport_module . close ( socket )
2056+ end
2057+ end )
2058+
2059+ # We need to use Map.filter as selected_pair might not
2060+ # be the same as succeeded pair
2061+ local_cands =
2062+ Map . filter (
2063+ ice_agent . local_cands ,
2064+ fn { cand_id , _cand } ->
2065+ cand_id in [ selected_pair . local_cand_id , succeeded_pair . local_cand_id ]
2066+ end
2067+ )
2068+
2069+ remote_cands =
2070+ Map . filter (
2071+ ice_agent . remote_cands ,
2072+ fn { cand_id , _cand } ->
2073+ cand_id in [ selected_pair . remote_cand_id , succeeded_pair . remote_cand_id ]
2074+ end
2075+ )
2076+
2077+ checklist =
2078+ Map . filter ( ice_agent . checklist , fn { pair_id , _pair } ->
2079+ pair_id in [ selected_pair . id , succeeded_pair . id ]
2080+ end )
2081+
2082+ % {
2083+ ice_agent
2084+ | sockets: [ local_cand . base . socket ] ,
2085+ local_cands: local_cands ,
2086+ remote_cands: remote_cands ,
2087+ checklist: checklist
2088+ }
2089+ |> do_change_connection_state ( :completed )
2090+ end
2091+
19602092 def change_connection_state ( ice_agent , new_conn_state ) do
2093+ do_change_connection_state ( ice_agent , new_conn_state )
2094+ end
2095+
2096+ defp do_change_connection_state ( ice_agent , new_conn_state ) do
19612097 Logger . debug ( "Connection state change: #{ ice_agent . state } -> #{ new_conn_state } " )
19622098 notify ( ice_agent . on_connection_state_change , { :connection_state_change , new_conn_state } )
19632099 % __MODULE__ { ice_agent | state: new_conn_state }
@@ -2135,6 +2271,8 @@ defmodule ExICE.Priv.ICEAgent do
21352271 % { ice_agent | ta_timer: timer }
21362272 end
21372273
2274+ defp disable_timer ( % { ta_timer: nil } = ice_agent ) , do: ice_agent
2275+
21382276 defp disable_timer ( ice_agent ) do
21392277 Process . cancel_timer ( ice_agent . ta_timer )
21402278
0 commit comments