@@ -673,24 +673,24 @@ defmodule ExICE.Priv.ICEAgent do
673
673
end
674
674
end
675
675
676
- @ spec handle_keepalive ( t ( ) , integer ( ) ) :: t ( )
677
- def handle_keepalive ( % __MODULE__ { selected_pair_id: id } = ice_agent , id ) do
676
+ @ spec handle_keepalive_timeout ( t ( ) , integer ( ) ) :: t ( )
677
+ def handle_keepalive_timeout ( % __MODULE__ { selected_pair_id: id } = ice_agent , id ) do
678
678
# if pair was selected, send keepalives only on that pair
679
679
s_pair = Map . fetch! ( ice_agent . checklist , id )
680
680
pair = CandidatePair . schedule_keepalive ( s_pair )
681
681
ice_agent = % __MODULE__ { ice_agent | checklist: Map . put ( ice_agent . checklist , id , pair ) }
682
682
send_keepalive ( ice_agent , ice_agent . checklist [ id ] )
683
683
end
684
684
685
- def handle_keepalive ( % __MODULE__ { selected_pair_id: s_pair_id } = ice_agent , _id )
685
+ def handle_keepalive_timeout ( % __MODULE__ { selected_pair_id: s_pair_id } = ice_agent , _id )
686
686
when not is_nil ( s_pair_id ) do
687
687
# note: current implementation assumes that, if selected pair exists, none of the already existing
688
688
# valid pairs will ever become selected (only new appearing valid pairs)
689
689
# that's why there's no call to `CandidatePair.schedule_keepalive/1`
690
690
ice_agent
691
691
end
692
692
693
- def handle_keepalive ( ice_agent , id ) do
693
+ def handle_keepalive_timeout ( ice_agent , id ) do
694
694
# TODO: keepalives should be sent only if no data has been sent for @tr_timeout
695
695
# atm, we send keepalives anyways, also it might be better to pace them with ta_timer
696
696
# TODO: candidates not in a valid pair also should be kept alive (RFC 8445, sect 5.1.1.4)
@@ -1246,16 +1246,7 @@ defmodule ExICE.Priv.ICEAgent do
1246
1246
% Type { class: class , method: :binding }
1247
1247
when is_response ( class ) and is_map_key ( ice_agent . keepalives , msg . transaction_id ) ->
1248
1248
# TODO: this a good basis to implement consent freshness
1249
- Logger . debug ( """
1250
- Received keepalive response from from #{ inspect ( { src_ip , src_port } ) } , \
1251
- on: #{ inspect ( { local_cand . base . base_address , local_cand . base . base_port } ) } \
1252
- """ )
1253
-
1254
- { pair_id , ice_agent } = pop_in ( ice_agent . keepalives [ msg . transaction_id ] )
1255
-
1256
- pair = Map . fetch! ( ice_agent . checklist , pair_id )
1257
- pair = % CandidatePair { pair | last_seen: now ( ) }
1258
- put_in ( ice_agent . checklist [ pair . id ] , pair )
1249
+ handle_keepalive_response ( ice_agent , local_cand , src_ip , src_port , msg )
1259
1250
1260
1251
% Type { class: class , method: :binding } when is_response ( class ) ->
1261
1252
Logger . warning ( """
@@ -1475,7 +1466,6 @@ defmodule ExICE.Priv.ICEAgent do
1475
1466
end
1476
1467
1477
1468
## BINDING RESPONSE HANDLING ##
1478
-
1479
1469
defp handle_conn_check_response ( ice_agent , local_cand , src_ip , src_port , msg ) do
1480
1470
{ % { pair_id: pair_id } , conn_checks } = Map . pop! ( ice_agent . conn_checks , msg . transaction_id )
1481
1471
ice_agent = % __MODULE__ { ice_agent | conn_checks: conn_checks }
@@ -1492,7 +1482,7 @@ defmodule ExICE.Priv.ICEAgent do
1492
1482
cc_local_cand = Map . fetch! ( ice_agent . local_cands , conn_check_pair . local_cand_id )
1493
1483
cc_remote_cand = Map . fetch! ( ice_agent . remote_cands , conn_check_pair . remote_cand_id )
1494
1484
1495
- Logger . warning ( """
1485
+ Logger . debug ( """
1496
1486
Ignoring conn check response, non-symmetric src and dst addresses.
1497
1487
Sent from: #{ inspect ( { cc_local_cand . base . base_address , cc_local_cand . base . base_port } ) } , \
1498
1488
to: #{ inspect ( { cc_remote_cand . address , cc_remote_cand . port } ) }
@@ -1647,6 +1637,66 @@ defmodule ExICE.Priv.ICEAgent do
1647
1637
ice_agent
1648
1638
end
1649
1639
1640
+ defp handle_keepalive_response (
1641
+ ice_agent ,
1642
+ local_cand ,
1643
+ src_ip ,
1644
+ src_port ,
1645
+ % Message { type: % Type { class: :success_response } } = msg
1646
+ ) do
1647
+ { pair_id , ice_agent } = pop_in ( ice_agent . keepalives [ msg . transaction_id ] )
1648
+ pair = Map . fetch! ( ice_agent . checklist , pair_id )
1649
+
1650
+ with true <- symmetric? ( ice_agent , local_cand . base . socket , { src_ip , src_port } , pair ) ,
1651
+ :ok <- authenticate_msg ( msg , ice_agent . remote_pwd ) do
1652
+ Logger . debug ( "Received keepalive success response on: #{ pair_info ( ice_agent , pair ) } " )
1653
+ pair = % CandidatePair { pair | last_seen: now ( ) }
1654
+ put_in ( ice_agent . checklist [ pair . id ] , pair )
1655
+ else
1656
+ false ->
1657
+ ka_local_cand = Map . fetch! ( ice_agent . local_cands , pair . local_cand_id )
1658
+ ka_remote_cand = Map . fetch! ( ice_agent . remote_cands , pair . remote_cand_id )
1659
+
1660
+ Logger . debug ( """
1661
+ Ignoring keepalive success response, non-symmetric src and dst addresses.
1662
+ Sent from: #{ inspect ( { ka_local_cand . base . base_address , ka_local_cand . base . base_port } ) } , \
1663
+ to: #{ inspect ( { ka_remote_cand . address , ka_remote_cand . port } ) }
1664
+ Recv from: #{ inspect ( { src_ip , src_port } ) } , on: #{ inspect ( { local_cand . base . base_address , local_cand . base . base_port } ) } \
1665
+ Not refreshing last_seen time. \
1666
+ """ )
1667
+
1668
+ ice_agent
1669
+
1670
+ { :error , reason } ->
1671
+ Logger . debug ( """
1672
+ Couldn't authenticate keepalive success response, reason: #{ reason } . \
1673
+ Not refreshing last_seen time.\
1674
+ """ )
1675
+
1676
+ ice_agent
1677
+ end
1678
+ end
1679
+
1680
+ defp handle_keepalive_response (
1681
+ ice_agent ,
1682
+ local_cand ,
1683
+ src_ip ,
1684
+ src_port ,
1685
+ % Message { type: % Type { class: :error_response } } = msg
1686
+ ) do
1687
+ { pair_id , ice_agent } = pop_in ( ice_agent . keepalives [ msg . transaction_id ] )
1688
+ pair = Map . fetch! ( ice_agent . checklist , pair_id )
1689
+
1690
+ Logger . debug ( """
1691
+ Received keepalive error response from #{ inspect ( { src_ip , src_port } ) } , \
1692
+ on: #{ inspect ( { local_cand . base . base_address , local_cand . base . base_port } ) } . \
1693
+ pair: #{ pair_info ( ice_agent , pair ) } \
1694
+ Not refreshing last_seen time. \
1695
+ """ )
1696
+
1697
+ ice_agent
1698
+ end
1699
+
1650
1700
# Adds valid pair according to sec 7.2.5.3.2
1651
1701
# TODO sec. 7.2.5.3.3
1652
1702
# The agent MUST set the states for all other Frozen candidate pairs in
@@ -2090,8 +2140,19 @@ defmodule ExICE.Priv.ICEAgent do
2090
2140
{ ufrag , pwd }
2091
2141
end
2092
2142
2093
- defp authenticate_msg ( msg , local_pwd ) do
2094
- with :ok <- Message . authenticate ( msg , local_pwd ) ,
2143
+ defp pair_info ( ice_agent , pair ) do
2144
+ local_cand = Map . fetch! ( ice_agent . local_cands , pair . local_cand_id )
2145
+ remote_cand = Map . fetch! ( ice_agent . remote_cands , pair . remote_cand_id )
2146
+
2147
+ """
2148
+ #{ pair . id } \
2149
+ l: #{ :inet . ntoa ( local_cand . base . address ) } :#{ local_cand . base . port } \
2150
+ r: #{ :inet . ntoa ( remote_cand . address ) } :#{ remote_cand . port } \
2151
+ """
2152
+ end
2153
+
2154
+ defp authenticate_msg ( msg , pwd ) do
2155
+ with :ok <- Message . authenticate ( msg , pwd ) ,
2095
2156
:ok <- Message . check_fingerprint ( msg ) do
2096
2157
:ok
2097
2158
else
@@ -2402,17 +2463,11 @@ defmodule ExICE.Priv.ICEAgent do
2402
2463
end
2403
2464
2404
2465
defp send_keepalive ( ice_agent , pair ) do
2405
- Logger . debug ( "Sending keepalive" )
2466
+ Logger . debug ( "Sending keepalive on #{ pair_info ( ice_agent , pair ) } " )
2406
2467
local_cand = Map . fetch! ( ice_agent . local_cands , pair . local_cand_id )
2407
2468
remote_cand = Map . fetch! ( ice_agent . remote_cands , pair . remote_cand_id )
2408
2469
2409
- type = % Type { class: :request , method: :binding }
2410
-
2411
- req =
2412
- type
2413
- |> Message . new ( )
2414
- |> Message . with_integrity ( ice_agent . remote_pwd )
2415
- |> Message . with_fingerprint ( )
2470
+ req = binding_request ( ice_agent , false )
2416
2471
2417
2472
dst = { remote_cand . address , remote_cand . port }
2418
2473
@@ -2430,39 +2485,10 @@ defmodule ExICE.Priv.ICEAgent do
2430
2485
local_cand = Map . fetch! ( ice_agent . local_cands , pair . local_cand_id )
2431
2486
remote_cand = Map . fetch! ( ice_agent . remote_cands , pair . remote_cand_id )
2432
2487
2433
- type = % Type { class: :request , method: :binding }
2434
-
2435
- role_attr =
2436
- if ice_agent . role == :controlling do
2437
- % ICEControlling { tiebreaker: ice_agent . tiebreaker }
2438
- else
2439
- % ICEControlled { tiebreaker: ice_agent . tiebreaker }
2440
- end
2441
-
2442
- # priority sent to the other side has to be
2443
- # computed with the candidate type preference of
2444
- # peer-reflexive; refer to sec 7.1.1
2445
- priority = Candidate . priority ( :prflx )
2446
-
2447
- attrs = [
2448
- % Username { value: "#{ ice_agent . remote_ufrag } :#{ ice_agent . local_ufrag } " } ,
2449
- % Priority { priority: priority } ,
2450
- role_attr
2451
- ]
2452
-
2453
2488
# we can nominate only when being the controlling agent
2454
2489
# the controlled agent uses nominate? flag according to 7.3.1.5
2455
- attrs =
2456
- if pair . nominate? and ice_agent . role == :controlling do
2457
- attrs ++ [ % UseCandidate { } ]
2458
- else
2459
- attrs
2460
- end
2461
-
2462
- req =
2463
- Message . new ( type , attrs )
2464
- |> Message . with_integrity ( ice_agent . remote_pwd )
2465
- |> Message . with_fingerprint ( )
2490
+ nominate = pair . nominate? and ice_agent . role == :controlling
2491
+ req = binding_request ( ice_agent , nominate )
2466
2492
2467
2493
raw_req = Message . encode ( req )
2468
2494
@@ -2489,6 +2515,34 @@ defmodule ExICE.Priv.ICEAgent do
2489
2515
end
2490
2516
end
2491
2517
2518
+ defp binding_request ( ice_agent , nominate ) do
2519
+ type = % Type { class: :request , method: :binding }
2520
+
2521
+ role_attr =
2522
+ if ice_agent . role == :controlling do
2523
+ % ICEControlling { tiebreaker: ice_agent . tiebreaker }
2524
+ else
2525
+ % ICEControlled { tiebreaker: ice_agent . tiebreaker }
2526
+ end
2527
+
2528
+ # priority sent to the other side has to be
2529
+ # computed with the candidate type preference of
2530
+ # peer-reflexive; refer to sec 7.1.1
2531
+ priority = Candidate . priority ( :prflx )
2532
+
2533
+ attrs = [
2534
+ % Username { value: "#{ ice_agent . remote_ufrag } :#{ ice_agent . local_ufrag } " } ,
2535
+ % Priority { priority: priority } ,
2536
+ role_attr
2537
+ ]
2538
+
2539
+ attrs = if nominate , do: attrs ++ [ % UseCandidate { } ] , else: attrs
2540
+
2541
+ Message . new ( type , attrs )
2542
+ |> Message . with_integrity ( ice_agent . remote_pwd )
2543
+ |> Message . with_fingerprint ( )
2544
+ end
2545
+
2492
2546
defp do_send ( ice_agent , % cand_mod { } = local_cand , dst , data , retry \\ true ) do
2493
2547
{ dst_ip , dst_port } = dst
2494
2548
0 commit comments