diff --git a/p2p/base/fake_dtls_transport.h b/p2p/base/fake_dtls_transport.h index cf6fd784b1..7061ea4b3e 100644 --- a/p2p/base/fake_dtls_transport.h +++ b/p2p/base/fake_dtls_transport.h @@ -83,7 +83,10 @@ class FakeDtlsTransport : public DtlsTransportInternal { 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 @@ class FakeDtlsTransport : public DtlsTransportInternal { 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(dest->ice_transport()), asymmetric); } else { diff --git a/pc/data_channel.cc b/pc/data_channel.cc index c5a8aebdf3..e87bb85ca6 100644 --- a/pc/data_channel.cc +++ b/pc/data_channel.cc @@ -359,9 +359,10 @@ void DataChannel::OnTransportChannelCreated() { } } -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 728226cc35..c7dc6ea0ce 100644 --- a/pc/data_channel.h +++ b/pc/data_channel.h @@ -185,10 +185,10 @@ class DataChannel : public DataChannelInterface, public sigslot::has_slots<> { // 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 ad0e9b6d31..46e1df2d49 100644 --- a/pc/data_channel_unittest.cc +++ b/pc/data_channel_unittest.cc @@ -610,10 +610,10 @@ TEST_F(SctpDataChannelTest, TransportDestroyedWhileDataBuffered) { 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 1d7b4ea667..9fac7485ca 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -1106,7 +1106,7 @@ void PeerConnection::DestroyAllChannels() { DestroyTransceiverChannel(transceiver); } } - DestroyDataChannel(); + DestroyDataChannelTransport(); } bool PeerConnection::Initialize( @@ -3597,7 +3597,7 @@ RTCError PeerConnection::UpdateDataChannel( } 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::OnSctpDataChannelClosed(DataChannel* channel) { } } -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> 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> 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 @@ void PeerConnection::RemoveUnusedChannels(const SessionDescription* desc) { const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc); if (!data_info || data_info->rejected) { - DestroyDataChannel(); + DestroyDataChannelTransport(); } } @@ -7709,9 +7709,9 @@ void PeerConnection::DestroyTransceiverChannel( } } -void PeerConnection::DestroyDataChannel() { +void PeerConnection::DestroyDataChannelTransport() { if (rtp_data_channel_) { - OnDataChannelDestroyed(); + OnTransportChannelClosed(); DestroyChannelInterface(rtp_data_channel_); rtp_data_channel_ = nullptr; } @@ -7723,7 +7723,7 @@ void PeerConnection::DestroyDataChannel() { // rtc::Bind will cause "Pure virtual function called" error to appear. if (sctp_mid_) { - OnDataChannelDestroyed(); + OnTransportChannelClosed(); network_thread()->Invoke(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 cbff7e7050..19af912506 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h @@ -854,7 +854,8 @@ class PeerConnection : public PeerConnectionInternal, 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 @@ class PeerConnection : public PeerConnectionInternal, 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> 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 6c4a8bea9c..532e91c67d 100644 --- a/pc/sctp_transport.cc +++ b/pc/sctp_transport.cc @@ -86,6 +86,8 @@ void SctpTransport::SetDtlsTransport( 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 @@ void SctpTransport::OnAssociationChangeCommunicationUp() { 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 c7727df115..a13a58c68e 100644 --- a/pc/sctp_transport.h +++ b/pc/sctp_transport.h @@ -65,6 +65,8 @@ class SctpTransport : public SctpTransportInterface, 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 8566ef3eb5..f3070cd9a7 100644 --- a/pc/sctp_transport_unittest.cc +++ b/pc/sctp_transport_unittest.cc @@ -195,4 +195,17 @@ TEST_F(SctpTransportTest, MaxChannelsSignalled) { *(observer_.LastReceivedInformation().MaxChannels())); } +TEST_F(SctpTransportTest, CloseWhenTransportCloses) { + CreateTransport(); + transport()->RegisterObserver(observer()); + AddDtlsTransport(); + CompleteSctpHandshake(); + ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(), + kDefaultTimeout); + static_cast(dtls_transport_->internal()) + ->SetDtlsState(cricket::DTLS_TRANSPORT_CLOSED); + ASSERT_EQ_WAIT(SctpTransportState::kClosed, observer_.State(), + kDefaultTimeout); +} + } // namespace webrtc