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}
This commit is contained in:
Zhi Huang
2017-11-29 10:41:57 -08:00
committed by Commit Bot
parent e932457201
commit cd3fc5d90c
12 changed files with 381 additions and 484 deletions

View File

@ -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<rtc::RTCCertificate>& certificate) override {
do_dtls_ = true;
local_cert_ = certificate;
return true;
}

View File

@ -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<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 @@ 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<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 @@ 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<void>(
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<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 @@ bool BaseChannel::CheckSrtpConfig_n(const std::vector<CryptoParams>& 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<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 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& 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<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 @@ 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<void>(
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<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,

View File

@ -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<rtc::NetworkRoute> 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<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 @@ 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<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 @@ 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<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,

View File

@ -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<VoiceTraits>::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) {

View File

@ -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<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 @@ 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,

View File

@ -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<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 @@ 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);

View File

@ -70,8 +70,6 @@ class DtlsSrtpTransportTest : public testing::Test,
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 @@ 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

View File

@ -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<rtc::NetworkRoute>());
}
@ -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<rtc::NetworkRoute>());
}
@ -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);
}

View File

@ -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<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.

View File

@ -57,13 +57,15 @@ class RtpTransportInternal : public RtpTransportInterface,
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;

View File

@ -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,

View File

@ -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<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.