Make SCTPtransport enter "closed" state when DTLStransport does.
Bug: webrtc:11090
Change-Id: I30e0b70387746d6c544ed1818f276569d4258cf4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159888
Reviewed-by: Emad Omara <emadomara@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29810}
diff --git a/p2p/base/fake_dtls_transport.h b/p2p/base/fake_dtls_transport.h
index cf6fd78..7061ea4 100644
--- a/p2p/base/fake_dtls_transport.h
+++ b/p2p/base/fake_dtls_transport.h
@@ -83,7 +83,10 @@
ice_transport_->SetReceiving(receiving);
set_receiving(receiving);
}
- void SetDtlsState(DtlsTransportState state) { dtls_state_ = state; }
+ void SetDtlsState(DtlsTransportState state) {
+ dtls_state_ = state;
+ SignalDtlsState(this, dtls_state_);
+ }
// Simulates the two DTLS transports connecting to each other.
// If |asymmetric| is true this method only affects this FakeDtlsTransport.
@@ -108,12 +111,11 @@
if (!asymmetric) {
dest->SetDestination(this, true);
}
- dtls_state_ = DTLS_TRANSPORT_CONNECTED;
// If the |dtls_role_| is unset, set it to SSL_CLIENT by default.
if (!dtls_role_) {
dtls_role_ = std::move(rtc::SSL_CLIENT);
}
- SignalDtlsState(this, dtls_state_);
+ SetDtlsState(DTLS_TRANSPORT_CONNECTED);
ice_transport_->SetDestination(
static_cast<FakeIceTransport*>(dest->ice_transport()), asymmetric);
} else {
diff --git a/pc/data_channel.cc b/pc/data_channel.cc
index c5a8aeb..e87bb85 100644
--- a/pc/data_channel.cc
+++ b/pc/data_channel.cc
@@ -359,9 +359,10 @@
}
}
-void DataChannel::OnTransportChannelDestroyed() {
- // The SctpTransport is going away (for example, because the SCTP m= section
- // was rejected), so we need to close abruptly.
+void DataChannel::OnTransportChannelClosed() {
+ // The SctpTransport is unusable (for example, because the SCTP m= section
+ // was rejected, or because the DTLS transport closed), so we need to close
+ // abruptly.
CloseAbruptly();
}
diff --git a/pc/data_channel.h b/pc/data_channel.h
index 728226c..c7dc6ea 100644
--- a/pc/data_channel.h
+++ b/pc/data_channel.h
@@ -185,10 +185,10 @@
// Called when the transport channel is created.
// Only needs to be called for SCTP data channels.
void OnTransportChannelCreated();
- // Called when the transport channel is destroyed.
+ // Called when the transport channel is unusable.
// This method makes sure the DataChannel is disconnected and changes state
// to kClosed.
- void OnTransportChannelDestroyed();
+ void OnTransportChannelClosed();
/*******************************************
* The following methods are for RTP only. *
diff --git a/pc/data_channel_unittest.cc b/pc/data_channel_unittest.cc
index ad0e9b6..46e1df2 100644
--- a/pc/data_channel_unittest.cc
+++ b/pc/data_channel_unittest.cc
@@ -610,10 +610,10 @@
provider_->set_send_blocked(true);
EXPECT_TRUE(webrtc_data_channel_->Send(packet));
- // Tell the data channel that its tranpsort is being destroyed.
+ // Tell the data channel that its transport is being destroyed.
// It should then stop using the transport (allowing us to delete it) and
// transition to the "closed" state.
- webrtc_data_channel_->OnTransportChannelDestroyed();
+ webrtc_data_channel_->OnTransportChannelClosed();
provider_.reset(nullptr);
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed,
webrtc_data_channel_->state(), kDefaultTimeout);
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 1d7b4ea..9fac748 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -1106,7 +1106,7 @@
DestroyTransceiverChannel(transceiver);
}
}
- DestroyDataChannel();
+ DestroyDataChannelTransport();
}
bool PeerConnection::Initialize(
@@ -3597,7 +3597,7 @@
}
if (content.rejected) {
RTC_LOG(LS_INFO) << "Rejected data channel, mid=" << content.mid();
- DestroyDataChannel();
+ DestroyDataChannelTransport();
} else {
if (!rtp_data_channel_ && !data_channel_transport_) {
RTC_LOG(LS_INFO) << "Creating data channel, mid=" << content.mid();
@@ -5907,19 +5907,19 @@
}
}
-void PeerConnection::OnDataChannelDestroyed() {
+void PeerConnection::OnTransportChannelClosed() {
// Use a temporary copy of the RTP/SCTP DataChannel list because the
// DataChannel may callback to us and try to modify the list.
std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
temp_rtp_dcs.swap(rtp_data_channels_);
for (const auto& kv : temp_rtp_dcs) {
- kv.second->OnTransportChannelDestroyed();
+ kv.second->OnTransportChannelClosed();
}
std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
temp_sctp_dcs.swap(sctp_data_channels_);
for (const auto& channel : temp_sctp_dcs) {
- channel->OnTransportChannelDestroyed();
+ channel->OnTransportChannelClosed();
}
}
@@ -6978,7 +6978,7 @@
const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
if (!data_info || data_info->rejected) {
- DestroyDataChannel();
+ DestroyDataChannelTransport();
}
}
@@ -7709,9 +7709,9 @@
}
}
-void PeerConnection::DestroyDataChannel() {
+void PeerConnection::DestroyDataChannelTransport() {
if (rtp_data_channel_) {
- OnDataChannelDestroyed();
+ OnTransportChannelClosed();
DestroyChannelInterface(rtp_data_channel_);
rtp_data_channel_ = nullptr;
}
@@ -7723,7 +7723,7 @@
// rtc::Bind will cause "Pure virtual function called" error to appear.
if (sctp_mid_) {
- OnDataChannelDestroyed();
+ OnTransportChannelClosed();
network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
RTC_DCHECK_RUN_ON(network_thread());
TeardownDataChannelTransport_n();
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index cbff7e7..19af912 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -854,7 +854,8 @@
void OnSctpDataChannelClosed(DataChannel* channel)
RTC_RUN_ON(signaling_thread());
- void OnDataChannelDestroyed() RTC_RUN_ON(signaling_thread());
+ // Called when the transport for the data channels is closed or destroyed.
+ void OnTransportChannelClosed() RTC_RUN_ON(signaling_thread());
// Called when a valid data channel OPEN message is received.
void OnDataChannelOpenMessage(const std::string& label,
const InternalDataChannelInit& config)
@@ -1169,14 +1170,19 @@
const std::string GetTransportName(const std::string& content_name)
RTC_RUN_ON(signaling_thread());
+ // Functions for dealing with transports.
+ // Note that cricket code uses the term "channel" for what other code
+ // refers to as "transport".
+
// Destroys and clears the BaseChannel associated with the given transceiver,
// if such channel is set.
void DestroyTransceiverChannel(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
transceiver);
- // Destroys the RTP data channel and/or the SCTP data channel and clears it.
- void DestroyDataChannel() RTC_RUN_ON(signaling_thread());
+ // Destroys the RTP data channel transport and/or the SCTP data channel
+ // transport and clears it.
+ void DestroyDataChannelTransport() RTC_RUN_ON(signaling_thread());
// Destroys the given ChannelInterface.
// The channel cannot be accessed after this method is called.
diff --git a/pc/sctp_transport.cc b/pc/sctp_transport.cc
index 6c4a8be..532e91c 100644
--- a/pc/sctp_transport.cc
+++ b/pc/sctp_transport.cc
@@ -86,6 +86,8 @@
if (internal_sctp_transport_) {
if (transport) {
internal_sctp_transport_->SetDtlsTransport(transport->internal());
+ transport->internal()->SignalDtlsState.connect(
+ this, &SctpTransport::OnDtlsStateChange);
if (info_.state() == SctpTransportState::kNew) {
next_state = SctpTransportState::kConnecting;
}
@@ -162,4 +164,15 @@
UpdateInformation(SctpTransportState::kConnected);
}
+void SctpTransport::OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
+ cricket::DtlsTransportState state) {
+ RTC_DCHECK_RUN_ON(owner_thread_);
+ RTC_CHECK(transport == dtls_transport_->internal());
+ if (state == cricket::DTLS_TRANSPORT_CLOSED ||
+ state == cricket::DTLS_TRANSPORT_FAILED) {
+ UpdateInformation(SctpTransportState::kClosed);
+ // TODO(http://bugs.webrtc.org/11090): Close all the data channels
+ }
+}
+
} // namespace webrtc
diff --git a/pc/sctp_transport.h b/pc/sctp_transport.h
index c7727df..a13a58c 100644
--- a/pc/sctp_transport.h
+++ b/pc/sctp_transport.h
@@ -65,6 +65,8 @@
void OnAssociationChangeCommunicationUp();
void OnInternalClosingProcedureStartedRemotely(int sid);
void OnInternalClosingProcedureComplete(int sid);
+ void OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
+ cricket::DtlsTransportState state);
// Note - owner_thread never changes, but can't be const if we do
// Invoke() on it.
diff --git a/pc/sctp_transport_unittest.cc b/pc/sctp_transport_unittest.cc
index 8566ef3..f3070cd 100644
--- a/pc/sctp_transport_unittest.cc
+++ b/pc/sctp_transport_unittest.cc
@@ -195,4 +195,17 @@
*(observer_.LastReceivedInformation().MaxChannels()));
}
+TEST_F(SctpTransportTest, CloseWhenTransportCloses) {
+ CreateTransport();
+ transport()->RegisterObserver(observer());
+ AddDtlsTransport();
+ CompleteSctpHandshake();
+ ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
+ kDefaultTimeout);
+ static_cast<cricket::FakeDtlsTransport*>(dtls_transport_->internal())
+ ->SetDtlsState(cricket::DTLS_TRANSPORT_CLOSED);
+ ASSERT_EQ_WAIT(SctpTransportState::kClosed, observer_.State(),
+ kDefaultTimeout);
+}
+
} // namespace webrtc