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:
@ -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;
|
||||
}
|
||||
|
||||
558
pc/channel.cc
558
pc/channel.cc
@ -32,8 +32,6 @@
|
||||
#include "p2p/base/packettransportinternal.h"
|
||||
#include "pc/channelmanager.h"
|
||||
#include "pc/rtpmediautils.h"
|
||||
#include "pc/rtptransport.h"
|
||||
#include "pc/srtptransport.h"
|
||||
|
||||
namespace cricket {
|
||||
using rtc::Bind;
|
||||
@ -64,9 +62,6 @@ enum {
|
||||
MSG_FIRSTPACKETRECEIVED,
|
||||
};
|
||||
|
||||
// Value specified in RFC 5764.
|
||||
static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
||||
|
||||
static const int kAgcMinus10db = -10;
|
||||
|
||||
static void SafeSetError(const std::string& message, std::string* error_desc) {
|
||||
@ -144,30 +139,13 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread,
|
||||
signaling_thread_(signaling_thread),
|
||||
content_name_(content_name),
|
||||
rtcp_mux_required_(rtcp_mux_required),
|
||||
unencrypted_rtp_transport_(
|
||||
rtc::MakeUnique<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();
|
||||
|
||||
// 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());
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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,35 +840,26 @@ 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();
|
||||
}
|
||||
|
||||
UpdateEncryptedHeaderExtensionIds(src, encrypted_extension_ids);
|
||||
|
||||
if (!dtls) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
ret = sdes_negotiator_.SetAnswer(cryptos, src);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -1058,37 +867,30 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
|
||||
|
||||
// If setting an SDES answer succeeded, apply the negotiated parameters
|
||||
// to the SRTP transport.
|
||||
if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) {
|
||||
if ((action == CA_PRANSWER || action == CA_ANSWER) && 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(
|
||||
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()),
|
||||
*(catched_send_extension_ids_),
|
||||
*(cached_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_));
|
||||
*(cached_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
|
||||
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|.
|
||||
srtp_transport_->ResetParams();
|
||||
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) {
|
||||
@ -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;
|
||||
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 {
|
||||
return !catched_send_extension_ids_ ||
|
||||
(*catched_send_extension_ids_) != new_extension_ids;
|
||||
rtp_transport_->SetRtcpPacketTransport(nullptr);
|
||||
}
|
||||
SignalRtcpMuxFullyActive(transport_name_);
|
||||
}
|
||||
UpdateWritableState_n();
|
||||
}
|
||||
|
||||
VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
|
||||
|
||||
67
pc/channel.h
67
pc/channel.h
@ -29,10 +29,13 @@
|
||||
#include "p2p/base/packettransportinternal.h"
|
||||
#include "p2p/client/socketmonitor.h"
|
||||
#include "pc/audiomonitor.h"
|
||||
#include "pc/dtlssrtptransport.h"
|
||||
#include "pc/mediamonitor.h"
|
||||
#include "pc/mediasession.h"
|
||||
#include "pc/rtcpmuxfilter.h"
|
||||
#include "pc/rtptransport.h"
|
||||
#include "pc/srtpfilter.h"
|
||||
#include "pc/srtptransport.h"
|
||||
#include "pc/transportcontroller.h"
|
||||
#include "rtc_base/asyncinvoker.h"
|
||||
#include "rtc_base/asyncudpsocket.h"
|
||||
@ -43,8 +46,6 @@
|
||||
|
||||
namespace webrtc {
|
||||
class AudioSinkInterface;
|
||||
class RtpTransportInternal;
|
||||
class SrtpTransport;
|
||||
} // namespace webrtc
|
||||
|
||||
namespace cricket {
|
||||
@ -101,9 +102,13 @@ class BaseChannel
|
||||
bool enabled() const { return enabled_; }
|
||||
|
||||
// This function returns true if we are using SDES.
|
||||
bool sdes_active() const { return sdes_negotiator_.IsActive(); }
|
||||
bool sdes_active() const {
|
||||
return sdes_transport_ && sdes_negotiator_.IsActive();
|
||||
}
|
||||
// The following function returns true if we are using DTLS-based keying.
|
||||
bool dtls_active() const { return dtls_active_; }
|
||||
bool dtls_active() const {
|
||||
return dtls_srtp_transport_ && dtls_srtp_transport_->IsActive();
|
||||
}
|
||||
// This function returns true if using SRTP (DTLS-based keying or SDES).
|
||||
bool srtp_active() const { return sdes_active() || dtls_active(); }
|
||||
|
||||
@ -225,11 +230,6 @@ class BaseChannel
|
||||
bool IsReadyToSendMedia_w() const;
|
||||
rtc::Thread* signaling_thread() { return signaling_thread_; }
|
||||
|
||||
void ConnectToDtlsTransport(DtlsTransportInternal* transport);
|
||||
void DisconnectFromDtlsTransport(DtlsTransportInternal* transport);
|
||||
void ConnectToPacketTransport(rtc::PacketTransportInternal* transport);
|
||||
void DisconnectFromPacketTransport(rtc::PacketTransportInternal* transport);
|
||||
|
||||
void FlushRtcpMessages_n();
|
||||
|
||||
// NetworkInterface implementation, called by MediaEngine
|
||||
@ -238,10 +238,8 @@ class BaseChannel
|
||||
bool SendRtcp(rtc::CopyOnWriteBuffer* packet,
|
||||
const rtc::PacketOptions& options) override;
|
||||
|
||||
// From TransportChannel
|
||||
void OnWritableState(rtc::PacketTransportInternal* transport);
|
||||
|
||||
void OnDtlsState(DtlsTransportInternal* transport, DtlsTransportState state);
|
||||
// From RtpTransportInternal
|
||||
void OnWritableState(bool writable);
|
||||
|
||||
void OnNetworkRouteChanged(rtc::Optional<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,
|
||||
// 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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
const std::string transport_name =
|
||||
rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
|
||||
|
||||
// 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 RTCP Transport on "
|
||||
<< rtcp_dtls_transport->transport_name() << " transport "
|
||||
<< rtcp_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 "
|
||||
<< rtp_dtls_transport->transport_name() << " transport "
|
||||
<< rtp_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,19 +84,29 @@ 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.
|
||||
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.
|
||||
if (DtlsHandshakeCompleted()) {
|
||||
// Reset the crypto parameters to update the receive extension IDs.
|
||||
SetupRtpDtlsSrtp();
|
||||
}
|
||||
}
|
||||
|
||||
bool DtlsSrtpTransport::IsDtlsActive() {
|
||||
auto rtcp_dtls_transport =
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
Reference in New Issue
Block a user