mirror of
https://github.com/pion/webrtc.git
synced 2025-12-24 11:51:03 +08:00
Return early if aborted
Do not wait on data channel Accept when SCTP association is aborted
This commit is contained in:
@@ -190,6 +190,17 @@ func (r *SCTPTransport) acceptDataChannels(
|
||||
}
|
||||
ACCEPT:
|
||||
for {
|
||||
// check if the association has been stopped before calling accept.
|
||||
r.lock.RLock()
|
||||
currentAssoc := r.sctpAssociation
|
||||
shouldStop := currentAssoc == nil || currentAssoc != assoc
|
||||
r.lock.RUnlock()
|
||||
if shouldStop {
|
||||
r.onClose(nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
dc, err := datachannel.Accept(assoc, &datachannel.Config{
|
||||
LoggerFactory: r.api.settingEngine.LoggerFactory,
|
||||
}, dataChannels...)
|
||||
|
||||
@@ -116,11 +116,77 @@ func TestSCTPTransportOnClose(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(15 * time.Second):
|
||||
assert.Fail(t, "timed out")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSCTPTransportOnCloseImmediate tests that OnClose fires immediately
|
||||
// when Stop() is called directly on the SCTP transport, even if acceptDataChannels
|
||||
// is blocked waiting for a new data channel. This test would fail "sometimes" without the fix
|
||||
// because without the check before datachannel.Accept(), the goroutine would be
|
||||
// blocked in Accept() and might not detect the closure until Accept() returns.
|
||||
func TestSCTPTransportOnCloseImmediate(t *testing.T) {
|
||||
offerPC, answerPC, err := newPair()
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer closePairNow(t, offerPC, answerPC)
|
||||
|
||||
connected := make(chan struct{}, 1)
|
||||
offerPC.OnConnectionStateChange(func(state PeerConnectionState) {
|
||||
if state == PeerConnectionStateConnected {
|
||||
connected <- struct{}{}
|
||||
}
|
||||
})
|
||||
|
||||
err = signalPair(offerPC, answerPC)
|
||||
assert.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-connected:
|
||||
case <-time.After(5 * time.Second):
|
||||
assert.Fail(t, "connection establishment timed out")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Create and open a data channel to ensure SCTP is fully established
|
||||
// and acceptDataChannels goroutine has processed it and is back in Accept()
|
||||
dc, err := offerPC.CreateDataChannel("test", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
dcOpened := make(chan struct{}, 1)
|
||||
dc.OnOpen(func() {
|
||||
dcOpened <- struct{}{}
|
||||
})
|
||||
|
||||
select {
|
||||
case <-dcOpened:
|
||||
case <-time.After(5 * time.Second):
|
||||
assert.Fail(t, "data channel open timed out")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// wait a bit to ensure acceptDataChannels loop is back in Accept()
|
||||
// This increases the chance that Accept() is blocking when we call Stop()
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
onCloseFired := make(chan error, 1)
|
||||
answerPC.SCTP().OnClose(func(err error) {
|
||||
onCloseFired <- err
|
||||
})
|
||||
|
||||
err = answerPC.SCTP().Stop()
|
||||
assert.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-onCloseFired:
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
assert.Fail(t, "OnClose did not fire immediately")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCTPTransportOutOfBandNegotiatedDataChannelDetach(t *testing.T) { //nolint:cyclop
|
||||
// nolint:varnamelen
|
||||
const N = 10
|
||||
|
||||
Reference in New Issue
Block a user