@@ -62,6 +62,11 @@ defmodule ExWebRTC.DTLSTransport do
6262 GenServer . call ( dtls_transport , :set_ice_connected )
6363 end
6464
65+ @ spec set_ice_disconnected ( dtls_transport ( ) ) :: :ok
66+ def set_ice_disconnected ( dtls_transport ) do
67+ GenServer . call ( dtls_transport , :set_ice_disconnected )
68+ end
69+
6570 @ spec get_certs_info ( dtls_transport ( ) ) :: % {
6671 local_cert_info: cert_info ( ) ,
6772 remote_cert_info: cert_info ( ) | nil
@@ -131,8 +136,8 @@ defmodule ExWebRTC.DTLSTransport do
131136 remote_cert: nil ,
132137 remote_base64_cert: nil ,
133138 remote_fingerprint: nil ,
134- in_srtp: ExLibSRTP . new ( ) ,
135- out_srtp: ExLibSRTP . new ( ) ,
139+ in_srtp: nil ,
140+ out_srtp: nil ,
136141 # sha256 hex dump
137142 peer_fingerprint: nil ,
138143 dtls_state: :new ,
@@ -187,6 +192,12 @@ defmodule ExWebRTC.DTLSTransport do
187192 { :reply , :ok , state }
188193 end
189194
195+ @ impl true
196+ def handle_call ( :set_ice_disconnected , _from , state ) do
197+ state = % { state | ice_connected: false }
198+ { :reply , :ok , state }
199+ end
200+
190201 @ impl true
191202 def handle_call ( :get_certs_info , _from , state ) do
192203 local_cert_info = % {
@@ -217,9 +228,18 @@ defmodule ExWebRTC.DTLSTransport do
217228 end
218229
219230 @ impl true
220- def handle_call ( { :start_dtls , mode , peer_fingerprint } , _from , % { dtls: nil } = state )
221- when mode in [ :active , :passive ] do
222- Logger . debug ( "Started DTLSTransport with role #{ mode } " )
231+ def handle_call (
232+ { :start_dtls , mode , peer_fingerprint } ,
233+ _from ,
234+ % { dtls: dtls , dtls_state: dtls_state } = state
235+ )
236+ when mode in [ :active , :passive ] and ( dtls == nil or dtls_state == :closed ) do
237+ if dtls_state == :closed do
238+ Logger . debug ( "Re-initializing DTLSTransport with role #{ mode } " )
239+ else
240+ Logger . debug ( "Starting DTLSTransport with role #{ mode } " )
241+ end
242+
223243 ex_dtls_mode = if mode == :active , do: :client , else: :server
224244
225245 dtls =
@@ -238,13 +258,20 @@ defmodule ExWebRTC.DTLSTransport do
238258 data -> send ( self ( ) , { :ex_ice , state . ice_pid , { :data , data } } )
239259 end
240260
241- state = % {
242- state
243- | dtls: dtls ,
244- mode: mode ,
245- peer_fingerprint: peer_fingerprint ,
246- buffered_remote_packets: nil
247- }
261+ state =
262+ % {
263+ state
264+ | dtls: dtls ,
265+ mode: mode ,
266+ in_srtp: ExLibSRTP . new ( ) ,
267+ out_srtp: ExLibSRTP . new ( ) ,
268+ peer_fingerprint: peer_fingerprint ,
269+ # cleare remote info in case we are re-initializing dtls transport
270+ remote_cert: nil ,
271+ remote_base64_cert: nil ,
272+ remote_fingerprint: nil
273+ }
274+ |> update_dtls_state ( :new )
248275
249276 { :reply , :ok , state }
250277 end
@@ -262,9 +289,7 @@ defmodule ExWebRTC.DTLSTransport do
262289
263290 @ impl true
264291 def handle_call ( :close , _from , state ) do
265- { :ok , packets } = ExDTLS . close ( state . dtls )
266- :ok = do_send ( state , packets )
267- state = update_dtls_state ( state , :closed , notify: false )
292+ state = do_close ( state , notify: false )
268293 { :reply , :ok , state }
269294 end
270295
@@ -360,8 +385,7 @@ defmodule ExWebRTC.DTLSTransport do
360385 # See W3C WebRTC sec. 5.5.1
361386 # peer_closed_for_writing is returned when the remote side
362387 # sends close_notify alert
363- ExDTLS . close ( state . dtls )
364- state = update_dtls_state ( state , :closed )
388+ state = do_close ( state )
365389 { :noreply , state }
366390
367391 { :error , _reason } ->
@@ -382,9 +406,19 @@ defmodule ExWebRTC.DTLSTransport do
382406 Logger . debug ( "Stopping DTLSTransport with reason: #{ inspect ( reason ) } " )
383407 end
384408
385- defp handle_ice_data ( { :data , _data } , % { dtls_state: dtls_state } = state )
386- when dtls_state in [ :failed , :closed ] do
387- Logger . debug ( "Received DTLS packets in state #{ dtls_state } . Ignoring." )
409+ defp handle_ice_data ( { :data , _data } , % { dtls_state: :closed } = state ) do
410+ # Ignore incoming packets when we are in the closed state.
411+ # IMPORTANT!!! This isn't optimal.
412+ # When DTLSTransport has been closed because of receiving close_notify alert,
413+ # it can still be re-used after doing an ice restart with a different peer.
414+ # In such case, we might start getting remote ICE packets before getting remote SDP answer
415+ # (see the case clause below).
416+ # These packets could be buffered and processed once we receive said SDP answer to speedup
417+ # connection establishment time (instead of waiting for retransmissions).
418+ # However, it is hard to differentiate this case from a case where DTLSTransport received
419+ # close_notify alert, but the remote side behaves incorrectly and is still sending ICE packets.
420+ # Buffering incoming packets in closed state, we don't know whether they belong to current or previous
421+ # session, which can lead to hard to find bugs.
388422 { :ok , state }
389423 end
390424
@@ -542,6 +576,23 @@ defmodule ExWebRTC.DTLSTransport do
542576 % { state | buffered_remote_rtp_packets: [ ] }
543577 end
544578
579+ defp do_close ( state , opts \\ [ ] ) do
580+ { :ok , packets } = ExDTLS . close ( state . dtls )
581+ :ok = do_send ( state , packets )
582+
583+ % {
584+ state
585+ | buffered_local_packets: nil ,
586+ buffered_remote_packets: nil ,
587+ buffered_remote_rtp_packets: [ ] ,
588+ in_srtp: nil ,
589+ out_srtp: nil ,
590+ dtls: nil ,
591+ mode: nil
592+ }
593+ |> update_dtls_state ( :closed , opts )
594+ end
595+
545596 defp do_send ( state , data ) when is_list ( data ) do
546597 Enum . each ( data , & ( :ok = do_send ( state , & 1 ) ) )
547598 end
0 commit comments