Skip to content

Commit 66ec1e3

Browse files
committed
Don't move to the closed state after receiving close_notify alert
1 parent 83fbefd commit 66ec1e3

File tree

10 files changed

+72
-79
lines changed

10 files changed

+72
-79
lines changed

examples/chat/lib/chat/peer_handler.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ defmodule Chat.PeerHandler do
106106
defp handle_webrtc_msg({:connection_state_change, conn_state}, state) do
107107
Logger.info("Connection state changed: #{conn_state}")
108108

109-
if conn_state in [:failed, :closed] do
110-
{:stop, {:shutdown, :pc_failed_or_closed}, state}
109+
if conn_state == :failed do
110+
{:stop, {:shutdown, :pc_failed}, state}
111111
else
112112
{:ok, state}
113113
end

examples/dtmf/lib/dtmf/peer_handler.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ defmodule Dtmf.PeerHandler do
125125
defp handle_webrtc_msg({:connection_state_change, conn_state}, state) do
126126
Logger.info("Connection state changed: #{conn_state}")
127127

128-
if conn_state in [:failed, :closed] do
129-
{:stop, {:shutdown, :pc_failed_or_closed}, state}
128+
if conn_state == :failed do
129+
{:stop, {:shutdown, :pc_failed}, state}
130130
else
131131
{:ok, state}
132132
end

examples/echo/lib/echo/peer_handler.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ defmodule Echo.PeerHandler do
115115
defp handle_webrtc_msg({:connection_state_change, conn_state}, state) do
116116
Logger.info("Connection state changed: #{conn_state}")
117117

118-
if conn_state in [:failed, :closed] do
119-
{:stop, {:shutdown, :pc_failed_or_closed}, state}
118+
if conn_state == :failed do
119+
{:stop, {:shutdown, :pc_failed}, state}
120120
else
121121
{:ok, state}
122122
end

examples/save_to_file/lib/save_to_file/peer_handler.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ defmodule SaveToFile.PeerHandler do
136136
defp handle_webrtc_msg({:connection_state_change, conn_state}, state) do
137137
Logger.info("Connection state changed: #{conn_state}")
138138

139-
if conn_state in [:failed, :closed] do
140-
{:stop, {:shutdown, :pc_failed_or_closed}, state}
139+
if conn_state == :failed do
140+
{:stop, {:shutdown, :pc_failed}, state}
141141
else
142142
{:ok, state}
143143
end

examples/send_from_file/lib/send_from_file/peer_handler.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ defmodule SendFromFile.PeerHandler do
249249
defp handle_webrtc_msg({:connection_state_change, conn_state}, state) do
250250
Logger.info("Connection state changed: #{conn_state}")
251251

252-
if conn_state in [:failed, :closed] do
253-
{:stop, {:shutdown, :pc_failed_or_closed}, state}
252+
if conn_state == :failed do
253+
{:stop, {:shutdown, :pc_failed}, state}
254254
else
255255
{:ok, state}
256256
end

examples/whip_whep/lib/whip_whep/forwarder.ex

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,8 @@ defmodule WhipWhep.Forwarder do
6969
end
7070

7171
@impl true
72-
def handle_info(
73-
{:ex_webrtc, pc, {:connection_state_change, conn_state}},
74-
%{input_pc: pc} = state
75-
)
76-
when conn_state in [:failed, :closed] do
77-
Logger.info("Input peer connection (#{inspect(pc)}) state change: #{conn_state}. Removing.")
72+
def handle_info({:ex_webrtc, pc, {:connection_state_change, :failed}}, %{input_pc: pc} = state) do
73+
Logger.info("Input peer connection (#{inspect(pc)}) state change: failed. Removing.")
7874
:ok = PeerConnection.stop(state.input_pc)
7975

8076
Enum.each(state.pending_outputs, &PeerConnection.close(&1))
@@ -124,9 +120,8 @@ defmodule WhipWhep.Forwarder do
124120
end
125121

126122
@impl true
127-
def handle_info({:ex_webrtc, pc, {:connection_state_change, conn_state}}, state)
128-
when conn_state in [:failed, :closed] do
129-
Logger.info("Output peer connection (#{inspect(pc)}) state change: #{conn_state}. Removing.")
123+
def handle_info({:ex_webrtc, pc, {:connection_state_change, :failed}}, state) do
124+
Logger.info("Output peer connection (#{inspect(pc)}) state change: failed. Removing.")
130125
:ok = PeerConnection.stop(pc)
131126
pending_outputs = List.delete(state.pending_outputs, pc)
132127
outputs = Map.delete(state.outputs, pc)

lib/ex_webrtc/dtls_transport.ex

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ defmodule ExWebRTC.DTLSTransport do
131131
remote_cert: nil,
132132
remote_base64_cert: nil,
133133
remote_fingerprint: nil,
134-
in_srtp: ExLibSRTP.new(),
135-
out_srtp: ExLibSRTP.new(),
134+
in_srtp: nil,
135+
out_srtp: nil,
136136
# sha256 hex dump
137137
peer_fingerprint: nil,
138138
dtls_state: :new,
@@ -217,9 +217,18 @@ defmodule ExWebRTC.DTLSTransport do
217217
end
218218

219219
@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}")
220+
def handle_call(
221+
{:start_dtls, mode, peer_fingerprint},
222+
_from,
223+
%{dtls: dtls, dtls_state: dtls_state} = state
224+
)
225+
when mode in [:active, :passive] and (dtls == nil or dtls_state == :closed) do
226+
if dtls_state == :closed do
227+
Logger.debug("Re-initializing DTLSTransport with role #{mode}")
228+
else
229+
Logger.debug("Starting DTLSTransport with role #{mode}")
230+
end
231+
223232
ex_dtls_mode = if mode == :active, do: :client, else: :server
224233

225234
dtls =
@@ -241,7 +250,10 @@ defmodule ExWebRTC.DTLSTransport do
241250
state = %{
242251
state
243252
| dtls: dtls,
253+
dtls_state: :new,
244254
mode: mode,
255+
in_srtp: ExLibSRTP.new(),
256+
out_srtp: ExLibSRTP.new(),
245257
peer_fingerprint: peer_fingerprint,
246258
buffered_remote_packets: nil
247259
}

lib/ex_webrtc/peer_connection.ex

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,8 +1388,22 @@ defmodule ExWebRTC.PeerConnection do
13881388
@impl true
13891389
def handle_call(:close, _from, state) do
13901390
Logger.debug("Closing peer connection")
1391-
# don't emit state change events
1392-
state = do_close(state, notify: false)
1391+
transceivers = Enum.map(state.transceivers, &RTPTransceiver.stop(&1))
1392+
sctp_transport = SCTPTransport.close_abruptly(state.sctp_transport)
1393+
:ok = DTLSTransport.close(state.dtls_transport)
1394+
:ok = state.ice_transport.close(state.ice_pid)
1395+
1396+
state =
1397+
%{
1398+
state
1399+
| ice_state: :closed,
1400+
dtls_state: :closed,
1401+
transceivers: transceivers,
1402+
sctp_transport: sctp_transport
1403+
}
1404+
|> update_signaling_state(:closed, notify: false)
1405+
|> update_conn_state(:closed, notify: false)
1406+
13931407
{:reply, :ok, state}
13941408
end
13951409

@@ -1548,17 +1562,12 @@ defmodule ExWebRTC.PeerConnection do
15481562

15491563
next_conn_state = next_conn_state(state.ice_state, new_dtls_state)
15501564

1551-
if next_conn_state == :closed and state.conn_state != :closed do
1552-
state = do_close(state)
1553-
{:noreply, state}
1554-
else
1555-
state =
1556-
%{state | dtls_state: new_dtls_state}
1557-
|> update_conn_state(next_conn_state)
1558-
|> maybe_connect_sctp()
1565+
state =
1566+
%{state | dtls_state: new_dtls_state}
1567+
|> update_conn_state(next_conn_state)
1568+
|> maybe_connect_sctp()
15591569

1560-
{:noreply, state}
1561-
end
1570+
{:noreply, state}
15621571
end
15631572

15641573
@impl true
@@ -2330,8 +2339,6 @@ defmodule ExWebRTC.PeerConnection do
23302339
# Closed connection can't be reused.
23312340
defp next_conn_state(:closed, _dtls_state), do: :closed
23322341

2333-
defp next_conn_state(_ice_state, :closed), do: :closed
2334-
23352342
defp next_conn_state(:failed, _dtls_state), do: :failed
23362343

23372344
defp next_conn_state(_ice_state, :failed), do: :failed
@@ -2342,8 +2349,9 @@ defmodule ExWebRTC.PeerConnection do
23422349
when ice_state in [:new, :checking] or dtls_state in [:new, :connecting],
23432350
do: :connecting
23442351

2345-
defp next_conn_state(ice_state, :connected) when ice_state in [:connected, :completed],
2346-
do: :connected
2352+
defp next_conn_state(ice_state, dtls_state)
2353+
when ice_state in [:connected, :completed] and dtls_state in [:connected, :closed],
2354+
do: :connected
23472355

23482356
defp update_conn_state(state, conn_state, opts \\ [])
23492357
defp update_conn_state(%{conn_state: conn_state} = state, conn_state, _opts), do: state
@@ -2551,27 +2559,6 @@ defmodule ExWebRTC.PeerConnection do
25512559
%SessionDescription{type: type, sdp: to_string(sdp)}
25522560
end
25532561

2554-
defp do_close(state, opts \\ []) do
2555-
transceivers = Enum.map(state.transceivers, &RTPTransceiver.stop(&1))
2556-
sctp_transport = SCTPTransport.close_abruptly(state.sctp_transport)
2557-
:ok = DTLSTransport.close(state.dtls_transport)
2558-
:ok = state.ice_transport.close(state.ice_pid)
2559-
2560-
if opts[:notify] != false do
2561-
notify(state.owner, {:ice_connection_state_change, :closed})
2562-
end
2563-
2564-
%{
2565-
state
2566-
| ice_state: :closed,
2567-
dtls_state: :closed,
2568-
transceivers: transceivers,
2569-
sctp_transport: sctp_transport
2570-
}
2571-
|> update_signaling_state(:closed, opts)
2572-
|> update_conn_state(:closed, opts)
2573-
end
2574-
25752562
defp generate_ssrcs(state) do
25762563
generate_ssrcs(state.transceivers, Map.keys(state.demuxer.ssrc_to_mid))
25772564
end

test/ex_webrtc/peer_connection_test.exs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,32 +1129,30 @@ defmodule ExWebRTC.PeerConnectionTest do
11291129

11301130
assert :ok = PeerConnection.close(pc2)
11311131

1132-
assert_receive {:ex_webrtc, ^pc1, {:signaling_state_change, :closed}}
1133-
assert_receive {:ex_webrtc, ^pc1, {:ice_connection_state_change, :closed}}
1132+
# only dtls transport should move to the closed state
1133+
# this way peer connection can do ice restart with a different peer
11341134
assert_receive {:ex_webrtc, ^pc1, {:dtls_transport_state_change, :closed}}
1135-
assert_receive {:ex_webrtc, ^pc1, {:connection_state_change, :closed}}
1135+
refute_receive {:ex_webrtc, ^pc1, {:signaling_state_change, :closed}}
1136+
refute_receive {:ex_webrtc, ^pc1, {:ice_connection_state_change, :closed}}
1137+
refute_receive {:ex_webrtc, ^pc1, {:connection_state_change, :closed}}
11361138

11371139
# the process should still be alive
11381140
assert true = Process.alive?(pc1)
11391141

11401142
# Here, we don't really know what should be the state of transceivers and data channels.
11411143
# W3C and browser behavior are unclear at the moment of writing this tes.
11421144
# To be consistent, we just mark them as stopped/closed.
1143-
[%{stopped: true}] = PeerConnection.get_transceivers(pc1)
1144-
%{ready_state: :closed} = PeerConnection.get_data_channel(pc1, data_channel.ref)
1145+
[%{stopped: false}] = PeerConnection.get_transceivers(pc1)
1146+
%{ready_state: :open} = PeerConnection.get_data_channel(pc1, data_channel.ref)
11451147

1146-
# Try to send RTP, it should be ignored
1147-
packet = ExRTP.Packet.new(<<1, 2, 3>>)
1148-
:ok = PeerConnection.send_rtp(pc1, track.id, packet)
1149-
refute_receive {:ex_webrtc, ^pc2, {:rtp, _track_id, nil, _packet}}
1148+
# try to do ice-restart with a different peer
1149+
{:ok, pc3} = PeerConnection.start_link()
11501150

1151-
# Try to send data, it should be ignored
1152-
:ok = PeerConnection.send_data(pc1, data_channel.ref, <<1, 2, 3>>)
1153-
refute_receive {:ex_webrtc, ^pc2, {:data, _dc_ref, _data}}
1151+
assert :ok = negotiate(pc1, pc3, ice_restart: true)
1152+
assert :ok = connect(pc1, pc3)
11541153

1155-
# Try to send RTCP, it should be ignored
1156-
:ok = PeerConnection.send_pli(pc1, track.id)
1157-
refute_receive {:ex_webrtc, ^pc2, {:rtcp, _}}
1154+
:ok = PeerConnection.send_rtp(pc1, track.id, ExRTP.Packet.new(<<1, 2, 3>>))
1155+
assert_receive {:ex_webrtc, ^pc3, {:rtp, _track_id, nil, _packet}}
11581156
end
11591157
end
11601158

test/support/test_utils.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ defmodule ExWebRTC.Support.TestUtils do
33

44
alias ExWebRTC.PeerConnection
55

6-
@spec negotiate(PeerConnection.peer_connection(), PeerConnection.peer_connection()) :: :ok
7-
def negotiate(pc1, pc2) do
8-
{:ok, offer} = PeerConnection.create_offer(pc1)
6+
@spec negotiate(PeerConnection.peer_connection(), PeerConnection.peer_connection(), Keyword.t()) ::
7+
:ok
8+
def negotiate(pc1, pc2, opts \\ []) do
9+
{:ok, offer} = PeerConnection.create_offer(pc1, ice_restart: opts[:ice_restart] || false)
910
:ok = PeerConnection.set_local_description(pc1, offer)
1011
:ok = PeerConnection.set_remote_description(pc2, offer)
1112
{:ok, answer} = PeerConnection.create_answer(pc2)

0 commit comments

Comments
 (0)