Skip to content

Commit

Permalink
Add ICETransport behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
mickel8 committed Nov 27, 2023
1 parent 6154a3b commit 2c6d578
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 20 deletions.
42 changes: 25 additions & 17 deletions lib/ex_webrtc/dtls_transport.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ defmodule ExWebRTC.DTLSTransport do

require Logger

alias ExICE.ICEAgent
alias ExWebRTC.ICETransport
alias ExWebRTC.DefaultICETransport

@type dtls_transport() :: GenServer.server()

Expand All @@ -30,15 +31,21 @@ defmodule ExWebRTC.DTLSTransport do
@type dtls_state() :: :new | :connecting | :connected | :closed | :failed

@doc false
@spec start_link(ExICE.ICEAgent.opts(), GenServer.server()) :: GenServer.on_start()
def start_link(ice_config, ice_module \\ ICEAgent) do
GenServer.start_link(__MODULE__, [ice_config, ice_module, self()])
@spec start_link(ICETransport.t(), ExICE.ICEAgent.opts()) :: GenServer.on_start()
def start_link(ice_transport \\ DefaultICETransport, ice_config) do
behaviour = ice_transport.__info__(:attributes)[:behaviour] || []

unless ICETransport in behaviour do
raise "DTLSTransport requires ice_transport to implement ExWebRTC.ICETransport beahviour."
end

GenServer.start_link(__MODULE__, [ice_transport, ice_config, self()])
end

@doc false
@spec get_ice_agent(dtls_transport()) :: GenServer.server()
def get_ice_agent(dtls_transport) do
GenServer.call(dtls_transport, :get_ice_agent)
@spec get_ice_transport(dtls_transport()) :: GenServer.server()
def get_ice_transport(dtls_transport) do
GenServer.call(dtls_transport, :get_ice_transport)
end

@doc false
Expand All @@ -60,19 +67,20 @@ defmodule ExWebRTC.DTLSTransport do
end

@impl true
def init([ice_config, ice_module, owner]) do
def init([ice_transport, ice_config, owner]) do
# temporary hack to generate certs
dtls = ExDTLS.init(client_mode: true, dtls_srtp: true)
cert = ExDTLS.get_cert(dtls)
pkey = ExDTLS.get_pkey(dtls)
fingerprint = ExDTLS.get_cert_fingerprint(dtls)

{:ok, ice_agent} = ice_module.start_link(:controlled, ice_config)
{:ok, ice_transport_state} = ice_transport.start_link(:controlled, ice_config)
srtp = ExLibSRTP.new()

state = %{
owner: owner,
ice_agent: ice_agent,
ice_transport: ice_transport,
ice_transport_state: ice_transport_state,
ice_state: nil,
buffered_packets: nil,
cert: cert,
Expand All @@ -90,8 +98,8 @@ defmodule ExWebRTC.DTLSTransport do
end

@impl true
def handle_call(:get_ice_agent, _from, state) do
{:reply, state.ice_agent, state}
def handle_call(:get_ice_transport, _from, state) do
{:reply, state.ice_transport_state, state}
end

@impl true
Expand Down Expand Up @@ -143,7 +151,7 @@ defmodule ExWebRTC.DTLSTransport do
) do
case ExDTLS.handle_timeout(state.dtls) do
{:retransmit, packets, timeout} when ice_state in [:connected, :completed] ->
ICEAgent.send_data(state.ice_agent, packets)
state.ice_transport.send_data(state.ice_transport_state, packets)
Process.send_after(self(), :dtls_timeout, timeout)

{:retransmit, ^buffered_packets, timeout} ->
Expand Down Expand Up @@ -181,7 +189,7 @@ defmodule ExWebRTC.DTLSTransport do
defp handle_ice({:data, <<f, _rest::binary>> = data}, state) when f in 20..64 do
case ExDTLS.handle_data(state.dtls, data) do
{:handshake_packets, packets, timeout} when state.ice_state in [:connected, :completed] ->
:ok = ICEAgent.send_data(state.ice_agent, packets)
:ok = state.ice_transport.send_data(state.ice_transport_state, packets)
Process.send_after(self(), :dtls_timeout, timeout)
update_dtls_state(state, :connecting)

Expand All @@ -197,7 +205,7 @@ defmodule ExWebRTC.DTLSTransport do

{:handshake_finished, _, remote_keying_material, profile, packets} ->
Logger.debug("DTLS handshake finished")
ICEAgent.send_data(state.ice_agent, packets)
state.ice_transport.send_data(state.ice_transport_state, packets)
# TODO: validate fingerprint
state = setup_srtp(state, remote_keying_material, profile)
update_dtls_state(state, :connected)
Expand Down Expand Up @@ -241,7 +249,7 @@ defmodule ExWebRTC.DTLSTransport do
if state.mode == :active do
{packets, timeout} = ExDTLS.do_handshake(state.dtls)
Process.send_after(self(), :dtls_timeout, timeout)
:ok = ICEAgent.send_data(state.ice_agent, packets)
:ok = state.ice_transport.send_data(state.ice_transport_state, packets)
update_dtls_state(state, :connecting)
else
state
Expand All @@ -252,7 +260,7 @@ defmodule ExWebRTC.DTLSTransport do
when new_ice_state in [:connected, :completed] do
if state.buffered_packets do
Logger.debug("Sending buffered DTLS packets")
:ok = ICEAgent.send_data(state.ice_agent, state.buffered_packets)
:ok = state.ice_transport.send_data(state.ice_transport_state, state.buffered_packets)
%{state | ice_state: new_ice_state, buffered_packets: nil}
else
state
Expand Down
20 changes: 20 additions & 0 deletions lib/ex_webrtc/ice_transport.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule ExWebRTC.ICETransport do

# module implementing this behaviour
@type t() :: module()

@callback start_link(:controlling | :controlled, Keyword.t()) :: {:ok, state :: any()}
@callback send_data(state :: any(), binary()) :: :ok
end

defmodule ExWebRTC.DefaultICETransport do
@behaviour ExWebRTC.ICETransport

alias ExICE.ICEAgent

@impl true
defdelegate start_link(role, opts), to: ICEAgent

@impl true
defdelegate send_data(state, data), to: ICEAgent
end
2 changes: 1 addition & 1 deletion lib/ex_webrtc/peer_connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ defmodule ExWebRTC.PeerConnection do
def init({owner, config}) do
ice_config = [stun_servers: config.ice_servers]
{:ok, dtls_transport} = DTLSTransport.start_link(ice_config)
ice_agent = DTLSTransport.get_ice_agent(dtls_transport)
ice_agent = DTLSTransport.get_ice_transport(dtls_transport)

state = %__MODULE__{
owner: owner,
Expand Down
8 changes: 6 additions & 2 deletions test/ex_webrtc/dtls_transport_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ defmodule ExWebRTC.DTLSTransportTest do
alias ExWebRTC.DTLSTransport

defmodule FakeICEAgent do
@behaviour ExWebRTC.ICETransport

use GenServer

@impl true
def start_link(_mode, config) do
GenServer.start_link(__MODULE__, {self(), config})
end

@impl true
def send_data(ice_agent, data) do
GenServer.cast(ice_agent, {:send_data, data})
end
Expand All @@ -36,9 +40,9 @@ defmodule ExWebRTC.DTLSTransportTest do
end

setup do
assert {:ok, dtls} = DTLSTransport.start_link([tester: self()], FakeICEAgent)
assert {:ok, dtls} = DTLSTransport.start_link(FakeICEAgent, [tester: self()])
assert_receive {:dtls_transport, ^dtls, {:state_change, :new}}
ice = DTLSTransport.get_ice_agent(dtls)
ice = DTLSTransport.get_ice_transport(dtls)
assert is_pid(ice)

%{dtls: dtls, ice: ice}
Expand Down

0 comments on commit 2c6d578

Please sign in to comment.