Skip to content

Commit 7948437

Browse files
digitalixSean-Der
authored andcommitted
Fixed deadlock in peerconnection.go
In some rare cases during ice connection stage change may result in deadlock. This fix makes iceConnectionState and connectionState atomic which should prevent deadlock.
1 parent 11f6a65 commit 7948437

File tree

2 files changed

+21
-39
lines changed

2 files changed

+21
-39
lines changed

peerconnection.go

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ type PeerConnection struct {
4545
currentRemoteDescription *SessionDescription
4646
pendingRemoteDescription *SessionDescription
4747
signalingState SignalingState
48-
iceConnectionState ICEConnectionState
49-
connectionState PeerConnectionState
48+
iceConnectionState atomic.Value // ICEConnectionState
49+
connectionState atomic.Value // PeerConnectionState
5050

5151
idpLoginURL *string
5252

@@ -66,8 +66,8 @@ type PeerConnection struct {
6666
rtpTransceivers []*RTPTransceiver
6767

6868
onSignalingStateChangeHandler func(SignalingState)
69-
onICEConnectionStateChangeHandler func(ICEConnectionState)
70-
onConnectionStateChangeHandler func(PeerConnectionState)
69+
onICEConnectionStateChangeHandler atomic.Value // func(ICEConnectionState)
70+
onConnectionStateChangeHandler atomic.Value // func(PeerConnectionState)
7171
onTrackHandler func(*TrackRemote, *RTPReceiver)
7272
onDataChannelHandler func(*DataChannel)
7373
onNegotiationNeededHandler atomic.Value // func()
@@ -128,12 +128,12 @@ func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection,
128128
lastAnswer: "",
129129
greaterMid: -1,
130130
signalingState: SignalingStateStable,
131-
iceConnectionState: ICEConnectionStateNew,
132-
connectionState: PeerConnectionStateNew,
133131

134132
api: api,
135133
log: api.settingEngine.LoggerFactory.NewLogger("pc"),
136134
}
135+
pc.iceConnectionState.Store(ICEConnectionStateNew)
136+
pc.connectionState.Store(PeerConnectionStateNew)
137137

138138
if !api.settingEngine.disableMediaEngineCopy {
139139
pc.api = &API{
@@ -458,29 +458,21 @@ func (pc *PeerConnection) onTrack(t *TrackRemote, r *RTPReceiver) {
458458
// OnICEConnectionStateChange sets an event handler which is called
459459
// when an ICE connection state is changed.
460460
func (pc *PeerConnection) OnICEConnectionStateChange(f func(ICEConnectionState)) {
461-
pc.mu.Lock()
462-
defer pc.mu.Unlock()
463-
pc.onICEConnectionStateChangeHandler = f
461+
pc.onICEConnectionStateChangeHandler.Store(f)
464462
}
465463

466464
func (pc *PeerConnection) onICEConnectionStateChange(cs ICEConnectionState) {
467-
pc.mu.Lock()
468-
pc.iceConnectionState = cs
469-
handler := pc.onICEConnectionStateChangeHandler
470-
pc.mu.Unlock()
471-
465+
pc.iceConnectionState.Store(cs)
472466
pc.log.Infof("ICE connection state changed: %s", cs)
473-
if handler != nil {
474-
go handler(cs)
467+
if handler := pc.onICEConnectionStateChangeHandler.Load(); handler != nil {
468+
handler.(func(ICEConnectionState))(cs)
475469
}
476470
}
477471

478472
// OnConnectionStateChange sets an event handler which is called
479473
// when the PeerConnectionState has changed
480474
func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) {
481-
pc.mu.Lock()
482-
defer pc.mu.Unlock()
483-
pc.onConnectionStateChangeHandler = f
475+
pc.onConnectionStateChangeHandler.Store(f)
484476
}
485477

486478
// SetConfiguration updates the configuration of this PeerConnection object.
@@ -714,9 +706,6 @@ func (pc *PeerConnection) createICEGatherer() (*ICEGatherer, error) {
714706
// Update the PeerConnectionState given the state of relevant transports
715707
// https://www.w3.org/TR/webrtc/#rtcpeerconnectionstate-enum
716708
func (pc *PeerConnection) updateConnectionState(iceConnectionState ICEConnectionState, dtlsTransportState DTLSTransportState) {
717-
pc.mu.Lock()
718-
defer pc.mu.Unlock()
719-
720709
connectionState := PeerConnectionStateNew
721710
switch {
722711
// The RTCPeerConnection object's [[IsClosed]] slot is true.
@@ -743,15 +732,14 @@ func (pc *PeerConnection) updateConnectionState(iceConnectionState ICEConnection
743732
connectionState = PeerConnectionStateConnecting
744733
}
745734

746-
if pc.connectionState == connectionState {
735+
if pc.connectionState.Load() == connectionState {
747736
return
748737
}
749738

750739
pc.log.Infof("peer connection state changed: %s", connectionState)
751-
pc.connectionState = connectionState
752-
handler := pc.onConnectionStateChangeHandler
753-
if handler != nil {
754-
go handler(connectionState)
740+
pc.connectionState.Store(connectionState)
741+
if handler := pc.onConnectionStateChangeHandler.Load(); handler != nil {
742+
go handler.(func(PeerConnectionState))(connectionState)
755743
}
756744
}
757745

@@ -1534,10 +1522,7 @@ func (pc *PeerConnection) AddICECandidate(candidate ICECandidateInit) error {
15341522
// ICEConnectionState returns the ICE connection state of the
15351523
// PeerConnection instance.
15361524
func (pc *PeerConnection) ICEConnectionState() ICEConnectionState {
1537-
pc.mu.RLock()
1538-
defer pc.mu.RUnlock()
1539-
1540-
return pc.iceConnectionState
1525+
return pc.iceConnectionState.Load().(ICEConnectionState)
15411526
}
15421527

15431528
// GetSenders returns the RTPSender that are currently attached to this PeerConnection
@@ -1959,10 +1944,7 @@ func (pc *PeerConnection) ICEGatheringState() ICEGatheringState {
19591944
// ConnectionState attribute returns the connection state of the
19601945
// PeerConnection instance.
19611946
func (pc *PeerConnection) ConnectionState() PeerConnectionState {
1962-
pc.mu.Lock()
1963-
defer pc.mu.Unlock()
1964-
1965-
return pc.connectionState
1947+
return pc.connectionState.Load().(PeerConnectionState)
19661948
}
19671949

19681950
// GetStats return data providing statistics about the overall connection

peerconnection_go_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,17 +384,17 @@ func TestPeerConnection_PropertyGetters(t *testing.T) {
384384
currentRemoteDescription: &SessionDescription{},
385385
pendingRemoteDescription: &SessionDescription{},
386386
signalingState: SignalingStateHaveLocalOffer,
387-
iceConnectionState: ICEConnectionStateChecking,
388-
connectionState: PeerConnectionStateConnecting,
389387
}
388+
pc.iceConnectionState.Store(ICEConnectionStateChecking)
389+
pc.connectionState.Store(PeerConnectionStateConnecting)
390390

391391
assert.Equal(t, pc.currentLocalDescription, pc.CurrentLocalDescription(), "should match")
392392
assert.Equal(t, pc.pendingLocalDescription, pc.PendingLocalDescription(), "should match")
393393
assert.Equal(t, pc.currentRemoteDescription, pc.CurrentRemoteDescription(), "should match")
394394
assert.Equal(t, pc.pendingRemoteDescription, pc.PendingRemoteDescription(), "should match")
395395
assert.Equal(t, pc.signalingState, pc.SignalingState(), "should match")
396-
assert.Equal(t, pc.iceConnectionState, pc.ICEConnectionState(), "should match")
397-
assert.Equal(t, pc.connectionState, pc.ConnectionState(), "should match")
396+
assert.Equal(t, pc.iceConnectionState.Load(), pc.ICEConnectionState(), "should match")
397+
assert.Equal(t, pc.connectionState.Load(), pc.ConnectionState(), "should match")
398398
}
399399

400400
func TestPeerConnection_AnswerWithoutOffer(t *testing.T) {

0 commit comments

Comments
 (0)