Skip to content

Commit cf3b814

Browse files
LValamickel8
andauthored
Use binding requests as keepalives (#51)
--------- Co-authored-by: Michał Śledź <michalsledz34@gmail.com>
1 parent 2c89826 commit cf3b814

File tree

4 files changed

+78
-13
lines changed

4 files changed

+78
-13
lines changed

lib/ex_ice/priv/candidate_pair.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule ExICE.Priv.CandidatePair do
55
alias ExICE.Priv.{Candidate, Utils}
66

77
# Tr timeout (keepalives) in ms
8-
@tr_timeout 15 * 1000
8+
@tr_timeout 5 * 1000
99

1010
@type state() :: :waiting | :in_progress | :succeeded | :failed | :frozen
1111

lib/ex_ice/priv/ice_agent.ex

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule ExICE.Priv.ICEAgent do
3030
# Pair timeout in ms.
3131
# If we don't receive any data in this time,
3232
# a pair is marked as faield.
33-
@pair_timeout 5_000
33+
@pair_timeout 8_000
3434

3535
# End-of-candidates timeout in ms.
3636
# If we don't receive end-of-candidates indication in this time,
@@ -72,6 +72,7 @@ defmodule ExICE.Priv.ICEAgent do
7272
gathering_transactions: %{},
7373
checklist: %{},
7474
conn_checks: %{},
75+
keepalives: %{},
7576
gathering_state: :new,
7677
eoc: false,
7778
# {did we nominate pair, pair id}
@@ -1049,6 +1050,20 @@ defmodule ExICE.Priv.ICEAgent do
10491050

10501051
handle_stun_gathering_transaction_response(ice_agent, msg)
10511052

1053+
%Type{class: class, method: :binding}
1054+
when is_response(class) and is_map_key(ice_agent.keepalives, msg.transaction_id) ->
1055+
# TODO: this a good basis to implement consent freshness
1056+
Logger.debug("""
1057+
Received keepalive response from from #{inspect({src_ip, src_port})}, \
1058+
on: #{inspect({local_cand.base.base_address, local_cand.base.base_port})} \
1059+
""")
1060+
1061+
{pair_id, ice_agent} = pop_in(ice_agent.keepalives, msg.transaction_id)
1062+
1063+
pair = Map.fetch!(ice_agent.checklist, pair_id)
1064+
pair = %CandidatePair{pair | last_seen: now()}
1065+
put_in(ice_agent.checklist[pair.id], pair)
1066+
10521067
%Type{class: class, method: :binding} when is_response(class) ->
10531068
Logger.warning("""
10541069
Ignoring binding response with unknown t_id: #{msg.transaction_id}.
@@ -2156,18 +2171,27 @@ defmodule ExICE.Priv.ICEAgent do
21562171

21572172
defp send_keepalive(ice_agent, pair) do
21582173
Logger.debug("Sending keepalive")
2159-
type = %Type{class: :indication, method: :binding}
21602174
local_cand = Map.fetch!(ice_agent.local_cands, pair.local_cand_id)
21612175
remote_cand = Map.fetch!(ice_agent.remote_cands, pair.remote_cand_id)
21622176

2177+
type = %Type{class: :request, method: :binding}
2178+
21632179
req =
21642180
type
21652181
|> Message.new()
2182+
|> Message.with_integrity(ice_agent.remote_pwd)
21662183
|> Message.with_fingerprint()
21672184

21682185
dst = {remote_cand.address, remote_cand.port}
2169-
{_result, ice_agent} = do_send(ice_agent, local_cand, dst, Message.encode(req))
2170-
ice_agent
2186+
2187+
case do_send(ice_agent, local_cand, dst, Message.encode(req)) do
2188+
{:ok, ice_agent} ->
2189+
keepalives = Map.put(ice_agent.keepalives, req.transaction_id, pair.id)
2190+
%__MODULE__{ice_agent | keepalives: keepalives}
2191+
2192+
{:error, ice_agent} ->
2193+
ice_agent
2194+
end
21712195
end
21722196

21732197
defp send_conn_check(ice_agent, pair) do

mix.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
%{
22
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
3-
"credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [: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", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"},
3+
"credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [: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", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
44
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
5-
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
5+
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
66
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"},
7-
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
8-
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
7+
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
8+
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [: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", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
99
"ex_stun": {:hex, :ex_stun, "0.2.0", "feb1fc7db0356406655b2a617805e6c712b93308c8ea2bf0ba1197b1f0866deb", [:mix], [], "hexpm", "1e01ba8290082ccbf37acaa5190d1f69b51edd6de2026a8d6d51368b29d115d0"},
1010
"ex_turn": {:hex, :ex_turn, "0.1.0", "177405aadf3d754567d0d37cf881a83f9cacf8f45314d188633b04c4a9e7c1ec", [:mix], [{:ex_stun, "~> 0.2.0", [hex: :ex_stun, repo: "hexpm", optional: false]}], "hexpm", "d677737fb7d45274d5dac19fe3c26b9038b6effbc0a6b3e7417bccc76b6d1cd3"},
1111
"excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"},
1212
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
13-
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
14-
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
13+
"jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"},
14+
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
1515
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [: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", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
16-
"makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"},
16+
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
1717
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
1818
}

test/priv/ice_agent_test.exs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,47 @@ defmodule ExICE.Priv.ICEAgentTest do
114114
end
115115
end
116116

117+
describe "sends keepalives" do
118+
setup do
119+
remote_cand = ExICE.Candidate.new(:host, address: {192, 168, 0, 2}, port: 8445)
120+
121+
ice_agent =
122+
ICEAgent.new(
123+
controlling_process: self(),
124+
role: :controlling,
125+
if_discovery_module: IfDiscovery.Mock,
126+
transport_module: Transport.Mock
127+
)
128+
|> ICEAgent.set_remote_credentials("someufrag", "somepwd")
129+
|> ICEAgent.gather_candidates()
130+
|> ICEAgent.add_remote_candidate(remote_cand)
131+
132+
%{ice_agent: ice_agent}
133+
end
134+
135+
test "on connected pair", %{ice_agent: ice_agent} do
136+
ice_agent = connect(ice_agent)
137+
138+
[socket] = ice_agent.sockets
139+
[pair] = Map.values(ice_agent.checklist)
140+
ice_agent = ICEAgent.handle_keepalive(ice_agent, pair.id)
141+
142+
assert packet = Transport.Mock.recv(socket)
143+
assert {:ok, msg} = ExSTUN.Message.decode(packet)
144+
assert msg.type == %ExSTUN.Message.Type{class: :request, method: :binding}
145+
assert :ok == ExSTUN.Message.check_fingerprint(msg)
146+
assert :ok == ExSTUN.Message.authenticate(msg, ice_agent.remote_pwd)
147+
end
148+
149+
test "on unconnected pair", %{ice_agent: ice_agent} do
150+
[socket] = ice_agent.sockets
151+
[pair] = Map.values(ice_agent.checklist)
152+
ICEAgent.handle_keepalive(ice_agent, pair.id)
153+
154+
assert nil == Transport.Mock.recv(socket)
155+
end
156+
end
157+
117158
describe "incoming binding request" do
118159
setup do
119160
ice_agent =
@@ -714,7 +755,7 @@ defmodule ExICE.Priv.ICEAgentTest do
714755

715756
# mock last_seen field
716757
[pair] = Map.values(ice_agent.checklist)
717-
last_seen = System.monotonic_time(:millisecond) - 5_000
758+
last_seen = System.monotonic_time(:millisecond) - 10_000
718759
pair = %{pair | last_seen: last_seen}
719760
ice_agent = put_in(ice_agent.checklist[pair.id], pair)
720761

0 commit comments

Comments
 (0)