diff --git a/p2p/base/fakedtlstransport.h b/p2p/base/fakedtlstransport.h index fef00fdd62..54b70180d1 100644 --- a/p2p/base/fakedtlstransport.h +++ b/p2p/base/fakedtlstransport.h @@ -91,6 +91,10 @@ class FakeDtlsTransport : public DtlsTransportInternal { dest_ = dest; if (local_cert_ && dest_->local_cert_) { do_dtls_ = true; + RTC_LOG(LS_INFO) << "FakeDtlsTransport is doing DTLS"; + } else { + do_dtls_ = false; + RTC_LOG(LS_INFO) << "FakeDtlsTransport is not doing DTLS"; } SetWritable(true); if (!asymmetric) { @@ -137,6 +141,7 @@ class FakeDtlsTransport : public DtlsTransportInternal { } bool SetLocalCertificate( const rtc::scoped_refptr& certificate) override { + do_dtls_ = true; local_cert_ = certificate; return true; } diff --git a/pc/channel.cc b/pc/channel.cc index b976cc0c37..ea4684f4f5 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -32,8 +32,6 @@ #include "p2p/base/packettransportinternal.h" #include "pc/channelmanager.h" #include "pc/rtpmediautils.h" -#include "pc/rtptransport.h" -#include "pc/srtptransport.h" namespace cricket { using rtc::Bind; @@ -64,9 +62,6 @@ enum { MSG_FIRSTPACKETRECEIVED, }; -// Value specified in RFC 5764. -static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp"; - static const int kAgcMinus10db = -10; static void SafeSetError(const std::string& message, std::string* error_desc) { @@ -144,30 +139,13 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread, signaling_thread_(signaling_thread), content_name_(content_name), rtcp_mux_required_(rtcp_mux_required), + unencrypted_rtp_transport_( + rtc::MakeUnique(rtcp_mux_required)), srtp_required_(srtp_required), media_channel_(std::move(media_channel)) { RTC_DCHECK_RUN_ON(worker_thread_); - if (srtp_required) { - auto transport = - rtc::MakeUnique(rtcp_mux_required, content_name); - srtp_transport_ = transport.get(); - rtp_transport_ = std::move(transport); -#if defined(ENABLE_EXTERNAL_AUTH) - srtp_transport_->EnableExternalAuth(); -#endif - } else { - rtp_transport_ = rtc::MakeUnique(rtcp_mux_required); - srtp_transport_ = nullptr; - } - rtp_transport_->SignalReadyToSend.connect( - this, &BaseChannel::OnTransportReadyToSend); - // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced - // with a callback interface later so that the demuxer can select which - // channel to signal. - rtp_transport_->SignalPacketReceived.connect(this, - &BaseChannel::OnPacketReceived); - rtp_transport_->SignalNetworkRouteChanged.connect( - this, &BaseChannel::OnNetworkRouteChanged); + rtp_transport_ = unencrypted_rtp_transport_.get(); + ConnectToRtpTransport(); RTC_LOG(LS_INFO) << "Created channel for " << content_name; } @@ -186,29 +164,30 @@ BaseChannel::~BaseChannel() { RTC_LOG(LS_INFO) << "Destroyed channel: " << content_name_; } -void BaseChannel::DisconnectTransportChannels_n() { - // Send any outstanding RTCP packets. - FlushRtcpMessages_n(); +void BaseChannel::ConnectToRtpTransport() { + RTC_DCHECK(rtp_transport_); + rtp_transport_->SignalReadyToSend.connect( + this, &BaseChannel::OnTransportReadyToSend); + // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced + // with a callback interface later so that the demuxer can select which + // channel to signal. + rtp_transport_->SignalPacketReceived.connect(this, + &BaseChannel::OnPacketReceived); + rtp_transport_->SignalNetworkRouteChanged.connect( + this, &BaseChannel::OnNetworkRouteChanged); + rtp_transport_->SignalWritableState.connect(this, + &BaseChannel::OnWritableState); + rtp_transport_->SignalSentPacket.connect(this, + &BaseChannel::SignalSentPacket_n); +} - // Stop signals from transport channels, but keep them alive because - // media_channel may use them from a different thread. - if (rtp_dtls_transport_) { - DisconnectFromDtlsTransport(rtp_dtls_transport_); - } else if (rtp_transport_->rtp_packet_transport()) { - DisconnectFromPacketTransport(rtp_transport_->rtp_packet_transport()); - } - if (rtcp_dtls_transport_) { - DisconnectFromDtlsTransport(rtcp_dtls_transport_); - } else if (rtp_transport_->rtcp_packet_transport()) { - DisconnectFromPacketTransport(rtp_transport_->rtcp_packet_transport()); - } - - rtp_transport_->SetRtpPacketTransport(nullptr); - rtp_transport_->SetRtcpPacketTransport(nullptr); - - // Clear pending read packets/messages. - network_thread_->Clear(&invoker_); - network_thread_->Clear(this); +void BaseChannel::DisconnectFromRtpTransport() { + RTC_DCHECK(rtp_transport_); + rtp_transport_->SignalReadyToSend.disconnect(this); + rtp_transport_->SignalPacketReceived.disconnect(this); + rtp_transport_->SignalNetworkRouteChanged.disconnect(this); + rtp_transport_->SignalWritableState.disconnect(this); + rtp_transport_->SignalSentPacket.disconnect(this); } void BaseChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, @@ -246,8 +225,19 @@ void BaseChannel::Deinit() { // Packets arrive on the network thread, processing packets calls virtual // functions, so need to stop this process in Deinit that is called in // derived classes destructor. - network_thread_->Invoke( - RTC_FROM_HERE, Bind(&BaseChannel::DisconnectTransportChannels_n, this)); + network_thread_->Invoke(RTC_FROM_HERE, [&] { + FlushRtcpMessages_n(); + + if (dtls_srtp_transport_) { + dtls_srtp_transport_->SetDtlsTransports(nullptr, nullptr); + } else { + rtp_transport_->SetRtpPacketTransport(nullptr); + rtp_transport_->SetRtcpPacketTransport(nullptr); + } + // Clear pending read packets/messages. + network_thread_->Clear(&invoker_); + network_thread_->Clear(this); + }); } void BaseChannel::SetTransports(DtlsTransportInternal* rtp_dtls_transport, @@ -290,6 +280,12 @@ void BaseChannel::SetTransports_n( RTC_DCHECK(rtp_dtls_transport->transport_name() == rtcp_dtls_transport->transport_name()); } + + if (rtp_packet_transport == rtp_transport_->rtp_packet_transport()) { + // Nothing to do if transport isn't changing. + return; + } + std::string debug_name; if (rtp_dtls_transport) { transport_name_ = rtp_dtls_transport->transport_name(); @@ -297,36 +293,31 @@ void BaseChannel::SetTransports_n( } else { debug_name = rtp_packet_transport->transport_name(); } - if (rtp_packet_transport == rtp_transport_->rtp_packet_transport()) { - // Nothing to do if transport isn't changing. - return; - } - - // When using DTLS-SRTP, we must reset the SrtpTransport every time the - // DtlsTransport changes and wait until the DTLS handshake is complete to set - // the newly negotiated parameters. - if (ShouldSetupDtlsSrtp_n()) { - // Set |writable_| to false such that UpdateWritableState_w can set up - // DTLS-SRTP when |writable_| becomes true again. - writable_ = false; - dtls_active_ = false; - if (srtp_transport_) { - srtp_transport_->ResetParams(); - } - } - // If this BaseChannel doesn't require RTCP mux and we haven't fully // negotiated RTCP mux, we need an RTCP transport. if (rtcp_packet_transport) { RTC_LOG(LS_INFO) << "Setting RTCP Transport for " << content_name() << " on " << debug_name << " transport " << rtcp_packet_transport; - SetTransport_n(true, rtcp_dtls_transport, rtcp_packet_transport); + SetTransport_n(/*rtcp=*/true, rtcp_dtls_transport, rtcp_packet_transport); } RTC_LOG(LS_INFO) << "Setting RTP Transport for " << content_name() << " on " << debug_name << " transport " << rtp_packet_transport; - SetTransport_n(false, rtp_dtls_transport, rtp_packet_transport); + SetTransport_n(/*rtcp=*/false, rtp_dtls_transport, rtp_packet_transport); + + // Set DtlsTransport/PacketTransport for RTP-level transport. + if ((rtp_dtls_transport_ || rtcp_dtls_transport_) && dtls_srtp_transport_) { + // When setting the transport with non-null |dtls_srtp_transport_|, we are + // using DTLS-SRTP. This could happen for bundling. If the + // |dtls_srtp_transport| is null, we cannot tell if it doing DTLS-SRTP or + // SDES until the description is set. So don't call |EnableDtlsSrtp_n| here. + dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport, + rtcp_dtls_transport); + } else { + rtp_transport_->SetRtpPacketTransport(rtp_packet_transport); + rtp_transport_->SetRtcpPacketTransport(rtcp_packet_transport); + } // Update aggregate writable/ready-to-send state between RTP and RTCP upon // setting new transport channels. @@ -353,20 +344,10 @@ void BaseChannel::SetTransport_n( } RTC_DCHECK(old_packet_transport != new_packet_transport); - if (old_dtls_transport) { - DisconnectFromDtlsTransport(old_dtls_transport); - } else if (old_packet_transport) { - DisconnectFromPacketTransport(old_packet_transport); - } - if (rtcp) { - rtp_transport_->SetRtcpPacketTransport(new_packet_transport); - } else { - rtp_transport_->SetRtpPacketTransport(new_packet_transport); - } old_dtls_transport = new_dtls_transport; - // If there's no new transport, we're done after disconnecting from old one. + // If there's no new transport, we're done. if (!new_packet_transport) { return; } @@ -377,48 +358,12 @@ void BaseChannel::SetTransport_n( << "should never happen."; } - if (new_dtls_transport) { - ConnectToDtlsTransport(new_dtls_transport); - } else { - ConnectToPacketTransport(new_packet_transport); - } auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; for (const auto& pair : socket_options) { new_packet_transport->SetOption(pair.first, pair.second); } } -void BaseChannel::ConnectToDtlsTransport(DtlsTransportInternal* transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // TODO(zstein): de-dup with ConnectToPacketTransport - transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState); - transport->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState); - transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n); -} - -void BaseChannel::DisconnectFromDtlsTransport( - DtlsTransportInternal* transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - transport->SignalWritableState.disconnect(this); - transport->SignalDtlsState.disconnect(this); - transport->SignalSentPacket.disconnect(this); -} - -void BaseChannel::ConnectToPacketTransport( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK_RUN_ON(network_thread_); - transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState); - transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n); -} - -void BaseChannel::DisconnectFromPacketTransport( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK_RUN_ON(network_thread_); - transport->SignalWritableState.disconnect(this); - transport->SignalSentPacket.disconnect(this); -} - bool BaseChannel::Enable(bool enable) { worker_thread_->Invoke( RTC_FROM_HERE, @@ -558,29 +503,17 @@ int BaseChannel::SetOption_n(SocketType type, return transport ? transport->SetOption(opt, value) : -1; } -void BaseChannel::OnWritableState(rtc::PacketTransportInternal* transport) { - RTC_DCHECK(transport == rtp_transport_->rtp_packet_transport() || - transport == rtp_transport_->rtcp_packet_transport()); +void BaseChannel::OnWritableState(bool writable) { RTC_DCHECK(network_thread_->IsCurrent()); - UpdateWritableState_n(); -} - -void BaseChannel::OnDtlsState(DtlsTransportInternal* transport, - DtlsTransportState state) { - if (!ShouldSetupDtlsSrtp_n()) { - return; - } - - // Reset the SrtpTransport if it's not the CONNECTED state. For the CONNECTED - // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to - // cover other scenarios like the whole transport is writable (not just this - // TransportChannel) or when TransportChannel is attached after DTLS is - // negotiated. - if (state != DTLS_TRANSPORT_CONNECTED) { - dtls_active_ = false; - if (srtp_transport_) { - srtp_transport_->ResetParams(); + if (writable) { + // This is used to cover the scenario when the DTLS handshake is completed + // and DtlsTransport becomes writable before the remote description is set. + if (ShouldSetupDtlsSrtp_n()) { + EnableDtlsSrtp_n(); } + ChannelWritable_n(); + } else { + ChannelNotWritable_n(); } } @@ -658,16 +591,18 @@ bool BaseChannel::SendPacket(bool rtcp, RTC_NOTREACHED(); return false; } - // Bon voyage. - return rtcp - ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS) - : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS); + + std::string packet_type = rtcp ? "RTCP" : "RTP"; + RTC_LOG(LS_WARNING) << "Sending an " << packet_type + << " packet without encryption."; + } else { + // Make sure we didn't accidentally send any packets without encryption. + RTC_DCHECK(rtp_transport_ == sdes_transport_.get() || + rtp_transport_ == dtls_srtp_transport_.get()); } - RTC_DCHECK(srtp_transport_); - RTC_DCHECK(srtp_transport_->IsActive()); // Bon voyage. - return rtcp ? srtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS) - : srtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS); + return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS) + : rtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS); } bool BaseChannel::HandlesPayloadType(int packet_type) const { @@ -763,164 +698,15 @@ void BaseChannel::ChannelWritable_n() { << (was_ever_writable_ ? "" : " for the first time"); was_ever_writable_ = true; - MaybeSetupDtlsSrtp_n(); writable_ = true; UpdateMediaSendRecvState(); } -void BaseChannel::SignalDtlsSrtpSetupFailure_n(bool rtcp) { - RTC_DCHECK(network_thread_->IsCurrent()); - invoker_.AsyncInvoke( - RTC_FROM_HERE, signaling_thread(), - Bind(&BaseChannel::SignalDtlsSrtpSetupFailure_s, this, rtcp)); -} - -void BaseChannel::SignalDtlsSrtpSetupFailure_s(bool rtcp) { - RTC_DCHECK(signaling_thread() == rtc::Thread::Current()); - SignalDtlsSrtpSetupFailure(this, rtcp); -} - bool BaseChannel::ShouldSetupDtlsSrtp_n() const { // Since DTLS is applied to all transports, checking RTP should be enough. return rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive(); } -// This function returns true if either DTLS-SRTP is not in use -// *or* DTLS-SRTP is successfully set up. -bool BaseChannel::SetupDtlsSrtp_n(bool rtcp) { - RTC_DCHECK(network_thread_->IsCurrent()); - bool ret = false; - - DtlsTransportInternal* transport = - rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_; - RTC_DCHECK(transport); - RTC_DCHECK(transport->IsDtlsActive()); - - int selected_crypto_suite; - - if (!transport->GetSrtpCryptoSuite(&selected_crypto_suite)) { - RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite"; - return false; - } - - RTC_LOG(LS_INFO) << "Installing keys from DTLS-SRTP on " << content_name() - << " " << RtpRtcpStringLiteral(rtcp); - - int key_len; - int salt_len; - if (!rtc::GetSrtpKeyAndSaltLengths(selected_crypto_suite, &key_len, - &salt_len)) { - RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite" - << selected_crypto_suite; - return false; - } - - // OK, we're now doing DTLS (RFC 5764) - std::vector dtls_buffer(key_len * 2 + salt_len * 2); - - // RFC 5705 exporter using the RFC 5764 parameters - if (!transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0, false, - &dtls_buffer[0], dtls_buffer.size())) { - RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed"; - RTC_NOTREACHED(); // This should never happen - return false; - } - - // Sync up the keys with the DTLS-SRTP interface - std::vector client_write_key(key_len + salt_len); - std::vector server_write_key(key_len + salt_len); - size_t offset = 0; - memcpy(&client_write_key[0], &dtls_buffer[offset], key_len); - offset += key_len; - memcpy(&server_write_key[0], &dtls_buffer[offset], key_len); - offset += key_len; - memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len); - offset += salt_len; - memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len); - - std::vector *send_key, *recv_key; - rtc::SSLRole role; - if (!transport->GetSslRole(&role)) { - RTC_LOG(LS_WARNING) << "GetSslRole failed"; - return false; - } - - if (role == rtc::SSL_SERVER) { - send_key = &server_write_key; - recv_key = &client_write_key; - } else { - send_key = &client_write_key; - recv_key = &server_write_key; - } - - // Use an empty encrypted header extension ID vector if not set. This could - // happen when the DTLS handshake is completed before processing the - // Offer/Answer which contains the encrypted header extension IDs. - std::vector send_extension_ids; - std::vector recv_extension_ids; - if (catched_send_extension_ids_) { - send_extension_ids = *catched_send_extension_ids_; - } - if (catched_recv_extension_ids_) { - recv_extension_ids = *catched_recv_extension_ids_; - } - - if (rtcp) { - if (!dtls_active()) { - RTC_DCHECK(srtp_transport_); - ret = srtp_transport_->SetRtcpParams( - selected_crypto_suite, &(*send_key)[0], - static_cast(send_key->size()), send_extension_ids, - selected_crypto_suite, &(*recv_key)[0], - static_cast(recv_key->size()), recv_extension_ids); - } else { - // RTCP doesn't need to call SetRtpParam because it is only used - // to make the updated encrypted RTP header extension IDs take effect. - ret = true; - } - } else { - RTC_DCHECK(srtp_transport_); - ret = srtp_transport_->SetRtpParams( - selected_crypto_suite, &(*send_key)[0], - static_cast(send_key->size()), send_extension_ids, - selected_crypto_suite, &(*recv_key)[0], - static_cast(recv_key->size()), recv_extension_ids); - dtls_active_ = ret; - } - - if (!ret) { - RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation failed"; - } - - return ret; -} - -void BaseChannel::MaybeSetupDtlsSrtp_n() { - if (dtls_active()) { - return; - } - - if (!ShouldSetupDtlsSrtp_n()) { - return; - } - - if (!srtp_transport_) { - EnableSrtpTransport_n(); - } - - if (!SetupDtlsSrtp_n(false)) { - SignalDtlsSrtpSetupFailure_n(false); - return; - } - - if (rtcp_dtls_transport_) { - if (!SetupDtlsSrtp_n(true)) { - SignalDtlsSrtpSetupFailure_n(true); - return; - } - } -} - void BaseChannel::ChannelNotWritable_n() { RTC_DCHECK(network_thread_->IsCurrent()); if (!writable_) @@ -986,25 +772,57 @@ bool BaseChannel::CheckSrtpConfig_n(const std::vector& cryptos, return true; } -void BaseChannel::EnableSrtpTransport_n() { - if (srtp_transport_ == nullptr) { - rtp_transport_->SignalReadyToSend.disconnect(this); - rtp_transport_->SignalPacketReceived.disconnect(this); - rtp_transport_->SignalNetworkRouteChanged.disconnect(this); - - auto transport = rtc::MakeUnique( - std::move(rtp_transport_), content_name_); - srtp_transport_ = transport.get(); - rtp_transport_ = std::move(transport); - - rtp_transport_->SignalReadyToSend.connect( - this, &BaseChannel::OnTransportReadyToSend); - rtp_transport_->SignalPacketReceived.connect( - this, &BaseChannel::OnPacketReceived); - rtp_transport_->SignalNetworkRouteChanged.connect( - this, &BaseChannel::OnNetworkRouteChanged); - RTC_LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport."; +void BaseChannel::EnableSdes_n() { + if (sdes_transport_) { + return; } + // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same + // time. + RTC_DCHECK(!dtls_srtp_transport_); + RTC_DCHECK(unencrypted_rtp_transport_); + DisconnectFromRtpTransport(); + sdes_transport_ = rtc::MakeUnique( + std::move(unencrypted_rtp_transport_), content_name_); + rtp_transport_ = sdes_transport_.get(); + ConnectToRtpTransport(); + RTC_LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport."; +} + +void BaseChannel::EnableDtlsSrtp_n() { + if (dtls_srtp_transport_) { + return; + } + // DtlsSrtpTransport and SrtpTransport shouldn't be enabled at the same + // time. + RTC_DCHECK(!sdes_transport_); + RTC_DCHECK(unencrypted_rtp_transport_); + DisconnectFromRtpTransport(); + + auto srtp_transport = rtc::MakeUnique( + std::move(unencrypted_rtp_transport_), content_name_); +#if defined(ENABLE_EXTERNAL_AUTH) + srtp_transport->EnableExternalAuth(); +#endif + dtls_srtp_transport_ = + rtc::MakeUnique(std::move(srtp_transport)); + + rtp_transport_ = dtls_srtp_transport_.get(); + ConnectToRtpTransport(); + if (cached_send_extension_ids_) { + dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds( + *cached_send_extension_ids_); + } + if (cached_recv_extension_ids_) { + dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds( + *cached_recv_extension_ids_); + } + // Set the DtlsTransport and the |dtls_srtp_transport_| will handle the DTLS + // relate signal internally. + RTC_DCHECK(rtp_dtls_transport_); + dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport_, + rtcp_dtls_transport_); + + RTC_LOG(LS_INFO) << "Wrapping SrtpTransport in DtlsSrtpTransport."; } bool BaseChannel::SetSrtp_n(const std::vector& cryptos, @@ -1022,75 +840,59 @@ bool BaseChannel::SetSrtp_n(const std::vector& cryptos, // If SRTP was not required, but we're setting a description that uses SDES, // we need to upgrade to an SrtpTransport. - if (!srtp_transport_ && !dtls && !cryptos.empty()) { - EnableSrtpTransport_n(); + if (!sdes_transport_ && !dtls && !cryptos.empty()) { + EnableSdes_n(); } - bool encrypted_header_extensions_id_changed = - EncryptedHeaderExtensionIdsChanged(src, encrypted_extension_ids); - CacheEncryptedHeaderExtensionIds(src, encrypted_extension_ids); + if ((action == CA_ANSWER || action == CA_PRANSWER) && dtls) { + EnableDtlsSrtp_n(); + } - switch (action) { - case CA_OFFER: - // If DTLS is already active on the channel, we could be renegotiating - // here. We don't update the srtp filter. - if (!dtls) { + UpdateEncryptedHeaderExtensionIds(src, encrypted_extension_ids); + + if (!dtls) { + switch (action) { + case CA_OFFER: ret = sdes_negotiator_.SetOffer(cryptos, src); - } - break; - case CA_PRANSWER: - // If we're doing DTLS-SRTP, we don't want to update the filter - // with an answer, because we already have SRTP parameters. - if (!dtls) { + break; + case CA_PRANSWER: ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src); - } - break; - case CA_ANSWER: - // If we're doing DTLS-SRTP, we don't want to update the filter - // with an answer, because we already have SRTP parameters. - if (!dtls) { + break; + case CA_ANSWER: ret = sdes_negotiator_.SetAnswer(cryptos, src); - } - break; - default: - break; - } + break; + default: + break; + } - // If setting an SDES answer succeeded, apply the negotiated parameters - // to the SRTP transport. - if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) { - if (sdes_negotiator_.send_cipher_suite() && - sdes_negotiator_.recv_cipher_suite()) { - RTC_DCHECK(catched_send_extension_ids_); - RTC_DCHECK(catched_recv_extension_ids_); - ret = srtp_transport_->SetRtpParams( - *(sdes_negotiator_.send_cipher_suite()), - sdes_negotiator_.send_key().data(), - static_cast(sdes_negotiator_.send_key().size()), - *(catched_send_extension_ids_), - *(sdes_negotiator_.recv_cipher_suite()), - sdes_negotiator_.recv_key().data(), - static_cast(sdes_negotiator_.recv_key().size()), - *(catched_recv_extension_ids_)); - } else { - RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES."; - if (action == CA_ANSWER && srtp_transport_) { - // Explicitly reset the |srtp_transport_| if no crypto param is - // provided in the answer. No need to call |ResetParams()| for - // |sdes_negotiator_| because it resets the params inside |SetAnswer|. - srtp_transport_->ResetParams(); + // If setting an SDES answer succeeded, apply the negotiated parameters + // to the SRTP transport. + if ((action == CA_PRANSWER || action == CA_ANSWER) && ret) { + if (sdes_negotiator_.send_cipher_suite() && + sdes_negotiator_.recv_cipher_suite()) { + RTC_DCHECK(cached_send_extension_ids_); + RTC_DCHECK(cached_recv_extension_ids_); + ret = sdes_transport_->SetRtpParams( + *(sdes_negotiator_.send_cipher_suite()), + sdes_negotiator_.send_key().data(), + static_cast(sdes_negotiator_.send_key().size()), + *(cached_send_extension_ids_), + *(sdes_negotiator_.recv_cipher_suite()), + sdes_negotiator_.recv_key().data(), + static_cast(sdes_negotiator_.recv_key().size()), + *(cached_recv_extension_ids_)); + } else { + RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES."; + if (action == CA_ANSWER && sdes_transport_) { + // Explicitly reset the |sdes_transport_| if no crypto param is + // provided in the answer. No need to call |ResetParams()| for + // |sdes_negotiator_| because it resets the params inside |SetAnswer|. + sdes_transport_->ResetParams(); + } } } } - // Only update SRTP transport if using DTLS. SDES is handled internally - // by the SRTP filter. - if (ret && dtls_active() && rtp_dtls_transport_ && - rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED && - encrypted_header_extensions_id_changed) { - ret = SetupDtlsSrtp_n(/*rtcp=*/false); - } - if (!ret) { SafeSetError("Failed to setup SRTP.", error_desc); return false; @@ -1124,20 +926,7 @@ bool BaseChannel::SetRtcpMux_n(bool enable, case CA_ANSWER: ret = rtcp_mux_filter_.SetAnswer(enable, src); if (ret && rtcp_mux_filter_.IsActive()) { - // We permanently activated RTCP muxing; signal that we no longer need - // the RTCP transport. - std::string debug_name = - transport_name_.empty() - ? rtp_transport_->rtp_packet_transport()->transport_name() - : transport_name_; - RTC_LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() - << "; no longer need RTCP transport for " - << debug_name; - if (rtp_transport_->rtcp_packet_transport()) { - SetTransport_n(true, nullptr, nullptr); - SignalRtcpMuxFullyActive(transport_name_); - } - UpdateWritableState_n(); + ActivateRtcpMux(); } break; default: @@ -1285,8 +1074,8 @@ void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w( void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( int rtp_abs_sendtime_extn_id) { - if (srtp_transport_) { - srtp_transport_->CacheRtpAbsSendTimeHeaderExtension( + if (sdes_transport_) { + sdes_transport_->CacheRtpAbsSendTimeHeaderExtension( rtp_abs_sendtime_extn_id); } else { RTC_LOG(LS_WARNING) @@ -1331,9 +1120,7 @@ void BaseChannel::FlushRtcpMessages_n() { } } -void BaseChannel::SignalSentPacket_n( - rtc::PacketTransportInternal* /* transport */, - const rtc::SentPacket& sent_packet) { +void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) { RTC_DCHECK(network_thread_->IsCurrent()); invoker_.AsyncInvoke( RTC_FROM_HERE, worker_thread_, @@ -1345,24 +1132,45 @@ void BaseChannel::SignalSentPacket_w(const rtc::SentPacket& sent_packet) { SignalSentPacket(sent_packet); } -void BaseChannel::CacheEncryptedHeaderExtensionIds( +void BaseChannel::UpdateEncryptedHeaderExtensionIds( cricket::ContentSource source, const std::vector& extension_ids) { - source == ContentSource::CS_LOCAL - ? catched_recv_extension_ids_.emplace(extension_ids) - : catched_send_extension_ids_.emplace(extension_ids); + if (source == ContentSource::CS_LOCAL) { + cached_recv_extension_ids_ = std::move(extension_ids); + if (dtls_srtp_transport_) { + dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds( + extension_ids); + } + } else { + cached_send_extension_ids_ = std::move(extension_ids); + if (dtls_srtp_transport_) { + dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds( + extension_ids); + } + } } -bool BaseChannel::EncryptedHeaderExtensionIdsChanged( - cricket::ContentSource source, - const std::vector& new_extension_ids) { - if (source == ContentSource::CS_LOCAL) { - return !catched_recv_extension_ids_ || - (*catched_recv_extension_ids_) != new_extension_ids; - } else { - return !catched_send_extension_ids_ || - (*catched_send_extension_ids_) != new_extension_ids; +void BaseChannel::ActivateRtcpMux() { + // We permanently activated RTCP muxing; signal that we no longer need + // the RTCP transport. + std::string debug_name = + transport_name_.empty() + ? rtp_transport_->rtp_packet_transport()->transport_name() + : transport_name_; + RTC_LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() + << "; no longer need RTCP transport for " << debug_name; + if (rtp_transport_->rtcp_packet_transport()) { + SetTransport_n(/*rtcp=*/true, nullptr, nullptr); + if (dtls_srtp_transport_) { + RTC_DCHECK(rtp_dtls_transport_); + dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport_, + /*rtcp_dtls_transport_=*/nullptr); + } else { + rtp_transport_->SetRtcpPacketTransport(nullptr); + } + SignalRtcpMuxFullyActive(transport_name_); } + UpdateWritableState_n(); } VoiceChannel::VoiceChannel(rtc::Thread* worker_thread, diff --git a/pc/channel.h b/pc/channel.h index dbc636773d..1c4e50a016 100644 --- a/pc/channel.h +++ b/pc/channel.h @@ -29,10 +29,13 @@ #include "p2p/base/packettransportinternal.h" #include "p2p/client/socketmonitor.h" #include "pc/audiomonitor.h" +#include "pc/dtlssrtptransport.h" #include "pc/mediamonitor.h" #include "pc/mediasession.h" #include "pc/rtcpmuxfilter.h" +#include "pc/rtptransport.h" #include "pc/srtpfilter.h" +#include "pc/srtptransport.h" #include "pc/transportcontroller.h" #include "rtc_base/asyncinvoker.h" #include "rtc_base/asyncudpsocket.h" @@ -43,8 +46,6 @@ namespace webrtc { class AudioSinkInterface; -class RtpTransportInternal; -class SrtpTransport; } // namespace webrtc namespace cricket { @@ -101,9 +102,13 @@ class BaseChannel bool enabled() const { return enabled_; } // This function returns true if we are using SDES. - bool sdes_active() const { return sdes_negotiator_.IsActive(); } + bool sdes_active() const { + return sdes_transport_ && sdes_negotiator_.IsActive(); + } // The following function returns true if we are using DTLS-based keying. - bool dtls_active() const { return dtls_active_; } + bool dtls_active() const { + return dtls_srtp_transport_ && dtls_srtp_transport_->IsActive(); + } // This function returns true if using SRTP (DTLS-based keying or SDES). bool srtp_active() const { return sdes_active() || dtls_active(); } @@ -225,11 +230,6 @@ class BaseChannel bool IsReadyToSendMedia_w() const; rtc::Thread* signaling_thread() { return signaling_thread_; } - void ConnectToDtlsTransport(DtlsTransportInternal* transport); - void DisconnectFromDtlsTransport(DtlsTransportInternal* transport); - void ConnectToPacketTransport(rtc::PacketTransportInternal* transport); - void DisconnectFromPacketTransport(rtc::PacketTransportInternal* transport); - void FlushRtcpMessages_n(); // NetworkInterface implementation, called by MediaEngine @@ -238,10 +238,8 @@ class BaseChannel bool SendRtcp(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options) override; - // From TransportChannel - void OnWritableState(rtc::PacketTransportInternal* transport); - - void OnDtlsState(DtlsTransportInternal* transport, DtlsTransportState state); + // From RtpTransportInternal + void OnWritableState(bool writable); void OnNetworkRouteChanged(rtc::Optional network_route); @@ -349,30 +347,34 @@ class BaseChannel void AddHandledPayloadType(int payload_type); private: + void ConnectToRtpTransport(); + void DisconnectFromRtpTransport(); void InitNetwork_n(DtlsTransportInternal* rtp_dtls_transport, DtlsTransportInternal* rtcp_dtls_transport, rtc::PacketTransportInternal* rtp_packet_transport, rtc::PacketTransportInternal* rtcp_packet_transport); - void DisconnectTransportChannels_n(); - void SignalSentPacket_n(rtc::PacketTransportInternal* transport, - const rtc::SentPacket& sent_packet); + void SignalSentPacket_n(const rtc::SentPacket& sent_packet); void SignalSentPacket_w(const rtc::SentPacket& sent_packet); bool IsReadyToSendMedia_n() const; void CacheRtpAbsSendTimeHeaderExtension_n(int rtp_abs_sendtime_extn_id); // Wraps the existing RtpTransport in an SrtpTransport. - void EnableSrtpTransport_n(); + void EnableSdes_n(); - // Cache the encrypted header extension IDs when setting the local/remote + // Wraps the existing RtpTransport in a new SrtpTransport and wraps that in a + // new DtlsSrtpTransport. + void EnableDtlsSrtp_n(); + + // Update the encrypted header extension IDs when setting the local/remote // description and use them later together with other crypto parameters from - // DtlsTransport. - void CacheEncryptedHeaderExtensionIds(cricket::ContentSource source, - const std::vector& extension_ids); + // DtlsTransport. If DTLS-SRTP is enabled, it also update the encrypted header + // extension IDs for DtlsSrtpTransport. + void UpdateEncryptedHeaderExtensionIds(cricket::ContentSource source, + const std::vector& extension_ids); - // Return true if the new header extension IDs are different from the existing - // ones. - bool EncryptedHeaderExtensionIdsChanged( - cricket::ContentSource source, - const std::vector& new_extension_ids); + // Permanently enable RTCP muxing. Set null RTCP PacketTransport for + // BaseChannel and RtpTransport. If using DTLS-SRTP, set null DtlsTransport + // for DtlsSrtpTransport. + void ActivateRtcpMux(); rtc::Thread* const worker_thread_; rtc::Thread* const network_thread_; @@ -392,8 +394,14 @@ class BaseChannel // If non-null, "X_dtls_transport_" will always equal "X_packet_transport_". DtlsTransportInternal* rtp_dtls_transport_ = nullptr; DtlsTransportInternal* rtcp_dtls_transport_ = nullptr; - std::unique_ptr rtp_transport_; - webrtc::SrtpTransport* srtp_transport_ = nullptr; + + webrtc::RtpTransportInternal* rtp_transport_ = nullptr; + // Only one of these transports is non-null at a time. One for DTLS-SRTP, one + // for SDES and one for unencrypted RTP. + std::unique_ptr sdes_transport_; + std::unique_ptr dtls_srtp_transport_; + std::unique_ptr unencrypted_rtp_transport_; + std::vector > socket_options_; std::vector > rtcp_socket_options_; SrtpFilter sdes_negotiator_; @@ -401,7 +409,6 @@ class BaseChannel bool writable_ = false; bool was_ever_writable_ = false; bool has_received_packet_ = false; - bool dtls_active_ = false; const bool srtp_required_ = true; // MediaChannel related members that should be accessed from the worker @@ -419,8 +426,8 @@ class BaseChannel webrtc::RtpTransceiverDirection::kInactive; // The cached encrypted header extension IDs. - rtc::Optional> catched_send_extension_ids_; - rtc::Optional> catched_recv_extension_ids_; + rtc::Optional> cached_send_extension_ids_; + rtc::Optional> cached_recv_extension_ids_; }; // VoiceChannel is a specialization that adds support for early media, DTMF, diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc index d1ceac5160..7cc5dec8af 100644 --- a/pc/channel_unittest.cc +++ b/pc/channel_unittest.cc @@ -1398,6 +1398,17 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtcp2()); } + // Test that the DTLS to SDES fallback is not supported and the negotiation + // between DTLS to SDES end points will fail. + void SendDtlsToSdesNotSupported() { + int flags1 = SECURE | DTLS; + int flags2 = SECURE; + CreateChannels(flags1, flags2); + EXPECT_FALSE(channel1_->srtp_active()); + EXPECT_FALSE(channel2_->srtp_active()); + EXPECT_FALSE(SendInitiate()); + } + // Test that we properly handling SRTP negotiating down to RTP. void SendSrtpToRtp() { CreateChannels(SECURE, 0); @@ -1982,7 +1993,7 @@ void ChannelTest::CreateContent( cricket::AudioContentDescription* audio) { audio->AddCodec(audio_codec); audio->set_rtcp_mux((flags & RTCP_MUX) != 0); - if (flags & SECURE) { + if ((flags & SECURE) && !(flags & DTLS)) { audio->AddCrypto(cricket::CryptoParams( 1, rtc::CS_AES_CM_128_HMAC_SHA1_32, "inline:" + rtc::CreateRandomString(40), std::string())); @@ -2295,7 +2306,7 @@ TEST_F(VoiceChannelSingleThreadTest, SendSrtcpMux) { } TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendSrtpToSrtp(DTLS, 0); + Base::SendDtlsToSdesNotSupported(); } TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) { @@ -2646,7 +2657,7 @@ TEST_F(VoiceChannelDoubleThreadTest, SendSrtcpMux) { } TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendSrtpToSrtp(DTLS, 0); + Base::SendDtlsToSdesNotSupported(); } TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) { @@ -2947,7 +2958,7 @@ TEST_F(VideoChannelSingleThreadTest, SendSrtpToRtp) { } TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendSrtpToSrtp(DTLS, 0); + Base::SendDtlsToSdesNotSupported(); } TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) { @@ -3170,7 +3181,7 @@ TEST_F(VideoChannelDoubleThreadTest, SendSrtpToRtp) { } TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendSrtpToSrtp(DTLS, 0); + Base::SendDtlsToSdesNotSupported(); } TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) { diff --git a/pc/dtlssrtptransport.cc b/pc/dtlssrtptransport.cc index 1c2d21f429..bc5d3aa900 100644 --- a/pc/dtlssrtptransport.cc +++ b/pc/dtlssrtptransport.cc @@ -33,6 +33,10 @@ DtlsSrtpTransport::DtlsSrtpTransport( this, &DtlsSrtpTransport::OnPacketReceived); srtp_transport_->SignalReadyToSend.connect(this, &DtlsSrtpTransport::OnReadyToSend); + srtp_transport_->SignalWritableState.connect( + this, &DtlsSrtpTransport::OnWritableState); + srtp_transport_->SignalSentPacket.connect(this, + &DtlsSrtpTransport::OnSentPacket); } void DtlsSrtpTransport::SetDtlsTransports( @@ -51,23 +55,22 @@ void DtlsSrtpTransport::SetDtlsTransports( srtp_transport_->ResetParams(); } - if (rtcp_dtls_transport) { - // This would only be possible if using BUNDLE but not rtcp-mux, which isn't - // allowed according to the BUNDLE spec. - RTC_CHECK(!(IsActive())) - << "Setting RTCP for DTLS/SRTP after the DTLS is active " - << "should never happen."; + const std::string transport_name = + rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null"; - RTC_LOG(LS_INFO) << "Setting RTCP Transport on " - << rtcp_dtls_transport->transport_name() << " transport " - << rtcp_dtls_transport; - SetRtcpDtlsTransport(rtcp_dtls_transport); - SetRtcpPacketTransport(rtcp_dtls_transport); - } + // This would only be possible if using BUNDLE but not rtcp-mux, which isn't + // allowed according to the BUNDLE spec. + RTC_CHECK(!(IsActive())) + << "Setting RTCP for DTLS/SRTP after the DTLS is active " + << "should never happen."; - RTC_LOG(LS_INFO) << "Setting RTP Transport on " - << rtp_dtls_transport->transport_name() << " transport " - << rtp_dtls_transport; + RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name + << " transport " << rtcp_dtls_transport; + SetRtcpDtlsTransport(rtcp_dtls_transport); + SetRtcpPacketTransport(rtcp_dtls_transport); + + RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name + << " transport " << rtp_dtls_transport; SetRtpDtlsTransport(rtp_dtls_transport); SetRtpPacketTransport(rtp_dtls_transport); @@ -81,18 +84,28 @@ void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) { } } -void DtlsSrtpTransport::SetSendEncryptedHeaderExtensionIds( +void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds( const std::vector& send_extension_ids) { + if (send_extension_ids_ == send_extension_ids) { + return; + } send_extension_ids_.emplace(send_extension_ids); - // Reset the crypto parameters to update the send_extension IDs. - SetupRtpDtlsSrtp(); + if (DtlsHandshakeCompleted()) { + // Reset the crypto parameters to update the send extension IDs. + SetupRtpDtlsSrtp(); + } } -void DtlsSrtpTransport::SetRecvEncryptedHeaderExtensionIds( +void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds( const std::vector& recv_extension_ids) { + if (recv_extension_ids_ == recv_extension_ids) { + return; + } recv_extension_ids_.emplace(recv_extension_ids); - // Reset the crypto parameters to update the send_extension IDs. - SetupRtpDtlsSrtp(); + if (DtlsHandshakeCompleted()) { + // Reset the crypto parameters to update the receive extension IDs. + SetupRtpDtlsSrtp(); + } } bool DtlsSrtpTransport::IsDtlsActive() { @@ -267,9 +280,12 @@ bool DtlsSrtpTransport::ExtractParams( void DtlsSrtpTransport::SetDtlsTransport( cricket::DtlsTransportInternal* new_dtls_transport, cricket::DtlsTransportInternal** old_dtls_transport) { + if (*old_dtls_transport == new_dtls_transport) { + return; + } + if (*old_dtls_transport) { (*old_dtls_transport)->SignalDtlsState.disconnect(this); - (*old_dtls_transport)->SignalWritableState.disconnect(this); } *old_dtls_transport = new_dtls_transport; @@ -277,8 +293,6 @@ void DtlsSrtpTransport::SetDtlsTransport( if (new_dtls_transport) { new_dtls_transport->SignalDtlsState.connect( this, &DtlsSrtpTransport::OnDtlsState); - new_dtls_transport->SignalWritableState.connect( - this, &DtlsSrtpTransport::OnWritableState); } } @@ -321,11 +335,15 @@ void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport, MaybeSetupDtlsSrtp(); } -void DtlsSrtpTransport::OnWritableState( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK(transport == srtp_transport_->rtp_packet_transport() || - transport == srtp_transport_->rtcp_packet_transport()); - UpdateWritableStateAndMaybeSetupDtlsSrtp(); +void DtlsSrtpTransport::OnWritableState(bool writable) { + SetWritable(writable); + if (writable) { + MaybeSetupDtlsSrtp(); + } +} + +void DtlsSrtpTransport::OnSentPacket(const rtc::SentPacket& sent_packet) { + SignalSentPacket(sent_packet); } void DtlsSrtpTransport::OnPacketReceived(bool rtcp, diff --git a/pc/dtlssrtptransport.h b/pc/dtlssrtptransport.h index 43f072a8fa..e03342597e 100644 --- a/pc/dtlssrtptransport.h +++ b/pc/dtlssrtptransport.h @@ -38,10 +38,10 @@ class DtlsSrtpTransport : public RtpTransportInternalAdapter { void SetRtcpMuxEnabled(bool enable) override; // Set the header extension ids that should be encrypted. - void SetSendEncryptedHeaderExtensionIds( + void UpdateSendEncryptedHeaderExtensionIds( const std::vector& send_extension_ids); - void SetRecvEncryptedHeaderExtensionIds( + void UpdateRecvEncryptedHeaderExtensionIds( const std::vector& recv_extension_ids); bool IsActive() { return srtp_transport_->IsActive(); } @@ -75,7 +75,8 @@ class DtlsSrtpTransport : public RtpTransportInternalAdapter { void OnDtlsState(cricket::DtlsTransportInternal* dtls_transport, cricket::DtlsTransportState state); - void OnWritableState(rtc::PacketTransportInternal* transport); + void OnWritableState(bool writable); + void OnSentPacket(const rtc::SentPacket& sent_packet); void OnPacketReceived(bool rtcp, rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time); diff --git a/pc/dtlssrtptransport_unittest.cc b/pc/dtlssrtptransport_unittest.cc index ac1af1cfbb..77c59026ca 100644 --- a/pc/dtlssrtptransport_unittest.cc +++ b/pc/dtlssrtptransport_unittest.cc @@ -70,8 +70,6 @@ class DtlsSrtpTransportTest : public testing::Test, bool rtcp_mux_enabled) { auto rtp_transport = rtc::MakeUnique(rtcp_mux_enabled); - rtp_transport->SetRtpPacketTransport(rtp_dtls); - rtp_transport->SetRtcpPacketTransport(rtcp_dtls); rtp_transport->AddHandledPayloadType(0x00); rtp_transport->AddHandledPayloadType(0xc9); @@ -437,11 +435,14 @@ TEST_F(DtlsSrtpTransportTest, EncryptedHeaderExtensionIdUpdated) { encrypted_headers.push_back(kHeaderExtensionIDs[0]); encrypted_headers.push_back(kHeaderExtensionIDs[1]); - dtls_srtp_transport1_->SetSendEncryptedHeaderExtensionIds(encrypted_headers); - dtls_srtp_transport1_->SetRecvEncryptedHeaderExtensionIds(encrypted_headers); - dtls_srtp_transport2_->SetSendEncryptedHeaderExtensionIds(encrypted_headers); - dtls_srtp_transport2_->SetRecvEncryptedHeaderExtensionIds(encrypted_headers); - SendRecvRtpPacketsWithHeaderExtension(encrypted_headers); + dtls_srtp_transport1_->UpdateSendEncryptedHeaderExtensionIds( + encrypted_headers); + dtls_srtp_transport1_->UpdateRecvEncryptedHeaderExtensionIds( + encrypted_headers); + dtls_srtp_transport2_->UpdateSendEncryptedHeaderExtensionIds( + encrypted_headers); + dtls_srtp_transport2_->UpdateRecvEncryptedHeaderExtensionIds( + encrypted_headers); } // Tests if RTCP muxing is enabled. DtlsSrtpTransport is ready to send once the diff --git a/pc/rtptransport.cc b/pc/rtptransport.cc index d2604f9eae..26f7e3e4c9 100644 --- a/pc/rtptransport.cc +++ b/pc/rtptransport.cc @@ -33,6 +33,8 @@ void RtpTransport::SetRtpPacketTransport( rtp_packet_transport_->SignalReadyToSend.disconnect(this); rtp_packet_transport_->SignalReadPacket.disconnect(this); rtp_packet_transport_->SignalNetworkRouteChanged.disconnect(this); + rtp_packet_transport_->SignalWritableState.disconnect(this); + rtp_packet_transport_->SignalSentPacket.disconnect(this); // Reset the network route of the old transport. SignalNetworkRouteChanged(rtc::Optional()); } @@ -43,6 +45,10 @@ void RtpTransport::SetRtpPacketTransport( &RtpTransport::OnReadPacket); new_packet_transport->SignalNetworkRouteChanged.connect( this, &RtpTransport::OnNetworkRouteChange); + new_packet_transport->SignalWritableState.connect( + this, &RtpTransport::OnWritableState); + new_packet_transport->SignalSentPacket.connect(this, + &RtpTransport::OnSentPacket); // Set the network route for the new transport. SignalNetworkRouteChanged(new_packet_transport->network_route()); } @@ -63,6 +69,8 @@ void RtpTransport::SetRtcpPacketTransport( rtcp_packet_transport_->SignalReadyToSend.disconnect(this); rtcp_packet_transport_->SignalReadPacket.disconnect(this); rtcp_packet_transport_->SignalNetworkRouteChanged.disconnect(this); + rtcp_packet_transport_->SignalWritableState.disconnect(this); + rtcp_packet_transport_->SignalSentPacket.disconnect(this); // Reset the network route of the old transport. SignalNetworkRouteChanged(rtc::Optional()); } @@ -73,6 +81,10 @@ void RtpTransport::SetRtcpPacketTransport( &RtpTransport::OnReadPacket); new_packet_transport->SignalNetworkRouteChanged.connect( this, &RtpTransport::OnNetworkRouteChange); + new_packet_transport->SignalWritableState.connect( + this, &RtpTransport::OnWritableState); + new_packet_transport->SignalSentPacket.connect(this, + &RtpTransport::OnSentPacket); // Set the network route for the new transport. SignalNetworkRouteChanged(new_packet_transport->network_route()); } @@ -172,6 +184,13 @@ RtpTransportAdapter* RtpTransport::GetInternal() { return nullptr; } +bool RtpTransport::IsRtpTransportWritable() { + auto rtcp_packet_transport = + rtcp_mux_enabled_ ? nullptr : rtcp_packet_transport_; + return rtp_packet_transport_ && rtp_packet_transport_->writable() && + (!rtcp_packet_transport || rtcp_packet_transport->writable()); +} + void RtpTransport::OnReadyToSend(rtc::PacketTransportInternal* transport) { SetReadyToSend(transport == rtcp_packet_transport_, true); } @@ -181,6 +200,20 @@ void RtpTransport::OnNetworkRouteChange( SignalNetworkRouteChanged(network_route); } +void RtpTransport::OnWritableState( + rtc::PacketTransportInternal* packet_transport) { + RTC_DCHECK(packet_transport == rtp_packet_transport_ || + packet_transport == rtcp_packet_transport_); + SignalWritableState(IsRtpTransportWritable()); +} + +void RtpTransport::OnSentPacket(rtc::PacketTransportInternal* packet_transport, + const rtc::SentPacket& sent_packet) { + RTC_DCHECK(packet_transport == rtp_packet_transport_ || + packet_transport == rtcp_packet_transport_); + SignalSentPacket(sent_packet); +} + void RtpTransport::SetReadyToSend(bool rtcp, bool ready) { if (rtcp) { rtcp_ready_to_send_ = ready; @@ -226,7 +259,6 @@ void RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport, if (!WantsPacket(rtcp, &packet)) { return; } - // This mutates |packet| if it is protected. SignalPacketReceived(rtcp, &packet, packet_time); } diff --git a/pc/rtptransport.h b/pc/rtptransport.h index a42493a563..497a7487b4 100644 --- a/pc/rtptransport.h +++ b/pc/rtptransport.h @@ -75,10 +75,14 @@ class RtpTransport : public RtpTransportInternal { RtpTransportAdapter* GetInternal() override; private: + bool IsRtpTransportWritable(); bool HandlesPacket(const uint8_t* data, size_t len); void OnReadyToSend(rtc::PacketTransportInternal* transport); void OnNetworkRouteChange(rtc::Optional network_route); + void OnWritableState(rtc::PacketTransportInternal* packet_transport); + void OnSentPacket(rtc::PacketTransportInternal* packet_transport, + const rtc::SentPacket& sent_packet); // Updates "ready to send" for an individual channel and fires // SignalReadyToSend. diff --git a/pc/rtptransportinternal.h b/pc/rtptransportinternal.h index afede1ea3a..2ad66ab1c3 100644 --- a/pc/rtptransportinternal.h +++ b/pc/rtptransportinternal.h @@ -57,13 +57,15 @@ class RtpTransportInternal : public RtpTransportInterface, sigslot::signal3 SignalPacketReceived; + // Called whenever the network route of the P2P layer transport changes. + // The argument is an optional network route. + sigslot::signal1> SignalNetworkRouteChanged; + // Called whenever a transport's writable state might change. The argument is // true if the transport is writable, otherwise it is false. sigslot::signal1 SignalWritableState; - // Called whenever the network route of the P2P layer transport changes. - // The argument is an optional network route. - sigslot::signal1> SignalNetworkRouteChanged; + sigslot::signal1 SignalSentPacket; virtual bool IsWritable(bool rtcp) const = 0; diff --git a/pc/srtptransport.cc b/pc/srtptransport.cc index 98a3beab30..32e5a00618 100644 --- a/pc/srtptransport.cc +++ b/pc/srtptransport.cc @@ -51,6 +51,9 @@ void SrtpTransport::ConnectToRtpTransport() { &SrtpTransport::OnReadyToSend); rtp_transport_->SignalNetworkRouteChanged.connect( this, &SrtpTransport::OnNetworkRouteChanged); + rtp_transport_->SignalWritableState.connect(this, + &SrtpTransport::OnWritableState); + rtp_transport_->SignalSentPacket.connect(this, &SrtpTransport::OnSentPacket); } bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet, diff --git a/pc/srtptransport.h b/pc/srtptransport.h index 8704351a3e..23e2a3c544 100644 --- a/pc/srtptransport.h +++ b/pc/srtptransport.h @@ -100,9 +100,8 @@ class SrtpTransport : public RtpTransportInternalAdapter { } private: - void CreateSrtpSessions(); - void ConnectToRtpTransport(); + void CreateSrtpSessions(); bool SendPacket(bool rtcp, rtc::CopyOnWriteBuffer* packet, @@ -115,6 +114,12 @@ class SrtpTransport : public RtpTransportInternalAdapter { void OnReadyToSend(bool ready) { SignalReadyToSend(ready); } void OnNetworkRouteChanged(rtc::Optional network_route); + void OnWritableState(bool writable) { SignalWritableState(writable); } + + void OnSentPacket(const rtc::SentPacket& sent_packet) { + SignalSentPacket(sent_packet); + } + bool ProtectRtp(void* data, int in_len, int max_len, int* out_len); // Overloaded version, outputs packet index.