Chromium Code Reviews| Index: webrtc/pc/channel.cc |
| diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc |
| index 59f0869431ae59aef1e26b3dbc555b0c897e7e14..e6a2c30c59ea6e6e16e2eb82faca6357230a7b1d 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 |
| @@ -321,7 +325,10 @@ void BaseChannel::SetTransports_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, |
| @@ -588,7 +594,10 @@ void BaseChannel::OnDtlsState(DtlsTransportInternal* transport, |
| // 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) |
| + : rtp_transport_->SendRtpPacket(packet, options); |
| } |
| - |
| + 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) |
| + : srtp_transport_->SendRtpPacket(packet, options); |
| } |
| 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,67 @@ bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos, |
| if (!ret) { |
| return false; |
| } |
| - srtp_filter_.SetEncryptedHeaderExtensionIds(src, encrypted_extension_ids); |
| + |
| + if (!srtp_transport_ && !dtls && !cryptos.empty()) { |
|
Taylor Brandstetter
2017/08/30 21:24:26
nit: May be helpful to add a comment here, saying
Zhi Huang
2017/08/31 17:42:41
Done.
|
| + 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 +1176,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 +1404,8 @@ void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w( |
| void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( |
| int rtp_abs_sendtime_extn_id) { |
| - rtp_abs_sendtime_extn_id_ = rtp_abs_sendtime_extn_id; |
| + RTC_DCHECK(srtp_transport_); |
| + srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(rtp_abs_sendtime_extn_id); |
| } |
| void BaseChannel::OnMessage(rtc::Message *pmsg) { |
| @@ -1724,9 +1689,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; |
| } |