Transition data channnel to kClosed when not connected to a transport.
If a data channel object was closed (via calling Close()) right after
construction and before attaching to a transport, it would never
transition to the `kClosed` state. This addresses that corner case,
which caused a DCHECK to trigger but might also cause a situation
whereby more than one DC instance existed for a given sctp sid.
Bug: chromium:1421534
Change-Id: Id757c0528f929f2e2daa5343236d7f62e309f6cc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/296341
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39513}
diff --git a/pc/data_channel_unittest.cc b/pc/data_channel_unittest.cc
index 8099716..d9575f0 100644
--- a/pc/data_channel_unittest.cc
+++ b/pc/data_channel_unittest.cc
@@ -618,6 +618,15 @@
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 cb7c1c3..d41baaf 100644
--- a/pc/sctp_data_channel.cc
+++ b/pc/sctp_data_channel.cc
@@ -539,18 +539,25 @@
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;
}