Skip to content

Commit c895252

Browse files
authored
Gracefully close connecting channels (#2991)
Fixes an issue where calling dataChannel.Close on 'connecting' state channels didn't work as expected. When handling the `OnOpen` event detect if the user has requested close. Fixes #2659
1 parent 1ee0299 commit c895252

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

datachannel.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,13 @@ func (d *DataChannel) onMessage(msg DataChannelMessage) {
320320

321321
func (d *DataChannel) handleOpen(dc *datachannel.DataChannel, isRemote, isAlreadyNegotiated bool) {
322322
d.mu.Lock()
323-
if d.isGracefulClosed {
323+
if d.isGracefulClosed { // The channel was closed during the connecting state
324324
d.mu.Unlock()
325+
if err := dc.Close(); err != nil {
326+
d.log.Errorf("Failed to close DataChannel that was closed during connecting state %v", err.Error())
327+
}
328+
d.onClose()
329+
325330
return
326331
}
327332
d.dataChannel = dc

datachannel_go_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,3 +745,80 @@ func TestDetachRemovesDatachannelReference(t *testing.T) {
745745
}
746746
}
747747
}
748+
749+
func TestDataChannelClose(t *testing.T) {
750+
// Test if onClose is fired for self and remote after Close is called
751+
t.Run("close open channels", func(t *testing.T) {
752+
options := &DataChannelInit{}
753+
754+
offerPC, answerPC, dc, done := setUpDataChannelParametersTest(t, options)
755+
756+
answerPC.OnDataChannel(func(dataChannel *DataChannel) {
757+
// Make sure this is the data channel we were looking for. (Not the one
758+
// created in signalPair).
759+
if dataChannel.Label() != expectedLabel {
760+
return
761+
}
762+
763+
dataChannel.OnOpen(func() {
764+
assert.NoError(t, dataChannel.Close())
765+
})
766+
767+
dataChannel.OnClose(func() {
768+
done <- true
769+
})
770+
})
771+
772+
dc.OnClose(func() {
773+
done <- true
774+
})
775+
776+
assert.NoError(t, signalPair(offerPC, answerPC))
777+
778+
// Offer and Answer OnClose
779+
<-done
780+
<-done
781+
782+
assert.NoError(t, offerPC.Close())
783+
assert.NoError(t, answerPC.Close())
784+
})
785+
786+
// Test if OnClose is fired for self and remote after Close is called on non-established channel
787+
// https://github.com/pion/webrtc/issues/2659
788+
t.Run("Close connecting channels", func(t *testing.T) {
789+
options := &DataChannelInit{}
790+
791+
offerPC, answerPC, dc, done := setUpDataChannelParametersTest(t, options)
792+
793+
answerPC.OnDataChannel(func(dataChannel *DataChannel) {
794+
// Make sure this is the data channel we were looking for. (Not the one
795+
// created in signalPair).
796+
if dataChannel.Label() != expectedLabel {
797+
return
798+
}
799+
800+
dataChannel.OnOpen(func() {
801+
t.Fatal("OnOpen must not be fired after we call Close")
802+
})
803+
804+
dataChannel.OnClose(func() {
805+
done <- true
806+
})
807+
808+
assert.NoError(t, dataChannel.Close())
809+
})
810+
811+
dc.OnClose(func() {
812+
done <- true
813+
})
814+
815+
assert.NoError(t, signalPair(offerPC, answerPC))
816+
817+
// Offer and Answer OnClose
818+
<-done
819+
<-done
820+
821+
assert.NoError(t, offerPC.Close())
822+
assert.NoError(t, answerPC.Close())
823+
})
824+
}

0 commit comments

Comments
 (0)