diff --git a/pc/data_channel_unittest.cc b/pc/data_channel_unittest.cc index 80997161cf..d9575f0312 100644 --- a/pc/data_channel_unittest.cc +++ b/pc/data_channel_unittest.cc @@ -618,6 +618,15 @@ TEST_F(SctpDataChannelTest, NeverOpened) { webrtc_data_channel_->Close(); } +// Tests that a data channel that's not connected to a transport can transition +// directly to the `kClosed` state when closed. +// See also chromium:1421534. +TEST_F(SctpDataChannelTest, UnusedTransitionsDirectlyToClosed) { + webrtc_data_channel_->Close(); + EXPECT_EQ(webrtc::DataChannelInterface::kClosed, + webrtc_data_channel_->state()); +} + // Test that the data channel goes to the "closed" state (and doesn't crash) // when its transport goes away, even while data is buffered. TEST_F(SctpDataChannelTest, TransportDestroyedWhileDataBuffered) { diff --git a/pc/sctp_data_channel.cc b/pc/sctp_data_channel.cc index cb7c1c31d9..d41baafc9d 100644 --- a/pc/sctp_data_channel.cc +++ b/pc/sctp_data_channel.cc @@ -539,18 +539,25 @@ void SctpDataChannel::UpdateState() { break; } case kClosing: { - // Wait for all queued data to be sent before beginning the closing - // procedure. - if (queued_send_data_.Empty() && queued_control_data_.Empty()) { - // For SCTP data channels, we need to wait for the closing procedure - // to complete; after calling RemoveSctpDataStream, - // OnClosingProcedureComplete will end up called asynchronously - // afterwards. - if (connected_to_transport_ && !started_closing_procedure_ && - controller_ && config_.id >= 0) { - started_closing_procedure_ = true; - controller_->RemoveSctpDataStream(config_.id); + if (connected_to_transport_) { + // Wait for all queued data to be sent before beginning the closing + // procedure. + if (queued_send_data_.Empty() && queued_control_data_.Empty()) { + // For SCTP data channels, we need to wait for the closing procedure + // to complete; after calling RemoveSctpDataStream, + // OnClosingProcedureComplete will end up called asynchronously + // afterwards. + if (!started_closing_procedure_ && controller_ && config_.id >= 0) { + started_closing_procedure_ = true; + controller_->RemoveSctpDataStream(config_.id); + } } + } else { + // When we're not connected to a transport, we'll transition + // directly to the `kClosed` state from here. + queued_send_data_.Clear(); + queued_control_data_.Clear(); + SetState(kClosed); } break; }