Use the DtlsSrtpTransport in BaseChannel.
The DtlsSrtpTransport takes the reponsiblity of setting up DTLS-SRTP from
the BaseChannel.
The BaseChannel doesn't handle the signals from the P2P layer transport anymore.
The RtpTransport handles the signals from the PacketTransportInternal and the
DtlsSrtpTransport handles the DTLS-specific signals and determines when to extract
the keys and setting the parameters.
In channel_unittests.cc, call from DTLS to SDES is expected to fail since the
fallback from DTLS to SDES is not supported.
Bug: webrtc:7013
Change-Id: I0a54e017986f5a8ae9710e79643a4651bef3c38f
Reviewed-on: https://webrtc-review.googlesource.com/24702
Commit-Queue: Zhi Huang <zhihuang@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20941}
diff --git a/p2p/base/fakedtlstransport.h b/p2p/base/fakedtlstransport.h
index fef00fd..54b7018 100644
--- a/p2p/base/fakedtlstransport.h
+++ b/p2p/base/fakedtlstransport.h
@@ -91,6 +91,10 @@
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 @@
}
bool SetLocalCertificate(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
+ do_dtls_ = true;
local_cert_ = certificate;
return true;
}
diff --git a/pc/channel.cc b/pc/channel.cc
index b976cc0..ea4684f 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 @@
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 @@
signaling_thread_(signaling_thread),
content_name_(content_name),
rtcp_mux_required_(rtcp_mux_required),
+ unencrypted_rtp_transport_(
+ rtc::MakeUnique<webrtc::RtpTransport>(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<webrtc::SrtpTransport>(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<webrtc::RtpTransport>(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 @@
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 @@
// 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<void>(
- RTC_FROM_HERE, Bind(&BaseChannel::DisconnectTransportChannels_n, this));
+ network_thread_->Invoke<void>(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 @@
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 @@
} 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 @@
}
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 @@
<< "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<void>(
RTC_FROM_HERE,
@@ -558,29 +503,17 @@
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 @@
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 @@
<< (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<void>(
- 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<unsigned char> 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<unsigned char> client_write_key(key_len + salt_len);
- std::vector<unsigned char> 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<unsigned char> *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<int> send_extension_ids;
- std::vector<int> 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<int>(send_key->size()), send_extension_ids,
- selected_crypto_suite, &(*recv_key)[0],
- static_cast<int>(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<int>(send_key->size()), send_extension_ids,
- selected_crypto_suite, &(*recv_key)[0],
- static_cast<int>(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 @@
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<webrtc::SrtpTransport>(
- 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<webrtc::SrtpTransport>(
+ 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<webrtc::SrtpTransport>(
+ std::move(unencrypted_rtp_transport_), content_name_);
+#if defined(ENABLE_EXTERNAL_AUTH)
+ srtp_transport->EnableExternalAuth();
+#endif
+ dtls_srtp_transport_ =
+ rtc::MakeUnique<webrtc::DtlsSrtpTransport>(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<CryptoParams>& cryptos,
@@ -1022,75 +840,59 @@
// 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<int>(sdes_negotiator_.send_key().size()),
- *(catched_send_extension_ids_),
- *(sdes_negotiator_.recv_cipher_suite()),
- sdes_negotiator_.recv_key().data(),
- static_cast<int>(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<int>(sdes_negotiator_.send_key().size()),
+ *(cached_send_extension_ids_),
+ *(sdes_negotiator_.recv_cipher_suite()),
+ sdes_negotiator_.recv_key().data(),
+ static_cast<int>(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 @@
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::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::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<void>(
RTC_FROM_HERE, worker_thread_,
@@ -1345,24 +1132,45 @@
SignalSentPacket(sent_packet);
}
-void BaseChannel::CacheEncryptedHeaderExtensionIds(
+void BaseChannel::UpdateEncryptedHeaderExtensionIds(
cricket::ContentSource source,
const std::vector<int>& 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<int>& 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 dbc6367..1c4e50a 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 @@
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 @@
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 @@
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<rtc::NetworkRoute> network_route);
@@ -349,30 +347,34 @@
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<int>& 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<int>& extension_ids);
- // Return true if the new header extension IDs are different from the existing
- // ones.
- bool EncryptedHeaderExtensionIdsChanged(
- cricket::ContentSource source,
- const std::vector<int>& 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 @@
// 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<webrtc::RtpTransportInternal> 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<webrtc::SrtpTransport> sdes_transport_;
+ std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport_;
+ std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport_;
+
std::vector<std::pair<rtc::Socket::Option, int> > socket_options_;
std::vector<std::pair<rtc::Socket::Option, int> > rtcp_socket_options_;
SrtpFilter sdes_negotiator_;
@@ -401,7 +409,6 @@
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 @@
webrtc::RtpTransceiverDirection::kInactive;
// The cached encrypted header extension IDs.
- rtc::Optional<std::vector<int>> catched_send_extension_ids_;
- rtc::Optional<std::vector<int>> catched_recv_extension_ids_;
+ rtc::Optional<std::vector<int>> cached_send_extension_ids_;
+ rtc::Optional<std::vector<int>> 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 d1ceac5..7cc5dec 100644
--- a/pc/channel_unittest.cc
+++ b/pc/channel_unittest.cc
@@ -1398,6 +1398,17 @@
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 @@
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, SendDtlsSrtpToSrtp) {
- Base::SendSrtpToSrtp(DTLS, 0);
+ Base::SendDtlsToSdesNotSupported();
}
TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) {
@@ -2646,7 +2657,7 @@
}
TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToSrtp) {
- Base::SendSrtpToSrtp(DTLS, 0);
+ Base::SendDtlsToSdesNotSupported();
}
TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) {
@@ -2947,7 +2958,7 @@
}
TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToSrtp) {
- Base::SendSrtpToSrtp(DTLS, 0);
+ Base::SendDtlsToSdesNotSupported();
}
TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) {
@@ -3170,7 +3181,7 @@
}
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 1c2d21f..bc5d3aa 100644
--- a/pc/dtlssrtptransport.cc
+++ b/pc/dtlssrtptransport.cc
@@ -33,6 +33,10 @@
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 @@
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::SetSendEncryptedHeaderExtensionIds(
+void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
const std::vector<int>& 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<int>& 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 @@
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 @@
if (new_dtls_transport) {
new_dtls_transport->SignalDtlsState.connect(
this, &DtlsSrtpTransport::OnDtlsState);
- new_dtls_transport->SignalWritableState.connect(
- this, &DtlsSrtpTransport::OnWritableState);
}
}
@@ -321,11 +335,15 @@
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 43f072a..e033425 100644
--- a/pc/dtlssrtptransport.h
+++ b/pc/dtlssrtptransport.h
@@ -38,10 +38,10 @@
void SetRtcpMuxEnabled(bool enable) override;
// Set the header extension ids that should be encrypted.
- void SetSendEncryptedHeaderExtensionIds(
+ void UpdateSendEncryptedHeaderExtensionIds(
const std::vector<int>& send_extension_ids);
- void SetRecvEncryptedHeaderExtensionIds(
+ void UpdateRecvEncryptedHeaderExtensionIds(
const std::vector<int>& recv_extension_ids);
bool IsActive() { return srtp_transport_->IsActive(); }
@@ -75,7 +75,8 @@
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 ac1af1c..77c5902 100644
--- a/pc/dtlssrtptransport_unittest.cc
+++ b/pc/dtlssrtptransport_unittest.cc
@@ -70,8 +70,6 @@
bool rtcp_mux_enabled) {
auto rtp_transport = rtc::MakeUnique<RtpTransport>(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 @@
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 d2604f9..26f7e3e 100644
--- a/pc/rtptransport.cc
+++ b/pc/rtptransport.cc
@@ -33,6 +33,8 @@
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<rtc::NetworkRoute>());
}
@@ -43,6 +45,10 @@
&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 @@
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<rtc::NetworkRoute>());
}
@@ -73,6 +81,10 @@
&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 @@
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 @@
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 @@
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 a42493a..497a748 100644
--- a/pc/rtptransport.h
+++ b/pc/rtptransport.h
@@ -75,10 +75,14 @@
RtpTransportAdapter* GetInternal() override;
private:
+ bool IsRtpTransportWritable();
bool HandlesPacket(const uint8_t* data, size_t len);
void OnReadyToSend(rtc::PacketTransportInternal* transport);
void OnNetworkRouteChange(rtc::Optional<rtc::NetworkRoute> 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 afede1e..2ad66ab 100644
--- a/pc/rtptransportinternal.h
+++ b/pc/rtptransportinternal.h
@@ -57,13 +57,15 @@
sigslot::signal3<bool, rtc::CopyOnWriteBuffer*, const rtc::PacketTime&>
SignalPacketReceived;
+ // Called whenever the network route of the P2P layer transport changes.
+ // The argument is an optional network route.
+ sigslot::signal1<rtc::Optional<rtc::NetworkRoute>> 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<bool> SignalWritableState;
- // Called whenever the network route of the P2P layer transport changes.
- // The argument is an optional network route.
- sigslot::signal1<rtc::Optional<rtc::NetworkRoute>> SignalNetworkRouteChanged;
+ sigslot::signal1<const rtc::SentPacket&> SignalSentPacket;
virtual bool IsWritable(bool rtcp) const = 0;
diff --git a/pc/srtptransport.cc b/pc/srtptransport.cc
index 98a3bea..32e5a00 100644
--- a/pc/srtptransport.cc
+++ b/pc/srtptransport.cc
@@ -51,6 +51,9 @@
&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 8704351..23e2a3c 100644
--- a/pc/srtptransport.h
+++ b/pc/srtptransport.h
@@ -100,9 +100,8 @@
}
private:
- void CreateSrtpSessions();
-
void ConnectToRtpTransport();
+ void CreateSrtpSessions();
bool SendPacket(bool rtcp,
rtc::CopyOnWriteBuffer* packet,
@@ -115,6 +114,12 @@
void OnReadyToSend(bool ready) { SignalReadyToSend(ready); }
void OnNetworkRouteChanged(rtc::Optional<rtc::NetworkRoute> 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.