| Index: webrtc/pc/channel.cc
|
| diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
|
| index 59f0869431ae59aef1e26b3dbc555b0c897e7e14..d99a1058683f0e6c51a00e862463edfcce6f9c05 100644
|
| --- a/webrtc/pc/channel.cc
|
| +++ b/webrtc/pc/channel.cc
|
| @@ -158,18 +158,22 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread,
|
| signaling_thread_(signaling_thread),
|
| content_name_(content_name),
|
| rtcp_mux_required_(rtcp_mux_required),
|
| - rtp_transport_(
|
| - srtp_required
|
| - ? rtc::WrapUnique<webrtc::RtpTransportInternal>(
|
| - new webrtc::SrtpTransport(rtcp_mux_required, content_name))
|
| - : rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required)),
|
| srtp_required_(srtp_required),
|
| media_channel_(media_channel),
|
| selected_candidate_pair_(nullptr) {
|
| RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
|
| + 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_filter_.EnableExternalAuth();
|
| + 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
|
| @@ -314,14 +318,17 @@ void BaseChannel::SetTransports_n(
|
| return;
|
| }
|
|
|
| - // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport
|
| - // changes and wait until the DTLS handshake is complete to set the newly
|
| - // negotiated parameters.
|
| + // 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;
|
| - srtp_filter_.ResetParams();
|
| + dtls_active_ = false;
|
| + if (srtp_transport_) {
|
| + srtp_transport_->ResetParams();
|
| + }
|
| }
|
|
|
| // If this BaseChannel doesn't require RTCP mux and we haven't fully
|
| @@ -377,8 +384,8 @@ void BaseChannel::SetTransport_n(
|
| }
|
|
|
| if (rtcp && new_dtls_transport) {
|
| - RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_filter_.IsActive()))
|
| - << "Setting RTCP for DTLS/SRTP after SrtpFilter is active "
|
| + RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_active()))
|
| + << "Setting RTCP for DTLS/SRTP after the DTLS is active "
|
| << "should never happen.";
|
| }
|
|
|
| @@ -529,8 +536,7 @@ bool BaseChannel::IsReadyToSendMedia_n() const {
|
| // and we have had some form of connectivity.
|
| return enabled() && IsReceiveContentDirection(remote_content_direction_) &&
|
| IsSendContentDirection(local_content_direction_) &&
|
| - was_ever_writable() &&
|
| - (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp_n());
|
| + was_ever_writable() && (srtp_active() || !ShouldSetupDtlsSrtp_n());
|
| }
|
|
|
| bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
|
| @@ -582,13 +588,16 @@ void BaseChannel::OnDtlsState(DtlsTransportInternal* transport,
|
| return;
|
| }
|
|
|
| - // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED
|
| + // 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) {
|
| - srtp_filter_.ResetParams();
|
| + dtls_active_ = false;
|
| + if (srtp_transport_) {
|
| + srtp_transport_->ResetParams();
|
| + }
|
| }
|
| }
|
|
|
| @@ -662,91 +671,30 @@ bool BaseChannel::SendPacket(bool rtcp,
|
| return false;
|
| }
|
|
|
| - rtc::PacketOptions updated_options;
|
| - updated_options = options;
|
| - // Protect if needed.
|
| - if (srtp_filter_.IsActive()) {
|
| - TRACE_EVENT0("webrtc", "SRTP Encode");
|
| - bool res;
|
| - uint8_t* data = packet->data();
|
| - int len = static_cast<int>(packet->size());
|
| - if (!rtcp) {
|
| - // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
|
| - // inside libsrtp for a RTP packet. A external HMAC module will be writing
|
| - // a fake HMAC value. This is ONLY done for a RTP packet.
|
| - // Socket layer will update rtp sendtime extension header if present in
|
| - // packet with current time before updating the HMAC.
|
| -#if !defined(ENABLE_EXTERNAL_AUTH)
|
| - res = srtp_filter_.ProtectRtp(
|
| - data, len, static_cast<int>(packet->capacity()), &len);
|
| -#else
|
| - if (!srtp_filter_.IsExternalAuthActive()) {
|
| - res = srtp_filter_.ProtectRtp(
|
| - data, len, static_cast<int>(packet->capacity()), &len);
|
| - } else {
|
| - updated_options.packet_time_params.rtp_sendtime_extension_id =
|
| - rtp_abs_sendtime_extn_id_;
|
| - res = srtp_filter_.ProtectRtp(
|
| - data, len, static_cast<int>(packet->capacity()), &len,
|
| - &updated_options.packet_time_params.srtp_packet_index);
|
| - // If protection succeeds, let's get auth params from srtp.
|
| - if (res) {
|
| - uint8_t* auth_key = NULL;
|
| - int key_len;
|
| - res = srtp_filter_.GetRtpAuthParams(
|
| - &auth_key, &key_len,
|
| - &updated_options.packet_time_params.srtp_auth_tag_len);
|
| - if (res) {
|
| - updated_options.packet_time_params.srtp_auth_key.resize(key_len);
|
| - updated_options.packet_time_params.srtp_auth_key.assign(
|
| - auth_key, auth_key + key_len);
|
| - }
|
| - }
|
| - }
|
| -#endif
|
| - if (!res) {
|
| - int seq_num = -1;
|
| - uint32_t ssrc = 0;
|
| - GetRtpSeqNum(data, len, &seq_num);
|
| - GetRtpSsrc(data, len, &ssrc);
|
| - LOG(LS_ERROR) << "Failed to protect " << content_name_
|
| - << " RTP packet: size=" << len
|
| - << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
|
| - return false;
|
| - }
|
| - } else {
|
| - res = srtp_filter_.ProtectRtcp(data, len,
|
| - static_cast<int>(packet->capacity()),
|
| - &len);
|
| - if (!res) {
|
| - int type = -1;
|
| - GetRtcpType(data, len, &type);
|
| - LOG(LS_ERROR) << "Failed to protect " << content_name_
|
| - << " RTCP packet: size=" << len << ", type=" << type;
|
| + if (!srtp_active()) {
|
| + if (srtp_required_) {
|
| + // The audio/video engines may attempt to send RTCP packets as soon as the
|
| + // streams are created, so don't treat this as an error for RTCP.
|
| + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
|
| + if (rtcp) {
|
| return false;
|
| }
|
| - }
|
| -
|
| - // Update the length of the packet now that we've added the auth tag.
|
| - packet->SetSize(len);
|
| - } else if (srtp_required_) {
|
| - // The audio/video engines may attempt to send RTCP packets as soon as the
|
| - // streams are created, so don't treat this as an error for RTCP.
|
| - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
|
| - if (rtcp) {
|
| + // However, there shouldn't be any RTP packets sent before SRTP is set up
|
| + // (and SetSend(true) is called).
|
| + LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive"
|
| + << " and crypto is required";
|
| + RTC_NOTREACHED();
|
| return false;
|
| }
|
| - // However, there shouldn't be any RTP packets sent before SRTP is set up
|
| - // (and SetSend(true) is called).
|
| - LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive"
|
| - << " and crypto is required";
|
| - RTC_NOTREACHED();
|
| - return false;
|
| + // Bon voyage.
|
| + return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_NORMAL)
|
| + : rtp_transport_->SendRtpPacket(packet, options, PF_NORMAL);
|
| }
|
| -
|
| + RTC_DCHECK(srtp_transport_);
|
| + RTC_DCHECK(srtp_transport_->IsActive());
|
| // Bon voyage.
|
| - int flags = (secure() && secure_dtls()) ? PF_SRTP_BYPASS : PF_NORMAL;
|
| - return rtp_transport_->SendPacket(rtcp, packet, updated_options, flags);
|
| + return rtcp ? srtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
|
| + : srtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
|
| }
|
|
|
| bool BaseChannel::HandlesPayloadType(int packet_type) const {
|
| @@ -761,37 +709,7 @@ void BaseChannel::OnPacketReceived(bool rtcp,
|
| signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
|
| }
|
|
|
| - // Unprotect the packet, if needed.
|
| - if (srtp_filter_.IsActive()) {
|
| - TRACE_EVENT0("webrtc", "SRTP Decode");
|
| - char* data = packet->data<char>();
|
| - int len = static_cast<int>(packet->size());
|
| - bool res;
|
| - if (!rtcp) {
|
| - res = srtp_filter_.UnprotectRtp(data, len, &len);
|
| - if (!res) {
|
| - int seq_num = -1;
|
| - uint32_t ssrc = 0;
|
| - GetRtpSeqNum(data, len, &seq_num);
|
| - GetRtpSsrc(data, len, &ssrc);
|
| - LOG(LS_ERROR) << "Failed to unprotect " << content_name_
|
| - << " RTP packet: size=" << len << ", seqnum=" << seq_num
|
| - << ", SSRC=" << ssrc;
|
| - return;
|
| - }
|
| - } else {
|
| - res = srtp_filter_.UnprotectRtcp(data, len, &len);
|
| - if (!res) {
|
| - int type = -1;
|
| - GetRtcpType(data, len, &type);
|
| - LOG(LS_ERROR) << "Failed to unprotect " << content_name_
|
| - << " RTCP packet: size=" << len << ", type=" << type;
|
| - return;
|
| - }
|
| - }
|
| -
|
| - packet->SetSize(len);
|
| - } else if (srtp_required_) {
|
| + if (!srtp_active() && srtp_required_) {
|
| // Our session description indicates that SRTP is required, but we got a
|
| // packet before our SRTP filter is active. This means either that
|
| // a) we got SRTP packets before we received the SDES keys, in which case
|
| @@ -995,43 +913,37 @@ bool BaseChannel::SetupDtlsSrtp_n(bool rtcp) {
|
| recv_key = &server_write_key;
|
| }
|
|
|
| - if (!srtp_filter_.IsActive()) {
|
| - if (rtcp) {
|
| - ret = srtp_filter_.SetRtcpParams(selected_crypto_suite, &(*send_key)[0],
|
| - static_cast<int>(send_key->size()),
|
| - selected_crypto_suite, &(*recv_key)[0],
|
| - static_cast<int>(recv_key->size()));
|
| + 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()), selected_crypto_suite,
|
| + &(*recv_key)[0], static_cast<int>(recv_key->size()));
|
| } else {
|
| - ret = srtp_filter_.SetRtpParams(selected_crypto_suite, &(*send_key)[0],
|
| - static_cast<int>(send_key->size()),
|
| - selected_crypto_suite, &(*recv_key)[0],
|
| - static_cast<int>(recv_key->size()));
|
| - }
|
| - } else {
|
| - if (rtcp) {
|
| - // RTCP doesn't need to be updated because UpdateRtpParams is only used
|
| - // to update the set of encrypted RTP header extension IDs.
|
| + // 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 {
|
| - ret = srtp_filter_.UpdateRtpParams(
|
| - selected_crypto_suite,
|
| - &(*send_key)[0], static_cast<int>(send_key->size()),
|
| - selected_crypto_suite,
|
| - &(*recv_key)[0], static_cast<int>(recv_key->size()));
|
| }
|
| + } else {
|
| + RTC_DCHECK(srtp_transport_);
|
| + ret = srtp_transport_->SetRtpParams(selected_crypto_suite, &(*send_key)[0],
|
| + static_cast<int>(send_key->size()),
|
| + selected_crypto_suite, &(*recv_key)[0],
|
| + static_cast<int>(recv_key->size()));
|
| + dtls_active_ = ret;
|
| }
|
|
|
| if (!ret) {
|
| LOG(LS_WARNING) << "DTLS-SRTP key installation failed";
|
| } else {
|
| - dtls_keyed_ = true;
|
| UpdateTransportOverhead();
|
| }
|
| return ret;
|
| }
|
|
|
| void BaseChannel::MaybeSetupDtlsSrtp_n() {
|
| - if (srtp_filter_.IsActive()) {
|
| + if (dtls_active()) {
|
| return;
|
| }
|
|
|
| @@ -1039,6 +951,10 @@ void BaseChannel::MaybeSetupDtlsSrtp_n() {
|
| return;
|
| }
|
|
|
| + if (!srtp_transport_) {
|
| + EnableSrtpTransport_n();
|
| + }
|
| +
|
| if (!SetupDtlsSrtp_n(false)) {
|
| SignalDtlsSrtpSetupFailure_n(false);
|
| return;
|
| @@ -1122,6 +1038,24 @@ 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);
|
| +
|
| + 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);
|
| + LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport.";
|
| + }
|
| +}
|
| +
|
| bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
|
| ContentAction action,
|
| ContentSource src,
|
| @@ -1138,36 +1072,69 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
|
| if (!ret) {
|
| return false;
|
| }
|
| - srtp_filter_.SetEncryptedHeaderExtensionIds(src, encrypted_extension_ids);
|
| +
|
| + // 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 (srtp_transport_) {
|
| + srtp_transport_->SetEncryptedHeaderExtensionIds(src,
|
| + encrypted_extension_ids);
|
| + }
|
| 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 = srtp_filter_.SetOffer(cryptos, src);
|
| + 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 = srtp_filter_.SetProvisionalAnswer(cryptos, src);
|
| + 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 = srtp_filter_.SetAnswer(cryptos, src);
|
| + ret = sdes_negotiator_.SetAnswer(cryptos, src);
|
| }
|
| 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()) {
|
| + ret = srtp_transport_->SetRtpParams(
|
| + *(sdes_negotiator_.send_cipher_suite()),
|
| + sdes_negotiator_.send_key().data(),
|
| + static_cast<int>(sdes_negotiator_.send_key().size()),
|
| + *(sdes_negotiator_.recv_cipher_suite()),
|
| + sdes_negotiator_.recv_key().data(),
|
| + static_cast<int>(sdes_negotiator_.recv_key().size()));
|
| + } else {
|
| + 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();
|
| + }
|
| + }
|
| + }
|
| +
|
| // Only update SRTP filter if using DTLS. SDES is handled internally
|
| // by the SRTP filter.
|
| // TODO(jbauch): Only update if encrypted extension ids have changed.
|
| - if (ret && dtls_keyed_ && rtp_dtls_transport_ &&
|
| + if (ret && dtls_active() && rtp_dtls_transport_ &&
|
| rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED) {
|
| bool rtcp = false;
|
| ret = SetupDtlsSrtp_n(rtcp);
|
| @@ -1211,7 +1178,6 @@ bool BaseChannel::SetRtcpMux_n(bool enable,
|
| transport_name_.empty()
|
| ? rtp_transport_->rtp_packet_transport()->debug_name()
|
| : transport_name_;
|
| - ;
|
| LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name()
|
| << "; no longer need RTCP transport for " << debug_name;
|
| if (rtp_transport_->rtcp_packet_transport()) {
|
| @@ -1440,7 +1406,13 @@ void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w(
|
|
|
| void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n(
|
| int rtp_abs_sendtime_extn_id) {
|
| - rtp_abs_sendtime_extn_id_ = rtp_abs_sendtime_extn_id;
|
| + if (srtp_transport_) {
|
| + srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
|
| + rtp_abs_sendtime_extn_id);
|
| + } else {
|
| + LOG(LS_WARNING) << "Trying to cache the Absolute Send Time extension id "
|
| + "but the SRTP is not active.";
|
| + }
|
| }
|
|
|
| void BaseChannel::OnMessage(rtc::Message *pmsg) {
|
| @@ -1724,9 +1696,9 @@ int BaseChannel::GetTransportOverheadPerPacket() const {
|
| ? kTcpOverhaed
|
| : kUdpOverhaed;
|
|
|
| - if (secure()) {
|
| + if (sdes_active()) {
|
| int srtp_overhead = 0;
|
| - if (srtp_filter_.GetSrtpOverhead(&srtp_overhead))
|
| + if (srtp_transport_->GetSrtpOverhead(&srtp_overhead))
|
| transport_overhead_per_packet += srtp_overhead;
|
| }
|
|
|
|
|