@@ -240,6 +240,11 @@ defmodule ExICE.Priv.ICEAgent do
240
240
end
241
241
242
242
@ spec set_role ( t ( ) , ExICE.ICEAgent . role ( ) ) :: t ( )
243
+ def set_role ( % __MODULE__ { state: :closed } = ice_agent , _ ) do
244
+ Logger . debug ( "Tried to set role in closed state. Ignoring." )
245
+ ice_agent
246
+ end
247
+
243
248
def set_role ( % __MODULE__ { role: nil } = ice_agent , role ) do
244
249
% __MODULE__ { ice_agent | role: role }
245
250
end
@@ -250,8 +255,9 @@ defmodule ExICE.Priv.ICEAgent do
250
255
end
251
256
252
257
@ 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." )
258
+ def set_remote_credentials ( % __MODULE__ { state: state } = ice_agent , _ , _ )
259
+ when state in [ :failed , :closed ] do
260
+ Logger . debug ( "Tried to set remote credentials in state #{ state } . Ignoring." )
255
261
ice_agent
256
262
end
257
263
@@ -286,8 +292,8 @@ defmodule ExICE.Priv.ICEAgent do
286
292
end
287
293
288
294
@ 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." )
295
+ def gather_candidates ( % __MODULE__ { state: state } = ice_agent ) when state in [ :failed , :closed ] do
296
+ Logger . warning ( "Can't gather candidates in state #{ state } . Ignoring." )
291
297
ice_agent
292
298
end
293
299
@@ -364,9 +370,10 @@ defmodule ExICE.Priv.ICEAgent do
364
370
end
365
371
366
372
@ spec add_remote_candidate ( t ( ) , Candidate . t ( ) ) :: t ( )
367
- def add_remote_candidate ( % __MODULE__ { state: :failed } = ice_agent , _ ) do
373
+ def add_remote_candidate ( % __MODULE__ { state: state } = ice_agent , _ )
374
+ when state in [ :failed , :closed ] do
368
375
# Completed state will be caught by the next clause
369
- Logger . debug ( "Can't add remote candidate in state failed. ICE restart needed . Ignoring." )
376
+ Logger . debug ( "Can't add remote candidate in state #{ state } . Ignoring." )
370
377
ice_agent
371
378
end
372
379
@@ -455,8 +462,8 @@ defmodule ExICE.Priv.ICEAgent do
455
462
end
456
463
457
464
@ spec end_of_candidates ( t ( ) ) :: t ( )
458
- def end_of_candidates ( % __MODULE__ { state: :failed } = ice_agent ) do
459
- Logger . debug ( "Can't set end-of-candidates flag in state failed . Ignoring." )
465
+ def end_of_candidates ( % __MODULE__ { state: state } = ice_agent ) when state in [ :failed , :closed ] do
466
+ Logger . debug ( "Can't set end-of-candidates flag in state #{ state } . Ignoring." )
460
467
ice_agent
461
468
end
462
469
@@ -537,12 +544,22 @@ defmodule ExICE.Priv.ICEAgent do
537
544
end
538
545
539
546
@ spec restart ( t ( ) ) :: t ( )
547
+ def restart ( % __MODULE__ { state: :closed } = ice_agent ) do
548
+ Logger . debug ( "Can't restart ICE in state closed. Ignoring." )
549
+ ice_agent
550
+ end
551
+
540
552
def restart ( ice_agent ) do
541
553
Logger . debug ( "Restarting ICE" )
542
554
do_restart ( ice_agent )
543
555
end
544
556
545
557
@ spec handle_ta_timeout ( t ( ) ) :: t ( )
558
+ def handle_ta_timeout ( % __MODULE__ { state: :closed } = ice_agent ) do
559
+ Logger . debug ( "Ta timer fired in closed state. Ignoring." )
560
+ ice_agent
561
+ end
562
+
546
563
def handle_ta_timeout ( % __MODULE__ { state: state } = ice_agent )
547
564
when state in [ :completed , :failed ] do
548
565
Logger . warning ( """
@@ -694,6 +711,11 @@ defmodule ExICE.Priv.ICEAgent do
694
711
end
695
712
696
713
@ spec handle_tr_rtx_timeout ( t ( ) , integer ( ) ) :: t ( )
714
+ def handle_tr_rtx_timeout ( % __MODULE__ { state: :closed } = ice_agent , _ ) do
715
+ Logger . debug ( "Transaction rtx timer fired in state closed. Ignoring." )
716
+ ice_agent
717
+ end
718
+
697
719
def handle_tr_rtx_timeout ( ice_agent , t_id ) when is_map_key ( ice_agent . conn_checks , t_id ) do
698
720
# Mark transaction id as ready to be retransmitted.
699
721
# We will do this in handle_ta_timeout as it has to be paced.
@@ -725,8 +747,9 @@ defmodule ExICE.Priv.ICEAgent do
725
747
end
726
748
727
749
@ 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." )
750
+ def handle_eoc_timeout ( % __MODULE__ { state: state } = ice_agent )
751
+ when state in [ :failed , :closed ] do
752
+ Logger . debug ( "EOC timer fired but we are in the #{ state } state. Ignoring." )
730
753
% { ice_agent | eoc_timer: nil }
731
754
end
732
755
@@ -742,6 +765,11 @@ defmodule ExICE.Priv.ICEAgent do
742
765
end
743
766
744
767
@ spec handle_pair_timeout ( t ( ) ) :: t ( )
768
+ def handle_pair_timeout ( % __MODULE__ { state: :closed } = ice_agent ) do
769
+ Logger . debug ( "Pair timer fired in closed state. Ignoring." )
770
+ ice_agent
771
+ end
772
+
745
773
def handle_pair_timeout ( ice_agent ) do
746
774
start_pair_timer ( )
747
775
@@ -792,6 +820,11 @@ defmodule ExICE.Priv.ICEAgent do
792
820
end
793
821
794
822
@ spec handle_keepalive_timeout ( t ( ) , integer ( ) ) :: t ( )
823
+ def handle_keepalive_timeout ( % __MODULE__ { state: :closed } = ice_agent , _ ) do
824
+ Logger . debug ( "Keepalive timer fired in closed state. Ignoring." )
825
+ ice_agent
826
+ end
827
+
795
828
def handle_keepalive_timeout ( % __MODULE__ { selected_pair_id: id } = ice_agent , id ) do
796
829
# if pair was selected, send keepalives only on that pair
797
830
s_pair = Map . fetch! ( ice_agent . checklist , id )
@@ -842,7 +875,8 @@ defmodule ExICE.Priv.ICEAgent do
842
875
:inet . port_number ( ) ,
843
876
binary ( )
844
877
) :: t ( )
845
- def handle_udp ( % { state: :failed } = ice_agent , _socket , _src_ip , _src_port , _packet ) do
878
+ def handle_udp ( % { state: state } = ice_agent , _socket , _src_ip , _src_port , _packet )
879
+ when state in [ :failed , :closed ] do
846
880
ice_agent
847
881
end
848
882
@@ -868,6 +902,11 @@ defmodule ExICE.Priv.ICEAgent do
868
902
end
869
903
870
904
@ spec handle_ex_turn_msg ( t ( ) , reference ( ) , ExTURN.Client . notification_message ( ) ) :: t ( )
905
+ def handle_ex_turn_msg ( % __MODULE__ { state: :closed } = ice_agent , _ , _ ) do
906
+ Logger . debug ( "Received ex_turn message in closed state. Ignoring." )
907
+ ice_agent
908
+ end
909
+
871
910
def handle_ex_turn_msg ( ice_agent , client_ref , msg ) do
872
911
tr_id_tr = find_gathering_transaction ( ice_agent . gathering_transactions , client_ref )
873
912
@@ -919,6 +958,18 @@ defmodule ExICE.Priv.ICEAgent do
919
958
end
920
959
end
921
960
961
+ @ spec close ( t ( ) ) :: t ( )
962
+ def close ( % __MODULE__ { state: :closed } = ice_agent ) do
963
+ ice_agent
964
+ end
965
+
966
+ def close ( % __MODULE__ { } = ice_agent ) do
967
+ ice_agent . sockets
968
+ |> Enum . reduce ( ice_agent , fn socket , ice_agent -> close_socket ( ice_agent , socket ) end )
969
+ |> change_gathering_state ( :complete , notify: false )
970
+ |> change_connection_state ( :closed , notify: false )
971
+ end
972
+
922
973
## PRIV API
923
974
924
975
defp create_srflx_gathering_transactions ( stun_servers , sockets ) do
@@ -2290,6 +2341,17 @@ defmodule ExICE.Priv.ICEAgent do
2290
2341
end
2291
2342
2292
2343
defp close_socket ( ice_agent , socket ) do
2344
+ # Use sockname/1 to determine if a socket is still open.
2345
+ # Alternatively, we could create a callback for `:inet.info/1`,
2346
+ # but it's return type is not standardized - sometimes it's %{states: [:closed]},
2347
+ # some other time %{rstates: [:closed], wstates: [:closed]}.
2348
+ case ice_agent . transport_module . sockname ( socket ) do
2349
+ { :error , :closed } -> ice_agent
2350
+ _ -> do_close_socket ( ice_agent , socket )
2351
+ end
2352
+ end
2353
+
2354
+ defp do_close_socket ( ice_agent , socket ) do
2293
2355
Logger . debug ( "Closing socket: #{ inspect ( socket ) } " )
2294
2356
2295
2357
ice_agent =
@@ -2308,9 +2370,21 @@ defmodule ExICE.Priv.ICEAgent do
2308
2370
2309
2371
tr_rtx = ice_agent . tr_rtx -- Map . keys ( removed_gathering_transactions )
2310
2372
2373
+ :ok = ice_agent . transport_module . close ( socket )
2374
+ :ok = flush_socket_msg ( socket )
2375
+
2311
2376
% { ice_agent | tr_rtx: tr_rtx , gathering_transactions: gathering_transactions }
2312
2377
end
2313
2378
2379
+ defp flush_socket_msg ( socket ) do
2380
+ receive do
2381
+ { :udp , ^ socket , _src_ip , _src_port , _packet } ->
2382
+ flush_socket_msg ( socket )
2383
+ after
2384
+ 0 -> :ok
2385
+ end
2386
+ end
2387
+
2314
2388
defp maybe_nominate ( ice_agent ) do
2315
2389
if time_to_nominate? ( ice_agent ) do
2316
2390
Logger . debug ( "Time to nominate a pair! Looking for a best valid pair..." )
@@ -2367,6 +2441,7 @@ defmodule ExICE.Priv.ICEAgent do
2367
2441
# clearing the whole state anyway, we can close the socket manually
2368
2442
Logger . debug ( "Closing socket: #{ inspect ( ip ) } :#{ port } ." )
2369
2443
:ok = ice_agent . transport_module . close ( socket )
2444
+ :ok = flush_socket_msg ( socket )
2370
2445
2371
2446
{ :error , :closed } ->
2372
2447
# socket already closed
@@ -2497,7 +2572,6 @@ defmodule ExICE.Priv.ICEAgent do
2497
2572
end
2498
2573
2499
2574
defp generate_credentials ( ) do
2500
- # TODO am I using Base.encode64 correctly?
2501
2575
ufrag = :crypto . strong_rand_bytes ( 3 ) |> Base . encode64 ( )
2502
2576
pwd = :crypto . strong_rand_bytes ( 16 ) |> Base . encode64 ( )
2503
2577
{ ufrag , pwd }
@@ -2523,9 +2597,13 @@ defmodule ExICE.Priv.ICEAgent do
2523
2597
end
2524
2598
end
2525
2599
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 } )
2600
+ defp change_gathering_state ( ice_agent , new_gathering_state , opts \\ [ ] ) do
2601
+ Logger . debug ( "Gatering state change: #{ ice_agent . gathering_state } -> #{ new_gathering_state } " )
2602
+
2603
+ if opts [ :notify ] != false do
2604
+ notify ( ice_agent . on_gathering_state_change , { :gathering_state_change , new_gathering_state } )
2605
+ end
2606
+
2529
2607
% __MODULE__ { ice_agent | gathering_state: new_gathering_state }
2530
2608
end
2531
2609
@@ -2550,8 +2628,10 @@ defmodule ExICE.Priv.ICEAgent do
2550
2628
end
2551
2629
2552
2630
@ doc false
2553
- @ spec change_connection_state ( t ( ) , atom ( ) ) :: t ( )
2554
- def change_connection_state ( ice_agent , :failed ) do
2631
+ @ spec change_connection_state ( t ( ) , atom ( ) , Keyword . t ( ) ) :: t ( )
2632
+ def change_connection_state ( ice_agent , new_state , opts \\ [ ] )
2633
+
2634
+ def change_connection_state ( ice_agent , :failed , opts ) do
2555
2635
ice_agent =
2556
2636
Enum . reduce ( ice_agent . sockets , ice_agent , fn socket , ice_agent ->
2557
2637
close_socket ( ice_agent , socket )
@@ -2599,10 +2679,10 @@ defmodule ExICE.Priv.ICEAgent do
2599
2679
nominating?: { false , nil }
2600
2680
}
2601
2681
|> disable_timer ( )
2602
- |> do_change_connection_state ( :failed )
2682
+ |> do_change_connection_state ( :failed , opts )
2603
2683
end
2604
2684
2605
- def change_connection_state ( ice_agent , :completed ) do
2685
+ def change_connection_state ( ice_agent , :completed , opts ) do
2606
2686
selected_pair = Map . fetch! ( ice_agent . checklist , ice_agent . selected_pair_id )
2607
2687
succeeded_pair = Map . fetch! ( ice_agent . checklist , selected_pair . succeeded_pair_id )
2608
2688
@@ -2632,16 +2712,20 @@ defmodule ExICE.Priv.ICEAgent do
2632
2712
end
2633
2713
end )
2634
2714
2635
- do_change_connection_state ( ice_agent , :completed )
2715
+ do_change_connection_state ( ice_agent , :completed , opts )
2636
2716
end
2637
2717
2638
- def change_connection_state ( ice_agent , new_conn_state ) do
2639
- do_change_connection_state ( ice_agent , new_conn_state )
2718
+ def change_connection_state ( ice_agent , new_conn_state , opts ) do
2719
+ do_change_connection_state ( ice_agent , new_conn_state , opts )
2640
2720
end
2641
2721
2642
- defp do_change_connection_state ( ice_agent , new_conn_state ) do
2722
+ defp do_change_connection_state ( ice_agent , new_conn_state , opts ) do
2643
2723
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 } )
2724
+
2725
+ if opts [ :notify ] != false do
2726
+ notify ( ice_agent . on_connection_state_change , { :connection_state_change , new_conn_state } )
2727
+ end
2728
+
2645
2729
% __MODULE__ { ice_agent | state: new_conn_state }
2646
2730
end
2647
2731
0 commit comments