Stop an SCTP connection when the DTLS transport closes.
This CL propagates a "closed" signal from DTLS up to the
SCTP section of the data channel controller, where it causes
closing of all open datachannels.
Bug: chromium:1030631, webrtc:10360
Change-Id: I88bb9e1aff5c25f330edfd092ef609d4fcc3a9f8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/162206
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30099}
diff --git a/api/transport/data_channel_transport_interface.h b/api/transport/data_channel_transport_interface.h
index db53a5e..671deff 100644
--- a/api/transport/data_channel_transport_interface.h
+++ b/api/transport/data_channel_transport_interface.h
@@ -84,6 +84,11 @@
// invoked again following send errors (eg. due to the transport being
// temporarily blocked or unavailable).
virtual void OnReadyToSend() = 0;
+
+ // Callback issued when the data channel becomes unusable (closed).
+ // TODO(https://crbug.com/webrtc/10360): Make pure virtual when all
+ // consumers updated.
+ virtual void OnTransportClosed() {}
};
// Transport for data channels.
diff --git a/media/sctp/sctp_transport.cc b/media/sctp/sctp_transport.cc
index 9f1e862..31489eb 100644
--- a/media/sctp/sctp_transport.cc
+++ b/media/sctp/sctp_transport.cc
@@ -662,6 +662,7 @@
transport_->SignalWritableState.connect(this,
&SctpTransport::OnWritableState);
transport_->SignalReadPacket.connect(this, &SctpTransport::OnPacketRead);
+ transport_->SignalClosed.connect(this, &SctpTransport::OnClosed);
}
void SctpTransport::DisconnectTransportSignals() {
@@ -671,6 +672,7 @@
}
transport_->SignalWritableState.disconnect(this);
transport_->SignalReadPacket.disconnect(this);
+ transport_->SignalClosed.disconnect(this);
}
bool SctpTransport::Connect() {
@@ -990,6 +992,10 @@
}
}
+void SctpTransport::OnClosed(rtc::PacketTransportInternal* transport) {
+ SignalClosedAbruptly();
+}
+
void SctpTransport::OnSendThresholdCallback() {
RTC_DCHECK_RUN_ON(network_thread_);
if (partial_outgoing_message_.has_value()) {
diff --git a/media/sctp/sctp_transport.h b/media/sctp/sctp_transport.h
index 7337f01..d346cfc 100644
--- a/media/sctp/sctp_transport.h
+++ b/media/sctp/sctp_transport.h
@@ -164,6 +164,7 @@
size_t len,
const int64_t& packet_time_us,
int flags);
+ void OnClosed(rtc::PacketTransportInternal* transport);
// Methods related to usrsctp callbacks.
void OnSendThresholdCallback();
diff --git a/media/sctp/sctp_transport_internal.h b/media/sctp/sctp_transport_internal.h
index 378453a..b0e0e0f 100644
--- a/media/sctp/sctp_transport_internal.h
+++ b/media/sctp/sctp_transport_internal.h
@@ -134,6 +134,9 @@
// Parameter is SID; fired when closing procedure is complete (both incoming
// and outgoing streams reset).
sigslot::signal1<int> SignalClosingProcedureComplete;
+ // Fired when the underlying DTLS transport has closed due to an error
+ // or an incoming DTLS disconnect.
+ sigslot::signal0<> SignalClosedAbruptly;
// Helper for debugging.
virtual void set_debug_name_for_testing(const char* debug_name) = 0;
diff --git a/p2p/base/dtls_transport.cc b/p2p/base/dtls_transport.cc
index acd5765..538aa86 100644
--- a/p2p/base/dtls_transport.cc
+++ b/p2p/base/dtls_transport.cc
@@ -656,6 +656,7 @@
RTC_LOG(LS_INFO) << ToString() << ": DTLS transport closed by remote";
set_writable(false);
set_dtls_state(DTLS_TRANSPORT_CLOSED);
+ SignalClosed(this);
} else if (ret == rtc::SR_ERROR) {
// Remote peer shut down the association with an error.
RTC_LOG(LS_INFO)
@@ -664,6 +665,7 @@
<< read_error;
set_writable(false);
set_dtls_state(DTLS_TRANSPORT_FAILED);
+ SignalClosed(this);
}
} while (ret == rtc::SR_SUCCESS);
}
diff --git a/p2p/base/packet_transport_internal.h b/p2p/base/packet_transport_internal.h
index a532183..f65d7f4 100644
--- a/p2p/base/packet_transport_internal.h
+++ b/p2p/base/packet_transport_internal.h
@@ -95,6 +95,9 @@
// Signalled when the current network route has changed.
sigslot::signal1<absl::optional<rtc::NetworkRoute>> SignalNetworkRouteChanged;
+ // Signalled when the transport is closed.
+ sigslot::signal1<PacketTransportInternal*> SignalClosed;
+
protected:
PacketTransportInternal();
~PacketTransportInternal() override;
diff --git a/pc/data_channel_controller.cc b/pc/data_channel_controller.cc
index cb93384..2800992 100644
--- a/pc/data_channel_controller.cc
+++ b/pc/data_channel_controller.cc
@@ -181,6 +181,15 @@
});
}
+void DataChannelController::OnTransportClosed() {
+ RTC_DCHECK_RUN_ON(network_thread());
+ data_channel_transport_invoker_->AsyncInvoke<void>(
+ RTC_FROM_HERE, signaling_thread(), [this] {
+ RTC_DCHECK_RUN_ON(signaling_thread());
+ OnTransportChannelClosed();
+ });
+}
+
void DataChannelController::SetupDataChannelTransport_n() {
RTC_DCHECK_RUN_ON(network_thread());
data_channel_transport_invoker_ = std::make_unique<rtc::AsyncInvoker>();
diff --git a/pc/data_channel_controller.h b/pc/data_channel_controller.h
index 91bba66..5e00259 100644
--- a/pc/data_channel_controller.h
+++ b/pc/data_channel_controller.h
@@ -46,6 +46,7 @@
void OnChannelClosing(int channel_id) override;
void OnChannelClosed(int channel_id) override;
void OnReadyToSend() override;
+ void OnTransportClosed() override;
// Called from PeerConnection::SetupDataChannelTransport_n
void SetupDataChannelTransport_n();
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
index 7a8d152..58f5aa6 100644
--- a/pc/peer_connection_integrationtest.cc
+++ b/pc/peer_connection_integrationtest.cc
@@ -5989,6 +5989,44 @@
ASSERT_TRUE(caller()->data_observer()->IsOpen());
}
+TEST_F(PeerConnectionIntegrationTestUnifiedPlan, DataChannelClosesWhenClosed) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+ caller()->data_channel()->Close();
+ ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
+ DataChannelClosesWhenClosedReverse) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+ callee()->data_channel()->Close();
+ ASSERT_TRUE_WAIT(!caller()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
+ DataChannelClosesWhenPeerConnectionClosed) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->CreateDataChannel();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+ ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+ caller()->pc()->Close();
+ ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
#endif // HAVE_SCTP
} // namespace
diff --git a/pc/sctp_data_channel_transport.cc b/pc/sctp_data_channel_transport.cc
index d1505f3..497e11f 100644
--- a/pc/sctp_data_channel_transport.cc
+++ b/pc/sctp_data_channel_transport.cc
@@ -24,6 +24,8 @@
this, &SctpDataChannelTransport::OnClosingProcedureStartedRemotely);
sctp_transport_->SignalClosingProcedureComplete.connect(
this, &SctpDataChannelTransport::OnClosingProcedureComplete);
+ sctp_transport_->SignalClosedAbruptly.connect(
+ this, &SctpDataChannelTransport::OnClosedAbruptly);
}
RTCError SctpDataChannelTransport::OpenChannel(int channel_id) {
@@ -109,4 +111,10 @@
}
}
+void SctpDataChannelTransport::OnClosedAbruptly() {
+ if (sink_) {
+ sink_->OnTransportClosed();
+ }
+}
+
} // namespace webrtc
diff --git a/pc/sctp_data_channel_transport.h b/pc/sctp_data_channel_transport.h
index 281c30e..623a490 100644
--- a/pc/sctp_data_channel_transport.h
+++ b/pc/sctp_data_channel_transport.h
@@ -38,6 +38,7 @@
const rtc::CopyOnWriteBuffer& buffer);
void OnClosingProcedureStartedRemotely(int channel_id);
void OnClosingProcedureComplete(int channel_id);
+ void OnClosedAbruptly();
cricket::SctpTransportInternal* const sctp_transport_;