diff --git a/api/ortc/packettransportinterface.h b/api/ortc/packettransportinterface.h index 9d53ad311b..f357f8af63 100644 --- a/api/ortc/packettransportinterface.h +++ b/api/ortc/packettransportinterface.h @@ -31,6 +31,7 @@ class PacketTransportInterface { // Classes that can use this internal interface. friend class RtpTransportControllerAdapter; + friend class RtpTransportAdapter; }; } // namespace webrtc diff --git a/ortc/ortcfactory.cc b/ortc/ortcfactory.cc index 506fc86708..dd3c6db614 100644 --- a/ortc/ortcfactory.cc +++ b/ortc/ortcfactory.cc @@ -232,7 +232,7 @@ OrtcFactory::CreateRtpTransportController() { RTC_DCHECK_RUN_ON(signaling_thread_); return RtpTransportControllerAdapter::CreateProxied( cricket::MediaConfig(), channel_manager_.get(), null_event_log_.get(), - signaling_thread_, worker_thread_.get()); + signaling_thread_, worker_thread_.get(), network_thread_); } RTCErrorOr> diff --git a/ortc/rtptransportadapter.cc b/ortc/rtptransportadapter.cc index 0cf9217c6c..acd71db25b 100644 --- a/ortc/rtptransportadapter.cc +++ b/ortc/rtptransportadapter.cc @@ -17,6 +17,7 @@ #include "api/proxy.h" #include "rtc_base/logging.h" +#include "rtc_base/ptr_util.h" namespace webrtc { @@ -115,10 +116,11 @@ RtpTransportAdapter::CreateSrtpProxied( LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Must provide an RTP transport controller."); } - std::unique_ptr transport_adapter( - new RtpTransportAdapter(parameters.rtcp, rtp, rtcp, - rtp_transport_controller, - true /*is_srtp_transport*/)); + + std::unique_ptr transport_adapter; + transport_adapter.reset(new RtpTransportAdapter(parameters.rtcp, rtp, rtcp, + rtp_transport_controller, + true /*is_srtp_transport*/)); RTCError params_result = transport_adapter->SetParameters(parameters); if (!params_result.ok()) { return std::move(params_result); @@ -145,25 +147,40 @@ RtpTransportAdapter::RtpTransportAdapter( : rtp_packet_transport_(rtp), rtcp_packet_transport_(rtcp), rtp_transport_controller_(rtp_transport_controller), - is_srtp_transport_(is_srtp_transport) { + network_thread_(rtp_transport_controller_->network_thread()) { parameters_.rtcp = rtcp_params; // CNAME should have been filled by OrtcFactory if empty. RTC_DCHECK(!parameters_.rtcp.cname.empty()); RTC_DCHECK(rtp_transport_controller); + + if (is_srtp_transport) { + srtp_transport_ = rtc::MakeUnique(rtcp == nullptr); + transport_ = srtp_transport_.get(); + } else { + unencrypted_rtp_transport_ = rtc::MakeUnique(rtcp == nullptr); + transport_ = unencrypted_rtp_transport_.get(); + } + RTC_DCHECK(transport_); + + network_thread_->Invoke(RTC_FROM_HERE, [=] { + SetRtpPacketTransport(rtp->GetInternal()); + if (rtcp) { + SetRtcpPacketTransport(rtcp->GetInternal()); + } + }); + + transport_->SignalReadyToSend.connect(this, + &RtpTransportAdapter::OnReadyToSend); + transport_->SignalPacketReceived.connect( + this, &RtpTransportAdapter::OnPacketReceived); + transport_->SignalWritableState.connect( + this, &RtpTransportAdapter::OnWritableState); } RtpTransportAdapter::~RtpTransportAdapter() { SignalDestroyed(this); } -PacketTransportInterface* RtpTransportAdapter::GetRtpPacketTransport() const { - return rtp_packet_transport_; -} - -PacketTransportInterface* RtpTransportAdapter::GetRtcpPacketTransport() const { - return rtcp_packet_transport_; -} - RTCError RtpTransportAdapter::SetParameters( const RtpTransportParameters& parameters) { if (!parameters.rtcp.mux && parameters_.rtcp.mux) { @@ -194,34 +211,20 @@ RTCError RtpTransportAdapter::SetParameters( RTCError RtpTransportAdapter::SetSrtpSendKey( const cricket::CryptoParams& params) { - if (send_key_) { - LOG_AND_RETURN_ERROR( - webrtc::RTCErrorType::UNSUPPORTED_OPERATION, - "Setting the SRTP send key twice is currently unsupported."); + if (!network_thread_->IsCurrent()) { + return network_thread_->Invoke( + RTC_FROM_HERE, [&] { return SetSrtpSendKey(params); }); } - if (receive_key_ && receive_key_->cipher_suite != params.cipher_suite) { - LOG_AND_RETURN_ERROR( - webrtc::RTCErrorType::UNSUPPORTED_OPERATION, - "The send key and receive key must have the same cipher suite."); - } - send_key_ = params; - return RTCError::OK(); + return transport_->SetSrtpSendKey(params); } RTCError RtpTransportAdapter::SetSrtpReceiveKey( const cricket::CryptoParams& params) { - if (receive_key_) { - LOG_AND_RETURN_ERROR( - webrtc::RTCErrorType::UNSUPPORTED_OPERATION, - "Setting the SRTP receive key twice is currently unsupported."); + if (!network_thread_->IsCurrent()) { + return network_thread_->Invoke( + RTC_FROM_HERE, [&] { return SetSrtpReceiveKey(params); }); } - if (send_key_ && send_key_->cipher_suite != params.cipher_suite) { - LOG_AND_RETURN_ERROR( - webrtc::RTCErrorType::UNSUPPORTED_OPERATION, - "The send key and receive key must have the same cipher suite."); - } - receive_key_ = params; - return RTCError::OK(); + return transport_->SetSrtpReceiveKey(params); } } // namespace webrtc diff --git a/ortc/rtptransportadapter.h b/ortc/rtptransportadapter.h index 2c98f5df87..72bd3f61ab 100644 --- a/ortc/rtptransportadapter.h +++ b/ortc/rtptransportadapter.h @@ -19,19 +19,25 @@ #include "media/base/streamparams.h" #include "ortc/rtptransportcontrolleradapter.h" #include "pc/channel.h" +#include "pc/rtptransport.h" +#include "pc/rtptransportinternal.h" +#include "pc/srtptransport.h" #include "rtc_base/constructormagic.h" #include "rtc_base/sigslot.h" namespace webrtc { - -// Implementation of SrtpTransportInterface to be used with RtpSenderAdapter, -// RtpReceiverAdapter, and RtpTransportControllerAdapter classes. This class -// is used to implement both a secure and insecure RTP transport. +// This class is a wrapper over an RtpTransport or an SrtpTransport. The base +// class RtpTransportInternalAdapter keeps a raw pointer, |transport_|, of the +// transport object and implements both the public SrtpTransportInterface and +// RtpTransport internal interface by calling the |transport_| underneath. +// +// This adapter can be used as an unencrypted RTP transport or an SrtpTransport +// with RtpSenderAdapter, RtpReceiverAdapter, and RtpTransportControllerAdapter. // // TODO(deadbeef): When BaseChannel is split apart into separate // "RtpTransport"/"RtpTransceiver"/"RtpSender"/"RtpReceiver" objects, this // adapter object can be removed. -class RtpTransportAdapter : public SrtpTransportInterface { +class RtpTransportAdapter : public RtpTransportInternalAdapter { public: // |rtp| can't be null. |rtcp| can if RTCP muxing is used immediately (meaning // |rtcp_parameters.mux| is also true). @@ -50,8 +56,12 @@ class RtpTransportAdapter : public SrtpTransportInterface { ~RtpTransportAdapter() override; // RtpTransportInterface implementation. - PacketTransportInterface* GetRtpPacketTransport() const override; - PacketTransportInterface* GetRtcpPacketTransport() const override; + PacketTransportInterface* GetRtpPacketTransport() const override { + return rtp_packet_transport_; + } + PacketTransportInterface* GetRtcpPacketTransport() const override { + return rtcp_packet_transport_; + } RTCError SetParameters(const RtpTransportParameters& parameters) override; RtpTransportParameters GetParameters() const override { return parameters_; } @@ -70,13 +80,9 @@ class RtpTransportAdapter : public SrtpTransportInterface { // returning this transport from GetTransports(). sigslot::signal1 SignalDestroyed; - // Used by the RtpTransportControllerAdapter to tell if an rtp sender or - // receiver can be created. - bool is_srtp_transport() { return is_srtp_transport_; } - // Used by the RtpTransportControllerAdapter to set keys for senders and - // receivers. - rtc::Optional send_key() { return send_key_; } - rtc::Optional receive_key() { return receive_key_; } + bool IsSrtpActive() const override { return transport_->IsSrtpActive(); } + + bool IsSrtpTransport() const { return srtp_transport_ != nullptr; } protected: RtpTransportAdapter* GetInternal() override { return this; } @@ -88,18 +94,29 @@ class RtpTransportAdapter : public SrtpTransportInterface { RtpTransportControllerAdapter* rtp_transport_controller, bool is_srtp_transport); - PacketTransportInterface* rtp_packet_transport_; - PacketTransportInterface* rtcp_packet_transport_; - RtpTransportControllerAdapter* const rtp_transport_controller_; + void OnReadyToSend(bool ready) { SignalReadyToSend(ready); } + + void OnPacketReceived(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketTime& time) { + SignalPacketReceived(rtcp, packet, time); + } + + void OnWritableState(bool writable) { SignalWritableState(writable); } + + PacketTransportInterface* rtp_packet_transport_ = nullptr; + PacketTransportInterface* rtcp_packet_transport_ = nullptr; + RtpTransportControllerAdapter* const rtp_transport_controller_ = nullptr; // Non-null if this class owns the transport controller. std::unique_ptr owned_rtp_transport_controller_; RtpTransportParameters parameters_; - // SRTP specific members. - rtc::Optional send_key_; - rtc::Optional receive_key_; - bool is_srtp_transport_; + // Only one of them is non-null; + std::unique_ptr unencrypted_rtp_transport_; + std::unique_ptr srtp_transport_; + + rtc::Thread* network_thread_ = nullptr; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpTransportAdapter); }; diff --git a/ortc/rtptransportcontroller_unittest.cc b/ortc/rtptransportcontroller_unittest.cc index a663b82e7f..49548417ee 100644 --- a/ortc/rtptransportcontroller_unittest.cc +++ b/ortc/rtptransportcontroller_unittest.cc @@ -185,6 +185,7 @@ TEST_F(RtpTransportControllerTest, auto video_sender_result = ortc_factory_->CreateRtpSender( cricket::MEDIA_TYPE_VIDEO, rtp_transport2.get()); EXPECT_TRUE(video_sender_result.ok()); + auto video_receiver_result = ortc_factory_->CreateRtpReceiver( cricket::MEDIA_TYPE_VIDEO, rtp_transport1.get()); EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION, diff --git a/ortc/rtptransportcontrolleradapter.cc b/ortc/rtptransportcontrolleradapter.cc index 5477eff516..b772ffadd8 100644 --- a/ortc/rtptransportcontrolleradapter.cc +++ b/ortc/rtptransportcontrolleradapter.cc @@ -97,10 +97,12 @@ RtpTransportControllerAdapter::CreateProxied( cricket::ChannelManager* channel_manager, webrtc::RtcEventLog* event_log, rtc::Thread* signaling_thread, - rtc::Thread* worker_thread) { + rtc::Thread* worker_thread, + rtc::Thread* network_thread) { std::unique_ptr wrapped( new RtpTransportControllerAdapter(config, channel_manager, event_log, - signaling_thread, worker_thread)); + signaling_thread, worker_thread, + network_thread)); return RtpTransportControllerProxyWithInternal< RtpTransportControllerAdapter>::Create(signaling_thread, worker_thread, std::move(wrapped)); @@ -610,9 +612,11 @@ RtpTransportControllerAdapter::RtpTransportControllerAdapter( cricket::ChannelManager* channel_manager, webrtc::RtcEventLog* event_log, rtc::Thread* signaling_thread, - rtc::Thread* worker_thread) + rtc::Thread* worker_thread, + rtc::Thread* network_thread) : signaling_thread_(signaling_thread), worker_thread_(worker_thread), + network_thread_(network_thread), media_config_(config), channel_manager_(channel_manager), event_log_(event_log), @@ -678,11 +682,7 @@ RTCError RtpTransportControllerAdapter::AttachAudioSender( "RtpSender and RtpReceiver is not currently " "supported."); } - RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_, - &remote_audio_description_); - if (!err.ok()) { - return err; - } + // If setting new transport, extract its RTCP parameters and create voice // channel. if (!inner_audio_transport_) { @@ -713,11 +713,7 @@ RTCError RtpTransportControllerAdapter::AttachVideoSender( "RtpSender and RtpReceiver is not currently " "supported."); } - RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_, - &remote_video_description_); - if (!err.ok()) { - return err; - } + // If setting new transport, extract its RTCP parameters and create video // channel. if (!inner_video_transport_) { @@ -748,11 +744,7 @@ RTCError RtpTransportControllerAdapter::AttachAudioReceiver( "RtpReceiver and RtpReceiver is not currently " "supported."); } - RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_, - &remote_audio_description_); - if (!err.ok()) { - return err; - } + // If setting new transport, extract its RTCP parameters and create voice // channel. if (!inner_audio_transport_) { @@ -783,11 +775,6 @@ RTCError RtpTransportControllerAdapter::AttachVideoReceiver( "RtpReceiver and RtpReceiver is not currently " "supported."); } - RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_, - &remote_video_description_); - if (!err.ok()) { - return err; - } // If setting new transport, extract its RTCP parameters and create video // channel. if (!inner_video_transport_) { @@ -877,26 +864,24 @@ void RtpTransportControllerAdapter::OnVideoReceiverDestroyed() { void RtpTransportControllerAdapter::CreateVoiceChannel() { voice_channel_ = channel_manager_->CreateVoiceChannel( - call_.get(), media_config_, - inner_audio_transport_->GetRtpPacketTransport()->GetInternal(), - inner_audio_transport_->GetRtcpPacketTransport() - ? inner_audio_transport_->GetRtcpPacketTransport()->GetInternal() - : nullptr, - signaling_thread_, "audio", false, cricket::AudioOptions()); + call_.get(), media_config_, inner_audio_transport_->GetInternal(), + signaling_thread_, "audio", false, rtc::CryptoOptions(), + cricket::AudioOptions()); RTC_DCHECK(voice_channel_); voice_channel_->Enable(true); + voice_channel_->DisableEncryption( + !inner_audio_transport_->GetInternal()->IsSrtpTransport()); } void RtpTransportControllerAdapter::CreateVideoChannel() { video_channel_ = channel_manager_->CreateVideoChannel( - call_.get(), media_config_, - inner_video_transport_->GetRtpPacketTransport()->GetInternal(), - inner_video_transport_->GetRtcpPacketTransport() - ? inner_video_transport_->GetRtcpPacketTransport()->GetInternal() - : nullptr, - signaling_thread_, "video", false, cricket::VideoOptions()); + call_.get(), media_config_, inner_video_transport_->GetInternal(), + signaling_thread_, "video", false, rtc::CryptoOptions(), + cricket::VideoOptions()); RTC_DCHECK(video_channel_); video_channel_->Enable(true); + video_channel_->DisableEncryption( + !inner_video_transport_->GetInternal()->IsSrtpTransport()); } void RtpTransportControllerAdapter::DestroyVoiceChannel() { @@ -989,25 +974,4 @@ RtpTransportControllerAdapter::MakeSendStreamParamsVec( return result; } -RTCError RtpTransportControllerAdapter::MaybeSetCryptos( - RtpTransportInterface* rtp_transport, - cricket::MediaContentDescription* local_description, - cricket::MediaContentDescription* remote_description) { - if (rtp_transport->GetInternal()->is_srtp_transport()) { - if (!rtp_transport->GetInternal()->send_key() || - !rtp_transport->GetInternal()->receive_key()) { - LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER, - "The SRTP send key or receive key is not set.") - } - std::vector cryptos; - cryptos.push_back(*(rtp_transport->GetInternal()->receive_key())); - local_description->set_cryptos(cryptos); - - cryptos.clear(); - cryptos.push_back(*(rtp_transport->GetInternal()->send_key())); - remote_description->set_cryptos(cryptos); - } - return RTCError::OK(); -} - } // namespace webrtc diff --git a/ortc/rtptransportcontrolleradapter.h b/ortc/rtptransportcontrolleradapter.h index ec30687979..bdc245dc6e 100644 --- a/ortc/rtptransportcontrolleradapter.h +++ b/ortc/rtptransportcontrolleradapter.h @@ -66,7 +66,8 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface, cricket::ChannelManager* channel_manager, webrtc::RtcEventLog* event_log, rtc::Thread* signaling_thread, - rtc::Thread* worker_thread); + rtc::Thread* worker_thread, + rtc::Thread* network_thread); ~RtpTransportControllerAdapter() override; @@ -100,6 +101,7 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface, // Methods used internally by other "adapter" classes. rtc::Thread* signaling_thread() const { return signaling_thread_; } rtc::Thread* worker_thread() const { return worker_thread_; } + rtc::Thread* network_thread() const { return network_thread_; } // |parameters.keepalive| will be set for ALL RTP transports in the call. RTCError SetRtpTransportParameters(const RtpTransportParameters& parameters, @@ -131,7 +133,8 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface, cricket::ChannelManager* channel_manager, webrtc::RtcEventLog* event_log, rtc::Thread* signaling_thread, - rtc::Thread* worker_thread); + rtc::Thread* worker_thread, + rtc::Thread* network_thread); void Init_w(); void Close_w(); @@ -180,15 +183,9 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface, const std::string& cname, const cricket::MediaContentDescription& description) const; - // If the |rtp_transport| is a SrtpTransport, set the cryptos of the - // audio/video content descriptions. - RTCError MaybeSetCryptos( - RtpTransportInterface* rtp_transport, - cricket::MediaContentDescription* local_description, - cricket::MediaContentDescription* remote_description); - rtc::Thread* signaling_thread_; rtc::Thread* worker_thread_; + rtc::Thread* network_thread_; // |transport_proxies_| and |inner_audio_transport_|/|inner_audio_transport_| // are somewhat redundant, but the latter are only set when // RtpSenders/RtpReceivers are attached to the transport. diff --git a/ortc/srtptransport_unittest.cc b/ortc/srtptransport_unittest.cc index 8323603af0..1506aa7041 100644 --- a/ortc/srtptransport_unittest.cc +++ b/ortc/srtptransport_unittest.cc @@ -122,49 +122,4 @@ TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyDifferentCipherSuite) { EXPECT_TRUE(receiver_result.ok()); } -class SrtpTransportTestWithMediaType - : public SrtpTransportTest, - public ::testing::WithParamInterface {}; - -// Tests that the senders cannot be created before setting the keys. -TEST_P(SrtpTransportTestWithMediaType, CreateSenderBeforeSettingKeys) { - auto sender_result = - ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get()); - EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type()); - EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok()); - sender_result = - ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get()); - EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type()); - EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok()); - // Ensure that after the keys are set, a sender can be created, despite the - // previous errors. - sender_result = - ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get()); - EXPECT_TRUE(sender_result.ok()); -} - -// Tests that the receivers cannot be created before setting the keys. -TEST_P(SrtpTransportTestWithMediaType, CreateReceiverBeforeSettingKeys) { - auto receiver_result = - ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get()); - EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, - receiver_result.error().type()); - EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok()); - receiver_result = - ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get()); - EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, - receiver_result.error().type()); - EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok()); - // Ensure that after the keys are set, a receiver can be created, despite the - // previous errors. - receiver_result = - ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get()); - EXPECT_TRUE(receiver_result.ok()); -} - -INSTANTIATE_TEST_CASE_P(SenderCreatationTest, - SrtpTransportTestWithMediaType, - ::testing::Values(cricket::MEDIA_TYPE_AUDIO, - cricket::MEDIA_TYPE_VIDEO)); - } // namespace webrtc diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 907d199168..b59de48ab3 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -42,8 +42,6 @@ rtc_static_library("rtc_pc_base") { "dtlssrtptransport.h", "externalhmac.cc", "externalhmac.h", - "jseptransport.cc", - "jseptransport.h", "jseptransport2.cc", "jseptransport2.h", "jseptransportcontroller.cc", @@ -66,8 +64,6 @@ rtc_static_library("rtc_pc_base") { "srtpsession.h", "srtptransport.cc", "srtptransport.h", - "transportcontroller.cc", - "transportcontroller.h", "transportstats.cc", "transportstats.h", ] @@ -280,7 +276,6 @@ if (rtc_include_tests) { "currentspeakermonitor_unittest.cc", "dtlssrtptransport_unittest.cc", "jseptransport2_unittest.cc", - "jseptransport_unittest.cc", "jseptransportcontroller_unittest.cc", "mediasession_unittest.cc", "rtcpmuxfilter_unittest.cc", @@ -290,7 +285,6 @@ if (rtc_include_tests) { "srtpsession_unittest.cc", "srtptestutil.h", "srtptransport_unittest.cc", - "transportcontroller_unittest.cc", ] include_dirs = [ "//third_party/libsrtp/srtp" ] @@ -350,7 +344,6 @@ if (rtc_include_tests) { "test/fakeperiodicvideosource.h", "test/fakertccertificategenerator.h", "test/fakesctptransport.h", - "test/faketransportcontroller.h", "test/fakevideotrackrenderer.h", "test/fakevideotracksource.h", "test/mock_datachannel.h", diff --git a/pc/channel.cc b/pc/channel.cc index 358cb77e55..6da647054c 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -98,20 +98,16 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread, rtc::Thread* signaling_thread, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required) + bool srtp_required, + rtc::CryptoOptions crypto_options) : worker_thread_(worker_thread), network_thread_(network_thread), signaling_thread_(signaling_thread), content_name_(content_name), - rtcp_mux_required_(rtcp_mux_required), - unencrypted_rtp_transport_( - rtc::MakeUnique(rtcp_mux_required)), srtp_required_(srtp_required), + crypto_options_(crypto_options), media_channel_(std::move(media_channel)) { RTC_DCHECK_RUN_ON(worker_thread_); - rtp_transport_ = unencrypted_rtp_transport_.get(); - ConnectToRtpTransport(); RTC_LOG(LS_INFO) << "Created channel for " << content_name; } @@ -162,33 +158,10 @@ void BaseChannel::DisconnectFromRtpTransport() { rtp_transport_->SetMetricsObserver(nullptr); } -void BaseChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport) { - RTC_DCHECK_RUN_ON(worker_thread_); - network_thread_->Invoke(RTC_FROM_HERE, [&] { - SetTransports_n(rtp_dtls_transport, rtcp_dtls_transport, - rtp_packet_transport, rtcp_packet_transport); - - if (rtcp_mux_required_) { - rtcp_mux_filter_.SetActive(); - } - }); - - // Both RTP and RTCP channels should be set, we can call SetInterface on - // the media channel and it can set network options. - media_channel_->SetInterface(this); -} - void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) { RTC_DCHECK_RUN_ON(worker_thread_); network_thread_->Invoke(RTC_FROM_HERE, [&] { SetRtpTransport(rtp_transport); - - if (rtcp_mux_required_) { - rtcp_mux_filter_.SetActive(); - } }); // Both RTP and RTCP channels should be set, we can call SetInterface on @@ -205,11 +178,8 @@ void BaseChannel::Deinit() { network_thread_->Invoke(RTC_FROM_HERE, [&] { FlushRtcpMessages_n(); - if (dtls_srtp_transport_) { - dtls_srtp_transport_->SetDtlsTransports(nullptr, nullptr); - } else { - rtp_transport_->SetRtpPacketTransport(nullptr); - rtp_transport_->SetRtcpPacketTransport(nullptr); + if (rtp_transport_) { + DisconnectFromRtpTransport(); } // Clear pending read packets/messages. network_thread_->Clear(&invoker_); @@ -221,143 +191,34 @@ void BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) { if (!network_thread_->IsCurrent()) { network_thread_->Invoke(RTC_FROM_HERE, [&] { SetRtpTransport(rtp_transport); - return; }); + return; } - RTC_DCHECK(rtp_transport); - if (rtp_transport_) { DisconnectFromRtpTransport(); } + rtp_transport_ = rtp_transport; - RTC_LOG(LS_INFO) << "Setting the RtpTransport for " << content_name(); - ConnectToRtpTransport(); + if (rtp_transport_) { + RTC_DCHECK(rtp_transport_->rtp_packet_transport()); + transport_name_ = rtp_transport_->rtp_packet_transport()->transport_name(); - UpdateWritableState_n(); -} + ConnectToRtpTransport(); + OnTransportReadyToSend(rtp_transport_->IsReadyToSend()); + UpdateWritableState_n(); -void BaseChannel::SetTransports(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { - network_thread_->Invoke( - RTC_FROM_HERE, - Bind(&BaseChannel::SetTransports_n, this, rtp_dtls_transport, - rtcp_dtls_transport, rtp_dtls_transport, rtcp_dtls_transport)); -} - -void BaseChannel::SetTransports( - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport) { - network_thread_->Invoke( - RTC_FROM_HERE, Bind(&BaseChannel::SetTransports_n, this, nullptr, nullptr, - rtp_packet_transport, rtcp_packet_transport)); -} - -void BaseChannel::SetTransports_n( - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - // Validate some assertions about the input. - RTC_DCHECK(rtp_packet_transport); - RTC_DCHECK_EQ(NeedsRtcpTransport(), rtcp_packet_transport != nullptr); - if (rtp_dtls_transport || rtcp_dtls_transport) { - // DTLS/non-DTLS pointers should be to the same object. - RTC_DCHECK(rtp_dtls_transport == rtp_packet_transport); - RTC_DCHECK(rtcp_dtls_transport == rtcp_packet_transport); - // Can't go from non-DTLS to DTLS. - RTC_DCHECK(!rtp_transport_->rtp_packet_transport() || rtp_dtls_transport_); - } else { - // Can't go from DTLS to non-DTLS. - RTC_DCHECK(!rtp_dtls_transport_); - } - // Transport names should be the same. - if (rtp_dtls_transport && rtcp_dtls_transport) { - 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(); - debug_name = transport_name_; - } else { - debug_name = rtp_packet_transport->transport_name(); - } - // 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(/*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(/*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. - UpdateWritableState_n(); -} - -void BaseChannel::SetTransport_n( - bool rtcp, - DtlsTransportInternal* new_dtls_transport, - rtc::PacketTransportInternal* new_packet_transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - if (new_dtls_transport) { - RTC_DCHECK(new_dtls_transport == new_packet_transport); - } - DtlsTransportInternal*& old_dtls_transport = - rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_; - rtc::PacketTransportInternal* old_packet_transport = - rtcp ? rtp_transport_->rtcp_packet_transport() - : rtp_transport_->rtp_packet_transport(); - - if (!old_packet_transport && !new_packet_transport) { - // Nothing to do. - return; - } - - RTC_DCHECK(old_packet_transport != new_packet_transport); - - old_dtls_transport = new_dtls_transport; - - // If there's no new transport, we're done. - if (!new_packet_transport) { - return; - } - - if (rtcp && new_dtls_transport) { - RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_active())) - << "Setting RTCP for DTLS/SRTP after the DTLS is active " - << "should never happen."; - } - - auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; - for (const auto& pair : socket_options) { - new_packet_transport->SetOption(pair.first, pair.second); + // Set the cached socket options. + for (const auto& pair : socket_options_) { + rtp_transport_->rtp_packet_transport()->SetOption(pair.first, + pair.second); + } + if (rtp_transport_->rtcp_packet_transport()) { + for (const auto& pair : rtcp_socket_options_) { + rtp_transport_->rtp_packet_transport()->SetOption(pair.first, + pair.second); + } + } } } @@ -416,12 +277,6 @@ bool BaseChannel::SetRemoteContent(const MediaContentDescription* content, Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc)); } -bool BaseChannel::NeedsRtcpTransport() { - // If this BaseChannel doesn't require RTCP mux and we haven't fully - // negotiated RTCP mux, we need an RTCP transport. - return !rtcp_mux_required_ && !rtcp_mux_filter_.IsFullyActive(); -} - bool BaseChannel::IsReadyToReceiveMedia_w() const { // Receive data if we are enabled and have local content, return enabled() && @@ -440,7 +295,7 @@ bool BaseChannel::IsReadyToSendMedia_n() const { return enabled() && webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) && webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) && - was_ever_writable() && (srtp_active() || !ShouldSetupDtlsSrtp_n()); + was_ever_writable() && (srtp_active() || encryption_disabled_); } bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet, @@ -463,6 +318,7 @@ int BaseChannel::SetOption_n(SocketType type, rtc::Socket::Option opt, int value) { RTC_DCHECK(network_thread_->IsCurrent()); + RTC_DCHECK(rtp_transport_); rtc::PacketTransportInternal* transport = nullptr; switch (type) { case ST_RTP: @@ -482,11 +338,6 @@ int BaseChannel::SetOption_n(SocketType type, void BaseChannel::OnWritableState(bool writable) { RTC_DCHECK(network_thread_->IsCurrent()); 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(); @@ -533,13 +384,14 @@ bool BaseChannel::SendPacket(bool rtcp, network_thread_->Post(RTC_FROM_HERE, this, message_id, data); return true; } + TRACE_EVENT0("webrtc", "BaseChannel::SendPacket"); // Now that we are on the correct thread, ensure we have a place to send this // packet before doing anything. (We might get RTCP packets that we don't // intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP // transport. - if (!rtp_transport_->IsWritable(rtcp)) { + if (!rtp_transport_ || !rtp_transport_->IsWritable(rtcp)) { return false; } @@ -571,18 +423,15 @@ bool BaseChannel::SendPacket(bool rtcp, 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()); } + // Bon voyage. 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 { - return rtp_transport_->HandlesPayloadType(packet_type); + return bundle_filter_.FindPayloadType(packet_type); } void BaseChannel::OnPacketReceived(bool rtcp, @@ -593,6 +442,11 @@ void BaseChannel::OnPacketReceived(bool rtcp, signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED); } + // Filter out the packet this channel cannot handle. + if (!rtcp && !bundle_filter_.DemuxPacket(packet->data(), packet->size())) { + return; + } + 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 @@ -652,12 +506,8 @@ void BaseChannel::DisableMedia_w() { } void BaseChannel::UpdateWritableState_n() { - rtc::PacketTransportInternal* rtp_packet_transport = - rtp_transport_->rtp_packet_transport(); - rtc::PacketTransportInternal* rtcp_packet_transport = - rtp_transport_->rtcp_packet_transport(); - if (rtp_packet_transport && rtp_packet_transport->writable() && - (!rtcp_packet_transport || rtcp_packet_transport->writable())) { + if (rtp_transport_->IsWritable(/*rtcp=*/true) && + rtp_transport_->IsWritable(/*rtcp=*/false)) { ChannelWritable_n(); } else { ChannelNotWritable_n(); @@ -678,11 +528,6 @@ void BaseChannel::ChannelWritable_n() { UpdateMediaSendRecvState(); } -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(); -} - void BaseChannel::ChannelNotWritable_n() { RTC_DCHECK(network_thread_->IsCurrent()); if (!writable_) @@ -693,238 +538,6 @@ void BaseChannel::ChannelNotWritable_n() { UpdateMediaSendRecvState(); } -bool BaseChannel::SetRtpTransportParameters( - const MediaContentDescription* content, - SdpType type, - ContentSource src, - const RtpHeaderExtensions& extensions, - std::string* error_desc) { - std::vector encrypted_extension_ids; - for (const webrtc::RtpExtension& extension : extensions) { - if (extension.encrypt) { - RTC_LOG(LS_INFO) << "Using " << (src == CS_LOCAL ? "local" : "remote") - << " encrypted extension: " << extension.ToString(); - encrypted_extension_ids.push_back(extension.id); - } - } - - // Cache srtp_required_ for belt and suspenders check on SendPacket - return network_thread_->Invoke( - RTC_FROM_HERE, - Bind(&BaseChannel::SetRtpTransportParameters_n, this, content, type, src, - encrypted_extension_ids, error_desc)); -} - -bool BaseChannel::SetRtpTransportParameters_n( - const MediaContentDescription* content, - SdpType type, - ContentSource src, - const std::vector& encrypted_extension_ids, - std::string* error_desc) { - RTC_DCHECK(network_thread_->IsCurrent()); - - if (!SetSrtp_n(content->cryptos(), type, src, encrypted_extension_ids, - error_desc)) { - return false; - } - - if (!SetRtcpMux_n(content->rtcp_mux(), type, src, error_desc)) { - return false; - } - - return true; -} - -// |dtls| will be set to true if DTLS is active for transport and crypto is -// empty. -bool BaseChannel::CheckSrtpConfig_n(const std::vector& cryptos, - bool* dtls, - std::string* error_desc) { - *dtls = rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive(); - if (*dtls && !cryptos.empty()) { - SafeSetError("Cryptos must be empty when DTLS is active.", error_desc); - return false; - } - return true; -} - -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_); - sdes_transport_ = rtc::MakeUnique( - std::move(unencrypted_rtp_transport_)); -#if defined(ENABLE_EXTERNAL_AUTH) - sdes_transport_->EnableExternalAuth(); -#endif - SetRtpTransport(sdes_transport_.get()); - 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_); - - auto srtp_transport = rtc::MakeUnique( - std::move(unencrypted_rtp_transport_)); -#if defined(ENABLE_EXTERNAL_AUTH) - srtp_transport->EnableExternalAuth(); -#endif - dtls_srtp_transport_ = - rtc::MakeUnique(std::move(srtp_transport)); - - SetRtpTransport(dtls_srtp_transport_.get()); - 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& cryptos, - SdpType type, - ContentSource src, - const std::vector& encrypted_extension_ids, - std::string* error_desc) { - TRACE_EVENT0("webrtc", "BaseChannel::SetSrtp_w"); - bool ret = false; - bool dtls = false; - ret = CheckSrtpConfig_n(cryptos, &dtls, error_desc); - if (!ret) { - return false; - } - - // If SRTP was not required, but we're setting a description that uses SDES, - // we need to upgrade to an SrtpTransport. - if (!sdes_transport_ && !dtls && !cryptos.empty()) { - EnableSdes_n(); - } - - if ((type == SdpType::kAnswer || type == SdpType::kPrAnswer) && dtls) { - EnableDtlsSrtp_n(); - } - - UpdateEncryptedHeaderExtensionIds(src, encrypted_extension_ids); - - if (!dtls) { - switch (type) { - case SdpType::kOffer: - ret = sdes_negotiator_.SetOffer(cryptos, src); - break; - case SdpType::kPrAnswer: - ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src); - break; - case SdpType::kAnswer: - ret = sdes_negotiator_.SetAnswer(cryptos, src); - break; - default: - break; - } - - // If setting an SDES answer succeeded, apply the negotiated parameters - // to the SRTP transport. - if ((type == SdpType::kPrAnswer || type == SdpType::kAnswer) && 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(sdes_negotiator_.send_key().size()), - *(cached_send_extension_ids_), - *(sdes_negotiator_.recv_cipher_suite()), - sdes_negotiator_.recv_key().data(), - static_cast(sdes_negotiator_.recv_key().size()), - *(cached_recv_extension_ids_)); - } else { - RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES."; - if (type == SdpType::kAnswer && 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(); - } - } - } - } - - if (!ret) { - SafeSetError("Failed to setup SRTP.", error_desc); - return false; - } - return true; -} - -bool BaseChannel::SetRtcpMux_n(bool enable, - SdpType type, - ContentSource src, - std::string* error_desc) { - // Provide a more specific error message for the RTCP mux "require" policy - // case. - if (rtcp_mux_required_ && !enable) { - SafeSetError( - "rtcpMuxPolicy is 'require', but media description does not " - "contain 'a=rtcp-mux'.", - error_desc); - return false; - } - bool ret = false; - switch (type) { - case SdpType::kOffer: - ret = rtcp_mux_filter_.SetOffer(enable, src); - break; - case SdpType::kPrAnswer: - // This may activate RTCP muxing, but we don't yet destroy the transport - // because the final answer may deactivate it. - ret = rtcp_mux_filter_.SetProvisionalAnswer(enable, src); - break; - case SdpType::kAnswer: - ret = rtcp_mux_filter_.SetAnswer(enable, src); - if (ret && rtcp_mux_filter_.IsActive()) { - ActivateRtcpMux(); - } - break; - default: - break; - } - if (!ret) { - SafeSetError("Failed to setup RTCP mux filter.", error_desc); - return false; - } - rtp_transport_->SetRtcpMuxEnabled(rtcp_mux_filter_.IsActive()); - // |rtcp_mux_filter_| can be active if |action| is SdpType::kPrAnswer or - // SdpType::kAnswer, but we only want to tear down the RTCP transport if we - // received a final answer. - if (rtcp_mux_filter_.IsActive()) { - // If the RTP transport is already writable, then so are we. - if (rtp_transport_->rtp_packet_transport()->writable()) { - ChannelWritable_n(); - } - } - - return true; -} - bool BaseChannel::AddRecvStream_w(const StreamParams& sp) { RTC_DCHECK(worker_thread() == rtc::Thread::Current()); return media_channel()->AddRecvStream(sp); @@ -1008,9 +621,8 @@ bool BaseChannel::UpdateRemoteStreams_w( RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions( const RtpHeaderExtensions& extensions) { - if (!rtp_dtls_transport_ || - !rtp_dtls_transport_->crypto_options() - .enable_encrypted_rtp_header_extensions) { + RTC_DCHECK(rtp_transport_); + if (crypto_options_.enable_encrypted_rtp_header_extensions) { RtpHeaderExtensions filtered; auto pred = [](const webrtc::RtpExtension& extension) { return !extension.encrypt; @@ -1023,39 +635,6 @@ RtpHeaderExtensions BaseChannel::GetFilteredRtpHeaderExtensions( return webrtc::RtpExtension::FilterDuplicateNonEncrypted(extensions); } -void BaseChannel::MaybeCacheRtpAbsSendTimeHeaderExtension_w( - const std::vector& extensions) { -// Absolute Send Time extension id is used only with external auth, -// so do not bother searching for it and making asyncronious call to set -// something that is not used. -#if defined(ENABLE_EXTERNAL_AUTH) - const webrtc::RtpExtension* send_time_extension = - webrtc::RtpExtension::FindHeaderExtensionByUri( - extensions, webrtc::RtpExtension::kAbsSendTimeUri); - int rtp_abs_sendtime_extn_id = - send_time_extension ? send_time_extension->id : -1; - invoker_.AsyncInvoke( - RTC_FROM_HERE, network_thread_, - Bind(&BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n, this, - rtp_abs_sendtime_extn_id)); -#endif -} - -void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n( - int rtp_abs_sendtime_extn_id) { - if (sdes_transport_) { - sdes_transport_->CacheRtpAbsSendTimeHeaderExtension( - rtp_abs_sendtime_extn_id); - } else if (dtls_srtp_transport_) { - dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension( - rtp_abs_sendtime_extn_id); - } else { - RTC_LOG(LS_WARNING) - << "Trying to cache the Absolute Send Time extension id " - "but the SRTP is not active."; - } -} - void BaseChannel::OnMessage(rtc::Message *pmsg) { TRACE_EVENT0("webrtc", "BaseChannel::OnMessage"); switch (pmsg->message_id) { @@ -1077,7 +656,7 @@ void BaseChannel::OnMessage(rtc::Message *pmsg) { } void BaseChannel::AddHandledPayloadType(int payload_type) { - rtp_transport_->AddHandledPayloadType(payload_type); + bundle_filter_.AddPayloadType(payload_type); } void BaseChannel::FlushRtcpMessages_n() { @@ -1104,47 +683,6 @@ void BaseChannel::SignalSentPacket_w(const rtc::SentPacket& sent_packet) { SignalSentPacket(sent_packet); } -void BaseChannel::UpdateEncryptedHeaderExtensionIds( - cricket::ContentSource source, - const std::vector& 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); - } - } -} - -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, rtc::Thread* network_thread, rtc::Thread* signaling_thread, @@ -1152,21 +690,20 @@ VoiceChannel::VoiceChannel(rtc::Thread* worker_thread, MediaEngineInterface* /* media_engine */, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required) + bool srtp_required, + rtc::CryptoOptions crypto_options) : BaseChannel(worker_thread, network_thread, signaling_thread, std::move(media_channel), content_name, - rtcp_mux_required, - srtp_required) {} + srtp_required, + crypto_options) {} VoiceChannel::~VoiceChannel() { TRACE_EVENT0("webrtc", "VoiceChannel::~VoiceChannel"); // this can't be done in the base class, since it calls a virtual DisableMedia_w(); - Deinit(); } void BaseChannel::UpdateMediaSendRecvState() { @@ -1208,11 +745,6 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content, RtpHeaderExtensions rtp_header_extensions = GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions()); - if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions, - error_desc)) { - return false; - } - AudioRecvParameters recv_params = last_recv_params_; RtpParametersFromMediaDescription(audio, rtp_header_extensions, &recv_params); if (!media_channel()->SetRecvParameters(recv_params)) { @@ -1257,11 +789,6 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content, RtpHeaderExtensions rtp_header_extensions = GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions()); - if (!SetRtpTransportParameters(content, type, CS_REMOTE, - rtp_header_extensions, error_desc)) { - return false; - } - AudioSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(audio, rtp_header_extensions, &send_params); @@ -1284,10 +811,6 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content, return false; } - if (audio->rtp_header_extensions_set()) { - MaybeCacheRtpAbsSendTimeHeaderExtension_w(rtp_header_extensions); - } - set_remote_content_direction(content->direction()); UpdateMediaSendRecvState_w(); return true; @@ -1298,22 +821,20 @@ VideoChannel::VideoChannel(rtc::Thread* worker_thread, rtc::Thread* signaling_thread, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required) + bool srtp_required, + rtc::CryptoOptions crypto_options) : BaseChannel(worker_thread, network_thread, signaling_thread, std::move(media_channel), content_name, - rtcp_mux_required, - srtp_required) {} + srtp_required, + crypto_options) {} VideoChannel::~VideoChannel() { TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel"); // this can't be done in the base class, since it calls a virtual DisableMedia_w(); - - Deinit(); } void VideoChannel::UpdateMediaSendRecvState_w() { @@ -1351,11 +872,6 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content, RtpHeaderExtensions rtp_header_extensions = GetFilteredRtpHeaderExtensions(video->rtp_header_extensions()); - if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions, - error_desc)) { - return false; - } - VideoRecvParameters recv_params = last_recv_params_; RtpParametersFromMediaDescription(video, rtp_header_extensions, &recv_params); if (!media_channel()->SetRecvParameters(recv_params)) { @@ -1400,11 +916,6 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content, RtpHeaderExtensions rtp_header_extensions = GetFilteredRtpHeaderExtensions(video->rtp_header_extensions()); - if (!SetRtpTransportParameters(content, type, CS_REMOTE, - rtp_header_extensions, error_desc)) { - return false; - } - VideoSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(video, rtp_header_extensions, &send_params); @@ -1430,11 +941,6 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content, SafeSetError("Failed to set remote video description streams.", error_desc); return false; } - - if (video->rtp_header_extensions_set()) { - MaybeCacheRtpAbsSendTimeHeaderExtension_w(rtp_header_extensions); - } - set_remote_content_direction(content->direction()); UpdateMediaSendRecvState_w(); return true; @@ -1445,36 +951,20 @@ RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread, rtc::Thread* signaling_thread, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required) + bool srtp_required, + rtc::CryptoOptions crypto_options) : BaseChannel(worker_thread, network_thread, signaling_thread, std::move(media_channel), content_name, - rtcp_mux_required, - srtp_required) {} + srtp_required, + crypto_options) {} RtpDataChannel::~RtpDataChannel() { TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel"); // this can't be done in the base class, since it calls a virtual DisableMedia_w(); - - Deinit(); -} - -void RtpDataChannel::Init_w( - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport) { - BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport, - rtp_packet_transport, rtcp_packet_transport); - - media_channel()->SignalDataReceived.connect(this, - &RtpDataChannel::OnDataReceived); - media_channel()->SignalReadyToSend.connect( - this, &RtpDataChannel::OnDataChannelReadyToSend); } void RtpDataChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) { @@ -1529,11 +1019,6 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, RtpHeaderExtensions rtp_header_extensions = GetFilteredRtpHeaderExtensions(data->rtp_header_extensions()); - if (!SetRtpTransportParameters(content, type, CS_LOCAL, rtp_header_extensions, - error_desc)) { - return false; - } - DataRecvParameters recv_params = last_recv_params_; RtpParametersFromMediaDescription(data, rtp_header_extensions, &recv_params); if (!media_channel()->SetRecvParameters(recv_params)) { @@ -1588,11 +1073,6 @@ bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content, GetFilteredRtpHeaderExtensions(data->rtp_header_extensions()); RTC_LOG(LS_INFO) << "Setting remote data description"; - if (!SetRtpTransportParameters(content, type, CS_REMOTE, - rtp_header_extensions, error_desc)) { - return false; - } - DataSendParameters send_params = last_send_params_; RtpSendParametersFromMediaDescription(data, rtp_header_extensions, &send_params); diff --git a/pc/channel.h b/pc/channel.h index 6a8367a754..cf04b5c0b0 100644 --- a/pc/channel.h +++ b/pc/channel.h @@ -29,13 +29,12 @@ #include "p2p/base/dtlstransportinternal.h" #include "p2p/base/packettransportinternal.h" #include "pc/audiomonitor.h" +#include "pc/bundlefilter.h" #include "pc/dtlssrtptransport.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" #include "rtc_base/criticalsection.h" @@ -75,20 +74,16 @@ class BaseChannel public: // If |srtp_required| is true, the channel will not send or receive any // RTP/RTCP packets without using SRTP (either using SDES or DTLS-SRTP). + // TODO(zhihuang:) Create a BaseChannel::Config struct for the parameter lists + // which will make it easier to change the constructor. BaseChannel(rtc::Thread* worker_thread, rtc::Thread* network_thread, rtc::Thread* signaling_thread, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required); + bool srtp_required, + rtc::CryptoOptions crypto_options); virtual ~BaseChannel(); - // TODO(zhihuang): Remove this once the RtpTransport can be shared between - // BaseChannels. - void Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport); void Init_w(webrtc::RtpTransportInternal* rtp_transport); // Deinit may be called multiple times and is simply ignored if it's already @@ -102,16 +97,10 @@ class BaseChannel const std::string& transport_name() const { return transport_name_; } bool enabled() const { return enabled_; } - // This function returns true if we are using SDES. - 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_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(); } + bool srtp_active() const { + return rtp_transport_ && rtp_transport_->IsSrtpActive(); + } bool writable() const { return writable_; } @@ -121,20 +110,6 @@ class BaseChannel // internally. It would replace the |SetTransports| and its variants. void SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport); - // Set the transport(s), and update writability and "ready-to-send" state. - // |rtp_transport| must be non-null. - // |rtcp_transport| must be supplied if NeedsRtcpTransport() is true (meaning - // RTCP muxing is not fully active yet). - // |rtp_transport| and |rtcp_transport| must share the same transport name as - // well. - // Can not start with "rtc::PacketTransportInternal" and switch to - // "DtlsTransportInternal", or vice-versa. - // TODO(zhihuang): Remove these two once the RtpTransport can be shared - // between BaseChannels. - void SetTransports(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); - void SetTransports(rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport); // Channel control bool SetLocalContent(const MediaContentDescription* content, webrtc::SdpType type, @@ -173,15 +148,19 @@ class BaseChannel // Fired on the network thread. sigslot::signal1 SignalRtcpMuxFullyActive; - // Only public for unit tests. Otherwise, consider private. - DtlsTransportInternal* rtp_dtls_transport() const { - return rtp_dtls_transport_; - } - DtlsTransportInternal* rtcp_dtls_transport() const { - return rtcp_dtls_transport_; + rtc::PacketTransportInternal* rtp_packet_transport() { + if (rtp_transport_) { + return rtp_transport_->rtp_packet_transport(); + } + return nullptr; } - bool NeedsRtcpTransport(); + rtc::PacketTransportInternal* rtcp_packet_transport() { + if (rtp_transport_) { + return rtp_transport_->rtcp_packet_transport(); + } + return nullptr; + } // From RtpTransport - public for testing only void OnTransportReadyToSend(bool ready); @@ -207,22 +186,11 @@ class BaseChannel void SetMetricsObserver( rtc::scoped_refptr metrics_observer); + void DisableEncryption(bool disabled) { encryption_disabled_ = disabled; } + protected: virtual MediaChannel* media_channel() const { return media_channel_.get(); } - void SetTransports_n(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport); - - // This does not update writability or "ready-to-send" state; it just - // disconnects from the old channel and connects to the new one. - // TODO(zhihuang): Remove this once the RtpTransport can be shared between - // BaseChannels. - void SetTransport_n(bool rtcp, - DtlsTransportInternal* new_dtls_transport, - rtc::PacketTransportInternal* new_packet_transport); - bool was_ever_writable() const { return was_ever_writable_; } void set_local_content_direction(webrtc::RtpTransceiverDirection direction) { local_content_direction_ = direction; @@ -289,11 +257,6 @@ class BaseChannel bool RemoveRecvStream_w(uint32_t ssrc); bool AddSendStream_w(const StreamParams& sp); bool RemoveSendStream_w(uint32_t ssrc); - bool ShouldSetupDtlsSrtp_n() const; - // Do the DTLS key expansion and impose it on the SRTP/SRTCP filters. - // |rtcp_channel| indicates whether to set up the RTP or RTCP filter. - bool SetupDtlsSrtp_n(bool rtcp); - void MaybeSetupDtlsSrtp_n(); // Should be called whenever the conditions for // IsReadyToReceiveMedia/IsReadyToSendMedia are satisfied (or unsatisfied). @@ -313,18 +276,6 @@ class BaseChannel virtual bool SetRemoteContent_w(const MediaContentDescription* content, webrtc::SdpType type, std::string* error_desc) = 0; - bool SetRtpTransportParameters(const MediaContentDescription* content, - webrtc::SdpType type, - ContentSource src, - const RtpHeaderExtensions& extensions, - std::string* error_desc); - bool SetRtpTransportParameters_n( - const MediaContentDescription* content, - webrtc::SdpType type, - ContentSource src, - const std::vector& encrypted_extension_ids, - std::string* error_desc); - // Return a list of RTP header extensions with the non-encrypted extensions // removed depending on the current crypto_options_ and only if both the // non-encrypted and encrypted extension is present for the same URI. @@ -336,19 +287,6 @@ class BaseChannel void MaybeCacheRtpAbsSendTimeHeaderExtension_w( const std::vector& extensions); - bool CheckSrtpConfig_n(const std::vector& cryptos, - bool* dtls, - std::string* error_desc); - bool SetSrtp_n(const std::vector& params, - webrtc::SdpType type, - ContentSource src, - const std::vector& encrypted_extension_ids, - std::string* error_desc); - bool SetRtcpMux_n(bool enable, - webrtc::SdpType type, - ContentSource src, - std::string* error_desc); - // From MessageHandler void OnMessage(rtc::Message* pmsg) override; @@ -366,26 +304,6 @@ class BaseChannel 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 EnableSdes_n(); - - // 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. If DTLS-SRTP is enabled, it also update the encrypted header - // extension IDs for DtlsSrtpTransport. - void UpdateEncryptedHeaderExtensionIds(cricket::ContentSource source, - const std::vector& 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_; rtc::Thread* const signaling_thread_; @@ -396,16 +314,8 @@ class BaseChannel // Won't be set when using raw packet transports. SDP-specific thing. std::string transport_name_; - const bool rtcp_mux_required_; - rtc::scoped_refptr metrics_observer_; - // Separate DTLS/non-DTLS pointers to support using BaseChannel without DTLS. - // Temporary measure until more refactoring is done. - // If non-null, "X_dtls_transport_" will always equal "X_packet_transport_". - DtlsTransportInternal* rtp_dtls_transport_ = nullptr; - DtlsTransportInternal* rtcp_dtls_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. @@ -415,12 +325,11 @@ class BaseChannel std::vector > socket_options_; std::vector > rtcp_socket_options_; - SrtpFilter sdes_negotiator_; - RtcpMuxFilter rtcp_mux_filter_; bool writable_ = false; bool was_ever_writable_ = false; bool has_received_packet_ = false; const bool srtp_required_ = true; + rtc::CryptoOptions crypto_options_; // MediaChannel related members that should be accessed from the worker // thread. @@ -439,6 +348,11 @@ class BaseChannel // The cached encrypted header extension IDs. rtc::Optional> cached_send_extension_ids_; rtc::Optional> cached_recv_extension_ids_; + + // TODO(zhihuang): These two variables can be removed once switching to + // RtpDemuxer. + BundleFilter bundle_filter_; + bool encryption_disabled_ = false; }; // VoiceChannel is a specialization that adds support for early media, DTMF, @@ -451,8 +365,8 @@ class VoiceChannel : public BaseChannel { MediaEngineInterface* media_engine, std::unique_ptr channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required); + bool srtp_required, + rtc::CryptoOptions crypto_options); ~VoiceChannel(); // downcasts a MediaChannel @@ -491,8 +405,8 @@ class VideoChannel : public BaseChannel { rtc::Thread* signaling_thread, std::unique_ptr media_channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required); + bool srtp_required, + rtc::CryptoOptions crypto_options); ~VideoChannel(); // downcasts a MediaChannel @@ -530,8 +444,8 @@ class RtpDataChannel : public BaseChannel { rtc::Thread* signaling_thread, std::unique_ptr channel, const std::string& content_name, - bool rtcp_mux_required, - bool srtp_required); + bool srtp_required, + rtc::CryptoOptions crypto_options); ~RtpDataChannel(); // TODO(zhihuang): Remove this once the RtpTransport can be shared between // BaseChannels. diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc index 7ee35013ac..c398f07263 100644 --- a/pc/channel_unittest.cc +++ b/pc/channel_unittest.cc @@ -91,15 +91,11 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { public: enum Flags { RTCP_MUX = 0x1, - RTCP_MUX_REQUIRED = 0x2, - SECURE = 0x4, SSRC_MUX = 0x8, DTLS = 0x10, // Use BaseChannel with PacketTransportInternal rather than // DtlsTransportInternal. RAW_PACKET_TRANSPORT = 0x20, - GCM_CIPHER = 0x40, - ENCRYPTED_HEADERS = 0x80, }; ChannelTest(bool verify_playout, @@ -135,9 +131,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { if (network_thread_keeper_) { network_thread_keeper_->Start(); } - // Make sure RTCP_MUX_REQUIRED isn't set without RTCP_MUX. - RTC_DCHECK_NE(RTCP_MUX_REQUIRED, flags1 & (RTCP_MUX | RTCP_MUX_REQUIRED)); - RTC_DCHECK_NE(RTCP_MUX_REQUIRED, flags2 & (RTCP_MUX | RTCP_MUX_REQUIRED)); + // Make sure if using raw packet transports, they're used for both // channels. RTC_DCHECK_EQ(flags1 & RAW_PACKET_TRANSPORT, flags2 & RAW_PACKET_TRANSPORT); @@ -153,7 +147,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { fake_rtp_packet_transport1_.reset( new rtc::FakePacketTransport("channel1_rtp")); rtp1 = fake_rtp_packet_transport1_.get(); - if (!(flags1 & RTCP_MUX_REQUIRED)) { + if (!(flags1 & RTCP_MUX)) { fake_rtcp_packet_transport1_.reset( new rtc::FakePacketTransport("channel1_rtcp")); rtcp1 = fake_rtcp_packet_transport1_.get(); @@ -163,7 +157,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { fake_rtp_dtls_transport1_.reset(new cricket::FakeDtlsTransport( "channel1", cricket::ICE_CANDIDATE_COMPONENT_RTP)); rtp1 = fake_rtp_dtls_transport1_.get(); - if (!(flags1 & RTCP_MUX_REQUIRED)) { + if (!(flags1 & RTCP_MUX)) { fake_rtcp_dtls_transport1_.reset(new cricket::FakeDtlsTransport( "channel1", cricket::ICE_CANDIDATE_COMPONENT_RTCP)); rtcp1 = fake_rtcp_dtls_transport1_.get(); @@ -177,29 +171,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { fake_rtcp_dtls_transport1_->SetLocalCertificate(cert1); } } - if (flags1 & ENCRYPTED_HEADERS) { - rtc::CryptoOptions crypto_options; - crypto_options.enable_encrypted_rtp_header_extensions = true; - fake_rtp_dtls_transport1_->SetCryptoOptions(crypto_options); - if (fake_rtcp_dtls_transport1_) { - fake_rtcp_dtls_transport1_->SetCryptoOptions(crypto_options); - } - } - if (flags1 & GCM_CIPHER) { - fake_rtp_dtls_transport1_->SetSrtpCryptoSuite( - rtc::SRTP_AEAD_AES_256_GCM); - if (fake_rtcp_dtls_transport1_) { - fake_rtcp_dtls_transport1_->SetSrtpCryptoSuite( - rtc::SRTP_AEAD_AES_256_GCM); - } - } } // Based on flags, create fake DTLS or raw packet transports. if (flags2 & RAW_PACKET_TRANSPORT) { fake_rtp_packet_transport2_.reset( new rtc::FakePacketTransport("channel2_rtp")); rtp2 = fake_rtp_packet_transport2_.get(); - if (!(flags2 & RTCP_MUX_REQUIRED)) { + if (!(flags2 & RTCP_MUX)) { fake_rtcp_packet_transport2_.reset( new rtc::FakePacketTransport("channel2_rtcp")); rtcp2 = fake_rtcp_packet_transport2_.get(); @@ -209,7 +187,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { fake_rtp_dtls_transport2_.reset(new cricket::FakeDtlsTransport( "channel2", cricket::ICE_CANDIDATE_COMPONENT_RTP)); rtp2 = fake_rtp_dtls_transport2_.get(); - if (!(flags2 & RTCP_MUX_REQUIRED)) { + if (!(flags2 & RTCP_MUX)) { fake_rtcp_dtls_transport2_.reset(new cricket::FakeDtlsTransport( "channel2", cricket::ICE_CANDIDATE_COMPONENT_RTCP)); rtcp2 = fake_rtcp_dtls_transport2_.get(); @@ -223,39 +201,24 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { fake_rtcp_dtls_transport2_->SetLocalCertificate(cert2); } } - if (flags2 & ENCRYPTED_HEADERS) { - rtc::CryptoOptions crypto_options; - crypto_options.enable_encrypted_rtp_header_extensions = true; - fake_rtp_dtls_transport2_->SetCryptoOptions(crypto_options); - if (fake_rtcp_dtls_transport2_) { - fake_rtcp_dtls_transport2_->SetCryptoOptions(crypto_options); - } - } - if (flags2 & GCM_CIPHER) { - fake_rtp_dtls_transport2_->SetSrtpCryptoSuite( - rtc::SRTP_AEAD_AES_256_GCM); - if (fake_rtcp_dtls_transport2_) { - fake_rtcp_dtls_transport2_->SetSrtpCryptoSuite( - rtc::SRTP_AEAD_AES_256_GCM); - } - } } - channel1_ = - CreateChannel(worker_thread, network_thread_, &media_engine_, - std::move(ch1), fake_rtp_dtls_transport1_.get(), - fake_rtcp_dtls_transport1_.get(), rtp1, rtcp1, flags1); - channel2_ = - CreateChannel(worker_thread, network_thread_, &media_engine_, - std::move(ch2), fake_rtp_dtls_transport2_.get(), - fake_rtcp_dtls_transport2_.get(), rtp2, rtcp2, flags2); + rtp_transport1_ = CreateRtpTransportBasedOnFlags( + fake_rtp_packet_transport1_.get(), fake_rtcp_packet_transport1_.get(), + fake_rtp_dtls_transport1_.get(), fake_rtcp_dtls_transport1_.get(), + flags1); + rtp_transport2_ = CreateRtpTransportBasedOnFlags( + fake_rtp_packet_transport2_.get(), fake_rtcp_packet_transport2_.get(), + fake_rtp_dtls_transport2_.get(), fake_rtcp_dtls_transport2_.get(), + flags2); + + channel1_ = CreateChannel(worker_thread, network_thread_, &media_engine_, + std::move(ch1), rtp_transport1_.get(), flags1); + channel2_ = CreateChannel(worker_thread, network_thread_, &media_engine_, + std::move(ch2), rtp_transport2_.get(), flags2); channel1_->SignalRtcpMuxFullyActive.connect( this, &ChannelTest::OnRtcpMuxFullyActive1); channel2_->SignalRtcpMuxFullyActive.connect( this, &ChannelTest::OnRtcpMuxFullyActive2); - if ((flags1 & DTLS) && (flags2 & DTLS)) { - flags1 = (flags1 & ~SECURE); - flags2 = (flags2 & ~SECURE); - } CreateContent(flags1, kPcmuCodec, kH264Codec, &local_media_content1_); CreateContent(flags2, kPcmuCodec, kH264Codec, @@ -276,30 +239,81 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { if (flags2 & SSRC_MUX) { AddLegacyStreamInContent(kSsrc2, flags2, &remote_media_content2_); } + + if (!(flags1 & DTLS)) { + channel1_->DisableEncryption(true); + } + if (!(flags2 & DTLS)) { + channel2_->DisableEncryption(true); + } } std::unique_ptr CreateChannel( rtc::Thread* worker_thread, rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, std::unique_ptr ch, - cricket::DtlsTransportInternal* fake_rtp_dtls_transport, - cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, - rtc::PacketTransportInternal* fake_rtp_packet_transport, - rtc::PacketTransportInternal* fake_rtcp_packet_transport, + webrtc::RtpTransportInternal* rtp_transport, int flags) { rtc::Thread* signaling_thread = rtc::Thread::Current(); auto channel = rtc::MakeUnique( worker_thread, network_thread, signaling_thread, engine, std::move(ch), - cricket::CN_AUDIO, (flags & RTCP_MUX_REQUIRED) != 0, - (flags & SECURE) != 0); - if (!channel->NeedsRtcpTransport()) { - fake_rtcp_dtls_transport = nullptr; - } - channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, - fake_rtp_packet_transport, fake_rtcp_packet_transport); + cricket::CN_AUDIO, (flags & DTLS) != 0, rtc::CryptoOptions()); + channel->Init_w(rtp_transport); return channel; } + std::unique_ptr CreateRtpTransportBasedOnFlags( + rtc::PacketTransportInternal* rtp_packet_transport, + rtc::PacketTransportInternal* rtcp_packet_transport, + DtlsTransportInternal* rtp_dtls_transport, + DtlsTransportInternal* rtcp_dtls_transport, + int flags) { + if (flags & RTCP_MUX) { + rtcp_packet_transport = nullptr; + rtcp_dtls_transport = nullptr; + } + + if (flags & DTLS) { + return CreateDtlsSrtpTransport(rtp_dtls_transport, rtcp_dtls_transport); + } else { + if (flags & RAW_PACKET_TRANSPORT) { + return CreateUnencryptedTransport(rtp_packet_transport, + rtcp_packet_transport); + } else { + return CreateUnencryptedTransport(rtp_dtls_transport, + rtcp_dtls_transport); + } + } + } + + std::unique_ptr CreateUnencryptedTransport( + rtc::PacketTransportInternal* rtp_packet_transport, + rtc::PacketTransportInternal* rtcp_packet_transport) { + bool rtcp_mux_enabled = (rtcp_packet_transport == nullptr); + auto rtp_transport = + rtc::MakeUnique(rtcp_mux_enabled); + + rtp_transport->SetRtpPacketTransport(rtp_packet_transport); + if (rtcp_packet_transport) { + rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport); + } + return rtp_transport; + } + + std::unique_ptr CreateDtlsSrtpTransport( + cricket::DtlsTransportInternal* rtp_dtls_transport, + cricket::DtlsTransportInternal* rtcp_dtls_transport) { + bool rtcp_mux_enabled = (rtcp_dtls_transport == nullptr); + auto srtp_transport = + rtc::MakeUnique(rtcp_mux_enabled); + auto dtls_srtp_transport = + rtc::MakeUnique(std::move(srtp_transport)); + + dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport, + rtcp_dtls_transport); + return dtls_srtp_transport; + } + void ConnectFakeTransports() { network_thread_->Invoke(RTC_FROM_HERE, [this] { bool asymmetric = false; @@ -507,7 +521,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // kPcmuCodec is used as audio codec and kH264Codec is used as video codec. typename T::Content* CreateMediaContentWithStream(uint32_t ssrc) { typename T::Content* content = new typename T::Content(); - CreateContent(SECURE, kPcmuCodec, kH264Codec, content); + CreateContent(0, kPcmuCodec, kH264Codec, content); AddLegacyStreamInContent(ssrc, 0, content); return content; } @@ -693,7 +707,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Let channel 2 update the content by sending |stream2| and enable SRTP. typename T::Content content3; - CreateContent(SECURE, kPcmuCodec, kH264Codec, &content3); + CreateContent(0, kPcmuCodec, kH264Codec, &content3); content3.AddStream(stream2); EXPECT_TRUE(channel2_->SetLocalContent(&content3, SdpType::kOffer, NULL)); ASSERT_EQ(1u, media_channel2_->send_streams().size()); @@ -705,197 +719,18 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Channel 1 replies but stop sending stream1. typename T::Content content4; - CreateContent(SECURE, kPcmuCodec, kH264Codec, &content4); + CreateContent(0, kPcmuCodec, kH264Codec, &content4); EXPECT_TRUE(channel1_->SetLocalContent(&content4, SdpType::kAnswer, NULL)); EXPECT_EQ(0u, media_channel1_->send_streams().size()); EXPECT_TRUE(channel2_->SetRemoteContent(&content4, SdpType::kAnswer, NULL)); EXPECT_EQ(0u, media_channel2_->recv_streams().size()); - EXPECT_TRUE(channel1_->srtp_active()); - EXPECT_TRUE(channel2_->srtp_active()); SendCustomRtp2(kSsrc2, 0); WaitForThreads(); EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); } - enum EncryptedHeaderTestScenario { - // Offer/Answer are processed before DTLS completes. - DEFAULT, - // DTLS completes before any Offer/Answer have been sent. - DTLS_BEFORE_OFFER_ANSWER, - // DTLS completes after channel 2 has processed (remote) Offer and (local) - // Answer. - DTLS_AFTER_CHANNEL2_READY, - }; - - // Test that encrypted header extensions are working and can be changed when - // sending a new OFFER/ANSWER. - void TestChangeEncryptedHeaderExtensions(int flags, - EncryptedHeaderTestScenario scenario = DEFAULT) { - RTC_CHECK(scenario == 0 || (flags & DTLS)); - struct PacketListener : public sigslot::has_slots<> { - PacketListener() {} - void OnReadPacket(rtc::PacketTransportInternal* transport, - const char* data, size_t size, const rtc::PacketTime& time, - int flags) { - CompareHeaderExtensions( - reinterpret_cast(kPcmuFrameWithExtensions), - sizeof(kPcmuFrameWithExtensions), data, size, encrypted_headers, - false); - } - std::vector encrypted_headers; - } packet_listener1, packet_listener2; - - cricket::StreamParams stream1; - stream1.groupid = "group1"; - stream1.id = "stream1"; - stream1.ssrcs.push_back(kSsrc1); - stream1.cname = "stream1_cname"; - - cricket::StreamParams stream2; - stream2.groupid = "group1"; - stream2.id = "stream2"; - stream2.ssrcs.push_back(kSsrc2); - stream2.cname = "stream2_cname"; - - // Use SRTP when testing encrypted extensions. - int channel_flags = flags | SECURE | ENCRYPTED_HEADERS; - // Enable SDES if channel is not using DTLS. - int content_flags = (channel_flags & DTLS) == 0 ? SECURE : 0; - - // kPcmuFrameWithExtensions contains RTP extension headers with ids 1-4. - // Make sure to use URIs that are supported for encryption. - cricket::RtpHeaderExtensions extensions1; - extensions1.push_back( - RtpExtension(RtpExtension::kAudioLevelUri, 10)); - extensions1.push_back( - RtpExtension(RtpExtension::kAudioLevelUri, 1, true)); - - cricket::RtpHeaderExtensions extensions2; - extensions2.push_back( - RtpExtension(RtpExtension::kAudioLevelUri, 10)); - extensions2.push_back( - RtpExtension(RtpExtension::kAudioLevelUri, 2, true)); - extensions2.push_back( - RtpExtension(RtpExtension::kVideoRotationUri, 3)); - extensions2.push_back( - RtpExtension(RtpExtension::kTimestampOffsetUri, 4, true)); - - // Setup a call where channel 1 send |stream1| to channel 2. - CreateChannels(channel_flags, channel_flags); - fake_rtp_dtls_transport1_->fake_ice_transport()->SignalReadPacket.connect( - &packet_listener1, &PacketListener::OnReadPacket); - fake_rtp_dtls_transport2_->fake_ice_transport()->SignalReadPacket.connect( - &packet_listener2, &PacketListener::OnReadPacket); - - if (scenario == DTLS_BEFORE_OFFER_ANSWER) { - ConnectFakeTransports(); - WaitForThreads(); - } - - typename T::Content content1; - CreateContent(content_flags, kPcmuCodec, kH264Codec, &content1); - content1.AddStream(stream1); - content1.set_rtp_header_extensions(extensions1); - EXPECT_TRUE(channel1_->SetLocalContent(&content1, SdpType::kOffer, NULL)); - EXPECT_TRUE(channel1_->Enable(true)); - EXPECT_EQ(1u, media_channel1_->send_streams().size()); - packet_listener1.encrypted_headers.push_back(1); - - EXPECT_TRUE(channel2_->SetRemoteContent(&content1, SdpType::kOffer, NULL)); - EXPECT_EQ(1u, media_channel2_->recv_streams().size()); - - // Channel 2 sends back |stream2|. - typename T::Content content2; - CreateContent(content_flags, kPcmuCodec, kH264Codec, &content2); - content2.AddStream(stream2); - content2.set_rtp_header_extensions(extensions1); - EXPECT_TRUE(channel2_->SetLocalContent(&content2, SdpType::kAnswer, NULL)); - EXPECT_TRUE(channel2_->Enable(true)); - EXPECT_EQ(1u, media_channel2_->send_streams().size()); - packet_listener2.encrypted_headers.push_back(1); - - if (scenario == DTLS_AFTER_CHANNEL2_READY) { - ConnectFakeTransports(); - WaitForThreads(); - } - - if (scenario == DTLS_BEFORE_OFFER_ANSWER || - scenario == DTLS_AFTER_CHANNEL2_READY) { - // In both scenarios with partially completed Offer/Answer, sending - // packets from Channel 2 to Channel 1 should work. - SendCustomRtp2(kSsrc2, 0); - WaitForThreads(); - EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); - } - - EXPECT_TRUE(channel1_->SetRemoteContent(&content2, SdpType::kAnswer, NULL)); - EXPECT_EQ(1u, media_channel1_->recv_streams().size()); - - if (scenario == DEFAULT) { - ConnectFakeTransports(); - WaitForThreads(); - } - - SendCustomRtp1(kSsrc1, 0); - SendCustomRtp2(kSsrc2, 0); - WaitForThreads(); - EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); - EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); - - // Let channel 2 update the encrypted header extensions. - typename T::Content content3; - CreateContent(content_flags, kPcmuCodec, kH264Codec, &content3); - content3.AddStream(stream2); - content3.set_rtp_header_extensions(extensions2); - EXPECT_TRUE(channel2_->SetLocalContent(&content3, SdpType::kOffer, NULL)); - ASSERT_EQ(1u, media_channel2_->send_streams().size()); - EXPECT_EQ(stream2, media_channel2_->send_streams()[0]); - packet_listener2.encrypted_headers.clear(); - packet_listener2.encrypted_headers.push_back(2); - packet_listener2.encrypted_headers.push_back(4); - - EXPECT_TRUE(channel1_->SetRemoteContent(&content3, SdpType::kOffer, NULL)); - ASSERT_EQ(1u, media_channel1_->recv_streams().size()); - EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]); - - // Channel 1 is already sending the new encrypted extensions. These - // can be decrypted by channel 2. Channel 2 is still sending the old - // encrypted extensions (which can be decrypted by channel 1). - - if (flags & DTLS) { - // DTLS supports updating the encrypted extensions with only the OFFER - // being processed. For SDES both the OFFER and ANSWER must have been - // processed to update encrypted extensions, so we can't check this case. - SendCustomRtp1(kSsrc1, 0); - SendCustomRtp2(kSsrc2, 0); - WaitForThreads(); - EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); - EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); - } - - // Channel 1 replies with the same extensions. - typename T::Content content4; - CreateContent(content_flags, kPcmuCodec, kH264Codec, &content4); - content4.AddStream(stream1); - content4.set_rtp_header_extensions(extensions2); - EXPECT_TRUE(channel1_->SetLocalContent(&content4, SdpType::kAnswer, NULL)); - EXPECT_EQ(1u, media_channel1_->send_streams().size()); - packet_listener1.encrypted_headers.clear(); - packet_listener1.encrypted_headers.push_back(2); - packet_listener1.encrypted_headers.push_back(4); - - EXPECT_TRUE(channel2_->SetRemoteContent(&content4, SdpType::kAnswer, NULL)); - EXPECT_EQ(1u, media_channel2_->recv_streams().size()); - - SendCustomRtp1(kSsrc1, 0); - SendCustomRtp2(kSsrc2, 0); - WaitForThreads(); - EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); - EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); - } - // Test that we only start playout and sending at the right times. void TestPlayoutAndSendingStates() { CreateChannels(0, 0); @@ -1122,11 +957,11 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Send voice RTP data to the other side and ensure it gets there. void SendRtpToRtp() { - CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); + CreateChannels(RTCP_MUX, RTCP_MUX); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); + EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport()); + EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport()); SendRtp1(); SendRtp2(); WaitForThreads(); @@ -1154,8 +989,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); + EXPECT_NE(nullptr, channel1_->rtcp_packet_transport()); + EXPECT_NE(nullptr, channel2_->rtcp_packet_transport()); SendRtcp1(); SendRtcp2(); WaitForThreads(); @@ -1165,205 +1000,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtcp2()); } - // Check that RTCP is transmitted if only the initiator supports mux. - void SendRtcpMuxToRtcp() { - CreateChannels(RTCP_MUX, 0); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(SendAccept()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - - // Check that RTP and RTCP are transmitted ok when both sides support mux. - void SendRtcpMuxToRtcpMux() { - CreateChannels(RTCP_MUX, RTCP_MUX); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); - EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); - SendRtp1(); - SendRtp2(); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - - // Check that RTP and RTCP are transmitted ok when both sides - // support mux and one the offerer requires mux. - void SendRequireRtcpMuxToRtcpMux() { - CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX); - EXPECT_TRUE(SendInitiate()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - EXPECT_TRUE(SendAccept()); - SendRtp1(); - SendRtp2(); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - - // Check that RTP and RTCP are transmitted ok when both sides - // support mux and only the answerer requires rtcp mux. - void SendRtcpMuxToRequireRtcpMux() { - CreateChannels(RTCP_MUX, RTCP_MUX | RTCP_MUX_REQUIRED); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); - EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); - SendRtp1(); - SendRtp2(); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - - // Check that RTP and RTCP are transmitted ok when both sides - // require mux. - void SendRequireRtcpMuxToRequireRtcpMux() { - CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); - EXPECT_TRUE(SendInitiate()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - SendRtp1(); - SendRtp2(); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - - // Check that SendAccept fails if the answerer doesn't support mux - // and the offerer requires it. - void SendRequireRtcpMuxToNoRtcpMux() { - CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, 0); - EXPECT_TRUE(SendInitiate()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); - EXPECT_FALSE(SendAccept()); - } - - // Check that RTCP data sent by the initiator before the accept is not muxed. - void SendEarlyRtcpMuxToRtcp() { - CreateChannels(RTCP_MUX, 0); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); - - // RTCP can be sent before the call is accepted, if the transport is ready. - // It should not be muxed though, as the remote side doesn't support mux. - SendRtcp1(); - WaitForThreads(); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp2()); - - // Send RTCP packet from callee and verify that it is received. - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckRtcp1()); - - // Complete call setup and ensure everything is still OK. - EXPECT_TRUE(SendAccept()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckRtcp1()); - } - - - // Check that RTCP data is not muxed until both sides have enabled muxing, - // but that we properly demux before we get the accept message, since there - // is a race between RTP data and the jingle accept. - void SendEarlyRtcpMuxToRtcpMux() { - CreateChannels(RTCP_MUX, RTCP_MUX); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - - // RTCP can't be sent yet, since the RTCP transport isn't writable, and - // we haven't yet received the accept that says we should mux. - SendRtcp1(); - WaitForThreads(); - EXPECT_TRUE(CheckNoRtcp2()); - - // Send muxed RTCP packet from callee and verify that it is received. - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckRtcp1()); - - // Complete call setup and ensure everything is still OK. - EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); - EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckRtcp1()); - } - - // Test that we properly send SRTP with RTCP in both directions. - // You can pass in DTLS, RTCP_MUX, and RAW_PACKET_TRANSPORT as flags. - void SendSrtpToSrtp(int flags1_in = 0, int flags2_in = 0) { - RTC_CHECK((flags1_in & ~(RTCP_MUX | DTLS | RAW_PACKET_TRANSPORT)) == 0); - RTC_CHECK((flags2_in & ~(RTCP_MUX | DTLS | RAW_PACKET_TRANSPORT)) == 0); - - int flags1 = SECURE | flags1_in; - int flags2 = SECURE | flags2_in; - bool dtls1 = !!(flags1_in & DTLS); - bool dtls2 = !!(flags2_in & DTLS); - CreateChannels(flags1, flags2); + void SendDtlsSrtpToDtlsSrtp(int flags1, int flags2) { + CreateChannels(flags1 | DTLS, flags2 | DTLS); EXPECT_FALSE(channel1_->srtp_active()); EXPECT_FALSE(channel2_->srtp_active()); EXPECT_TRUE(SendInitiate()); @@ -1373,43 +1011,6 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(SendAccept()); EXPECT_TRUE(channel1_->srtp_active()); EXPECT_TRUE(channel2_->srtp_active()); - EXPECT_EQ(dtls1 && dtls2, channel1_->dtls_active()); - EXPECT_EQ(dtls1 && dtls2, channel2_->dtls_active()); - SendRtp1(); - SendRtp2(); - SendRtcp1(); - SendRtcp2(); - WaitForThreads(); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - 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); - EXPECT_FALSE(channel1_->srtp_active()); - EXPECT_FALSE(channel2_->srtp_active()); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->srtp_active()); - EXPECT_FALSE(channel2_->srtp_active()); SendRtp1(); SendRtp2(); SendRtcp1(); @@ -1430,14 +1031,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendEarlyMediaUsingRtcpMuxSrtp() { int sequence_number1_1 = 0, sequence_number2_2 = 0; - CreateChannels(SSRC_MUX | RTCP_MUX | SECURE, - SSRC_MUX | RTCP_MUX | SECURE); + CreateChannels(SSRC_MUX | RTCP_MUX | DTLS, SSRC_MUX | RTCP_MUX | DTLS); EXPECT_TRUE(SendOffer()); EXPECT_TRUE(SendProvisionalAnswer()); EXPECT_TRUE(channel1_->srtp_active()); EXPECT_TRUE(channel2_->srtp_active()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); + EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport()); + EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport()); WaitForThreads(); // Wait for 'sending' flag go through network thread. SendCustomRtcp1(kSsrc1); SendCustomRtp1(kSsrc1, ++sequence_number1_1); @@ -1453,13 +1053,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2)); // Complete call setup and ensure everything is still OK. - EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); - EXPECT_EQ(0, rtcp_mux_activated_callbacks2_); EXPECT_TRUE(SendFinalAnswer()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); - EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); - EXPECT_EQ(1, rtcp_mux_activated_callbacks2_); EXPECT_TRUE(channel1_->srtp_active()); EXPECT_TRUE(channel2_->srtp_active()); SendCustomRtcp1(kSsrc1); @@ -1496,37 +1090,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtcp2()); } - // Test that we properly send SRTP with RTCP from a thread. - void SendSrtpToSrtpOnThread() { - CreateChannels(SECURE, SECURE); - EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(SendAccept()); - ScopedCallThread send_rtp1([this] { SendRtp1(); }); - ScopedCallThread send_rtp2([this] { SendRtp2(); }); - ScopedCallThread send_rtcp1([this] { SendRtcp1(); }); - ScopedCallThread send_rtcp2([this] { SendRtcp2(); }); - rtc::Thread* involved_threads[] = {send_rtp1.thread(), send_rtp2.thread(), - send_rtcp1.thread(), - send_rtcp2.thread()}; - WaitForThreads(involved_threads); - EXPECT_TRUE(CheckRtp1()); - EXPECT_TRUE(CheckRtp2()); - EXPECT_TRUE(CheckNoRtp1()); - EXPECT_TRUE(CheckNoRtp2()); - EXPECT_TRUE(CheckRtcp1()); - EXPECT_TRUE(CheckRtcp2()); - EXPECT_TRUE(CheckNoRtcp1()); - EXPECT_TRUE(CheckNoRtcp2()); - } - // Test that the mediachannel retains its sending state after the transport // becomes non-writable. void SendWithWritabilityLoss() { - CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); + CreateChannels(RTCP_MUX, RTCP_MUX); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_FALSE(channel1_->NeedsRtcpTransport()); - EXPECT_FALSE(channel2_->NeedsRtcpTransport()); + EXPECT_EQ(nullptr, channel1_->rtcp_packet_transport()); + EXPECT_EQ(nullptr, channel2_->rtcp_packet_transport()); SendRtp1(); SendRtp2(); WaitForThreads(); @@ -1598,17 +1169,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { int pl_type1 = pl_types[0]; int pl_type2 = pl_types[1]; int flags = SSRC_MUX; - if (secure) flags |= SECURE; + if (secure) + flags |= DTLS; if (rtcp_mux) { flags |= RTCP_MUX; } CreateChannels(flags, flags); EXPECT_TRUE(SendInitiate()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(rtcp_mux, !channel1_->NeedsRtcpTransport()); - EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport()); EXPECT_TRUE(channel1_->HandlesPayloadType(pl_type1)); EXPECT_TRUE(channel2_->HandlesPayloadType(pl_type1)); EXPECT_FALSE(channel1_->HandlesPayloadType(pl_type2)); @@ -1623,13 +1191,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtp1()); EXPECT_TRUE(CheckNoRtp2()); - // RTCP test SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type2); SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type2); WaitForThreads(); EXPECT_FALSE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type2)); EXPECT_FALSE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type2)); + // RTCP test SendCustomRtcp1(kSsrc1); SendCustomRtcp2(kSsrc2); WaitForThreads(); @@ -1766,8 +1334,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_TRUE(channel1_->NeedsRtcpTransport()); - EXPECT_TRUE(channel2_->NeedsRtcpTransport()); + EXPECT_NE(nullptr, channel1_->rtcp_packet_transport()); + EXPECT_NE(nullptr, channel2_->rtcp_packet_transport()); // Send RTCP1 from a different thread. ScopedCallThread send_rtcp([this] { SendRtcp1(); }); @@ -1796,33 +1364,6 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_FALSE(media_channel1_->ready_to_send()); } - void TestOnTransportReadyToSendWithRtcpMux() { - CreateChannels(0, 0); - typename T::Content content; - CreateContent(0, kPcmuCodec, kH264Codec, &content); - // Both sides agree on mux. Should signal that RTCP mux is fully active. - content.set_rtcp_mux(true); - EXPECT_TRUE(channel1_->SetLocalContent(&content, SdpType::kOffer, NULL)); - EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); - EXPECT_TRUE(channel1_->SetRemoteContent(&content, SdpType::kAnswer, NULL)); - EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); - cricket::FakeDtlsTransport* rtp = fake_rtp_dtls_transport1_.get(); - EXPECT_FALSE(media_channel1_->ready_to_send()); - // In the case of rtcp mux, the SignalReadyToSend() from rtp channel - // should trigger the MediaChannel's OnReadyToSend. - network_thread_->Invoke(RTC_FROM_HERE, - [rtp] { rtp->SignalReadyToSend(rtp); }); - WaitForThreads(); - EXPECT_TRUE(media_channel1_->ready_to_send()); - - // TODO(zstein): Find a way to test this without making - // OnTransportReadyToSend public. - network_thread_->Invoke( - RTC_FROM_HERE, [this] { channel1_->OnTransportReadyToSend(false); }); - WaitForThreads(); - EXPECT_FALSE(media_channel1_->ready_to_send()); - } - bool SetRemoteContentWithBitrateLimit(int remote_limit) { typename T::Content content; CreateContent(0, kPcmuCodec, kH264Codec, &content); @@ -1853,9 +1394,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { rtc::nullopt); } - // Test that when a channel gets new transports with a call to - // |SetTransports|, the socket options from the old transports are merged with - // the options on the new transport. + // Test that when a channel gets new RtpTransport with a call to + // |SetRtpTransport|, the socket options from the old RtpTransport is merged + // with the options on the new one. + // For example, audio and video may use separate socket options, but initially // be unbundled, then later become bundled. When this happens, their preferred // socket options should be merged to the underlying transport they share. @@ -1863,22 +1405,27 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { constexpr int kSndBufSize = 4000; constexpr int kRcvBufSize = 8000; - CreateChannels(0, 0); + CreateChannels(DTLS, DTLS); channel1_->SetOption(cricket::BaseChannel::ST_RTP, rtc::Socket::Option::OPT_SNDBUF, kSndBufSize); channel2_->SetOption(cricket::BaseChannel::ST_RTP, rtc::Socket::Option::OPT_RCVBUF, kRcvBufSize); - channel1_->SetTransports(channel2_->rtp_dtls_transport(), - channel2_->rtcp_dtls_transport()); + new_rtp_transport_ = CreateDtlsSrtpTransport( + static_cast(channel2_->rtp_packet_transport()), + static_cast( + channel2_->rtcp_packet_transport())); + channel1_->SetRtpTransport(new_rtp_transport_.get()); int option_val; - ASSERT_TRUE(channel1_->rtp_dtls_transport()->GetOption( - rtc::Socket::Option::OPT_SNDBUF, &option_val)); + ASSERT_TRUE( + static_cast(channel1_->rtp_packet_transport()) + ->GetOption(rtc::Socket::Option::OPT_SNDBUF, &option_val)); EXPECT_EQ(kSndBufSize, option_val); - ASSERT_TRUE(channel1_->rtp_dtls_transport()->GetOption( - rtc::Socket::Option::OPT_RCVBUF, &option_val)); + ASSERT_TRUE( + static_cast(channel1_->rtp_packet_transport()) + ->GetOption(rtc::Socket::Option::OPT_RCVBUF, &option_val)); EXPECT_EQ(kRcvBufSize, option_val); } @@ -1918,6 +1465,9 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { std::unique_ptr fake_rtcp_packet_transport1_; std::unique_ptr fake_rtp_packet_transport2_; std::unique_ptr fake_rtcp_packet_transport2_; + std::unique_ptr rtp_transport1_; + std::unique_ptr rtp_transport2_; + std::unique_ptr new_rtp_transport_; cricket::FakeMediaEngine media_engine_; // The media channels are owned by the voice channel objects below. typename T::MediaChannel* media_channel1_ = nullptr; @@ -1944,11 +1494,6 @@ void ChannelTest::CreateContent( cricket::AudioContentDescription* audio) { audio->AddCodec(audio_codec); audio->set_rtcp_mux((flags & RTCP_MUX) != 0); - if ((flags & SECURE) && !(flags & DTLS)) { - audio->AddCrypto(cricket::CryptoParams( - 1, rtc::CS_AES_CM_128_HMAC_SHA1_32, - "inline:" + rtc::CreateRandomString(40), std::string())); - } } template<> @@ -2012,21 +1557,13 @@ std::unique_ptr ChannelTest::CreateChannel( rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, std::unique_ptr ch, - cricket::DtlsTransportInternal* fake_rtp_dtls_transport, - cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, - rtc::PacketTransportInternal* fake_rtp_packet_transport, - rtc::PacketTransportInternal* fake_rtcp_packet_transport, + webrtc::RtpTransportInternal* rtp_transport, int flags) { rtc::Thread* signaling_thread = rtc::Thread::Current(); auto channel = rtc::MakeUnique( worker_thread, network_thread, signaling_thread, std::move(ch), - cricket::CN_VIDEO, (flags & RTCP_MUX_REQUIRED) != 0, - (flags & SECURE) != 0); - if (!channel->NeedsRtcpTransport()) { - fake_rtcp_dtls_transport = nullptr; - } - channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, - fake_rtp_packet_transport, fake_rtcp_packet_transport); + cricket::CN_VIDEO, (flags & DTLS) != 0, rtc::CryptoOptions()); + channel->Init_w(rtp_transport); return channel; } @@ -2044,11 +1581,6 @@ void ChannelTest::CreateContent( cricket::VideoContentDescription* video) { video->AddCodec(video_codec); video->set_rtcp_mux((flags & RTCP_MUX) != 0); - if (flags & SECURE) { - video->AddCrypto(cricket::CryptoParams( - 1, rtc::CS_AES_CM_128_HMAC_SHA1_80, - "inline:" + rtc::CreateRandomString(40), std::string())); - } } template<> @@ -2120,48 +1652,6 @@ TEST_F(VoiceChannelSingleThreadTest, TestChangeStreamParamsInContent) { Base::TestChangeStreamParamsInContent(); } -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtls) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsScenario1) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsScenario2) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcm) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, - TestChangeEncryptedHeaderExtensionsSDES) { - int flags = 0; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - TEST_F(VoiceChannelSingleThreadTest, TestPlayoutAndSendingStates) { Base::TestPlayoutAndSendingStates(); } @@ -2190,66 +1680,12 @@ TEST_F(VoiceChannelSingleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToRtcpMux) { - Base::SendRequireRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendRtcpMuxToRequireRtcpMux) { - Base::SendRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) { - Base::SendRequireRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendRequireRtcpMuxToNoRtcpMux) { - Base::SendRequireRtcpMuxToNoRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpRtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - -TEST_F(VoiceChannelSingleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VoiceChannelSingleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - -TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendDtlsToSdesNotSupported(); -} - TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) { - Base::SendSrtpToSrtp(DTLS, DTLS); + Base::SendDtlsSrtpToDtlsSrtp(0, 0); } TEST_F(VoiceChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) { - Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX); -} - -// Test using the channel with a raw packet interface, as opposed to a DTLS -// transport interface. -TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpWithRawPacketTransport) { - Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT); + Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX); } TEST_F(VoiceChannelSingleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { @@ -2260,9 +1696,6 @@ TEST_F(VoiceChannelSingleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(VoiceChannelSingleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} TEST_F(VoiceChannelSingleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); @@ -2296,10 +1729,6 @@ TEST_F(VoiceChannelSingleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(VoiceChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(VoiceChannelSingleThreadTest, SendBundleToBundle) { Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, false); } @@ -2359,48 +1788,6 @@ TEST_F(VoiceChannelDoubleThreadTest, TestChangeStreamParamsInContent) { Base::TestChangeStreamParamsInContent(); } -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtls) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsScenario1) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsScenario2) { - int flags = DTLS; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcm) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcmScenario1) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_BEFORE_OFFER_ANSWER); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsDtlsGcmScenario2) { - int flags = DTLS | GCM_CIPHER; - Base::TestChangeEncryptedHeaderExtensions(flags, DTLS_AFTER_CHANNEL2_READY); -} - -TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, - TestChangeEncryptedHeaderExtensionsSDES) { - int flags = 0; - Base::TestChangeEncryptedHeaderExtensions(flags); -} - TEST_F(VoiceChannelDoubleThreadTest, TestPlayoutAndSendingStates) { Base::TestPlayoutAndSendingStates(); } @@ -2429,66 +1816,12 @@ TEST_F(VoiceChannelDoubleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToRtcpMux) { - Base::SendRequireRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendRtcpMuxToRequireRtcpMux) { - Base::SendRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) { - Base::SendRequireRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendRequireRtcpMuxToNoRtcpMux) { - Base::SendRequireRtcpMuxToNoRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpRtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - -TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendDtlsToSdesNotSupported(); -} - TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) { - Base::SendSrtpToSrtp(DTLS, DTLS); + Base::SendDtlsSrtpToDtlsSrtp(0, 0); } TEST_F(VoiceChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) { - Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX); -} - -// Test using the channel with a raw packet interface, as opposed to a DTLS -// transport interface. -TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpWithRawPacketTransport) { - Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT); + Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX); } TEST_F(VoiceChannelDoubleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { @@ -2499,10 +1832,6 @@ TEST_F(VoiceChannelDoubleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(VoiceChannelDoubleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} - TEST_F(VoiceChannelDoubleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); } @@ -2535,10 +1864,6 @@ TEST_F(VoiceChannelDoubleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(VoiceChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(VoiceChannelDoubleThreadTest, SendBundleToBundle) { Base::SendBundleToBundle(kAudioPts, arraysize(kAudioPts), false, false); } @@ -2624,66 +1949,12 @@ TEST_F(VideoChannelSingleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToRtcpMux) { - Base::SendRequireRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendRtcpMuxToRequireRtcpMux) { - Base::SendRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) { - Base::SendRequireRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendRequireRtcpMuxToNoRtcpMux) { - Base::SendRequireRtcpMuxToNoRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(VideoChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VideoChannelSingleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendDtlsToSdesNotSupported(); -} - TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtp) { - Base::SendSrtpToSrtp(DTLS, DTLS); + Base::SendDtlsSrtpToDtlsSrtp(0, 0); } TEST_F(VideoChannelSingleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) { - Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX); -} - -// Test using the channel with a raw packet interface, as opposed to a DTLS -// transport interface. -TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtpWithRawPacketTransport) { - Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT); -} - -TEST_F(VideoChannelSingleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); + Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX); } TEST_F(VideoChannelSingleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { @@ -2694,10 +1965,6 @@ TEST_F(VideoChannelSingleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(VideoChannelSingleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} - TEST_F(VideoChannelSingleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); } @@ -2746,10 +2013,6 @@ TEST_F(VideoChannelSingleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(VideoChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(VideoChannelSingleThreadTest, DefaultMaxBitrateIsUnlimited) { Base::DefaultMaxBitrateIsUnlimited(); } @@ -2819,66 +2082,12 @@ TEST_F(VideoChannelDoubleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToRtcpMux) { - Base::SendRequireRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendRtcpMuxToRequireRtcpMux) { - Base::SendRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToRequireRtcpMux) { - Base::SendRequireRtcpMuxToRequireRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendRequireRtcpMuxToNoRtcpMux) { - Base::SendRequireRtcpMuxToNoRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToSrtp) { - Base::SendDtlsToSdesNotSupported(); -} - TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtp) { - Base::SendSrtpToSrtp(DTLS, DTLS); + Base::SendDtlsSrtpToDtlsSrtp(0, 0); } TEST_F(VideoChannelDoubleThreadTest, SendDtlsSrtpToDtlsSrtpRtcpMux) { - Base::SendSrtpToSrtp(DTLS | RTCP_MUX, DTLS | RTCP_MUX); -} - -// Test using the channel with a raw packet interface, as opposed to a DTLS -// transport interface. -TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtpWithRawPacketTransport) { - Base::SendSrtpToSrtp(RAW_PACKET_TRANSPORT, RAW_PACKET_TRANSPORT); -} - -TEST_F(VideoChannelDoubleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); + Base::SendDtlsSrtpToDtlsSrtp(RTCP_MUX, RTCP_MUX); } TEST_F(VideoChannelDoubleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { @@ -2889,10 +2098,6 @@ TEST_F(VideoChannelDoubleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(VideoChannelDoubleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} - TEST_F(VideoChannelDoubleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); } @@ -2941,10 +2146,6 @@ TEST_F(VideoChannelDoubleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(VideoChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(VideoChannelDoubleThreadTest, DefaultMaxBitrateIsUnlimited) { Base::DefaultMaxBitrateIsUnlimited(); } @@ -2976,21 +2177,13 @@ std::unique_ptr ChannelTest::CreateChannel( rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, std::unique_ptr ch, - cricket::DtlsTransportInternal* fake_rtp_dtls_transport, - cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, - rtc::PacketTransportInternal* fake_rtp_packet_transport, - rtc::PacketTransportInternal* fake_rtcp_packet_transport, + webrtc::RtpTransportInternal* rtp_transport, int flags) { rtc::Thread* signaling_thread = rtc::Thread::Current(); auto channel = rtc::MakeUnique( worker_thread, network_thread, signaling_thread, std::move(ch), - cricket::CN_DATA, (flags & RTCP_MUX_REQUIRED) != 0, - (flags & SECURE) != 0); - if (!channel->NeedsRtcpTransport()) { - fake_rtcp_dtls_transport = nullptr; - } - channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, - fake_rtp_packet_transport, fake_rtcp_packet_transport); + cricket::CN_DATA, (flags & DTLS) != 0, rtc::CryptoOptions()); + channel->Init_w(rtp_transport); return channel; } @@ -3002,11 +2195,6 @@ void ChannelTest::CreateContent( cricket::DataContentDescription* data) { data->AddCodec(kGoogleDataCodec); data->set_rtcp_mux((flags & RTCP_MUX) != 0); - if (flags & SECURE) { - data->AddCrypto(cricket::CryptoParams( - 1, rtc::CS_AES_CM_128_HMAC_SHA1_32, - "inline:" + rtc::CreateRandomString(40), std::string())); - } } template <> @@ -3079,10 +2267,6 @@ TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtp) { Base::SendRtpToRtp(); } @@ -3091,42 +2275,10 @@ TEST_F(RtpDataChannelSingleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(RtpDataChannelSingleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToSrtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(RtpDataChannelSingleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(RtpDataChannelSingleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} - TEST_F(RtpDataChannelSingleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); } @@ -3199,10 +2351,6 @@ TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSend) { Base::TestOnTransportReadyToSend(); } -TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) { - Base::TestOnTransportReadyToSendWithRtcpMux(); -} - TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtp) { Base::SendRtpToRtp(); } @@ -3211,42 +2359,10 @@ TEST_F(RtpDataChannelDoubleThreadTest, SendRtcpToRtcp) { Base::SendRtcpToRtcp(); } -TEST_F(RtpDataChannelDoubleThreadTest, SendRtcpMuxToRtcp) { - Base::SendRtcpMuxToRtcp(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendRtcpMuxToRtcpMux) { - Base::SendRtcpMuxToRtcpMux(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcp) { - Base::SendEarlyRtcpMuxToRtcp(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendEarlyRtcpMuxToRtcpMux) { - Base::SendEarlyRtcpMuxToRtcpMux(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToSrtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToRtp) { - Base::SendSrtpToSrtp(); -} - -TEST_F(RtpDataChannelDoubleThreadTest, SendSrtcpMux) { - Base::SendSrtpToSrtp(RTCP_MUX, RTCP_MUX); -} - TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } -TEST_F(RtpDataChannelDoubleThreadTest, SendSrtpToSrtpOnThread) { - Base::SendSrtpToSrtpOnThread(); -} - TEST_F(RtpDataChannelDoubleThreadTest, SendWithWritabilityLoss) { Base::SendWithWritabilityLoss(); } @@ -3273,107 +2389,4 @@ TEST_F(RtpDataChannelDoubleThreadTest, TestSendData) { EXPECT_EQ("foo", media_channel1_->last_sent_data()); } -#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) - -// Verifies some DCHECKs are in place. -// Uses VoiceChannel, but any BaseChannel subclass would work. -class BaseChannelDeathTest : public testing::Test { - public: - BaseChannelDeathTest() - : fake_rtp_dtls_transport_("foo", cricket::ICE_CANDIDATE_COMPONENT_RTP), - fake_rtcp_dtls_transport_("foo", cricket::ICE_CANDIDATE_COMPONENT_RTCP), - // RTCP mux not required, SRTP required. - voice_channel_(rtc::Thread::Current(), - rtc::Thread::Current(), - rtc::Thread::Current(), - &fake_media_engine_, - rtc::MakeUnique( - nullptr, - cricket::AudioOptions()), - cricket::CN_AUDIO, - false, - true) {} - - protected: - cricket::FakeMediaEngine fake_media_engine_; - cricket::FakeDtlsTransport fake_rtp_dtls_transport_; - cricket::FakeDtlsTransport fake_rtcp_dtls_transport_; - cricket::VoiceChannel voice_channel_; -}; - -TEST_F(BaseChannelDeathTest, SetTransportsWithNullRtpTransport) { - voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_, - &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_); - cricket::FakeDtlsTransport new_rtcp_transport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP); - EXPECT_DEATH(voice_channel_.SetTransports(nullptr, &new_rtcp_transport), ""); -} - -TEST_F(BaseChannelDeathTest, SetTransportsWithMissingRtcpTransport) { - voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_, - &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_); - cricket::FakeDtlsTransport new_rtp_transport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - EXPECT_DEATH(voice_channel_.SetTransports(&new_rtp_transport, nullptr), ""); -} - -TEST_F(BaseChannelDeathTest, SetTransportsWithUnneededRtcpTransport) { - voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_, - &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_); - // Activate RTCP muxing, simulating offer/answer negotiation. - cricket::AudioContentDescription content; - content.set_rtcp_mux(true); - ASSERT_TRUE( - voice_channel_.SetLocalContent(&content, SdpType::kOffer, nullptr)); - ASSERT_TRUE( - voice_channel_.SetRemoteContent(&content, SdpType::kAnswer, nullptr)); - cricket::FakeDtlsTransport new_rtp_transport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::FakeDtlsTransport new_rtcp_transport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP); - // After muxing is enabled, no RTCP transport should be passed in here. - EXPECT_DEATH( - voice_channel_.SetTransports(&new_rtp_transport, &new_rtcp_transport), - ""); -} - -// This test will probably go away if/when we move the transport name out of -// the transport classes and into their parent classes. -TEST_F(BaseChannelDeathTest, SetTransportsWithMismatchingTransportNames) { - voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_, - &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_); - cricket::FakeDtlsTransport new_rtp_transport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::FakeDtlsTransport new_rtcp_transport( - "baz", cricket::ICE_CANDIDATE_COMPONENT_RTCP); - EXPECT_DEATH( - voice_channel_.SetTransports(&new_rtp_transport, &new_rtcp_transport), - ""); -} - -// Not expected to support going from DtlsTransportInternal to -// PacketTransportInternal. -TEST_F(BaseChannelDeathTest, SetTransportsDtlsToNonDtls) { - voice_channel_.Init_w(&fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_, - &fake_rtp_dtls_transport_, &fake_rtcp_dtls_transport_); - EXPECT_DEATH( - voice_channel_.SetTransports( - static_cast(&fake_rtp_dtls_transport_), - static_cast( - &fake_rtp_dtls_transport_)), - ""); -} - -// Not expected to support going from PacketTransportInternal to -// DtlsTransportInternal. -TEST_F(BaseChannelDeathTest, SetTransportsNonDtlsToDtls) { - voice_channel_.Init_w(nullptr, nullptr, &fake_rtp_dtls_transport_, - &fake_rtcp_dtls_transport_); - EXPECT_DEATH(voice_channel_.SetTransports(&fake_rtp_dtls_transport_, - &fake_rtp_dtls_transport_), - ""); -} - -#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) - // TODO(pthatcher): TestSetReceiver? diff --git a/pc/channelmanager.cc b/pc/channelmanager.cc index ead1da9cdd..e32f56a397 100644 --- a/pc/channelmanager.cc +++ b/pc/channelmanager.cc @@ -152,38 +152,6 @@ void ChannelManager::Terminate() { initialized_ = false; } -VoiceChannel* ChannelManager::CreateVoiceChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options) { - return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateVoiceChannel_w( - call, media_config, rtp_transport, rtcp_transport, rtp_transport, - rtcp_transport, signaling_thread, content_name, srtp_required, options); - }); -} - -VoiceChannel* ChannelManager::CreateVoiceChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - rtc::PacketTransportInternal* rtp_transport, - rtc::PacketTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options) { - return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateVoiceChannel_w(call, media_config, nullptr, nullptr, - rtp_transport, rtcp_transport, signaling_thread, - content_name, srtp_required, options); - }); -} - VoiceChannel* ChannelManager::CreateVoiceChannel( webrtc::Call* call, const cricket::MediaConfig& media_config, @@ -191,12 +159,13 @@ VoiceChannel* ChannelManager::CreateVoiceChannel( rtc::Thread* signaling_thread, const std::string& content_name, bool srtp_required, + const rtc::CryptoOptions& crypto_options, const AudioOptions& options) { if (!worker_thread_->IsCurrent()) { return worker_thread_->Invoke(RTC_FROM_HERE, [&] { return CreateVoiceChannel(call, media_config, rtp_transport, signaling_thread, content_name, srtp_required, - options); + crypto_options, options); }); } @@ -215,8 +184,8 @@ VoiceChannel* ChannelManager::CreateVoiceChannel( auto voice_channel = rtc::MakeUnique( worker_thread_, network_thread_, signaling_thread, media_engine_.get(), - rtc::WrapUnique(media_channel), content_name, - rtp_transport->rtcp_packet_transport() == nullptr, srtp_required); + rtc::WrapUnique(media_channel), content_name, srtp_required, + crypto_options); voice_channel->Init_w(rtp_transport); @@ -225,41 +194,6 @@ VoiceChannel* ChannelManager::CreateVoiceChannel( return voice_channel_ptr; } -VoiceChannel* ChannelManager::CreateVoiceChannel_w( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options) { - RTC_DCHECK_RUN_ON(worker_thread_); - RTC_DCHECK(initialized_); - RTC_DCHECK(call); - if (!media_engine_) { - return nullptr; - } - - VoiceMediaChannel* media_channel = media_engine_->CreateChannel( - call, media_config, options); - if (!media_channel) { - return nullptr; - } - - auto voice_channel = rtc::MakeUnique( - worker_thread_, network_thread_, signaling_thread, media_engine_.get(), - rtc::WrapUnique(media_channel), content_name, - rtcp_packet_transport == nullptr, srtp_required); - voice_channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport, - rtp_packet_transport, rtcp_packet_transport); - - VoiceChannel* voice_channel_ptr = voice_channel.get(); - voice_channels_.push_back(std::move(voice_channel)); - return voice_channel_ptr; -} void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) { TRACE_EVENT0("webrtc", "ChannelManager::DestroyVoiceChannel"); @@ -286,38 +220,6 @@ void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) { voice_channels_.erase(it); } -VideoChannel* ChannelManager::CreateVideoChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options) { - return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateVideoChannel_w( - call, media_config, rtp_transport, rtcp_transport, rtp_transport, - rtcp_transport, signaling_thread, content_name, srtp_required, options); - }); -} - -VideoChannel* ChannelManager::CreateVideoChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - rtc::PacketTransportInternal* rtp_transport, - rtc::PacketTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options) { - return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateVideoChannel_w(call, media_config, nullptr, nullptr, - rtp_transport, rtcp_transport, signaling_thread, - content_name, srtp_required, options); - }); -} - VideoChannel* ChannelManager::CreateVideoChannel( webrtc::Call* call, const cricket::MediaConfig& media_config, @@ -325,12 +227,13 @@ VideoChannel* ChannelManager::CreateVideoChannel( rtc::Thread* signaling_thread, const std::string& content_name, bool srtp_required, + const rtc::CryptoOptions& crypto_options, const VideoOptions& options) { if (!worker_thread_->IsCurrent()) { return worker_thread_->Invoke(RTC_FROM_HERE, [&] { return CreateVideoChannel(call, media_config, rtp_transport, signaling_thread, content_name, srtp_required, - options); + crypto_options, options); }); } @@ -349,8 +252,8 @@ VideoChannel* ChannelManager::CreateVideoChannel( auto video_channel = rtc::MakeUnique( worker_thread_, network_thread_, signaling_thread, - rtc::WrapUnique(media_channel), content_name, - rtp_transport->rtcp_packet_transport() == nullptr, srtp_required); + rtc::WrapUnique(media_channel), content_name, srtp_required, + crypto_options); video_channel->Init_w(rtp_transport); VideoChannel* video_channel_ptr = video_channel.get(); @@ -358,41 +261,7 @@ VideoChannel* ChannelManager::CreateVideoChannel( return video_channel_ptr; } -VideoChannel* ChannelManager::CreateVideoChannel_w( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options) { - RTC_DCHECK_RUN_ON(worker_thread_); - RTC_DCHECK(initialized_); - RTC_DCHECK(call); - if (!media_engine_) { - return nullptr; - } - VideoMediaChannel* media_channel = media_engine_->CreateVideoChannel( - call, media_config, options); - if (!media_channel) { - return nullptr; - } - - auto video_channel = rtc::MakeUnique( - worker_thread_, network_thread_, signaling_thread, - rtc::WrapUnique(media_channel), content_name, - rtcp_packet_transport == nullptr, srtp_required); - video_channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport, - rtp_packet_transport, rtcp_packet_transport); - - VideoChannel* video_channel_ptr = video_channel.get(); - video_channels_.push_back(std::move(video_channel)); - return video_channel_ptr; -} void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) { TRACE_EVENT0("webrtc", "ChannelManager::DestroyVideoChannel"); @@ -419,51 +288,17 @@ void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) { video_channels_.erase(it); } -RtpDataChannel* ChannelManager::CreateRtpDataChannel( - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required) { - if (!worker_thread_->IsCurrent()) { - return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateRtpDataChannel(media_config, rtp_transport, rtcp_transport, - signaling_thread, content_name, - srtp_required); - }); - } - - // This is ok to alloc from a thread other than the worker thread. - RTC_DCHECK(initialized_); - DataMediaChannel* media_channel = data_engine_->CreateChannel(media_config); - if (!media_channel) { - RTC_LOG(LS_WARNING) << "Failed to create RTP data channel."; - return nullptr; - } - - auto data_channel = rtc::MakeUnique( - worker_thread_, network_thread_, signaling_thread, - rtc::WrapUnique(media_channel), content_name, rtcp_transport == nullptr, - srtp_required); - data_channel->Init_w(rtp_transport, rtcp_transport, rtp_transport, - rtcp_transport); - - RtpDataChannel* data_channel_ptr = data_channel.get(); - data_channels_.push_back(std::move(data_channel)); - return data_channel_ptr; -} - RtpDataChannel* ChannelManager::CreateRtpDataChannel( const cricket::MediaConfig& media_config, webrtc::RtpTransportInternal* rtp_transport, rtc::Thread* signaling_thread, const std::string& content_name, - bool srtp_required) { + bool srtp_required, + const rtc::CryptoOptions& crypto_options) { if (!worker_thread_->IsCurrent()) { return worker_thread_->Invoke(RTC_FROM_HERE, [&] { return CreateRtpDataChannel(media_config, rtp_transport, signaling_thread, - content_name, srtp_required); + content_name, srtp_required, crypto_options); }); } @@ -477,8 +312,8 @@ RtpDataChannel* ChannelManager::CreateRtpDataChannel( auto data_channel = rtc::MakeUnique( worker_thread_, network_thread_, signaling_thread, - rtc::WrapUnique(media_channel), content_name, - rtp_transport->rtcp_packet_transport() == nullptr, srtp_required); + rtc::WrapUnique(media_channel), content_name, srtp_required, + crypto_options); data_channel->Init_w(rtp_transport); RtpDataChannel* data_channel_ptr = data_channel.get(); diff --git a/pc/channelmanager.h b/pc/channelmanager.h index 72d218a228..c6b601ea8f 100644 --- a/pc/channelmanager.h +++ b/pc/channelmanager.h @@ -80,90 +80,38 @@ class ChannelManager final { // call the appropriate Destroy*Channel method when done. // Creates a voice channel, to be associated with the specified session. - // TODO(zhihuang): Replace this with the method taking an - // RtpTransportInternal*; - VoiceChannel* CreateVoiceChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options); - // Version of the above that takes PacketTransportInternal. - // TODO(zhihuang): Replace this with the method taking an - // RtpTransportInternal*; - VoiceChannel* CreateVoiceChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - rtc::PacketTransportInternal* rtp_transport, - rtc::PacketTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options); - VoiceChannel* CreateVoiceChannel(webrtc::Call* call, const cricket::MediaConfig& media_config, webrtc::RtpTransportInternal* rtp_transport, rtc::Thread* signaling_thread, const std::string& content_name, bool srtp_required, + const rtc::CryptoOptions& crypto_options, const AudioOptions& options); // Destroys a voice channel created by CreateVoiceChannel. void DestroyVoiceChannel(VoiceChannel* voice_channel); // Creates a video channel, synced with the specified voice channel, and // associated with the specified session. - // TODO(zhihuang): Replace this with the method taking an - // RtpTransportInternal*; - VideoChannel* CreateVideoChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options); // Version of the above that takes PacketTransportInternal. - // TODO(zhihuang): Replace this with the method taking an - // RtpTransportInternal*; - VideoChannel* CreateVideoChannel( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - rtc::PacketTransportInternal* rtp_transport, - rtc::PacketTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options); VideoChannel* CreateVideoChannel(webrtc::Call* call, const cricket::MediaConfig& media_config, webrtc::RtpTransportInternal* rtp_transport, rtc::Thread* signaling_thread, const std::string& content_name, bool srtp_required, + const rtc::CryptoOptions& crypto_options, const VideoOptions& options); // Destroys a video channel created by CreateVideoChannel. void DestroyVideoChannel(VideoChannel* video_channel); - // TODO(zhihuang): Replace this with the method taking an - // RtpTransportInternal*; - RtpDataChannel* CreateRtpDataChannel( - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_transport, - DtlsTransportInternal* rtcp_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required); RtpDataChannel* CreateRtpDataChannel( const cricket::MediaConfig& media_config, webrtc::RtpTransportInternal* rtp_transport, rtc::Thread* signaling_thread, const std::string& content_name, - bool srtp_required); + bool srtp_required, + const rtc::CryptoOptions& crypto_options); // Destroys a data channel created by CreateRtpDataChannel. void DestroyRtpDataChannel(RtpDataChannel* data_channel); @@ -191,29 +139,6 @@ class ChannelManager final { void StopAecDump(); private: - VoiceChannel* CreateVoiceChannel_w( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const AudioOptions& options); - VideoChannel* CreateVideoChannel_w( - webrtc::Call* call, - const cricket::MediaConfig& media_config, - DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport, - rtc::Thread* signaling_thread, - const std::string& content_name, - bool srtp_required, - const VideoOptions& options); - std::unique_ptr media_engine_; // Nullable. std::unique_ptr data_engine_; // Non-null. bool initialized_ = false; diff --git a/pc/channelmanager_unittest.cc b/pc/channelmanager_unittest.cc index d318ac5b20..38da139448 100644 --- a/pc/channelmanager_unittest.cc +++ b/pc/channelmanager_unittest.cc @@ -15,8 +15,8 @@ #include "media/base/fakevideocapturer.h" #include "media/base/testutils.h" #include "media/engine/fakewebrtccall.h" +#include "p2p/base/fakedtlstransport.h" #include "pc/channelmanager.h" -#include "pc/test/faketransportcontroller.h" #include "rtc_base/gunit.h" #include "rtc_base/logging.h" #include "rtc_base/thread.h" @@ -47,13 +47,47 @@ class ChannelManagerTest : public testing::Test { std::unique_ptr(fdme_), rtc::Thread::Current(), rtc::Thread::Current())), - fake_call_(), - transport_controller_( - new cricket::FakeTransportController(ICEROLE_CONTROLLING)) { + fake_call_() { fme_->SetAudioCodecs(MAKE_VECTOR(kAudioCodecs)); fme_->SetVideoCodecs(MAKE_VECTOR(kVideoCodecs)); } + std::unique_ptr CreateDtlsSrtpTransport() { + rtp_dtls_transport_ = rtc::MakeUnique( + "fake_dtls_transport", cricket::ICE_CANDIDATE_COMPONENT_RTP); + auto rtp_transport = + rtc::MakeUnique(/*rtcp_mux_required=*/true); + auto srtp_transport = + rtc::MakeUnique(std::move(rtp_transport)); + auto dtls_srtp_transport = + rtc::MakeUnique(std::move(srtp_transport)); + dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(), + /*rtcp_dtls_transport=*/nullptr); + return dtls_srtp_transport; + } + + void TestCreateDestroyChannels(webrtc::RtpTransportInternal* rtp_transport) { + cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel( + &fake_call_, cricket::MediaConfig(), rtp_transport, + rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired, + rtc::CryptoOptions(), AudioOptions()); + EXPECT_TRUE(voice_channel != nullptr); + cricket::VideoChannel* video_channel = cm_->CreateVideoChannel( + &fake_call_, cricket::MediaConfig(), rtp_transport, + rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired, + rtc::CryptoOptions(), VideoOptions()); + EXPECT_TRUE(video_channel != nullptr); + cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel( + cricket::MediaConfig(), rtp_transport, rtc::Thread::Current(), + cricket::CN_DATA, kDefaultSrtpRequired, rtc::CryptoOptions()); + EXPECT_TRUE(rtp_data_channel != nullptr); + cm_->DestroyVideoChannel(video_channel); + cm_->DestroyVoiceChannel(voice_channel); + cm_->DestroyRtpDataChannel(rtp_data_channel); + cm_->Terminate(); + } + + std::unique_ptr rtp_dtls_transport_; std::unique_ptr network_; std::unique_ptr worker_; // |fme_| and |fdme_| are actually owned by |cm_|. @@ -61,7 +95,6 @@ class ChannelManagerTest : public testing::Test { cricket::FakeDataEngine* fdme_; std::unique_ptr cm_; cricket::FakeCall fake_call_; - std::unique_ptr transport_controller_; }; // Test that we startup/shutdown properly. @@ -93,68 +126,6 @@ TEST_F(ChannelManagerTest, StartupShutdownOnThread) { EXPECT_FALSE(cm_->initialized()); } -// Test that we can create and destroy a voice and video channel. -TEST_F(ChannelManagerTest, CreateDestroyChannels) { - EXPECT_TRUE(cm_->Init()); - cricket::DtlsTransportInternal* rtp_transport = - transport_controller_->CreateDtlsTransport( - cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired, - AudioOptions()); - EXPECT_TRUE(voice_channel != nullptr); - cricket::VideoChannel* video_channel = cm_->CreateVideoChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired, - VideoOptions()); - EXPECT_TRUE(video_channel != nullptr); - cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel( - cricket::MediaConfig(), rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_DATA, kDefaultSrtpRequired); - EXPECT_TRUE(rtp_data_channel != nullptr); - cm_->DestroyVideoChannel(video_channel); - cm_->DestroyVoiceChannel(voice_channel); - cm_->DestroyRtpDataChannel(rtp_data_channel); - cm_->Terminate(); -} - -// Test that we can create and destroy a voice and video channel with a worker. -TEST_F(ChannelManagerTest, CreateDestroyChannelsOnThread) { - network_->Start(); - worker_->Start(); - EXPECT_TRUE(cm_->set_worker_thread(worker_.get())); - EXPECT_TRUE(cm_->set_network_thread(network_.get())); - EXPECT_TRUE(cm_->Init()); - transport_controller_.reset(new cricket::FakeTransportController( - network_.get(), ICEROLE_CONTROLLING)); - cricket::DtlsTransportInternal* rtp_transport = - transport_controller_->CreateDtlsTransport( - cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired, - AudioOptions()); - EXPECT_TRUE(voice_channel != nullptr); - cricket::VideoChannel* video_channel = cm_->CreateVideoChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired, - VideoOptions()); - EXPECT_TRUE(video_channel != nullptr); - cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel( - cricket::MediaConfig(), rtp_transport, nullptr /*rtcp_transport*/, - rtc::Thread::Current(), cricket::CN_DATA, kDefaultSrtpRequired); - EXPECT_TRUE(rtp_data_channel != nullptr); - cm_->DestroyVideoChannel(video_channel); - cm_->DestroyVoiceChannel(voice_channel); - cm_->DestroyRtpDataChannel(rtp_data_channel); - cm_->Terminate(); -} - TEST_F(ChannelManagerTest, SetVideoRtxEnabled) { std::vector codecs; const VideoCodec rtx_codec(96, "rtx"); @@ -185,89 +156,20 @@ TEST_F(ChannelManagerTest, SetVideoRtxEnabled) { EXPECT_TRUE(ContainsMatchingCodec(codecs, rtx_codec)); } -enum class RTPTransportType { kRtp, kSrtp, kDtlsSrtp }; - -class ChannelManagerTestWithRtpTransport - : public ChannelManagerTest, - public ::testing::WithParamInterface { - public: - std::unique_ptr CreateRtpTransport() { - RTPTransportType type = GetParam(); - switch (type) { - case RTPTransportType::kRtp: - return CreatePlainRtpTransport(); - case RTPTransportType::kSrtp: - return CreateSrtpTransport(); - case RTPTransportType::kDtlsSrtp: - return CreateDtlsSrtpTransport(); - } - return nullptr; - } - - void TestCreateDestroyChannels(webrtc::RtpTransportInternal* rtp_transport) { - cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel( - &fake_call_, cricket::MediaConfig(), rtp_transport, - rtc::Thread::Current(), cricket::CN_AUDIO, kDefaultSrtpRequired, - AudioOptions()); - EXPECT_TRUE(voice_channel != nullptr); - cricket::VideoChannel* video_channel = cm_->CreateVideoChannel( - &fake_call_, cricket::MediaConfig(), rtp_transport, - rtc::Thread::Current(), cricket::CN_VIDEO, kDefaultSrtpRequired, - VideoOptions()); - EXPECT_TRUE(video_channel != nullptr); - cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel( - cricket::MediaConfig(), rtp_transport, rtc::Thread::Current(), - cricket::CN_DATA, kDefaultSrtpRequired); - EXPECT_TRUE(rtp_data_channel != nullptr); - cm_->DestroyVideoChannel(video_channel); - cm_->DestroyVoiceChannel(voice_channel); - cm_->DestroyRtpDataChannel(rtp_data_channel); - cm_->Terminate(); - } - - private: - std::unique_ptr CreatePlainRtpTransport() { - return rtc::MakeUnique(/*rtcp_mux_required=*/true); - } - - std::unique_ptr CreateSrtpTransport() { - auto rtp_transport = - rtc::MakeUnique(/*rtcp_mux_required=*/true); - auto srtp_transport = - rtc::MakeUnique(std::move(rtp_transport)); - return srtp_transport; - } - - std::unique_ptr CreateDtlsSrtpTransport() { - auto rtp_transport = - rtc::MakeUnique(/*rtcp_mux_required=*/true); - auto srtp_transport = - rtc::MakeUnique(std::move(rtp_transport)); - auto dtls_srtp_transport_ = - rtc::MakeUnique(std::move(srtp_transport)); - return dtls_srtp_transport_; - } -}; - -TEST_P(ChannelManagerTestWithRtpTransport, CreateDestroyChannels) { +TEST_F(ChannelManagerTest, CreateDestroyChannels) { EXPECT_TRUE(cm_->Init()); - auto rtp_transport = CreateRtpTransport(); + auto rtp_transport = CreateDtlsSrtpTransport(); TestCreateDestroyChannels(rtp_transport.get()); } -TEST_P(ChannelManagerTestWithRtpTransport, CreateDestroyChannelsOnThread) { +TEST_F(ChannelManagerTest, CreateDestroyChannelsOnThread) { network_->Start(); worker_->Start(); EXPECT_TRUE(cm_->set_worker_thread(worker_.get())); EXPECT_TRUE(cm_->set_network_thread(network_.get())); EXPECT_TRUE(cm_->Init()); - auto rtp_transport = CreateRtpTransport(); + auto rtp_transport = CreateDtlsSrtpTransport(); TestCreateDestroyChannels(rtp_transport.get()); } -INSTANTIATE_TEST_CASE_P(ChannelManagerTest, - ChannelManagerTestWithRtpTransport, - ::testing::Values(RTPTransportType::kRtp, - RTPTransportType::kSrtp, - RTPTransportType::kDtlsSrtp)); } // namespace cricket diff --git a/pc/dtlssrtptransport.cc b/pc/dtlssrtptransport.cc index 0b98a96293..f40c96f925 100644 --- a/pc/dtlssrtptransport.cc +++ b/pc/dtlssrtptransport.cc @@ -53,7 +53,7 @@ void DtlsSrtpTransport::SetDtlsTransports( // 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 (IsActive()) { + if (IsSrtpActive()) { srtp_transport_->ResetParams(); } @@ -62,7 +62,7 @@ void DtlsSrtpTransport::SetDtlsTransports( // This would only be possible if using BUNDLE but not rtcp-mux, which isn't // allowed according to the BUNDLE spec. - RTC_CHECK(!(IsActive())) + RTC_CHECK(!(IsSrtpActive())) << "Setting RTCP for DTLS/SRTP after the DTLS is active " "should never happen."; @@ -140,7 +140,7 @@ bool DtlsSrtpTransport::DtlsHandshakeCompleted() { } void DtlsSrtpTransport::MaybeSetupDtlsSrtp() { - if (IsActive() || !DtlsHandshakeCompleted()) { + if (IsSrtpActive() || !DtlsHandshakeCompleted()) { return; } @@ -184,7 +184,7 @@ void DtlsSrtpTransport::SetupRtcpDtlsSrtp() { // Return if the DTLS-SRTP is active because the encrypted header extension // IDs don't need to be updated for RTCP and the crypto params don't need to // be reset. - if (IsActive()) { + if (IsSrtpActive()) { return; } diff --git a/pc/dtlssrtptransport.h b/pc/dtlssrtptransport.h index 02002b052a..889bd22234 100644 --- a/pc/dtlssrtptransport.h +++ b/pc/dtlssrtptransport.h @@ -45,7 +45,7 @@ class DtlsSrtpTransport : public RtpTransportInternalAdapter { void UpdateRecvEncryptedHeaderExtensionIds( const std::vector& recv_extension_ids); - bool IsActive() { return srtp_transport_->IsActive(); } + bool IsSrtpActive() const override { return srtp_transport_->IsSrtpActive(); } // Cache RTP Absoulute SendTime extension header ID. This is only used when // external authentication is enabled. @@ -54,11 +54,17 @@ class DtlsSrtpTransport : public RtpTransportInternalAdapter { rtp_abs_sendtime_extn_id); } - // TODO(zhihuang): Remove this when we remove RtpTransportAdapter. - RtpTransportAdapter* GetInternal() override { return nullptr; } - sigslot::signal2 SignalDtlsSrtpSetupFailure; + RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override { + return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, + "Set SRTP keys for DTLS-SRTP is not supported."); + } + RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override { + return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, + "Set SRTP keys for DTLS-SRTP is not supported."); + } + private: bool IsDtlsActive(); bool IsDtlsConnected(); diff --git a/pc/dtlssrtptransport_unittest.cc b/pc/dtlssrtptransport_unittest.cc index 08a8151ee7..f0e4f28b04 100644 --- a/pc/dtlssrtptransport_unittest.cc +++ b/pc/dtlssrtptransport_unittest.cc @@ -70,9 +70,6 @@ class DtlsSrtpTransportTest : public testing::Test, bool rtcp_mux_enabled) { auto rtp_transport = rtc::MakeUnique(rtcp_mux_enabled); - rtp_transport->AddHandledPayloadType(0x00); - rtp_transport->AddHandledPayloadType(0xc9); - auto srtp_transport = rtc::MakeUnique(std::move(rtp_transport)); auto dtls_srtp_transport = @@ -118,8 +115,8 @@ class DtlsSrtpTransportTest : public testing::Test, void SendRecvRtpPackets() { ASSERT_TRUE(dtls_srtp_transport1_); ASSERT_TRUE(dtls_srtp_transport2_); - ASSERT_TRUE(dtls_srtp_transport1_->IsActive()); - ASSERT_TRUE(dtls_srtp_transport2_->IsActive()); + ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive()); + ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive()); size_t rtp_len = sizeof(kPcmuFrame); size_t packet_size = rtp_len + kRtpAuthTagLen; @@ -181,8 +178,8 @@ class DtlsSrtpTransportTest : public testing::Test, const std::vector& encrypted_header_ids) { ASSERT_TRUE(dtls_srtp_transport1_); ASSERT_TRUE(dtls_srtp_transport2_); - ASSERT_TRUE(dtls_srtp_transport1_->IsActive()); - ASSERT_TRUE(dtls_srtp_transport2_->IsActive()); + ASSERT_TRUE(dtls_srtp_transport1_->IsSrtpActive()); + ASSERT_TRUE(dtls_srtp_transport2_->IsSrtpActive()); size_t rtp_len = sizeof(kPcmuFrameWithExtensions); size_t packet_size = rtp_len + kRtpAuthTagLen; @@ -353,8 +350,8 @@ TEST_F(DtlsSrtpTransportTest, rtcp_dtls2.get(), /*rtcp_mux_enabled=*/false); CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get()); - EXPECT_FALSE(dtls_srtp_transport1_->IsActive()); - EXPECT_FALSE(dtls_srtp_transport2_->IsActive()); + EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive()); + EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive()); CompleteDtlsHandshake(rtcp_dtls1.get(), rtcp_dtls2.get()); SendRecvPackets(); } @@ -372,8 +369,8 @@ TEST_F(DtlsSrtpTransportTest, DtlsSrtpResetAfterDtlsTransportChange) { /*rtcp_mux_enabled=*/true); CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get()); - EXPECT_TRUE(dtls_srtp_transport1_->IsActive()); - EXPECT_TRUE(dtls_srtp_transport2_->IsActive()); + EXPECT_TRUE(dtls_srtp_transport1_->IsSrtpActive()); + EXPECT_TRUE(dtls_srtp_transport2_->IsSrtpActive()); auto rtp_dtls3 = rtc::MakeUnique( "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP); @@ -383,8 +380,8 @@ TEST_F(DtlsSrtpTransportTest, DtlsSrtpResetAfterDtlsTransportChange) { // The previous context is reset. dtls_srtp_transport1_->SetDtlsTransports(rtp_dtls3.get(), nullptr); dtls_srtp_transport2_->SetDtlsTransports(rtp_dtls4.get(), nullptr); - EXPECT_FALSE(dtls_srtp_transport1_->IsActive()); - EXPECT_FALSE(dtls_srtp_transport2_->IsActive()); + EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive()); + EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive()); // Re-setup. CompleteDtlsHandshake(rtp_dtls3.get(), rtp_dtls4.get()); @@ -409,8 +406,8 @@ TEST_F(DtlsSrtpTransportTest, CompleteDtlsHandshake(rtp_dtls1.get(), rtp_dtls2.get()); // Inactive because the RTCP transport handshake didn't complete. - EXPECT_FALSE(dtls_srtp_transport1_->IsActive()); - EXPECT_FALSE(dtls_srtp_transport2_->IsActive()); + EXPECT_FALSE(dtls_srtp_transport1_->IsSrtpActive()); + EXPECT_FALSE(dtls_srtp_transport2_->IsSrtpActive()); dtls_srtp_transport1_->SetRtcpMuxEnabled(true); dtls_srtp_transport2_->SetRtcpMuxEnabled(true); diff --git a/pc/jseptransport.cc b/pc/jseptransport.cc deleted file mode 100644 index 0127d84398..0000000000 --- a/pc/jseptransport.cc +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/jseptransport.h" - -#include -#include // for std::pair - -#include "api/candidate.h" -#include "p2p/base/p2pconstants.h" -#include "p2p/base/p2ptransportchannel.h" -#include "p2p/base/port.h" -#include "rtc_base/bind.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" - -using webrtc::SdpType; - -namespace cricket { - -static bool BadTransportDescription(const std::string& desc, - std::string* err_desc) { - if (err_desc) { - *err_desc = desc; - } - RTC_LOG(LS_ERROR) << desc; - return false; -} - -static bool VerifyIceParams(const TransportDescription& desc) { - // For legacy protocols. - if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) - return true; - - if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH || - desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) { - return false; - } - if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH || - desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) { - return false; - } - return true; -} - -JsepTransport::JsepTransport( - const std::string& mid, - const rtc::scoped_refptr& certificate) - : mid_(mid), certificate_(certificate) {} - -JsepTransport::~JsepTransport() = default; - -bool JsepTransport::AddChannel(DtlsTransportInternal* dtls, int component) { - if (channels_.find(component) != channels_.end()) { - RTC_LOG(LS_ERROR) << "Adding channel for component " << component - << " twice."; - return false; - } - channels_[component] = dtls; - // Something's wrong if a channel is being added after a description is set. - // This may currently occur if rtcp-mux is negotiated, then a new m= section - // is added in a later offer/answer. But this is suboptimal and should be - // changed; we shouldn't support going from muxed to non-muxed. - // TODO(deadbeef): Once this is fixed, make the warning an error, and remove - // the calls to "ApplyXTransportDescription" below. - if (local_description_set_ || remote_description_set_) { - RTC_LOG(LS_WARNING) << "Adding new transport channel after " - "transport description already applied."; - } - bool ret = true; - std::string err; - if (local_description_set_) { - ret &= ApplyLocalTransportDescription(channels_[component], &err); - } - if (remote_description_set_) { - ret &= ApplyRemoteTransportDescription(channels_[component], &err); - } - if (local_description_set_ && remote_description_set_) { - ret &= ApplyNegotiatedTransportDescription(channels_[component], &err); - } - return ret; -} - -bool JsepTransport::RemoveChannel(int component) { - auto it = channels_.find(component); - if (it == channels_.end()) { - RTC_LOG(LS_ERROR) << "Trying to remove channel for component " << component - << ", which doesn't exist."; - return false; - } - channels_.erase(component); - return true; -} - -bool JsepTransport::HasChannels() const { - return !channels_.empty(); -} - -void JsepTransport::SetLocalCertificate( - const rtc::scoped_refptr& certificate) { - certificate_ = certificate; -} - -bool JsepTransport::GetLocalCertificate( - rtc::scoped_refptr* certificate) const { - if (!certificate_) { - return false; - } - - *certificate = certificate_; - return true; -} - -bool JsepTransport::SetLocalTransportDescription( - const TransportDescription& description, - SdpType type, - std::string* error_desc) { - bool ret = true; - - if (!VerifyIceParams(description)) { - return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", - error_desc); - } - - bool ice_restarting = - local_description_set_ && - IceCredentialsChanged(local_description_->ice_ufrag, - local_description_->ice_pwd, description.ice_ufrag, - description.ice_pwd); - local_description_.reset(new TransportDescription(description)); - - rtc::SSLFingerprint* local_fp = - local_description_->identity_fingerprint.get(); - - if (!local_fp) { - certificate_ = nullptr; - } else if (!VerifyCertificateFingerprint(certificate_.get(), local_fp, - error_desc)) { - return false; - } - - for (const auto& kv : channels_) { - ret &= ApplyLocalTransportDescription(kv.second, error_desc); - } - if (!ret) { - return false; - } - - // If PRANSWER/ANSWER is set, we should decide transport protocol type. - if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) { - ret &= NegotiateTransportDescription(type, error_desc); - } - if (!ret) { - return false; - } - - if (needs_ice_restart_ && ice_restarting) { - needs_ice_restart_ = false; - RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport " - << mid(); - } - - local_description_set_ = true; - return true; -} - -bool JsepTransport::SetRemoteTransportDescription( - const TransportDescription& description, - SdpType type, - std::string* error_desc) { - bool ret = true; - - if (!VerifyIceParams(description)) { - return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", - error_desc); - } - - remote_description_.reset(new TransportDescription(description)); - for (const auto& kv : channels_) { - ret &= ApplyRemoteTransportDescription(kv.second, error_desc); - } - - // If PRANSWER/ANSWER is set, we should decide transport protocol type. - if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) { - ret = NegotiateTransportDescription(SdpType::kOffer, error_desc); - } - if (ret) { - remote_description_set_ = true; - } - - return ret; -} - -void JsepTransport::SetNeedsIceRestartFlag() { - if (!needs_ice_restart_) { - needs_ice_restart_ = true; - RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid(); - } -} - -bool JsepTransport::NeedsIceRestart() const { - return needs_ice_restart_; -} - -rtc::Optional JsepTransport::GetSslRole() const { - return ssl_role_; -} - -bool JsepTransport::GetStats(TransportStats* stats) { - stats->transport_name = mid(); - stats->channel_stats.clear(); - for (auto& kv : channels_) { - DtlsTransportInternal* dtls_transport = kv.second; - TransportChannelStats substats; - substats.component = kv.first; - dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite); - dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite); - substats.dtls_state = dtls_transport->dtls_state(); - if (!dtls_transport->ice_transport()->GetStats( - &substats.connection_infos, &substats.candidate_stats_list)) { - return false; - } - stats->channel_stats.push_back(substats); - } - return true; -} - -bool JsepTransport::VerifyCertificateFingerprint( - const rtc::RTCCertificate* certificate, - const rtc::SSLFingerprint* fingerprint, - std::string* error_desc) const { - if (!fingerprint) { - return BadTransportDescription("No fingerprint.", error_desc); - } - if (!certificate) { - return BadTransportDescription( - "Fingerprint provided but no identity available.", error_desc); - } - std::unique_ptr fp_tmp(rtc::SSLFingerprint::Create( - fingerprint->algorithm, certificate->identity())); - RTC_DCHECK(fp_tmp.get() != NULL); - if (*fp_tmp == *fingerprint) { - return true; - } - std::ostringstream desc; - desc << "Local fingerprint does not match identity. Expected: "; - desc << fp_tmp->ToString(); - desc << " Got: " << fingerprint->ToString(); - return BadTransportDescription(desc.str(), error_desc); -} - -bool JsepTransport::ApplyLocalTransportDescription( - DtlsTransportInternal* dtls_transport, - std::string* error_desc) { - dtls_transport->ice_transport()->SetIceParameters( - local_description_->GetIceParameters()); - return true; -} - -bool JsepTransport::ApplyRemoteTransportDescription( - DtlsTransportInternal* dtls_transport, - std::string* error_desc) { - dtls_transport->ice_transport()->SetRemoteIceParameters( - remote_description_->GetIceParameters()); - dtls_transport->ice_transport()->SetRemoteIceMode( - remote_description_->ice_mode); - return true; -} - -bool JsepTransport::ApplyNegotiatedTransportDescription( - DtlsTransportInternal* dtls_transport, - std::string* error_desc) { - // Set SSL role. Role must be set before fingerprint is applied, which - // initiates DTLS setup. - if (ssl_role_ && !dtls_transport->SetDtlsRole(*ssl_role_)) { - return BadTransportDescription("Failed to set SSL role for the channel.", - error_desc); - } - // Apply remote fingerprint. - if (!dtls_transport->SetRemoteFingerprint( - remote_fingerprint_->algorithm, - reinterpret_cast(remote_fingerprint_->digest.data()), - remote_fingerprint_->digest.size())) { - return BadTransportDescription("Failed to apply remote fingerprint.", - error_desc); - } - return true; -} - -bool JsepTransport::NegotiateTransportDescription( - SdpType local_description_type, - std::string* error_desc) { - if (!local_description_ || !remote_description_) { - const std::string msg = - "Applying an answer transport description " - "without applying any offer."; - return BadTransportDescription(msg, error_desc); - } - rtc::SSLFingerprint* local_fp = - local_description_->identity_fingerprint.get(); - rtc::SSLFingerprint* remote_fp = - remote_description_->identity_fingerprint.get(); - if (remote_fp && local_fp) { - remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp)); - if (!NegotiateRole(local_description_type, error_desc)) { - return false; - } - } else if (local_fp && (local_description_type == SdpType::kAnswer)) { - return BadTransportDescription( - "Local fingerprint supplied when caller didn't offer DTLS.", - error_desc); - } else { - // We are not doing DTLS - remote_fingerprint_.reset(new rtc::SSLFingerprint("", nullptr, 0)); - } - // Now that we have negotiated everything, push it downward. - // Note that we cache the result so that if we have race conditions - // between future SetRemote/SetLocal invocations and new channel - // creation, we have the negotiation state saved until a new - // negotiation happens. - for (const auto& kv : channels_) { - if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) { - return false; - } - } - return true; -} - -bool JsepTransport::NegotiateRole(SdpType local_description_type, - std::string* error_desc) { - if (!local_description_ || !remote_description_) { - const std::string msg = - "Local and Remote description must be set before " - "transport descriptions are negotiated"; - return BadTransportDescription(msg, error_desc); - } - - // From RFC 4145, section-4.1, The following are the values that the - // 'setup' attribute can take in an offer/answer exchange: - // Offer Answer - // ________________ - // active passive / holdconn - // passive active / holdconn - // actpass active / passive / holdconn - // holdconn holdconn - // - // Set the role that is most conformant with RFC 5763, Section 5, bullet 1 - // The endpoint MUST use the setup attribute defined in [RFC4145]. - // The endpoint that is the offerer MUST use the setup attribute - // value of setup:actpass and be prepared to receive a client_hello - // before it receives the answer. The answerer MUST use either a - // setup attribute value of setup:active or setup:passive. Note that - // if the answerer uses setup:passive, then the DTLS handshake will - // not begin until the answerer is received, which adds additional - // latency. setup:active allows the answer and the DTLS handshake to - // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever - // party is active MUST initiate a DTLS handshake by sending a - // ClientHello over each flow (host/port quartet). - // IOW - actpass and passive modes should be treated as server and - // active as client. - ConnectionRole local_connection_role = local_description_->connection_role; - ConnectionRole remote_connection_role = remote_description_->connection_role; - - bool is_remote_server = false; - if (local_description_type == SdpType::kOffer) { - if (local_connection_role != CONNECTIONROLE_ACTPASS) { - return BadTransportDescription( - "Offerer must use actpass value for setup attribute.", error_desc); - } - - if (remote_connection_role == CONNECTIONROLE_ACTIVE || - remote_connection_role == CONNECTIONROLE_PASSIVE || - remote_connection_role == CONNECTIONROLE_NONE) { - is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE); - } else { - const std::string msg = - "Answerer must use either active or passive value " - "for setup attribute."; - return BadTransportDescription(msg, error_desc); - } - // If remote is NONE or ACTIVE it will act as client. - } else { - if (remote_connection_role != CONNECTIONROLE_ACTPASS && - remote_connection_role != CONNECTIONROLE_NONE) { - // Accept a remote role attribute that's not "actpass", but matches the - // current negotiated role. This is allowed by dtls-sdp, though our - // implementation will never generate such an offer as it's not - // recommended. - // - // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp, - // section 5.5. - if (!ssl_role_ || - (*ssl_role_ == rtc::SSL_CLIENT && - remote_connection_role == CONNECTIONROLE_ACTIVE) || - (*ssl_role_ == rtc::SSL_SERVER && - remote_connection_role == CONNECTIONROLE_PASSIVE)) { - return BadTransportDescription( - "Offerer must use actpass value or current negotiated role for " - "setup attribute.", - error_desc); - } - } - - if (local_connection_role == CONNECTIONROLE_ACTIVE || - local_connection_role == CONNECTIONROLE_PASSIVE) { - is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE); - } else { - const std::string msg = - "Answerer must use either active or passive value " - "for setup attribute."; - return BadTransportDescription(msg, error_desc); - } - - // If local is passive, local will act as server. - } - - ssl_role_.emplace(is_remote_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER); - return true; -} - -} // namespace cricket diff --git a/pc/jseptransport.h b/pc/jseptransport.h deleted file mode 100644 index 4a8aec8590..0000000000 --- a/pc/jseptransport.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef PC_JSEPTRANSPORT_H_ -#define PC_JSEPTRANSPORT_H_ - -#include -#include -#include -#include - -#include "api/candidate.h" -#include "api/jsep.h" -#include "api/optional.h" -#include "p2p/base/dtlstransport.h" -#include "p2p/base/p2pconstants.h" -#include "p2p/base/transportinfo.h" -#include "pc/sessiondescription.h" -#include "pc/transportstats.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/messagequeue.h" -#include "rtc_base/rtccertificate.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/sslstreamadapter.h" - -namespace cricket { - -class DtlsTransportInternal; - -// Helper class used by TransportController that processes -// TransportDescriptions. A TransportDescription represents the -// transport-specific properties of an SDP m= section, processed according to -// JSEP. Each transport consists of DTLS and ICE transport channels for RTP -// (and possibly RTCP, if rtcp-mux isn't used). -// -// On Threading: Transport performs work solely on the network thread, and so -// its methods should only be called on the network thread. -class JsepTransport : public sigslot::has_slots<> { - public: - // |mid| is just used for log statements in order to identify the Transport. - // Note that |certificate| is allowed to be null since a remote description - // may be set before a local certificate is generated. - JsepTransport(const std::string& mid, - const rtc::scoped_refptr& certificate); - ~JsepTransport() override; - - // Returns the MID of this transport. - const std::string& mid() const { return mid_; } - - // Add or remove channel that is affected when a local/remote transport - // description is set on this transport. Need to add all channels before - // setting a transport description. - bool AddChannel(DtlsTransportInternal* dtls, int component); - bool RemoveChannel(int component); - bool HasChannels() const; - - bool ready_for_remote_candidates() const { - return local_description_set_ && remote_description_set_; - } - - // Must be called before applying local session description. - // Needed in order to verify the local fingerprint. - void SetLocalCertificate( - const rtc::scoped_refptr& certificate); - - // Get a copy of the local certificate provided by SetLocalCertificate. - bool GetLocalCertificate( - rtc::scoped_refptr* certificate) const; - - // Set the local TransportDescription to be used by DTLS and ICE channels - // that are part of this Transport. - bool SetLocalTransportDescription(const TransportDescription& description, - webrtc::SdpType type, - std::string* error_desc); - - // Set the remote TransportDescription to be used by DTLS and ICE channels - // that are part of this Transport. - bool SetRemoteTransportDescription(const TransportDescription& description, - webrtc::SdpType type, - std::string* error_desc); - - // Set the "needs-ice-restart" flag as described in JSEP. After the flag is - // set, offers should generate new ufrags/passwords until an ICE restart - // occurs. - // - // This and the below method can be called safely from any thread as long as - // SetXTransportDescription is not in progress. - void SetNeedsIceRestartFlag(); - // Returns true if the ICE restart flag above was set, and no ICE restart has - // occurred yet for this transport (by applying a local description with - // changed ufrag/password). - bool NeedsIceRestart() const; - - // Returns role if negotiated, or empty Optional if it hasn't been negotiated - // yet. - rtc::Optional GetSslRole() const; - - // TODO(deadbeef): Make this const. See comment in transportcontroller.h. - bool GetStats(TransportStats* stats); - - // The current local transport description, possibly used - // by the transport controller. - const TransportDescription* local_description() const { - return local_description_.get(); - } - - // The current remote transport description, possibly used - // by the transport controller. - const TransportDescription* remote_description() const { - return remote_description_.get(); - } - - // TODO(deadbeef): The methods below are only public for testing. Should make - // them utility functions or objects so they can be tested independently from - // this class. - - // Returns false if the certificate's identity does not match the fingerprint, - // or either is NULL. - bool VerifyCertificateFingerprint(const rtc::RTCCertificate* certificate, - const rtc::SSLFingerprint* fingerprint, - std::string* error_desc) const; - - private: - // Negotiates the transport parameters based on the current local and remote - // transport description, such as the ICE role to use, and whether DTLS - // should be activated. - // - // Called when an answer TransportDescription is applied. - bool NegotiateTransportDescription(webrtc::SdpType local_description_type, - std::string* error_desc); - - // Negotiates the SSL role based off the offer and answer as specified by - // RFC 4145, section-4.1. Returns false if the SSL role cannot be determined - // from the local description and remote description. - bool NegotiateRole(webrtc::SdpType local_description_type, - std::string* error_desc); - - // Pushes down the transport parameters from the local description, such - // as the ICE ufrag and pwd. - bool ApplyLocalTransportDescription(DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - // Pushes down the transport parameters from the remote description to the - // transport channel. - bool ApplyRemoteTransportDescription(DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - // Pushes down the transport parameters obtained via negotiation. - bool ApplyNegotiatedTransportDescription( - DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - const std::string mid_; - // needs-ice-restart bit as described in JSEP. - bool needs_ice_restart_ = false; - rtc::scoped_refptr certificate_; - rtc::Optional ssl_role_; - std::unique_ptr remote_fingerprint_; - std::unique_ptr local_description_; - std::unique_ptr remote_description_; - bool local_description_set_ = false; - bool remote_description_set_ = false; - - // Candidate component => DTLS channel - std::map channels_; - - RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport); -}; - -} // namespace cricket - -#endif // PC_JSEPTRANSPORT_H_ diff --git a/pc/jseptransport2.cc b/pc/jseptransport2.cc index 11f943848b..a4a03487bd 100644 --- a/pc/jseptransport2.cc +++ b/pc/jseptransport2.cc @@ -54,10 +54,12 @@ JsepTransportDescription::JsepTransportDescription( bool rtcp_mux_enabled, const std::vector& cryptos, const std::vector& encrypted_header_extension_ids, + int rtp_abs_sendtime_extn_id, const TransportDescription& transport_desc) : rtcp_mux_enabled(rtcp_mux_enabled), cryptos(cryptos), encrypted_header_extension_ids(encrypted_header_extension_ids), + rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id), transport_desc(transport_desc) {} JsepTransportDescription::JsepTransportDescription( @@ -65,6 +67,7 @@ JsepTransportDescription::JsepTransportDescription( : rtcp_mux_enabled(from.rtcp_mux_enabled), cryptos(from.cryptos), encrypted_header_extension_ids(from.encrypted_header_extension_ids), + rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id), transport_desc(from.transport_desc) {} JsepTransportDescription::~JsepTransportDescription() = default; @@ -77,6 +80,7 @@ JsepTransportDescription& JsepTransportDescription::operator=( rtcp_mux_enabled = from.rtcp_mux_enabled; cryptos = from.cryptos; encrypted_header_extension_ids = from.encrypted_header_extension_ids; + rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id; transport_desc = from.transport_desc; return *this; @@ -218,11 +222,15 @@ webrtc::RTCError JsepTransport2::SetRemoteJsepTransportDescription( return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER, "Failed to setup SDES crypto parameters."); } + sdes_transport_->CacheRtpAbsSendTimeHeaderExtension( + jsep_description.rtp_abs_sendtime_extn_id); } else if (dtls_srtp_transport_) { RTC_DCHECK(!unencrypted_rtp_transport_); RTC_DCHECK(!sdes_transport_); dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds( jsep_description.encrypted_header_extension_ids); + dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension( + jsep_description.rtp_abs_sendtime_extn_id); } remote_description_.reset(new JsepTransportDescription(jsep_description)); diff --git a/pc/jseptransport2.h b/pc/jseptransport2.h index 16a20b9ab0..8656cf5747 100644 --- a/pc/jseptransport2.h +++ b/pc/jseptransport2.h @@ -46,6 +46,7 @@ struct JsepTransportDescription { bool rtcp_mux_enabled, const std::vector& cryptos, const std::vector& encrypted_header_extension_ids, + int rtp_abs_sendtime_extn_id, const TransportDescription& transport_description); JsepTransportDescription(const JsepTransportDescription& from); ~JsepTransportDescription(); @@ -55,6 +56,7 @@ struct JsepTransportDescription { bool rtcp_mux_enabled = true; std::vector cryptos; std::vector encrypted_header_extension_ids; + int rtp_abs_sendtime_extn_id = -1; // TODO(zhihuang): Add the ICE and DTLS related variables and methods from // TransportDescription and remove this extra layer of abstraction. TransportDescription transport_desc; diff --git a/pc/jseptransport2_unittest.cc b/pc/jseptransport2_unittest.cc index fc098ae9b6..2f015cdc69 100644 --- a/pc/jseptransport2_unittest.cc +++ b/pc/jseptransport2_unittest.cc @@ -9,8 +9,10 @@ */ #include +#include #include +#include "media/base/fakertp.h" #include "p2p/base/fakedtlstransport.h" #include "p2p/base/fakeicetransport.h" #include "pc/jseptransport2.h" @@ -40,7 +42,6 @@ struct NegotiateRoleParams { class JsepTransport2Test : public testing::Test, public sigslot::has_slots<> { protected: std::unique_ptr CreateSdesTransport( - const std::string& transport_name, rtc::PacketTransportInternal* rtp_packet_transport, rtc::PacketTransportInternal* rtcp_packet_transport) { bool rtcp_mux_enabled = (rtcp_packet_transport == nullptr); @@ -55,7 +56,6 @@ class JsepTransport2Test : public testing::Test, public sigslot::has_slots<> { } std::unique_ptr CreateDtlsSrtpTransport( - const std::string& transport_name, cricket::DtlsTransportInternal* rtp_dtls_transport, cricket::DtlsTransportInternal* rtcp_dtls_transport) { bool rtcp_mux_enabled = (rtcp_dtls_transport == nullptr); @@ -71,7 +71,8 @@ class JsepTransport2Test : public testing::Test, public sigslot::has_slots<> { // Create a new JsepTransport2 with a FakeDtlsTransport and a // FakeIceTransport. - void CreateJsepTransport2(bool rtcp_mux_enabled, SrtpMode srtp_mode) { + std::unique_ptr CreateJsepTransport2(bool rtcp_mux_enabled, + SrtpMode srtp_mode) { auto ice = rtc::MakeUnique(kTransportName, ICE_CANDIDATE_COMPONENT_RTP); auto rtp_dtls_transport = @@ -89,29 +90,28 @@ class JsepTransport2Test : public testing::Test, public sigslot::has_slots<> { std::unique_ptr dtls_srtp_transport; switch (srtp_mode) { case SrtpMode::kSdes: - sdes_transport = - CreateSdesTransport(kTransportName, rtp_dtls_transport.get(), - rtcp_dtls_transport.get()); + sdes_transport = CreateSdesTransport(rtp_dtls_transport.get(), + rtcp_dtls_transport.get()); sdes_transport_ = sdes_transport.get(); break; case SrtpMode::kDtlsSrtp: - dtls_srtp_transport = - CreateDtlsSrtpTransport(kTransportName, rtp_dtls_transport.get(), - rtcp_dtls_transport.get()); + dtls_srtp_transport = CreateDtlsSrtpTransport( + rtp_dtls_transport.get(), rtcp_dtls_transport.get()); break; default: RTC_NOTREACHED(); } - jsep_transport_ = rtc::MakeUnique( + auto jsep_transport = rtc::MakeUnique( kTransportName, /*local_certificate=*/nullptr, std::move(unencrypted_rtp_transport), std::move(sdes_transport), std::move(dtls_srtp_transport), std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport)); signal_rtcp_mux_active_received_ = false; - jsep_transport_->SignalRtcpMuxActive.connect( + jsep_transport->SignalRtcpMuxActive.connect( this, &JsepTransport2Test::OnRtcpMuxActive); + return jsep_transport; } JsepTransportDescription MakeJsepTransportDescription( @@ -159,7 +159,7 @@ class JsepTransport2WithRtcpMux : public JsepTransport2Test, // This test verifies the ICE parameters are properly applied to the transports. TEST_P(JsepTransport2WithRtcpMux, SetIceParameters) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); JsepTransportDescription jsep_description; jsep_description.transport_desc = TransportDescription(kIceUfrag1, kIcePwd1); @@ -205,7 +205,7 @@ TEST_P(JsepTransport2WithRtcpMux, SetIceParameters) { // Similarly, test DTLS parameters are properly applied to the transports. TEST_P(JsepTransport2WithRtcpMux, SetDtlsParameters) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); // Create certificates. rtc::scoped_refptr local_cert = @@ -256,7 +256,7 @@ TEST_P(JsepTransport2WithRtcpMux, SetDtlsParameters) { // CONNECTIONROLE_PASSIVE, expecting SSL_CLIENT role. TEST_P(JsepTransport2WithRtcpMux, SetDtlsParametersWithPassiveAnswer) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); // Create certificates. rtc::scoped_refptr local_cert = @@ -308,7 +308,7 @@ TEST_P(JsepTransport2WithRtcpMux, SetDtlsParametersWithPassiveAnswer) { // only starts returning "false" once an ICE restart has been initiated. TEST_P(JsepTransport2WithRtcpMux, NeedsIceRestart) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); // Use the same JsepTransportDescription for both offer and answer. JsepTransportDescription description; @@ -353,7 +353,7 @@ TEST_P(JsepTransport2WithRtcpMux, NeedsIceRestart) { TEST_P(JsepTransport2WithRtcpMux, GetStats) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); size_t expected_stats_size = rtcp_mux_enabled ? 1u : 2u; TransportStats stats; @@ -369,7 +369,7 @@ TEST_P(JsepTransport2WithRtcpMux, GetStats) { // certificate matches the fingerprint. TEST_P(JsepTransport2WithRtcpMux, VerifyCertificateFingerprint) { bool rtcp_mux_enabled = GetParam(); - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); EXPECT_FALSE( jsep_transport_->VerifyCertificateFingerprint(nullptr, nullptr).ok()); @@ -436,7 +436,8 @@ TEST_P(JsepTransport2WithRtcpMux, ValidDtlsRoleNegotiation) { SdpType::kPrAnswer}}; for (auto& param : valid_client_params) { - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); local_description.transport_desc.connection_role = param.local_role; @@ -477,7 +478,8 @@ TEST_P(JsepTransport2WithRtcpMux, ValidDtlsRoleNegotiation) { SdpType::kPrAnswer}}; for (auto& param : valid_server_params) { - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); local_description.transport_desc.connection_role = param.local_role; @@ -548,7 +550,8 @@ TEST_P(JsepTransport2WithRtcpMux, InvalidDtlsRoleNegotiation) { SdpType::kPrAnswer}}; for (auto& param : duplicate_params) { - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); local_description.transport_desc.connection_role = param.local_role; @@ -603,7 +606,8 @@ TEST_P(JsepTransport2WithRtcpMux, InvalidDtlsRoleNegotiation) { SdpType::kPrAnswer}}; for (auto& param : offerer_without_actpass_params) { - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); local_description.transport_desc.connection_role = param.local_role; @@ -645,7 +649,7 @@ TEST_F(JsepTransport2Test, ValidDtlsReofferFromAnswerer) { rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); bool rtcp_mux_enabled = true; - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); JsepTransportDescription local_offer = @@ -692,7 +696,7 @@ TEST_F(JsepTransport2Test, InvalidDtlsReofferFromAnswerer) { rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); bool rtcp_mux_enabled = true; - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); JsepTransportDescription local_offer = @@ -738,7 +742,7 @@ TEST_F(JsepTransport2Test, RemoteOfferWithCurrentNegotiatedDtlsRole) { rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); bool rtcp_mux_enabled = true; - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); JsepTransportDescription remote_desc = @@ -783,7 +787,7 @@ TEST_F(JsepTransport2Test, RemoteOfferThatChangesNegotiatedDtlsRole) { rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); bool rtcp_mux_enabled = true; - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); JsepTransportDescription remote_desc = @@ -828,7 +832,7 @@ TEST_F(JsepTransport2Test, DtlsSetupWithLegacyAsAnswerer) { rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); bool rtcp_mux_enabled = true; - CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); + jsep_transport_ = CreateJsepTransport2(rtcp_mux_enabled, SrtpMode::kDtlsSrtp); jsep_transport_->SetLocalCertificate(certificate); JsepTransportDescription remote_desc = @@ -860,7 +864,8 @@ TEST_F(JsepTransport2Test, DtlsSetupWithLegacyAsAnswerer) { // Tests that when the RTCP mux is successfully negotiated, the RTCP transport // will be destroyed and the SignalRtpMuxActive will be fired. TEST_F(JsepTransport2Test, RtcpMuxNegotiation) { - CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp); JsepTransportDescription local_desc; local_desc.rtcp_mux_enabled = true; EXPECT_NE(nullptr, jsep_transport_->rtcp_dtls_transport()); @@ -882,7 +887,8 @@ TEST_F(JsepTransport2Test, RtcpMuxNegotiation) { EXPECT_TRUE(signal_rtcp_mux_active_received_); // The remote side doesn't support RTCP-mux. - CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/false, SrtpMode::kDtlsSrtp); signal_rtcp_mux_active_received_ = false; remote_desc.rtcp_mux_enabled = false; ASSERT_TRUE( @@ -899,9 +905,10 @@ TEST_F(JsepTransport2Test, RtcpMuxNegotiation) { } TEST_F(JsepTransport2Test, SdesNegotiation) { - CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); ASSERT_TRUE(sdes_transport_); - EXPECT_FALSE(sdes_transport_->IsActive()); + EXPECT_FALSE(sdes_transport_->IsSrtpActive()); JsepTransportDescription offer_desc; offer_desc.cryptos.push_back(cricket::CryptoParams( @@ -920,13 +927,14 @@ TEST_F(JsepTransport2Test, SdesNegotiation) { jsep_transport_ ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer) .ok()); - EXPECT_TRUE(sdes_transport_->IsActive()); + EXPECT_TRUE(sdes_transport_->IsSrtpActive()); } TEST_F(JsepTransport2Test, SdesNegotiationWithEmptyCryptosInAnswer) { - CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); ASSERT_TRUE(sdes_transport_); - EXPECT_FALSE(sdes_transport_->IsActive()); + EXPECT_FALSE(sdes_transport_->IsSrtpActive()); JsepTransportDescription offer_desc; offer_desc.cryptos.push_back(cricket::CryptoParams( @@ -943,13 +951,14 @@ TEST_F(JsepTransport2Test, SdesNegotiationWithEmptyCryptosInAnswer) { ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer) .ok()); // SRTP is not active because the crypto parameter is answer is empty. - EXPECT_FALSE(sdes_transport_->IsActive()); + EXPECT_FALSE(sdes_transport_->IsSrtpActive()); } TEST_F(JsepTransport2Test, SdesNegotiationWithMismatchedCryptos) { - CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kSdes); ASSERT_TRUE(sdes_transport_); - EXPECT_FALSE(sdes_transport_->IsActive()); + EXPECT_FALSE(sdes_transport_->IsSrtpActive()); JsepTransportDescription offer_desc; offer_desc.cryptos.push_back(cricket::CryptoParams( @@ -974,7 +983,8 @@ TEST_F(JsepTransport2Test, SdesNegotiationWithMismatchedCryptos) { // Tests that the remote candidates can be added to the transports after both // local and remote descriptions are set. TEST_F(JsepTransport2Test, AddRemoteCandidates) { - CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kDtlsSrtp); + jsep_transport_ = + CreateJsepTransport2(/*rtcp_mux_enabled=*/true, SrtpMode::kDtlsSrtp); auto fake_ice_transport = static_cast( jsep_transport_->rtp_dtls_transport()->ice_transport()); @@ -997,4 +1007,237 @@ TEST_F(JsepTransport2Test, AddRemoteCandidates) { EXPECT_EQ(candidates.size(), fake_ice_transport->remote_candidates().size()); } +enum class Scenario { + kSdes, + kDtlsBeforeCallerSendOffer, + kDtlsBeforeCallerSetAnswer, + kDtlsAfterCallerSetAnswer, +}; + +class JsepTransport2HeaderExtensionTest + : public JsepTransport2Test, + public ::testing::WithParamInterface> { + protected: + JsepTransport2HeaderExtensionTest() {} + + void CreateJsepTransportPair(SrtpMode mode) { + jsep_transport1_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/true, mode); + jsep_transport2_ = CreateJsepTransport2(/*rtcp_mux_enabled=*/true, mode); + + auto fake_dtls1 = + static_cast(jsep_transport1_->rtp_dtls_transport()); + auto fake_dtls2 = + static_cast(jsep_transport2_->rtp_dtls_transport()); + + fake_dtls1->fake_ice_transport()->SignalReadPacket.connect( + this, &JsepTransport2HeaderExtensionTest::OnReadPacket1); + fake_dtls2->fake_ice_transport()->SignalReadPacket.connect( + this, &JsepTransport2HeaderExtensionTest::OnReadPacket2); + + if (mode == SrtpMode::kDtlsSrtp) { + auto cert1 = + rtc::RTCCertificate::Create(std::unique_ptr( + rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))); + jsep_transport1_->rtp_dtls_transport()->SetLocalCertificate(cert1); + auto cert2 = + rtc::RTCCertificate::Create(std::unique_ptr( + rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))); + jsep_transport2_->rtp_dtls_transport()->SetLocalCertificate(cert2); + } + } + + void OnReadPacket1(rtc::PacketTransportInternal* transport, + const char* data, + size_t size, + const rtc::PacketTime& time, + int flags) { + RTC_LOG(LS_INFO) << "JsepTransport 1 Received a packet."; + CompareHeaderExtensions( + reinterpret_cast(kPcmuFrameWithExtensions), + sizeof(kPcmuFrameWithExtensions), data, size, recv_encrypted_headers1_, + false); + received_packet_count_++; + } + + void OnReadPacket2(rtc::PacketTransportInternal* transport, + const char* data, + size_t size, + const rtc::PacketTime& time, + int flags) { + RTC_LOG(LS_INFO) << "JsepTransport 2 Received a packet."; + CompareHeaderExtensions( + reinterpret_cast(kPcmuFrameWithExtensions), + sizeof(kPcmuFrameWithExtensions), data, size, recv_encrypted_headers2_, + false); + received_packet_count_++; + } + + void ConnectTransport() { + auto rtp_dtls_transport1 = + static_cast(jsep_transport1_->rtp_dtls_transport()); + auto rtp_dtls_transport2 = + static_cast(jsep_transport2_->rtp_dtls_transport()); + rtp_dtls_transport1->SetDestination(rtp_dtls_transport2); + } + + int GetRtpAuthLen() { + bool use_gcm = std::get<1>(GetParam()); + if (use_gcm) { + return 16; + } + return 10; + } + + void TestSendRecvPacketWithEncryptedHeaderExtension() { + TestOneWaySendRecvPacketWithEncryptedHeaderExtension( + jsep_transport1_.get()); + TestOneWaySendRecvPacketWithEncryptedHeaderExtension( + jsep_transport2_.get()); + } + + void TestOneWaySendRecvPacketWithEncryptedHeaderExtension( + JsepTransport2* sender_transport) { + size_t rtp_len = sizeof(kPcmuFrameWithExtensions); + size_t packet_size = rtp_len + GetRtpAuthLen(); + rtc::Buffer rtp_packet_buffer(packet_size); + char* rtp_packet_data = rtp_packet_buffer.data(); + memcpy(rtp_packet_data, kPcmuFrameWithExtensions, rtp_len); + // In order to be able to run this test function multiple times we can not + // use the same sequence number twice. Increase the sequence number by one. + rtc::SetBE16(reinterpret_cast(rtp_packet_data) + 2, + ++sequence_number_); + rtc::CopyOnWriteBuffer rtp_packet(rtp_packet_data, rtp_len, packet_size); + + int packet_count_before = received_packet_count_; + rtc::PacketOptions options; + // Send a packet and verify that the packet can be successfully received and + // decrypted. + ASSERT_TRUE(sender_transport->rtp_transport()->SendRtpPacket( + &rtp_packet, options, cricket::PF_SRTP_BYPASS)); + EXPECT_EQ(packet_count_before + 1, received_packet_count_); + } + + int sequence_number_ = 0; + int received_packet_count_ = 0; + std::unique_ptr jsep_transport1_; + std::unique_ptr jsep_transport2_; + std::vector recv_encrypted_headers1_; + std::vector recv_encrypted_headers2_; +}; + +// Test that the encrypted header extension works and can be changed in +// different scenarios. +TEST_P(JsepTransport2HeaderExtensionTest, EncryptedHeaderExtensionNegotiation) { + Scenario scenario = std::get<0>(GetParam()); + bool use_gcm = std::get<1>(GetParam()); + SrtpMode mode = SrtpMode ::kDtlsSrtp; + if (scenario == Scenario::kSdes) { + mode = SrtpMode::kSdes; + } + CreateJsepTransportPair(mode); + recv_encrypted_headers1_.push_back(kHeaderExtensionIDs[0]); + recv_encrypted_headers2_.push_back(kHeaderExtensionIDs[1]); + + cricket::CryptoParams sdes_param(1, rtc::CS_AES_CM_128_HMAC_SHA1_80, + "inline:" + rtc::CreateRandomString(40), + std::string()); + if (use_gcm) { + auto fake_dtls1 = + static_cast(jsep_transport1_->rtp_dtls_transport()); + auto fake_dtls2 = + static_cast(jsep_transport2_->rtp_dtls_transport()); + + fake_dtls1->SetSrtpCryptoSuite(rtc::SRTP_AEAD_AES_256_GCM); + fake_dtls2->SetSrtpCryptoSuite(rtc::SRTP_AEAD_AES_256_GCM); + } + + if (scenario == Scenario::kDtlsBeforeCallerSendOffer) { + ConnectTransport(); + } + + JsepTransportDescription offer_desc; + offer_desc.encrypted_header_extension_ids = recv_encrypted_headers1_; + if (scenario == Scenario::kSdes) { + offer_desc.cryptos.push_back(sdes_param); + } + ASSERT_TRUE( + jsep_transport1_ + ->SetLocalJsepTransportDescription(offer_desc, SdpType::kOffer) + .ok()); + ASSERT_TRUE( + jsep_transport2_ + ->SetRemoteJsepTransportDescription(offer_desc, SdpType::kOffer) + .ok()); + + JsepTransportDescription answer_desc; + answer_desc.encrypted_header_extension_ids = recv_encrypted_headers2_; + if (scenario == Scenario::kSdes) { + answer_desc.cryptos.push_back(sdes_param); + } + ASSERT_TRUE( + jsep_transport2_ + ->SetLocalJsepTransportDescription(answer_desc, SdpType::kAnswer) + .ok()); + + if (scenario == Scenario::kDtlsBeforeCallerSetAnswer) { + ConnectTransport(); + // Sending packet from transport2 to transport1 should work when they are + // partially configured. + TestOneWaySendRecvPacketWithEncryptedHeaderExtension( + /*sender_transport=*/jsep_transport2_.get()); + } + + ASSERT_TRUE( + jsep_transport1_ + ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer) + .ok()); + + if (scenario == Scenario::kDtlsAfterCallerSetAnswer || + scenario == Scenario::kSdes) { + ConnectTransport(); + } + EXPECT_TRUE(jsep_transport1_->rtp_transport()->IsSrtpActive()); + EXPECT_TRUE(jsep_transport2_->rtp_transport()->IsSrtpActive()); + TestSendRecvPacketWithEncryptedHeaderExtension(); + + // Change the encrypted header extension in a new offer/answer exchange. + recv_encrypted_headers1_.clear(); + recv_encrypted_headers2_.clear(); + recv_encrypted_headers1_.push_back(kHeaderExtensionIDs[1]); + recv_encrypted_headers2_.push_back(kHeaderExtensionIDs[0]); + offer_desc.encrypted_header_extension_ids = recv_encrypted_headers1_; + answer_desc.encrypted_header_extension_ids = recv_encrypted_headers2_; + ASSERT_TRUE( + jsep_transport1_ + ->SetLocalJsepTransportDescription(offer_desc, SdpType::kOffer) + .ok()); + ASSERT_TRUE( + jsep_transport2_ + ->SetRemoteJsepTransportDescription(offer_desc, SdpType::kOffer) + .ok()); + ASSERT_TRUE( + jsep_transport2_ + ->SetLocalJsepTransportDescription(answer_desc, SdpType::kAnswer) + .ok()); + ASSERT_TRUE( + jsep_transport1_ + ->SetRemoteJsepTransportDescription(answer_desc, SdpType::kAnswer) + .ok()); + EXPECT_TRUE(jsep_transport1_->rtp_transport()->IsSrtpActive()); + EXPECT_TRUE(jsep_transport2_->rtp_transport()->IsSrtpActive()); + TestSendRecvPacketWithEncryptedHeaderExtension(); +} + +INSTANTIATE_TEST_CASE_P( + JsepTransport2Test, + JsepTransport2HeaderExtensionTest, + ::testing::Values( + std::make_tuple(Scenario::kSdes, false), + std::make_tuple(Scenario::kDtlsBeforeCallerSendOffer, true), + std::make_tuple(Scenario::kDtlsBeforeCallerSetAnswer, true), + std::make_tuple(Scenario::kDtlsAfterCallerSetAnswer, true), + std::make_tuple(Scenario::kDtlsBeforeCallerSendOffer, false), + std::make_tuple(Scenario::kDtlsBeforeCallerSetAnswer, false), + std::make_tuple(Scenario::kDtlsAfterCallerSetAnswer, false))); + } // namespace cricket diff --git a/pc/jseptransport_unittest.cc b/pc/jseptransport_unittest.cc deleted file mode 100644 index a40312ffca..0000000000 --- a/pc/jseptransport_unittest.cc +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright 2011 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include "pc/jseptransport.h" - -#include - -#include "p2p/base/fakedtlstransport.h" -#include "p2p/base/fakeicetransport.h" -#include "rtc_base/fakesslidentity.h" -#include "rtc_base/gunit.h" -#include "rtc_base/network.h" - -namespace cricket { - -using rtc::SocketAddress; -using webrtc::SdpType; - -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; - -static const char kIceUfrag2[] = "TESTICEUFRAG0002"; -static const char kIcePwd2[] = "TESTICEPWD00000000000002"; - -TransportDescription MakeTransportDescription( - const char* ufrag, - const char* pwd, - const rtc::scoped_refptr& cert, - ConnectionRole role = CONNECTIONROLE_NONE) { - std::unique_ptr fingerprint; - if (cert) { - fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(cert)); - } - return TransportDescription(std::vector(), ufrag, pwd, - ICEMODE_FULL, role, fingerprint.get()); -} - -class JsepTransportTest : public testing::Test, public sigslot::has_slots<> { - public: - JsepTransportTest() { RecreateTransport(); } - - bool SetupFakeTransports(int component) { - fake_ice_transports_.emplace_back( - new FakeIceTransport(transport_->mid(), component)); - fake_dtls_transports_.emplace_back( - new FakeDtlsTransport(fake_ice_transports_.back().get())); - return transport_->AddChannel(fake_dtls_transports_.back().get(), - component); - } - - void DestroyChannel(int component) { transport_->RemoveChannel(component); } - - void RecreateTransport() { - transport_.reset(new JsepTransport("test content name", nullptr)); - } - - bool IceCredentialsChanged(const std::string& old_ufrag, - const std::string& old_pwd, - const std::string& new_ufrag, - const std::string& new_pwd) { - return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); - } - - protected: - std::vector> fake_dtls_transports_; - std::vector> fake_ice_transports_; - std::unique_ptr transport_; -}; - -// This test verifies transports are created with proper ICE ufrag/password -// after a transport description is applied. -TEST_F(JsepTransportTest, TestIceTransportParameters) { - EXPECT_TRUE(SetupFakeTransports(1)); - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, - SdpType::kOffer, NULL)); - EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[0]->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, fake_ice_transports_[0]->ice_ufrag()); - EXPECT_EQ(kIcePwd1, fake_ice_transports_[0]->ice_pwd()); - - TransportDescription remote_desc(kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, NULL)); - EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[0]->remote_ice_mode()); - EXPECT_EQ(kIceUfrag2, fake_ice_transports_[0]->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd2, fake_ice_transports_[0]->remote_ice_pwd()); -} - -// Similarly, test that DTLS parameters are applied after a transport -// description is applied. -TEST_F(JsepTransportTest, TestDtlsTransportParameters) { - EXPECT_TRUE(SetupFakeTransports(1)); - - // Create certificates. - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT))); - rtc::scoped_refptr remote_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT))); - transport_->SetLocalCertificate(local_cert); - - // Apply offer/answer. - TransportDescription local_desc = MakeTransportDescription( - kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - TransportDescription remote_desc = MakeTransportDescription( - kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_ACTIVE); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - - // Verify that SSL role and remote fingerprint were set correctly based on - // transport descriptions. - rtc::SSLRole role; - EXPECT_TRUE(fake_dtls_transports_[0]->GetDtlsRole(&role)); - EXPECT_EQ(rtc::SSL_SERVER, role); // Because remote description was "active". - EXPECT_EQ(remote_desc.identity_fingerprint->ToString(), - fake_dtls_transports_[0]->dtls_fingerprint().ToString()); -} - -// Same as above test, but with remote transport description using -// CONNECTIONROLE_PASSIVE, expecting SSL_CLIENT role. -TEST_F(JsepTransportTest, TestDtlsTransportParametersWithPassiveAnswer) { - EXPECT_TRUE(SetupFakeTransports(1)); - - // Create certificates. - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT))); - rtc::scoped_refptr remote_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT))); - transport_->SetLocalCertificate(local_cert); - - // Apply offer/answer. - TransportDescription local_desc = MakeTransportDescription( - kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - TransportDescription remote_desc = MakeTransportDescription( - kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_PASSIVE); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - - // Verify that SSL role and remote fingerprint were set correctly based on - // transport descriptions. - rtc::SSLRole role; - EXPECT_TRUE(fake_dtls_transports_[0]->GetDtlsRole(&role)); - EXPECT_EQ(rtc::SSL_CLIENT, - role); // Because remote description was "passive". - EXPECT_EQ(remote_desc.identity_fingerprint->ToString(), - fake_dtls_transports_[0]->dtls_fingerprint().ToString()); -} - -// Add two DtlsTransports/IceTransports and make sure parameters are applied to -// both of them. Applicable when RTP/RTCP are not multiplexed, so they share -// the same parameters but different connections. -TEST_F(JsepTransportTest, TestTransportParametersAppliedToTwoComponents) { - EXPECT_TRUE(SetupFakeTransports(1)); - EXPECT_TRUE(SetupFakeTransports(2)); - - // Create certificates. - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("local", rtc::KT_DEFAULT))); - rtc::scoped_refptr remote_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("remote", rtc::KT_DEFAULT))); - transport_->SetLocalCertificate(local_cert); - - // Apply offer/answer. - TransportDescription local_desc = MakeTransportDescription( - kIceUfrag1, kIcePwd1, local_cert, CONNECTIONROLE_ACTPASS); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - TransportDescription remote_desc = MakeTransportDescription( - kIceUfrag2, kIcePwd2, remote_cert, CONNECTIONROLE_ACTIVE); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - - for (int i = 0; i < 1; ++i) { - // Verify parameters of ICE transports. - EXPECT_EQ(ICEMODE_FULL, fake_ice_transports_[i]->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, fake_ice_transports_[i]->ice_ufrag()); - EXPECT_EQ(kIcePwd1, fake_ice_transports_[i]->ice_pwd()); - EXPECT_EQ(kIceUfrag2, fake_ice_transports_[i]->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd2, fake_ice_transports_[i]->remote_ice_pwd()); - // Verify parameters of DTLS transports. - rtc::SSLRole role; - EXPECT_TRUE(fake_dtls_transports_[i]->GetDtlsRole(&role)); - EXPECT_EQ(rtc::SSL_SERVER, - role); // Because remote description was "active". - EXPECT_EQ(remote_desc.identity_fingerprint->ToString(), - fake_dtls_transports_[i]->dtls_fingerprint().ToString()); - } -} - -// Verifies that IceCredentialsChanged returns true when either ufrag or pwd -// changed, and false in other cases. -TEST_F(JsepTransportTest, TestIceCredentialsChanged) { - EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u2", "p2")); - EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u2", "p1")); - EXPECT_TRUE(IceCredentialsChanged("u1", "p1", "u1", "p2")); - EXPECT_FALSE(IceCredentialsChanged("u1", "p1", "u1", "p1")); -} - -// Tests SetNeedsIceRestartFlag and NeedsIceRestart, ensuring NeedsIceRestart -// only starts returning "false" once an ICE restart has been initiated. -TEST_F(JsepTransportTest, NeedsIceRestart) { - // Do initial offer/answer so there's something to restart. - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - TransportDescription remote_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - - // Flag initially should be false. - EXPECT_FALSE(transport_->NeedsIceRestart()); - - // After setting flag, it should be true. - transport_->SetNeedsIceRestartFlag(); - EXPECT_TRUE(transport_->NeedsIceRestart()); - - // Doing an identical offer/answer shouldn't clear the flag. - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - EXPECT_TRUE(transport_->NeedsIceRestart()); - - // Doing an offer/answer that restarts ICE should clear the flag. - TransportDescription ice_restart_local_desc(kIceUfrag2, kIcePwd2); - TransportDescription ice_restart_remote_desc(kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - ice_restart_local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - ice_restart_remote_desc, SdpType::kAnswer, nullptr)); - EXPECT_FALSE(transport_->NeedsIceRestart()); -} - -TEST_F(JsepTransportTest, TestGetStats) { - EXPECT_TRUE(SetupFakeTransports(1)); - TransportStats stats; - EXPECT_TRUE(transport_->GetStats(&stats)); - // Note that this tests the behavior of a FakeIceTransport. - ASSERT_EQ(1U, stats.channel_stats.size()); - EXPECT_EQ(1, stats.channel_stats[0].component); - // Set local transport description for FakeTransport before connecting. - TransportDescription faketransport_desc( - std::vector(), rtc::CreateRandomString(ICE_UFRAG_LENGTH), - rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL, - CONNECTIONROLE_NONE, nullptr); - transport_->SetLocalTransportDescription(faketransport_desc, SdpType::kOffer, - nullptr); - EXPECT_TRUE(transport_->GetStats(&stats)); - ASSERT_EQ(1U, stats.channel_stats.size()); - EXPECT_EQ(1, stats.channel_stats[0].component); -} - -// Tests that VerifyCertificateFingerprint only returns true when the -// certificate matches the fingerprint. -TEST_F(JsepTransportTest, TestVerifyCertificateFingerprint) { - std::string error_desc; - EXPECT_FALSE( - transport_->VerifyCertificateFingerprint(nullptr, nullptr, &error_desc)); - rtc::KeyType key_types[] = {rtc::KT_RSA, rtc::KT_ECDSA}; - - for (auto& key_type : key_types) { - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", key_type))); - ASSERT_NE(nullptr, certificate); - - std::string digest_algorithm; - ASSERT_TRUE(certificate->ssl_certificate().GetSignatureDigestAlgorithm( - &digest_algorithm)); - ASSERT_FALSE(digest_algorithm.empty()); - std::unique_ptr good_fingerprint( - rtc::SSLFingerprint::Create(digest_algorithm, certificate->identity())); - ASSERT_NE(nullptr, good_fingerprint); - - EXPECT_TRUE(transport_->VerifyCertificateFingerprint( - certificate.get(), good_fingerprint.get(), &error_desc)); - EXPECT_FALSE(transport_->VerifyCertificateFingerprint( - certificate.get(), nullptr, &error_desc)); - EXPECT_FALSE(transport_->VerifyCertificateFingerprint( - nullptr, good_fingerprint.get(), &error_desc)); - - rtc::SSLFingerprint bad_fingerprint = *good_fingerprint; - bad_fingerprint.digest.AppendData("0", 1); - EXPECT_FALSE(transport_->VerifyCertificateFingerprint( - certificate.get(), &bad_fingerprint, &error_desc)); - } -} - -// Tests the logic of DTLS role negotiation for an initial offer/answer. -TEST_F(JsepTransportTest, DtlsRoleNegotiation) { - // Just use the same certificate for both sides; doesn't really matter in a - // non end-to-end test. - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - - TransportDescription local_desc = - MakeTransportDescription(kIceUfrag1, kIcePwd1, certificate); - TransportDescription remote_desc = - MakeTransportDescription(kIceUfrag2, kIcePwd2, certificate); - - struct NegotiateRoleParams { - ConnectionRole local_role; - ConnectionRole remote_role; - SdpType local_type; - SdpType remote_type; - }; - - std::string error_desc; - - // Parameters which set the SSL role to SSL_CLIENT. - NegotiateRoleParams valid_client_params[] = { - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTPASS, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kPrAnswer}}; - - for (auto& param : valid_client_params) { - RecreateTransport(); - transport_->SetLocalCertificate(certificate); - - local_desc.connection_role = param.local_role; - remote_desc.connection_role = param.remote_role; - - // Set the offer first. - if (param.local_type == SdpType::kOffer) { - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - } else { - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - } - EXPECT_EQ(rtc::SSL_CLIENT, *transport_->GetSslRole()); - } - - // Parameters which set the SSL role to SSL_SERVER. - NegotiateRoleParams valid_server_params[] = { - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kPrAnswer}}; - - for (auto& param : valid_server_params) { - RecreateTransport(); - transport_->SetLocalCertificate(certificate); - - local_desc.connection_role = param.local_role; - remote_desc.connection_role = param.remote_role; - - // Set the offer first. - if (param.local_type == SdpType::kOffer) { - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - } else { - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - } - EXPECT_EQ(rtc::SSL_SERVER, *transport_->GetSslRole()); - } - - // Invalid parameters due to both peers having a duplicate role. - NegotiateRoleParams duplicate_params[] = { - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kPrAnswer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_ACTPASS, SdpType::kOffer, - SdpType::kPrAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kPrAnswer}}; - - for (auto& param : duplicate_params) { - RecreateTransport(); - transport_->SetLocalCertificate(certificate); - - local_desc.connection_role = param.local_role; - remote_desc.connection_role = param.remote_role; - - // Set the offer first. - if (param.local_type == SdpType::kOffer) { - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - EXPECT_FALSE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - } else { - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - EXPECT_FALSE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - } - } - - // Invalid parameters due to the offerer not using ACTPASS. - NegotiateRoleParams offerer_without_actpass_params[] = { - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTPASS, CONNECTIONROLE_PASSIVE, SdpType::kPrAnswer, - SdpType::kOffer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer, - SdpType::kAnswer}, - {CONNECTIONROLE_ACTIVE, CONNECTIONROLE_PASSIVE, SdpType::kOffer, - SdpType::kPrAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTIVE, SdpType::kOffer, - SdpType::kPrAnswer}, - {CONNECTIONROLE_PASSIVE, CONNECTIONROLE_ACTPASS, SdpType::kOffer, - SdpType::kPrAnswer}}; - - for (auto& param : offerer_without_actpass_params) { - RecreateTransport(); - transport_->SetLocalCertificate(certificate); - - local_desc.connection_role = param.local_role; - remote_desc.connection_role = param.remote_role; - - // Set the offer first. - // TODO(deadbeef): Really this should fail as soon as the offer is - // attempted to be applied, and not when the answer is applied. - if (param.local_type == SdpType::kOffer) { - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - EXPECT_FALSE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - } else { - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, param.remote_type, nullptr)); - EXPECT_FALSE(transport_->SetLocalTransportDescription( - local_desc, param.local_type, nullptr)); - } - } -} - -// Test that a reoffer in the opposite direction is successful as long as the -// role isn't changing. Doesn't test every possible combination like the test -// above. -TEST_F(JsepTransportTest, ValidDtlsReofferFromAnswerer) { - // Just use the same certificate for both sides; doesn't really matter in a - // non end-to-end test. - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - transport_->SetLocalCertificate(certificate); - - TransportDescription local_offer = MakeTransportDescription( - kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS); - TransportDescription remote_answer = MakeTransportDescription( - kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE); - - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_offer, SdpType::kOffer, nullptr)); - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_answer, SdpType::kAnswer, nullptr)); - - // We were actpass->active previously, now in the other direction it's - // actpass->passive. - TransportDescription remote_offer = MakeTransportDescription( - kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTPASS); - TransportDescription local_answer = MakeTransportDescription( - kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_PASSIVE); - - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_offer, SdpType::kOffer, nullptr)); - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_answer, SdpType::kAnswer, nullptr)); -} - -// Test that a reoffer in the opposite direction fails if the role changes. -// Inverse of test above. -TEST_F(JsepTransportTest, InvalidDtlsReofferFromAnswerer) { - // Just use the same certificate for both sides; doesn't really matter in a - // non end-to-end test. - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - transport_->SetLocalCertificate(certificate); - - TransportDescription local_offer = MakeTransportDescription( - kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS); - TransportDescription remote_answer = MakeTransportDescription( - kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE); - - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_offer, SdpType::kOffer, nullptr)); - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_answer, SdpType::kAnswer, nullptr)); - - // Changing role to passive here isn't allowed. Though for some reason this - // only fails in SetLocalTransportDescription. - TransportDescription remote_offer = MakeTransportDescription( - kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_PASSIVE); - TransportDescription local_answer = MakeTransportDescription( - kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTIVE); - - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_offer, SdpType::kOffer, nullptr)); - EXPECT_FALSE(transport_->SetLocalTransportDescription( - local_answer, SdpType::kAnswer, nullptr)); -} - -// Test that a remote offer with the current negotiated role can be accepted. -// This is allowed by dtls-sdp, though we'll never generate such an offer, -// since JSEP requires generating "actpass". -TEST_F(JsepTransportTest, RemoteOfferWithCurrentNegotiatedDtlsRole) { - // Just use the same certificate in both descriptions; the remote fingerprint - // doesn't matter in a non end-to-end test. - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - transport_->SetLocalCertificate(certificate); - - TransportDescription remote_desc = MakeTransportDescription( - kIceUfrag1, kIcePwd1, certificate, CONNECTIONROLE_ACTPASS); - TransportDescription local_desc = MakeTransportDescription( - kIceUfrag2, kIcePwd2, certificate, CONNECTIONROLE_ACTIVE); - - // Normal initial offer/answer with "actpass" in the offer and "active" in - // the answer. - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kAnswer, nullptr)); - - // Sanity check that role was actually negotiated. - rtc::Optional role = transport_->GetSslRole(); - ASSERT_TRUE(role); - EXPECT_EQ(rtc::SSL_CLIENT, *role); - - // Subsequent offer with current negotiated role of "passive". - remote_desc.connection_role = CONNECTIONROLE_PASSIVE; - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kOffer, nullptr)); - EXPECT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kAnswer, nullptr)); -} - -// Test that a remote offer with the inverse of the current negotiated DTLS -// role is rejected. -TEST_F(JsepTransportTest, RemoteOfferThatChangesNegotiatedDtlsRole) { - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - std::unique_ptr fingerprint( - rtc::SSLFingerprint::CreateFromCertificate(certificate)); - transport_->SetLocalCertificate(certificate); - - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - TransportDescription remote_desc(kIceUfrag2, kIcePwd2); - // Just use the same fingerprint in both descriptions; the remote fingerprint - // doesn't matter in a non end-to-end test. - local_desc.identity_fingerprint.reset( - TransportDescription::CopyFingerprint(fingerprint.get())); - remote_desc.identity_fingerprint.reset( - TransportDescription::CopyFingerprint(fingerprint.get())); - - remote_desc.connection_role = CONNECTIONROLE_ACTPASS; - local_desc.connection_role = CONNECTIONROLE_ACTIVE; - - // Normal initial offer/answer with "actpass" in the offer and "active" in - // the answer. - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kAnswer, nullptr)); - - // Sanity check that role was actually negotiated. - rtc::Optional role = transport_->GetSslRole(); - ASSERT_TRUE(role); - EXPECT_EQ(rtc::SSL_CLIENT, *role); - - // Subsequent offer with "active", which is the opposite of the remote - // endpoint's negotiated role. - // TODO(deadbeef): Really this should fail as soon as the offer is - // attempted to be applied, and not when the answer is applied. - remote_desc.connection_role = CONNECTIONROLE_ACTIVE; - EXPECT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kOffer, nullptr)); - EXPECT_FALSE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kAnswer, nullptr)); -} - -// Testing that a legacy client that doesn't use the setup attribute will be -// interpreted as having an active role. -TEST_F(JsepTransportTest, TestDtlsSetupWithLegacyAsAnswerer) { - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - std::unique_ptr fingerprint( - rtc::SSLFingerprint::CreateFromCertificate(certificate)); - transport_->SetLocalCertificate(certificate); - - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - TransportDescription remote_desc(kIceUfrag2, kIcePwd2); - // Just use the same fingerprint in both descriptions; the remote fingerprint - // doesn't matter in a non end-to-end test. - local_desc.identity_fingerprint.reset( - TransportDescription::CopyFingerprint(fingerprint.get())); - remote_desc.identity_fingerprint.reset( - TransportDescription::CopyFingerprint(fingerprint.get())); - - local_desc.connection_role = CONNECTIONROLE_ACTPASS; - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, SdpType::kOffer, nullptr)); - // Use CONNECTIONROLE_NONE to simulate legacy endpoint. - remote_desc.connection_role = CONNECTIONROLE_NONE; - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, SdpType::kAnswer, nullptr)); - - rtc::Optional role = transport_->GetSslRole(); - ASSERT_TRUE(role); - // Since legacy answer ommitted setup atribute, and we offered actpass, we - // should act as passive (server). - EXPECT_EQ(rtc::SSL_SERVER, *role); -} - -} // namespace cricket diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc index 5235791792..1a1fce8366 100644 --- a/pc/jseptransportcontroller.cc +++ b/pc/jseptransportcontroller.cc @@ -136,7 +136,7 @@ RTCError JsepTransportController::SetRemoteDescription( RtpTransportInternal* JsepTransportController::GetRtpTransport( const std::string& mid) const { - auto jsep_transport = GetJsepTransport(mid); + auto jsep_transport = GetJsepTransportForMid(mid); if (!jsep_transport) { return nullptr; } @@ -145,7 +145,7 @@ RtpTransportInternal* JsepTransportController::GetRtpTransport( cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport( const std::string& mid) const { - auto jsep_transport = GetJsepTransport(mid); + auto jsep_transport = GetJsepTransportForMid(mid); if (!jsep_transport) { return nullptr; } @@ -154,7 +154,7 @@ cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport( cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport( const std::string& mid) const { - auto jsep_transport = GetJsepTransport(mid); + auto jsep_transport = GetJsepTransportForMid(mid); if (!jsep_transport) { return nullptr; } @@ -174,14 +174,15 @@ void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) { } void JsepTransportController::SetNeedsIceRestartFlag() { - for (auto& kv : jsep_transports_by_mid_) { + for (auto& kv : jsep_transports_by_name_) { kv.second->SetNeedsIceRestartFlag(); } } bool JsepTransportController::NeedsIceRestart( const std::string& transport_name) const { - const cricket::JsepTransport2* transport = GetJsepTransport(transport_name); + const cricket::JsepTransport2* transport = + GetJsepTransportByName(transport_name); if (!transport) { return false; } @@ -189,13 +190,13 @@ bool JsepTransportController::NeedsIceRestart( } rtc::Optional JsepTransportController::GetDtlsRole( - const std::string& transport_name) const { + const std::string& mid) const { if (!network_thread_->IsCurrent()) { return network_thread_->Invoke>( - RTC_FROM_HERE, [&] { return GetDtlsRole(transport_name); }); + RTC_FROM_HERE, [&] { return GetDtlsRole(mid); }); } - const cricket::JsepTransport2* t = GetJsepTransport(transport_name); + const cricket::JsepTransport2* t = GetJsepTransportForMid(mid); if (!t) { return rtc::Optional(); } @@ -218,7 +219,7 @@ bool JsepTransportController::SetLocalCertificate( // Set certificate for JsepTransport, which verifies it matches the // fingerprint in SDP, and DTLS transport. // Fallback from DTLS to SDES is not supported. - for (auto& kv : jsep_transports_by_mid_) { + for (auto& kv : jsep_transports_by_name_) { kv.second->SetLocalCertificate(certificate_); } for (auto& dtls : GetDtlsTransports()) { @@ -236,7 +237,7 @@ JsepTransportController::GetLocalCertificate( RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); }); } - const cricket::JsepTransport2* t = GetJsepTransport(transport_name); + const cricket::JsepTransport2* t = GetJsepTransportByName(transport_name); if (!t) { return nullptr; } @@ -251,10 +252,14 @@ JsepTransportController::GetRemoteSSLCertChain( RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); }); } - // Get the certificate from the RTP channel's DTLS handshake. Should be - // identical to the RTCP channel's, since they were given the same remote + // Get the certificate from the RTP transport's DTLS handshake. Should be + // identical to the RTCP transport's, since they were given the same remote // fingerprint. - auto dtls = GetDtlsTransport(transport_name); + auto jsep_transport = GetJsepTransportByName(transport_name); + if (!jsep_transport) { + return nullptr; + } + auto dtls = jsep_transport->rtp_dtls_transport(); if (!dtls) { return nullptr; } @@ -288,13 +293,12 @@ RTCError JsepTransportController::AddRemoteCandidates( if (!error.ok()) { return error; } - - cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name); + auto jsep_transport = GetJsepTransportByName(transport_name); if (!jsep_transport) { - return RTCError(RTCErrorType::INVALID_PARAMETER, - "The transport doesn't exist."); + RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport " + "doesn't exist. Ignore it."; + return RTCError::OK(); } - return jsep_transport->AddRemoteCandidates(candidates); } @@ -325,10 +329,12 @@ RTCError JsepTransportController::RemoveRemoteCandidates( for (const auto& kv : candidates_by_transport_name) { const std::string& transport_name = kv.first; const cricket::Candidates& candidates = kv.second; - cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name); + cricket::JsepTransport2* jsep_transport = + GetJsepTransportByName(transport_name); if (!jsep_transport) { - return RTCError(RTCErrorType::INVALID_PARAMETER, - "The transport doesn't exist."); + RTC_LOG(LS_WARNING) + << "Not removing candidate because the JsepTransport doesn't exist."; + continue; } for (const cricket::Candidate& candidate : candidates) { auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP @@ -349,7 +355,7 @@ bool JsepTransportController::GetStats(const std::string& transport_name, RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); }); } - cricket::JsepTransport2* transport = GetJsepTransport(transport_name); + cricket::JsepTransport2* transport = GetJsepTransportByName(transport_name); if (!transport) { return false; } @@ -427,23 +433,27 @@ JsepTransportController::CreateUnencryptedRtpTransport( rtc::PacketTransportInternal* rtp_packet_transport, rtc::PacketTransportInternal* rtcp_packet_transport) { RTC_DCHECK(network_thread_->IsCurrent()); - // TODO(zhihuang): Add support of unencrypted RTP for testing. - return nullptr; + auto unencrypted_rtp_transport = + rtc::MakeUnique(rtcp_packet_transport == nullptr); + unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport); + if (rtcp_packet_transport) { + unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport); + } + return unencrypted_rtp_transport; } std::unique_ptr JsepTransportController::CreateSdesTransport( const std::string& transport_name, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport) { + cricket::DtlsTransportInternal* rtp_dtls_transport, + cricket::DtlsTransportInternal* rtcp_dtls_transport) { RTC_DCHECK(network_thread_->IsCurrent()); - bool rtcp_mux_enabled = rtcp_packet_transport == nullptr; auto srtp_transport = - rtc::MakeUnique(rtcp_mux_enabled); - RTC_DCHECK(rtp_packet_transport); - srtp_transport->SetRtpPacketTransport(rtp_packet_transport); - if (rtcp_packet_transport) { - srtp_transport->SetRtcpPacketTransport(rtp_packet_transport); + rtc::MakeUnique(rtcp_dtls_transport == nullptr); + RTC_DCHECK(rtp_dtls_transport); + srtp_transport->SetRtpPacketTransport(rtp_dtls_transport); + if (rtcp_dtls_transport) { + srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport); } if (config_.enable_external_auth) { srtp_transport->EnableExternalAuth(); @@ -457,9 +467,8 @@ JsepTransportController::CreateDtlsSrtpTransport( cricket::DtlsTransportInternal* rtp_dtls_transport, cricket::DtlsTransportInternal* rtcp_dtls_transport) { RTC_DCHECK(network_thread_->IsCurrent()); - bool rtcp_mux_enabled = rtcp_dtls_transport == nullptr; auto srtp_transport = - rtc::MakeUnique(rtcp_mux_enabled); + rtc::MakeUnique(rtcp_dtls_transport == nullptr); if (config_.enable_external_auth) { srtp_transport->EnableExternalAuth(); } @@ -475,8 +484,8 @@ JsepTransportController::CreateDtlsSrtpTransport( std::vector JsepTransportController::GetDtlsTransports() { std::vector dtls_transports; - for (auto it = jsep_transports_by_mid_.begin(); - it != jsep_transports_by_mid_.end(); ++it) { + for (auto it = jsep_transports_by_name_.begin(); + it != jsep_transports_by_name_.end(); ++it) { auto jsep_transport = it->second.get(); RTC_DCHECK(jsep_transport); if (jsep_transport->rtp_dtls_transport()) { @@ -535,7 +544,18 @@ RTCError JsepTransportController::ApplyDescription_n( } if (ShouldUpdateBundleGroup(type, description)) { - bundle_group_ = *description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); + if (!description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "max-bundle is used but no bundle group found."); + } else { + bundle_group_ = *description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); + } + } + + RTCError error; + error = ValidateBundleGroup(description); + if (!error.ok()) { + return error; } std::vector merged_encrypted_extension_ids; @@ -550,7 +570,10 @@ RTCError JsepTransportController::ApplyDescription_n( (IsBundled(content_info.name) && content_info.name != *bundled_mid())) { continue; } - MaybeCreateJsepTransport(content_info.name, content_info); + error = MaybeCreateJsepTransport(content_info.name, content_info); + if (!error.ok()) { + return error; + } } RTC_DCHECK(description->contents().size() == @@ -569,6 +592,11 @@ RTCError JsepTransportController::ApplyDescription_n( continue; } + error = ValidateContent(content_info); + if (!error.ok()) { + return error; + } + std::vector extension_ids; if (bundle_group_ && content_info.name == *bundled_mid()) { extension_ids = merged_encrypted_extension_ids; @@ -576,15 +604,18 @@ RTCError JsepTransportController::ApplyDescription_n( extension_ids = GetEncryptedHeaderExtensionIds(content_info); } - cricket::JsepTransport2* transport = GetJsepTransport(content_info.name); + int rtp_abs_sendtime_extn_id = + GetRtpAbsSendTimeHeaderExtensionId(content_info); + + cricket::JsepTransport2* transport = + GetJsepTransportForMid(content_info.name); RTC_DCHECK(transport); SetIceRole_n(DetermineIceRole(transport, transport_info, type, local)); - RTCError error; cricket::JsepTransportDescription jsep_description = CreateJsepTransportDescription(content_info, transport_info, - extension_ids); + extension_ids, rtp_abs_sendtime_extn_id); if (local) { error = transport->SetLocalJsepTransportDescription(jsep_description, type); @@ -602,6 +633,51 @@ RTCError JsepTransportController::ApplyDescription_n( return RTCError::OK(); } +RTCError JsepTransportController::ValidateBundleGroup( + const cricket::SessionDescription* description) { + RTC_DCHECK(description); + + if (!bundled_mid()) { + return RTCError::OK(); + } + + auto bundled_content = description->GetContentByName(*bundled_mid()); + if (!bundled_content) { + return RTCError( + RTCErrorType::INVALID_PARAMETER, + "An m= section associated with the BUNDLE-tag doesn't exist."); + } + + // If the |bundled_content| is rejected, other contents in the bundle group + // should be rejected. + if (bundled_content->rejected) { + for (auto content_name : bundle_group_->content_names()) { + auto other_content = description->GetContentByName(content_name); + if (!other_content->rejected) { + return RTCError( + RTCErrorType::INVALID_PARAMETER, + "The m= section:" + content_name + " should be rejected."); + } + } + } + + return RTCError::OK(); +} + +RTCError JsepTransportController::ValidateContent( + const cricket::ContentInfo& content_info) { + if (config_.rtcp_mux_policy == + PeerConnectionInterface::kRtcpMuxPolicyRequire && + content_info.type == cricket::MediaProtocolType::kRtp && + !content_info.media_description()->rtcp_mux()) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "The m= section:" + content_info.name + + " is invalid. RTCP-MUX is not " + "enabled when it is required."); + } + return RTCError::OK(); +} + void JsepTransportController::HandleRejectedContent( const cricket::ContentInfo& content_info) { // If the content is rejected, let the @@ -612,9 +688,24 @@ void JsepTransportController::HandleRejectedContent( } else { SignalDtlsTransportChanged(content_info.name, nullptr); } - // Remove the rejected content from the |bundle_group_|. - if (IsBundled(content_info.name)) { + // If the answerer rejects the first content, which other contents are bundled + // on, all the other contents in the bundle group will be rejected. + if (content_info.name == bundled_mid()) { + for (auto content_name : bundle_group_->content_names()) { + if (content_info.type == cricket::MediaProtocolType::kRtp) { + SignalRtpTransportChanged(content_name, nullptr); + } else { + SignalDtlsTransportChanged(content_name, nullptr); + } + } + bundle_group_.reset(); + } else if (IsBundled(content_info.name)) { + // Remove the rejected content from the |bundle_group_|. bundle_group_->RemoveContentName(content_info.name); + // Reset the bundle group if nothing left. + if (!bundle_group_->FirstContentName()) { + bundle_group_.reset(); + } } MaybeDestroyJsepTransport(content_info.name); } @@ -626,11 +717,11 @@ void JsepTransportController::HandleBundledContent( // then destroy the cricket::JsepTransport2. if (content_info.type == cricket::MediaProtocolType::kRtp) { auto rtp_transport = - jsep_transports_by_mid_[*bundled_mid()]->rtp_transport(); + jsep_transports_by_name_[*bundled_mid()]->rtp_transport(); SignalRtpTransportChanged(content_info.name, rtp_transport); } else { auto dtls_transport = - jsep_transports_by_mid_[*bundled_mid()]->rtp_dtls_transport(); + jsep_transports_by_name_[*bundled_mid()]->rtp_dtls_transport(); SignalDtlsTransportChanged(content_info.name, dtls_transport); } MaybeDestroyJsepTransport(content_info.name); @@ -640,7 +731,8 @@ cricket::JsepTransportDescription JsepTransportController::CreateJsepTransportDescription( cricket::ContentInfo content_info, cricket::TransportInfo transport_info, - const std::vector& encrypted_extension_ids) { + const std::vector& encrypted_extension_ids, + int rtp_abs_sendtime_extn_id) { const cricket::MediaContentDescription* content_desc = static_cast( content_info.description); @@ -651,7 +743,7 @@ JsepTransportController::CreateJsepTransportDescription( return cricket::JsepTransportDescription( rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids, - transport_info.description); + rtp_abs_sendtime_extn_id, transport_info.description); } bool JsepTransportController::ShouldUpdateBundleGroup( @@ -721,47 +813,79 @@ JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle( return merged_ids; } -const cricket::JsepTransport2* JsepTransportController::GetJsepTransport( - const std::string& mid) const { - auto target_mid = mid; - if (IsBundled(mid)) { - target_mid = *bundled_mid(); - } - auto it = jsep_transports_by_mid_.find(target_mid); - return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get(); -} - -cricket::JsepTransport2* JsepTransportController::GetJsepTransport( - const std::string& mid) { - auto target_mid = mid; - if (IsBundled(mid)) { - target_mid = *bundled_mid(); - } - auto it = jsep_transports_by_mid_.find(target_mid); - return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get(); -} - -void JsepTransportController::MaybeCreateJsepTransport( - const std::string& mid, +int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId( const cricket::ContentInfo& content_info) { - RTC_DCHECK(network_thread_->IsCurrent()); - - cricket::JsepTransport2* transport = GetJsepTransport(mid); - if (transport) { - return; + if (!config_.enable_external_auth) { + return -1; } const cricket::MediaContentDescription* content_desc = static_cast( content_info.description); - bool rtcp_mux_enabled = - content_desc->rtcp_mux() || - config_.rtcp_mux_policy == PeerConnectionInterface::kRtcpMuxPolicyRequire; + + const webrtc::RtpExtension* send_time_extension = + webrtc::RtpExtension::FindHeaderExtensionByUri( + content_desc->rtp_header_extensions(), + webrtc::RtpExtension::kAbsSendTimeUri); + return send_time_extension ? send_time_extension->id : -1; +} + +const cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid( + const std::string& mid) const { + auto target_mid = mid; + if (IsBundled(mid)) { + target_mid = *bundled_mid(); + } + auto it = jsep_transports_by_name_.find(target_mid); + return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get(); +} + +cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid( + const std::string& mid) { + auto target_mid = mid; + if (IsBundled(mid)) { + target_mid = *bundled_mid(); + } + auto it = jsep_transports_by_name_.find(target_mid); + return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get(); +} + +const cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName( + const std::string& transport_name) const { + auto it = jsep_transports_by_name_.find(transport_name); + return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get(); +} + +cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName( + const std::string& transport_name) { + auto it = jsep_transports_by_name_.find(transport_name); + return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get(); +} + +RTCError JsepTransportController::MaybeCreateJsepTransport( + const std::string& mid, + const cricket::ContentInfo& content_info) { + RTC_DCHECK(network_thread_->IsCurrent()); + cricket::JsepTransport2* transport = GetJsepTransportForMid(mid); + if (transport) { + return RTCError::OK(); + } + + const cricket::MediaContentDescription* content_desc = + static_cast( + content_info.description); + if (certificate_ && !content_desc->cryptos().empty()) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "SDES and DTLS-SRTP cannot be enabled at the same time."); + } + std::unique_ptr rtp_dtls_transport = - CreateDtlsTransport(mid, /*rtcp = */ false); + CreateDtlsTransport(mid, /*rtcp =*/false); std::unique_ptr rtcp_dtls_transport; - if (!rtcp_mux_enabled) { - rtcp_dtls_transport = CreateDtlsTransport(mid, /*rtcp = */ true); + if (config_.rtcp_mux_policy != + PeerConnectionInterface::kRtcpMuxPolicyRequire && + content_info.type == cricket::MediaProtocolType::kRtp) { + rtcp_dtls_transport = CreateDtlsTransport(mid, /*rtcp =*/true); } std::unique_ptr unencrypted_rtp_transport; @@ -785,19 +909,21 @@ void JsepTransportController::MaybeCreateJsepTransport( std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport)); jsep_transport->SignalRtcpMuxActive.connect( this, &JsepTransportController::UpdateAggregateStates_n); - jsep_transports_by_mid_[mid] = std::move(jsep_transport); + jsep_transports_by_name_[mid] = std::move(jsep_transport); UpdateAggregateStates_n(); + + return RTCError::OK(); } void JsepTransportController::MaybeDestroyJsepTransport( const std::string& mid) { - jsep_transports_by_mid_.erase(mid); + jsep_transports_by_name_.erase(mid); UpdateAggregateStates_n(); } void JsepTransportController::DestroyAllJsepTransports_n() { RTC_DCHECK(network_thread_->IsCurrent()); - jsep_transports_by_mid_.clear(); + jsep_transports_by_name_.clear(); } void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) { @@ -871,7 +997,7 @@ cricket::IceRole JsepTransportController::DetermineIceRole( jsep_transport->local_description()->transport_desc.ice_mode == cricket::ICEMODE_LITE && ice_role_ == cricket::ICEROLE_CONTROLLING && - tdesc.ice_mode == cricket::ICEMODE_LITE) { + tdesc.ice_mode == cricket::ICEMODE_FULL) { ice_role = cricket::ICEROLE_CONTROLLED; } } diff --git a/pc/jseptransportcontroller.h b/pc/jseptransportcontroller.h index fffdd33f33..f533cf8179 100644 --- a/pc/jseptransportcontroller.h +++ b/pc/jseptransportcontroller.h @@ -135,6 +135,7 @@ class JsepTransportController : public sigslot::has_slots<>, bool GetStats(const std::string& mid, cricket::TransportStats* stats); void SetMetricsObserver(webrtc::MetricsObserverInterface* metrics_observer); + bool initial_offerer() const { return initial_offerer_ && *initial_offerer_; } // All of these signals are fired on the signaling thread. // If any transport failed => failed, @@ -176,6 +177,8 @@ class JsepTransportController : public sigslot::has_slots<>, RTCError ApplyDescription_n(bool local, SdpType type, const cricket::SessionDescription* description); + RTCError ValidateBundleGroup(const cricket::SessionDescription* description); + RTCError ValidateContent(const cricket::ContentInfo& content_info); void HandleRejectedContent(const cricket::ContentInfo& content_info); void HandleBundledContent(const cricket::ContentInfo& content_info); @@ -183,7 +186,8 @@ class JsepTransportController : public sigslot::has_slots<>, cricket::JsepTransportDescription CreateJsepTransportDescription( cricket::ContentInfo content_info, cricket::TransportInfo transport_info, - const std::vector& encrypted_extension_ids); + const std::vector& encrypted_extension_ids, + int rtp_abs_sendtime_extn_id); rtc::Optional bundled_mid() const { rtc::Optional bundled_mid; @@ -202,15 +206,29 @@ class JsepTransportController : public sigslot::has_slots<>, std::vector MergeEncryptedHeaderExtensionIdsForBundle( const cricket::SessionDescription* description); - std::vector GetEncryptedHeaderExtensionIds( const cricket::ContentInfo& content_info); - const cricket::JsepTransport2* GetJsepTransport(const std::string& mid) const; - cricket::JsepTransport2* GetJsepTransport(const std::string& mid); + int GetRtpAbsSendTimeHeaderExtensionId( + const cricket::ContentInfo& content_info); - void MaybeCreateJsepTransport(const std::string& mid, - const cricket::ContentInfo& content_info); + // This method takes the BUNDLE group into account. If the JsepTransport is + // destroyed because of BUNDLE, it would return the transport which other + // transports are bundled on (In current implementation, it is the first + // content in the BUNDLE group). + const cricket::JsepTransport2* GetJsepTransportForMid( + const std::string& mid) const; + cricket::JsepTransport2* GetJsepTransportForMid(const std::string& mid); + + // Get the JsepTransport without considering the BUNDLE group. Return nullptr + // if the JsepTransport is destroyed. + const cricket::JsepTransport2* GetJsepTransportByName( + const std::string& transport_name) const; + cricket::JsepTransport2* GetJsepTransportByName( + const std::string& transport_name); + + RTCError MaybeCreateJsepTransport(const std::string& mid, + const cricket::ContentInfo& content_info); void MaybeDestroyJsepTransport(const std::string& mid); void DestroyAllJsepTransports_n(); @@ -232,8 +250,8 @@ class JsepTransportController : public sigslot::has_slots<>, rtc::PacketTransportInternal* rtcp_packet_transport); std::unique_ptr CreateSdesTransport( const std::string& transport_name, - rtc::PacketTransportInternal* rtp_packet_transport, - rtc::PacketTransportInternal* rtcp_packet_transport); + cricket::DtlsTransportInternal* rtp_dtls_transport, + cricket::DtlsTransportInternal* rtcp_dtls_transport); std::unique_ptr CreateDtlsSrtpTransport( const std::string& transport_name, cricket::DtlsTransportInternal* rtp_dtls_transport, @@ -265,9 +283,9 @@ class JsepTransportController : public sigslot::has_slots<>, cricket::PortAllocator* const port_allocator_ = nullptr; std::map> - jsep_transports_by_mid_; + jsep_transports_by_name_; - // Aggregate state for TransportChannelImpls. + // Aggregate state for Transports. cricket::IceConnectionState ice_connection_state_ = cricket::kIceConnectionConnecting; cricket::IceGatheringState ice_gathering_state_ = cricket::kIceGatheringNew; diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc index 78f4986914..73af35d18c 100644 --- a/pc/jseptransportcontroller_unittest.cc +++ b/pc/jseptransportcontroller_unittest.cc @@ -123,6 +123,8 @@ class JsepTransportControllerTest : public testing::Test, rtc::scoped_refptr cert) { std::unique_ptr audio( new cricket::AudioContentDescription()); + // Set RTCP-mux to be true because the default policy is "mux required". + audio->set_rtcp_mux(true); description->AddContent(mid, cricket::MediaProtocolType::kRtp, /*rejected=*/false, audio.release()); AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert); @@ -137,6 +139,8 @@ class JsepTransportControllerTest : public testing::Test, rtc::scoped_refptr cert) { std::unique_ptr video( new cricket::VideoContentDescription()); + // Set RTCP-mux to be true because the default policy is "mux required". + video->set_rtcp_mux(true); description->AddContent(mid, cricket::MediaProtocolType::kRtp, /*rejected=*/false, video.release()); AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert); @@ -152,6 +156,7 @@ class JsepTransportControllerTest : public testing::Test, rtc::scoped_refptr cert) { std::unique_ptr data( new cricket::DataContentDescription()); + data->set_rtcp_mux(true); description->AddContent(mid, protocol_type, /*rejected=*/false, data.release()); AddTransportInfo(description, mid, ufrag, pwd, ice_mode, conn_role, cert); @@ -325,6 +330,20 @@ TEST_F(JsepTransportControllerTest, GetDtlsTransport) { EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid2)); } +TEST_F(JsepTransportControllerTest, GetDtlsTransportWithRtcpMux) { + JsepTransportController::Config config; + config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire; + CreateJsepTransportController(config); + auto description = CreateSessionDescriptionWithoutBundle(); + EXPECT_TRUE(transport_controller_ + ->SetLocalDescription(SdpType::kOffer, description.get()) + .ok()); + EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kAudioMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1)); + EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1)); +} + TEST_F(JsepTransportControllerTest, SetIceConfig) { CreateJsepTransportController(JsepTransportController::Config()); auto description = CreateSessionDescriptionWithoutBundle(); @@ -1207,5 +1226,103 @@ TEST_F(JsepTransportControllerTest, ChangeBundledMidNotSupported) { ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) .ok()); } +// Test that rejecting only the first m= section of a BUNDLE group is treated as +// an error, but rejecting all of them works as expected. +TEST_F(JsepTransportControllerTest, RejectFirstContentInBundleGroup) { + CreateJsepTransportController(JsepTransportController::Config()); + cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE); + bundle_group.AddContentName(kAudioMid1); + bundle_group.AddContentName(kVideoMid1); + bundle_group.AddContentName(kDataMid1); + + auto local_offer = rtc::MakeUnique(); + AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + AddVideoSection(local_offer.get(), kVideoMid1, kIceUfrag2, kIcePwd2, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + AddDataSection(local_offer.get(), kDataMid1, + cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + + auto remote_answer = rtc::MakeUnique(); + AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + AddVideoSection(remote_answer.get(), kVideoMid1, kIceUfrag2, kIcePwd2, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + AddDataSection(remote_answer.get(), kDataMid1, + cricket::MediaProtocolType::kSctp, kIceUfrag3, kIcePwd3, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + // Reject audio content in answer. + remote_answer->contents()[0].rejected = true; + + local_offer->AddGroup(bundle_group); + remote_answer->AddGroup(bundle_group); + + EXPECT_TRUE(transport_controller_ + ->SetLocalDescription(SdpType::kOffer, local_offer.get()) + .ok()); + EXPECT_FALSE(transport_controller_ + ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) + .ok()); + + // Reject all the contents. + remote_answer->contents()[1].rejected = true; + remote_answer->contents()[2].rejected = true; + EXPECT_TRUE(transport_controller_ + ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) + .ok()); + EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kAudioMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetRtpTransport(kVideoMid1)); + EXPECT_EQ(nullptr, transport_controller_->GetDtlsTransport(kDataMid1)); +} + +// Tests that applying non-RTCP-mux offer would fail when kRtcpMuxPolicyRequire +// is used. +TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxOfferWhenMuxingRequired) { + JsepTransportController::Config config; + config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire; + CreateJsepTransportController(config); + auto local_offer = rtc::MakeUnique(); + AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + + local_offer->contents()[0].media_description()->set_rtcp_mux(false); + // Applying a non-RTCP-mux offer is expected to fail. + EXPECT_FALSE(transport_controller_ + ->SetLocalDescription(SdpType::kOffer, local_offer.get()) + .ok()); +} + +// Tests that applying non-RTCP-mux answer would fail when kRtcpMuxPolicyRequire +// is used. +TEST_F(JsepTransportControllerTest, ApplyNonRtcpMuxAnswerWhenMuxingRequired) { + JsepTransportController::Config config; + config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire; + CreateJsepTransportController(config); + auto local_offer = rtc::MakeUnique(); + AddAudioSection(local_offer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_ACTPASS, + nullptr); + EXPECT_TRUE(transport_controller_ + ->SetLocalDescription(SdpType::kOffer, local_offer.get()) + .ok()); + + auto remote_answer = rtc::MakeUnique(); + AddAudioSection(remote_answer.get(), kAudioMid1, kIceUfrag1, kIcePwd1, + cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_PASSIVE, + nullptr); + // Applying a non-RTCP-mux answer is expected to fail. + remote_answer->contents()[0].media_description()->set_rtcp_mux(false); + EXPECT_FALSE(transport_controller_ + ->SetRemoteDescription(SdpType::kAnswer, remote_answer.get()) + .ok()); +} } // namespace webrtc diff --git a/pc/mediasession.h b/pc/mediasession.h index 9b118e1ef1..72a756aa09 100644 --- a/pc/mediasession.h +++ b/pc/mediasession.h @@ -22,7 +22,7 @@ #include "media/base/mediaconstants.h" #include "media/base/mediaengine.h" // For DataChannelType #include "p2p/base/transportdescriptionfactory.h" -#include "pc/jseptransport.h" +#include "pc/jseptransport2.h" #include "pc/sessiondescription.h" namespace cricket { diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index eacfb8329b..ca54c44256 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -89,7 +89,6 @@ const char kDtlsSrtpSetupFailureRtp[] = "Couldn't set up DTLS-SRTP on RTP channel."; const char kDtlsSrtpSetupFailureRtcp[] = "Couldn't set up DTLS-SRTP on RTCP channel."; -const char kEnableBundleFailed[] = "Failed to enable BUNDLE."; namespace { @@ -907,25 +906,40 @@ bool PeerConnection::Initialize( return false; } + const PeerConnectionFactoryInterface::Options& options = factory_->options(); + // RFC 3264: The numeric value of the session id and version in the // o line MUST be representable with a "64 bit signed integer". // Due to this constraint session id |session_id_| is max limited to // LLONG_MAX. session_id_ = rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX); - transport_controller_.reset(factory_->CreateTransportController( - port_allocator_.get(), configuration.redetermine_role_on_ice_restart, - event_log_.get())); - transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED); - transport_controller_->SignalConnectionState.connect( + JsepTransportController::Config config; + config.redetermine_role_on_ice_restart = + configuration.redetermine_role_on_ice_restart; + config.ssl_max_version = factory_->options().ssl_max_version; + config.disable_encryption = options.disable_encryption; + config.bundle_policy = configuration.bundle_policy; + config.rtcp_mux_policy = configuration.rtcp_mux_policy; + config.crypto_options = options.crypto_options; +#if defined(ENABLE_EXTERNAL_AUTH) + config.enable_external_auth = true; +#endif + transport_controller_.reset(new JsepTransportController( + signaling_thread(), network_thread(), port_allocator_.get(), config)); + transport_controller_->SignalIceConnectionState.connect( this, &PeerConnection::OnTransportControllerConnectionState); - transport_controller_->SignalGatheringState.connect( + transport_controller_->SignalIceGatheringState.connect( this, &PeerConnection::OnTransportControllerGatheringState); - transport_controller_->SignalCandidatesGathered.connect( + transport_controller_->SignalIceCandidatesGathered.connect( this, &PeerConnection::OnTransportControllerCandidatesGathered); - transport_controller_->SignalCandidatesRemoved.connect( + transport_controller_->SignalIceCandidatesRemoved.connect( this, &PeerConnection::OnTransportControllerCandidatesRemoved); transport_controller_->SignalDtlsHandshakeError.connect( this, &PeerConnection::OnTransportControllerDtlsHandshakeError); + transport_controller_->SignalRtpTransportChanged.connect( + this, &PeerConnection::OnRtpTransportChanged); + transport_controller_->SignalDtlsTransportChanged.connect( + this, &PeerConnection::OnDtlsTransportChanged); sctp_factory_ = factory_->CreateSctpTransportInternalFactory(); @@ -934,10 +948,6 @@ bool PeerConnection::Initialize( configuration_ = configuration; - const PeerConnectionFactoryInterface::Options& options = factory_->options(); - - transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version); - // Obtain a certificate from RTCConfiguration if any were provided (optional). rtc::scoped_refptr certificate; if (!configuration.certificates.empty()) { @@ -1975,17 +1985,6 @@ RTCError PeerConnection::ApplyLocalDescription( // streams that might be removed by updating the session description. stats_->UpdateStats(kStatsOutputLevelStandard); - // Update the initial_offerer flag if this session is the initial_offerer. - SdpType type = desc->GetType(); - if (!initial_offerer_.has_value()) { - initial_offerer_.emplace(type == SdpType::kOffer); - if (*initial_offerer_) { - transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING); - } else { - transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED); - } - } - // Take a reference to the old local description since it's used below to // compare against the new local description. When setting the new local // description, grab ownership of the replaced session description in case it @@ -1994,6 +1993,7 @@ RTCError PeerConnection::ApplyLocalDescription( const SessionDescriptionInterface* old_local_description = local_description(); std::unique_ptr replaced_local_description; + SdpType type = desc->GetType(); if (type == SdpType::kAnswer) { replaced_local_description = pending_local_description_ ? std::move(pending_local_description_) @@ -2009,6 +2009,11 @@ RTCError PeerConnection::ApplyLocalDescription( // |local_description()|. RTC_DCHECK(local_description()); + RTCError error = PushdownTransportDescription(cricket::CS_LOCAL, type); + if (!error.ok()) { + return error; + } + if (IsUnifiedPlan()) { RTCError error = UpdateTransceiversAndDataChannels( cricket::CS_LOCAL, *local_description(), old_local_description, @@ -2031,7 +2036,8 @@ RTCError PeerConnection::ApplyLocalDescription( } } } else { - // Transport and Media channels will be created only when offer is set. + // Media channels will be created only when offer is set. These may use new + // transports just created by PushdownTransportDescription. if (type == SdpType::kOffer) { // TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local // description is applied. Restore back to old description. @@ -2040,12 +2046,12 @@ RTCError PeerConnection::ApplyLocalDescription( return error; } } - // Remove unused channels if MediaContentDescription is rejected. RemoveUnusedChannels(local_description()->description()); } - RTCError error = UpdateSessionState(type, cricket::CS_LOCAL); + error = UpdateSessionState(type, cricket::CS_LOCAL, + local_description()->description()); if (!error.ok()) { return error; } @@ -2246,6 +2252,10 @@ RTCError PeerConnection::ApplyRemoteDescription( // |remote_description()|. RTC_DCHECK(remote_description()); + RTCError error = PushdownTransportDescription(cricket::CS_REMOTE, type); + if (!error.ok()) { + return error; + } // Transport and Media channels will be created only when offer is set. if (IsUnifiedPlan()) { RTCError error = UpdateTransceiversAndDataChannels( @@ -2255,22 +2265,24 @@ RTCError PeerConnection::ApplyRemoteDescription( return error; } } else { + // Media channels will be created only when offer is set. These may use new + // transports just created by PushdownTransportDescription. if (type == SdpType::kOffer) { - // TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local + // TODO(mallinath) - Handle CreateChannel failure, as new local // description is applied. Restore back to old description. RTCError error = CreateChannels(*remote_description()->description()); if (!error.ok()) { return error; } } - // Remove unused channels if MediaContentDescription is rejected. RemoveUnusedChannels(remote_description()->description()); } - // NOTE: Candidates allocation will be initiated only when SetLocalDescription - // is called. - RTCError error = UpdateSessionState(type, cricket::CS_REMOTE); + // NOTE: Candidates allocation will be initiated only when + // SetLocalDescription is called. + error = UpdateSessionState(type, cricket::CS_REMOTE, + remote_description()->description()); if (!error.ok()) { return error; } @@ -2574,14 +2586,10 @@ RTCError PeerConnection::UpdateTransceiverChannel( } else { if (!channel) { if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { - channel = CreateVoiceChannel( - content.name, - GetTransportNameForMediaSection(content.name, bundle_group)); + channel = CreateVoiceChannel(content.name); } else { RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, transceiver->media_type()); - channel = CreateVideoChannel( - content.name, - GetTransportNameForMediaSection(content.name, bundle_group)); + channel = CreateVideoChannel(content.name); } if (!channel) { LOG_AND_RETURN_ERROR( @@ -2607,8 +2615,7 @@ RTCError PeerConnection::UpdateDataChannel( DestroyDataChannel(); } else { if (!rtp_data_channel_ && !sctp_transport_) { - if (!CreateDataChannel(content.name, GetTransportNameForMediaSection( - content.name, bundle_group))) { + if (!CreateDataChannel(content.name)) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create data channel."); } @@ -2919,10 +2926,10 @@ bool PeerConnection::RemoveIceCandidates( } // Remove the candidates from the transport controller. - std::string error; - bool res = transport_controller_->RemoveRemoteCandidates(candidates, &error); - if (!res && !error.empty()) { - RTC_LOG(LS_ERROR) << "Error when removing remote candidates: " << error; + RTCError error = transport_controller_->RemoveRemoteCandidates(candidates); + if (!error.ok()) { + RTC_LOG(LS_ERROR) << "Error when removing remote candidates: " + << error.message(); } return true; } @@ -3965,7 +3972,7 @@ rtc::Optional PeerConnection::GetDataMid() const { } return rtp_data_channel_->content_name(); case cricket::DCT_SCTP: - return sctp_content_name_; + return sctp_mid_; default: return rtc::nullopt; } @@ -4657,7 +4664,12 @@ bool PeerConnection::GetSctpSslRole(rtc::SSLRole* role) { return false; } - return transport_controller_->GetSslRole(*sctp_transport_name_, role); + auto dtls_role = transport_controller_->GetDtlsRole(*sctp_mid_); + if (dtls_role) { + *role = *dtls_role; + return true; + } + return false; } bool PeerConnection::GetSslRole(const std::string& content_name, @@ -4669,8 +4681,12 @@ bool PeerConnection::GetSslRole(const std::string& content_name, return false; } - return transport_controller_->GetSslRole(GetTransportName(content_name), - role); + auto dtls_role = transport_controller_->GetDtlsRole(content_name); + if (dtls_role) { + *role = *dtls_role; + return true; + } + return false; } void PeerConnection::SetSessionError(SessionError error, @@ -4682,42 +4698,16 @@ void PeerConnection::SetSessionError(SessionError error, } } -RTCError PeerConnection::UpdateSessionState(SdpType type, - cricket::ContentSource source) { +RTCError PeerConnection::UpdateSessionState( + SdpType type, + cricket::ContentSource source, + const cricket::SessionDescription* description) { RTC_DCHECK_RUN_ON(signaling_thread()); // If there's already a pending error then no state transition should happen. // But all call-sites should be verifying this before calling us! RTC_DCHECK(session_error() == SessionError::kNone); - // If this is an answer then we know whether to BUNDLE or not. If both the - // local and remote side have agreed to BUNDLE, go ahead and enable it. - if (type == SdpType::kAnswer) { - const cricket::ContentGroup* local_bundle = - local_description()->description()->GetGroupByName( - cricket::GROUP_TYPE_BUNDLE); - const cricket::ContentGroup* remote_bundle = - remote_description()->description()->GetGroupByName( - cricket::GROUP_TYPE_BUNDLE); - if (local_bundle && remote_bundle) { - // The answerer decides the transport to bundle on. - const cricket::ContentGroup* answer_bundle = - (source == cricket::CS_LOCAL ? local_bundle : remote_bundle); - if (!EnableBundle(*answer_bundle)) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, - kEnableBundleFailed); - } - } - } - - // Only push down the transport description after potentially enabling BUNDLE; - // we don't want to push down a description on a transport about to be - // destroyed. - RTCError error = PushdownTransportDescription(source, type); - if (!error.ok()) { - return error; - } - // If this is answer-ish we're ready to let media flow. if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) { EnableSending(); @@ -4740,7 +4730,7 @@ RTCError PeerConnection::UpdateSessionState(SdpType type, // Update internal objects according to the session description's media // descriptions. - error = PushdownMediaDescription(type, source); + RTCError error = PushdownMediaDescription(type, source); if (!error.ok()) { return error; } @@ -4834,29 +4824,17 @@ RTCError PeerConnection::PushdownTransportDescription( SdpType type) { RTC_DCHECK_RUN_ON(signaling_thread()); - const SessionDescriptionInterface* sdesc = - (source == cricket::CS_LOCAL ? local_description() - : remote_description()); - RTC_DCHECK(sdesc); - for (const cricket::TransportInfo& tinfo : - sdesc->description()->transport_infos()) { - std::string error; - bool success; - if (source == cricket::CS_LOCAL) { - success = transport_controller_->SetLocalTransportDescription( - tinfo.content_name, tinfo.description, type, &error); - } else { - success = transport_controller_->SetRemoteTransportDescription( - tinfo.content_name, tinfo.description, type, &error); - } - if (!success) { - LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, - "Failed to push down transport description for " + - tinfo.content_name + ": " + error); - } + if (source == cricket::CS_LOCAL) { + const SessionDescriptionInterface* sdesc = local_description(); + RTC_DCHECK(sdesc); + return transport_controller_->SetLocalDescription(type, + sdesc->description()); + } else { + const SessionDescriptionInterface* sdesc = remote_description(); + RTC_DCHECK(sdesc); + return transport_controller_->SetRemoteDescription(type, + sdesc->description()); } - - return RTCError::OK(); } bool PeerConnection::GetTransportDescription( @@ -4875,71 +4853,6 @@ bool PeerConnection::GetTransportDescription( return true; } -bool PeerConnection::EnableBundle(const cricket::ContentGroup& bundle) { - const std::string* first_content_name = bundle.FirstContentName(); - if (!first_content_name) { - RTC_LOG(LS_WARNING) << "Tried to BUNDLE with no contents."; - return false; - } - const std::string& transport_name = *first_content_name; - - auto maybe_set_transport = [this, bundle, - transport_name](cricket::BaseChannel* ch) { - if (!ch || !bundle.HasContentName(ch->content_name())) { - return; - } - - std::string old_transport_name = ch->transport_name(); - if (old_transport_name == transport_name) { - RTC_LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name() - << " on " << transport_name << "."; - return; - } - - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - bool need_rtcp = (ch->rtcp_dtls_transport() != nullptr); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (need_rtcp) { - rtcp_dtls_transport = transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - - ch->SetTransports(rtp_dtls_transport, rtcp_dtls_transport); - RTC_LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on " - << transport_name << "."; - transport_controller_->DestroyDtlsTransport( - old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - // If the channel needs rtcp, it means that the channel used to have a - // rtcp transport which needs to be deleted now. - if (need_rtcp) { - transport_controller_->DestroyDtlsTransport( - old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - }; - - for (auto transceiver : transceivers_) { - maybe_set_transport(transceiver->internal()->channel()); - } - maybe_set_transport(rtp_data_channel_); - - // For SCTP, transport creation/deletion happens here instead of in the - // object itself. - if (sctp_transport_) { - RTC_DCHECK(sctp_transport_name_); - RTC_DCHECK(sctp_content_name_); - if (transport_name != *sctp_transport_name_ && - bundle.HasContentName(*sctp_content_name_)) { - network_thread()->Invoke( - RTC_FROM_HERE, rtc::Bind(&PeerConnection::ChangeSctpTransport_n, this, - transport_name)); - } - } - - return true; -} - cricket::IceConfig PeerConnection::ParseIceConfig( const PeerConnectionInterface::RTCConfiguration& config) const { cricket::ContinualGatheringPolicy gathering_policy; @@ -5081,6 +4994,17 @@ bool PeerConnection::ReadyToSendData() const { sctp_ready_to_send_data_; } +rtc::Optional PeerConnection::sctp_transport_name() const { + if (sctp_mid_ && transport_controller_) { + auto dtls_transport = transport_controller_->GetDtlsTransport(*sctp_mid_); + if (dtls_transport) { + return dtls_transport->transport_name(); + } + return rtc::Optional(); + } + return rtc::Optional(); +} + cricket::CandidateStatsList PeerConnection::GetPooledCandidateStats() const { cricket::CandidateStatsList candidate_states_list; port_allocator_->GetCandidateStatsFromPooledSessions(&candidate_states_list); @@ -5102,7 +5026,9 @@ std::map PeerConnection::GetTransportNamesByMid() rtp_data_channel_->transport_name(); } if (sctp_transport_) { - transport_names_by_mid[*sctp_content_name_] = *sctp_transport_name_; + rtc::Optional transport_name = sctp_transport_name(); + RTC_DCHECK(transport_name); + transport_names_by_mid[*sctp_mid_] = *transport_name; } return transport_names_by_mid; } @@ -5134,8 +5060,11 @@ PeerConnection::GetTransportStatsByNames( bool PeerConnection::GetLocalCertificate( const std::string& transport_name, rtc::scoped_refptr* certificate) { - return transport_controller_->GetLocalCertificate(transport_name, - certificate); + if (!certificate) { + return false; + } + *certificate = transport_controller_->GetLocalCertificate(transport_name); + return *certificate != nullptr; } std::unique_ptr PeerConnection::GetRemoteSSLCertChain( @@ -5339,9 +5268,9 @@ bool PeerConnection::UseCandidate(const IceCandidateInterface* candidate) { std::vector candidates; candidates.push_back(candidate->candidate()); // Invoking BaseSession method to handle remote candidates. - std::string error; - if (transport_controller_->AddRemoteCandidates(content.name, candidates, - &error)) { + RTCError error = + transport_controller_->AddRemoteCandidates(content.name, candidates); + if (error.ok()) { // Candidates successfully submitted for checking. if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew || ice_connection_state_ == @@ -5357,10 +5286,8 @@ bool PeerConnection::UseCandidate(const IceCandidateInterface* candidate) { SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking); } // TODO(bemasc): If state is Completed, go back to Connected. - } else { - if (!error.empty()) { - RTC_LOG(LS_WARNING) << error; - } + } else if (error.message()) { + RTC_LOG(LS_WARNING) << error.message(); } return true; } @@ -5384,25 +5311,6 @@ void PeerConnection::RemoveUnusedChannels(const SessionDescription* desc) { } } -std::string PeerConnection::GetTransportNameForMediaSection( - const std::string& mid, - const cricket::ContentGroup* bundle_group) const { - if (!bundle_group) { - return mid; - } - const std::string* first_content_name = bundle_group->FirstContentName(); - if (!first_content_name) { - RTC_LOG(LS_WARNING) << "Tried to BUNDLE with no contents."; - return mid; - } - if (!bundle_group->HasContentName(mid)) { - RTC_LOG(LS_WARNING) << mid << " is not part of any bundle group"; - return mid; - } - RTC_LOG(LS_INFO) << "Bundling " << mid << " on " << *first_content_name; - return *first_content_name; -} - RTCErrorOr PeerConnection::GetEarlyBundleGroup( const SessionDescription& desc) const { const cricket::ContentGroup* bundle_group = nullptr; @@ -5419,19 +5327,12 @@ RTCErrorOr PeerConnection::GetEarlyBundleGroup( } RTCError PeerConnection::CreateChannels(const SessionDescription& desc) { - auto bundle_group_or_error = GetEarlyBundleGroup(desc); - if (!bundle_group_or_error.ok()) { - return bundle_group_or_error.MoveError(); - } - const cricket::ContentGroup* bundle_group = bundle_group_or_error.MoveValue(); - - // Creating the media channels and transport proxies. + // Creating the media channels. Transports should already have been created + // at this point. const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(&desc); if (voice && !voice->rejected && !GetAudioTransceiver()->internal()->channel()) { - cricket::VoiceChannel* voice_channel = CreateVoiceChannel( - voice->name, - GetTransportNameForMediaSection(voice->name, bundle_group)); + cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name); if (!voice_channel) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create voice channel."); @@ -5442,9 +5343,7 @@ RTCError PeerConnection::CreateChannels(const SessionDescription& desc) { const cricket::ContentInfo* video = cricket::GetFirstVideoContent(&desc); if (video && !video->rejected && !GetVideoTransceiver()->internal()->channel()) { - cricket::VideoChannel* video_channel = CreateVideoChannel( - video->name, - GetTransportNameForMediaSection(video->name, bundle_group)); + cricket::VideoChannel* video_channel = CreateVideoChannel(video->name); if (!video_channel) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create video channel."); @@ -5455,8 +5354,7 @@ RTCError PeerConnection::CreateChannels(const SessionDescription& desc) { const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc); if (data_channel_type_ != cricket::DCT_NONE && data && !data->rejected && !rtp_data_channel_ && !sctp_transport_) { - if (!CreateDataChannel(data->name, GetTransportNameForMediaSection( - data->name, bundle_group))) { + if (!CreateDataChannel(data->name)) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to create data channel."); } @@ -5467,37 +5365,25 @@ RTCError PeerConnection::CreateChannels(const SessionDescription& desc) { // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver. cricket::VoiceChannel* PeerConnection::CreateVoiceChannel( - const std::string& mid, - const std::string& transport_name) { - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (configuration_.rtcp_mux_policy != - PeerConnectionInterface::kRtcpMuxPolicyRequire) { - rtcp_dtls_transport = transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - + const std::string& mid) { + RtpTransportInternal* rtp_transport = + transport_controller_->GetRtpTransport(mid); + RTC_DCHECK(rtp_transport); cricket::VoiceChannel* voice_channel = channel_manager()->CreateVoiceChannel( - call_.get(), configuration_.media_config, rtp_dtls_transport, - rtcp_dtls_transport, signaling_thread(), mid, SrtpRequired(), - audio_options_); + call_.get(), configuration_.media_config, rtp_transport, + signaling_thread(), mid, SrtpRequired(), + factory_->options().crypto_options, audio_options_); if (!voice_channel) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - if (rtcp_dtls_transport) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } return nullptr; } - voice_channel->SignalRtcpMuxFullyActive.connect( - this, &PeerConnection::DestroyRtcpTransport_n); voice_channel->SignalDtlsSrtpSetupFailure.connect( this, &PeerConnection::OnDtlsSrtpSetupFailure); voice_channel->SignalSentPacket.connect(this, &PeerConnection::OnSentPacket_w); + voice_channel->SetRtpTransport(rtp_transport); + if (factory_->options().disable_encryption) { + voice_channel->DisableEncryption(true); + } if (uma_observer_) { voice_channel->SetMetricsObserver(uma_observer_); } @@ -5507,38 +5393,25 @@ cricket::VoiceChannel* PeerConnection::CreateVoiceChannel( // TODO(steveanton): Perhaps this should be managed by the RtpTransceiver. cricket::VideoChannel* PeerConnection::CreateVideoChannel( - const std::string& mid, - const std::string& transport_name) { - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (configuration_.rtcp_mux_policy != - PeerConnectionInterface::kRtcpMuxPolicyRequire) { - rtcp_dtls_transport = transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - + const std::string& mid) { + RtpTransportInternal* rtp_transport = + transport_controller_->GetRtpTransport(mid); + RTC_DCHECK(rtp_transport); cricket::VideoChannel* video_channel = channel_manager()->CreateVideoChannel( - call_.get(), configuration_.media_config, rtp_dtls_transport, - rtcp_dtls_transport, signaling_thread(), mid, SrtpRequired(), - video_options_); - + call_.get(), configuration_.media_config, rtp_transport, + signaling_thread(), mid, SrtpRequired(), + factory_->options().crypto_options, video_options_); if (!video_channel) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - if (rtcp_dtls_transport) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } return nullptr; } - video_channel->SignalRtcpMuxFullyActive.connect( - this, &PeerConnection::DestroyRtcpTransport_n); video_channel->SignalDtlsSrtpSetupFailure.connect( this, &PeerConnection::OnDtlsSrtpSetupFailure); video_channel->SignalSentPacket.connect(this, &PeerConnection::OnSentPacket_w); + video_channel->SetRtpTransport(rtp_transport); + if (factory_->options().disable_encryption) { + video_channel->DisableEncryption(true); + } if (uma_observer_) { video_channel->SetMetricsObserver(uma_observer_); } @@ -5546,8 +5419,7 @@ cricket::VideoChannel* PeerConnection::CreateVideoChannel( return video_channel; } -bool PeerConnection::CreateDataChannel(const std::string& mid, - const std::string& transport_name) { +bool PeerConnection::CreateDataChannel(const std::string& mid) { bool sctp = (data_channel_type_ == cricket::DCT_SCTP); if (sctp) { if (!sctp_factory_) { @@ -5557,44 +5429,31 @@ bool PeerConnection::CreateDataChannel(const std::string& mid, return false; } if (!network_thread()->Invoke( - RTC_FROM_HERE, rtc::Bind(&PeerConnection::CreateSctpTransport_n, - this, mid, transport_name))) { + RTC_FROM_HERE, + rtc::Bind(&PeerConnection::CreateSctpTransport_n, this, mid))) { return false; } for (const auto& channel : sctp_data_channels_) { channel->OnTransportChannelCreated(); } } else { - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (configuration_.rtcp_mux_policy != - PeerConnectionInterface::kRtcpMuxPolicyRequire) { - rtcp_dtls_transport = transport_controller_->CreateDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - + RtpTransportInternal* rtp_transport = + transport_controller_->GetRtpTransport(mid); + RTC_DCHECK(rtp_transport); rtp_data_channel_ = channel_manager()->CreateRtpDataChannel( - configuration_.media_config, rtp_dtls_transport, rtcp_dtls_transport, - signaling_thread(), mid, SrtpRequired()); - + configuration_.media_config, rtp_transport, signaling_thread(), mid, + SrtpRequired(), factory_->options().crypto_options); if (!rtp_data_channel_) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - if (rtcp_dtls_transport) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } return false; } - - rtp_data_channel_->SignalRtcpMuxFullyActive.connect( - this, &PeerConnection::DestroyRtcpTransport_n); rtp_data_channel_->SignalDtlsSrtpSetupFailure.connect( this, &PeerConnection::OnDtlsSrtpSetupFailure); rtp_data_channel_->SignalSentPacket.connect( this, &PeerConnection::OnSentPacket_w); + rtp_data_channel_->SetRtpTransport(rtp_transport); + if (factory_->options().disable_encryption) { + rtp_data_channel_->DisableEncryption(true); + } if (uma_observer_) { rtp_data_channel_->SetMetricsObserver(uma_observer_); } @@ -5615,13 +5474,12 @@ Call::Stats PeerConnection::GetCallStats() { } } -bool PeerConnection::CreateSctpTransport_n(const std::string& content_name, - const std::string& transport_name) { +bool PeerConnection::CreateSctpTransport_n(const std::string& mid) { RTC_DCHECK(network_thread()->IsCurrent()); RTC_DCHECK(sctp_factory_); cricket::DtlsTransportInternal* tc = - transport_controller_->CreateDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); + transport_controller_->GetDtlsTransport(mid); + RTC_DCHECK(tc); sctp_transport_ = sctp_factory_->CreateSctpTransport(tc); RTC_DCHECK(sctp_transport_); sctp_invoker_.reset(new rtc::AsyncInvoker()); @@ -5631,32 +5489,15 @@ bool PeerConnection::CreateSctpTransport_n(const std::string& content_name, this, &PeerConnection::OnSctpTransportDataReceived_n); sctp_transport_->SignalStreamClosedRemotely.connect( this, &PeerConnection::OnSctpStreamClosedRemotely_n); - sctp_transport_name_ = transport_name; - sctp_content_name_ = content_name; - return true; -} - -void PeerConnection::ChangeSctpTransport_n(const std::string& transport_name) { - RTC_DCHECK(network_thread()->IsCurrent()); - RTC_DCHECK(sctp_transport_); - RTC_DCHECK(sctp_transport_name_); - std::string old_sctp_transport_name = *sctp_transport_name_; - sctp_transport_name_ = transport_name; - cricket::DtlsTransportInternal* tc = - transport_controller_->CreateDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); + sctp_mid_ = mid; sctp_transport_->SetTransportChannel(tc); - transport_controller_->DestroyDtlsTransport_n( - old_sctp_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); + return true; } void PeerConnection::DestroySctpTransport_n() { RTC_DCHECK(network_thread()->IsCurrent()); sctp_transport_.reset(nullptr); - transport_controller_->DestroyDtlsTransport_n( - *sctp_transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTP); - sctp_content_name_.reset(); - sctp_transport_name_.reset(); + sctp_mid_.reset(); sctp_invoker_.reset(nullptr); sctp_ready_to_send_data_ = false; } @@ -5989,7 +5830,7 @@ bool PeerConnection::ReadyToUseRemoteCandidate( if (transport_name.empty()) { return false; } - return transport_controller_->ReadyForRemoteCandidates(transport_name); + return true; } bool PeerConnection::SrtpRequired() const { @@ -6022,10 +5863,13 @@ void PeerConnection::ReportTransportStats() { media_types_by_transport_name[rtp_data_channel()->transport_name()].insert( cricket::MEDIA_TYPE_DATA); } - if (sctp_transport_name_) { - media_types_by_transport_name[*sctp_transport_name_].insert( + + rtc::Optional transport_name = sctp_transport_name(); + if (transport_name) { + media_types_by_transport_name[*transport_name].insert( cricket::MEDIA_TYPE_DATA); } + for (const auto& entry : media_types_by_transport_name) { const std::string& transport_name = entry.first; const std::set media_types = entry.second; @@ -6145,22 +5989,15 @@ const std::string PeerConnection::GetTransportName( return channel->transport_name(); } if (sctp_transport_) { - RTC_DCHECK(sctp_content_name_); - RTC_DCHECK(sctp_transport_name_); - if (content_name == *sctp_content_name_) { - return *sctp_transport_name_; + RTC_DCHECK(sctp_mid_); + if (content_name == *sctp_mid_) { + return *sctp_transport_name(); } } // Return an empty string if failed to retrieve the transport name. return ""; } -void PeerConnection::DestroyRtcpTransport_n(const std::string& transport_name) { - RTC_DCHECK(network_thread()->IsCurrent()); - transport_controller_->DestroyDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); -} - void PeerConnection::DestroyTransceiverChannel( rtc::scoped_refptr> transceiver) { @@ -6195,13 +6032,6 @@ void PeerConnection::DestroyDataChannel() { void PeerConnection::DestroyBaseChannel(cricket::BaseChannel* channel) { RTC_DCHECK(channel); - RTC_DCHECK(channel->rtp_dtls_transport()); - - // Need to cache these before destroying the base channel so that we do not - // access uninitialized memory. - const std::string transport_name = - channel->rtp_dtls_transport()->transport_name(); - const bool need_to_delete_rtcp = (channel->rtcp_dtls_transport() != nullptr); switch (channel->media_type()) { case cricket::MEDIA_TYPE_AUDIO: @@ -6220,14 +6050,23 @@ void PeerConnection::DestroyBaseChannel(cricket::BaseChannel* channel) { RTC_NOTREACHED() << "Unknown media type: " << channel->media_type(); break; } +} - // |channel| can no longer be used. +void PeerConnection::OnRtpTransportChanged( + const std::string& mid, + RtpTransportInternal* rtp_transport) { + auto base_channel = GetChannel(mid); + if (base_channel) { + base_channel->SetRtpTransport(rtp_transport); + } +} - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - if (need_to_delete_rtcp) { - transport_controller_->DestroyDtlsTransport( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); +void PeerConnection::OnDtlsTransportChanged( + const std::string& mid, + cricket::DtlsTransportInternal* dtls_transport) { + if (sctp_transport_) { + RTC_DCHECK(mid == sctp_mid_); + sctp_transport_->SetTransportChannel(dtls_transport); } } diff --git a/pc/peerconnection.h b/pc/peerconnection.h index d1ba212e9c..fa46a4e151 100644 --- a/pc/peerconnection.h +++ b/pc/peerconnection.h @@ -20,6 +20,7 @@ #include "api/peerconnectioninterface.h" #include "api/turncustomizer.h" #include "pc/iceserverparsing.h" +#include "pc/jseptransportcontroller.h" #include "pc/peerconnectionfactory.h" #include "pc/peerconnectioninternal.h" #include "pc/rtcstatscollector.h" @@ -208,7 +209,7 @@ class PeerConnection : public PeerConnectionInternal, std::string session_id() const override { return session_id_; } bool initial_offerer() const override { - return initial_offerer_ && *initial_offerer_; + return transport_controller_ && transport_controller_->initial_offerer(); } std::vector< @@ -234,12 +235,10 @@ class PeerConnection : public PeerConnectionInternal, } rtc::Optional sctp_content_name() const override { - return sctp_content_name_; + return sctp_mid_; } - rtc::Optional sctp_transport_name() const override { - return sctp_transport_name_; - } + rtc::Optional sctp_transport_name() const override; cricket::CandidateStatsList GetPooledCandidateStats() const override; std::map GetTransportNamesByMid() const override; @@ -709,7 +708,7 @@ class PeerConnection : public PeerConnectionInternal, const rtc::scoped_refptr& certificate); void OnDtlsSrtpSetupFailure(cricket::BaseChannel*, bool rtcp); - cricket::TransportController* transport_controller() const { + JsepTransportController* transport_controller() const { return transport_controller_.get(); } @@ -727,7 +726,9 @@ class PeerConnection : public PeerConnectionInternal, // Updates the error state, signaling if necessary. void SetSessionError(SessionError error, const std::string& error_desc); - RTCError UpdateSessionState(SdpType type, cricket::ContentSource source); + RTCError UpdateSessionState(SdpType type, + cricket::ContentSource source, + const cricket::SessionDescription* description); // Push the media parts of the local or remote session description // down to all of the channels. RTCError PushdownMediaDescription(SdpType type, @@ -744,18 +745,6 @@ class PeerConnection : public PeerConnectionInternal, const std::string& content_name, cricket::TransportDescription* info); - // Returns the transport name for the given media section identified by |mid|. - // If BUNDLE is enabled and the media section is part of the bundle group, - // the transport name will be the first mid in the bundle group. Otherwise, - // the transport name will be the mid of the media section. - std::string GetTransportNameForMediaSection( - const std::string& mid, - const cricket::ContentGroup* bundle_group) const; - - // Cause all the BaseChannels in the bundle group to have the same - // transport channel. - bool EnableBundle(const cricket::ContentGroup& bundle); - // Enables media channels to allow sending of media. // This enables media to flow on all configured audio/video channels and the // RtpDataChannel. @@ -792,17 +781,12 @@ class PeerConnection : public PeerConnectionInternal, const cricket::SessionDescription& desc) const; // Helper methods to create media channels. - cricket::VoiceChannel* CreateVoiceChannel(const std::string& mid, - const std::string& transport_name); - cricket::VideoChannel* CreateVideoChannel(const std::string& mid, - const std::string& transport_name); - bool CreateDataChannel(const std::string& mid, - const std::string& transport_name); + cricket::VoiceChannel* CreateVoiceChannel(const std::string& mid); + cricket::VideoChannel* CreateVideoChannel(const std::string& mid); + bool CreateDataChannel(const std::string& mid); - bool CreateSctpTransport_n(const std::string& content_name, - const std::string& transport_name); + bool CreateSctpTransport_n(const std::string& mid); // For bundling. - void ChangeSctpTransport_n(const std::string& transport_name); void DestroySctpTransport_n(); // SctpTransport signal handlers. Needed to marshal signals from the network // to signaling thread. @@ -846,7 +830,7 @@ class PeerConnection : public PeerConnectionInternal, // this session. bool SrtpRequired() const; - // TransportController signal handlers. + // JsepTransportController signal handlers. void OnTransportControllerConnectionState(cricket::IceConnectionState state); void OnTransportControllerGatheringState(cricket::IceGatheringState state); void OnTransportControllerCandidatesGathered( @@ -880,8 +864,6 @@ class PeerConnection : public PeerConnectionInternal, const std::string GetTransportName(const std::string& content_name); - void DestroyRtcpTransport_n(const std::string& transport_name); - // Destroys and clears the BaseChannel associated with the given transceiver, // if such channel is set. void DestroyTransceiverChannel( @@ -895,6 +877,12 @@ class PeerConnection : public PeerConnectionInternal, // method is called. void DestroyBaseChannel(cricket::BaseChannel* channel); + void OnRtpTransportChanged(const std::string& mid, + RtpTransportInternal* rtp_transport); + + void OnDtlsTransportChanged(const std::string& mid, + cricket::DtlsTransportInternal* dtls_transport); + sigslot::signal1 SignalDataChannelCreated_; // Storing the factory as a scoped reference pointer ensures that the memory @@ -957,20 +945,16 @@ class PeerConnection : public PeerConnectionInternal, std::string session_error_desc_; std::string session_id_; - rtc::Optional initial_offerer_; - std::unique_ptr transport_controller_; + std::unique_ptr transport_controller_; std::unique_ptr sctp_factory_; // |rtp_data_channel_| is used if in RTP data channel mode, |sctp_transport_| // when using SCTP. cricket::RtpDataChannel* rtp_data_channel_ = nullptr; std::unique_ptr sctp_transport_; - // |sctp_transport_name_| keeps track of what DTLS transport the SCTP - // transport is using (which can change due to bundling). - rtc::Optional sctp_transport_name_; - // |sctp_content_name_| is the content name (MID) in SDP. - rtc::Optional sctp_content_name_; + // |sctp_mid_| is the content name (MID) in SDP. + rtc::Optional sctp_mid_; // Value cached on signaling thread. Only updated when SctpReadyToSendData // fires on the signaling thread. bool sctp_ready_to_send_data_ = false; diff --git a/pc/peerconnection_bundle_unittest.cc b/pc/peerconnection_bundle_unittest.cc index 16bd000dbe..98191153e9 100644 --- a/pc/peerconnection_bundle_unittest.cc +++ b/pc/peerconnection_bundle_unittest.cc @@ -67,12 +67,14 @@ class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper { return false; } - rtc::PacketTransportInternal* voice_rtp_transport_channel() { - return (voice_channel() ? voice_channel()->rtp_dtls_transport() : nullptr); + rtc::PacketTransportInternal* voice_rtp_transport() { + return (voice_channel() ? voice_channel()->rtp_packet_transport() + : nullptr); } - rtc::PacketTransportInternal* voice_rtcp_transport_channel() { - return (voice_channel() ? voice_channel()->rtcp_dtls_transport() : nullptr); + rtc::PacketTransportInternal* voice_rtcp_transport() { + return (voice_channel() ? voice_channel()->rtcp_packet_transport() + : nullptr); } cricket::VoiceChannel* voice_channel() { @@ -86,12 +88,14 @@ class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper { return nullptr; } - rtc::PacketTransportInternal* video_rtp_transport_channel() { - return (video_channel() ? video_channel()->rtp_dtls_transport() : nullptr); + rtc::PacketTransportInternal* video_rtp_transport() { + return (video_channel() ? video_channel()->rtp_packet_transport() + : nullptr); } - rtc::PacketTransportInternal* video_rtcp_transport_channel() { - return (video_channel() ? video_channel()->rtcp_dtls_transport() : nullptr); + rtc::PacketTransportInternal* video_rtcp_transport() { + return (video_channel() ? video_channel()->rtcp_packet_transport() + : nullptr); } cricket::VideoChannel* video_channel() { @@ -348,6 +352,24 @@ TEST_P(PeerConnectionBundleTest, EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size()); } +// It will fail if the offerer uses the mux-BUNDLE policy but the answerer +// doesn't support BUNDLE. +TEST_P(PeerConnectionBundleTest, MaxBundleNotSupportedInAnswer) { + RTCConfiguration config; + config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle; + auto caller = CreatePeerConnectionWithAudioVideo(config); + auto callee = CreatePeerConnectionWithAudioVideo(); + + ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); + bool equal_before = + (caller->voice_rtp_transport() == caller->video_rtp_transport()); + EXPECT_EQ(true, equal_before); + RTCOfferAnswerOptions options; + options.use_rtp_mux = false; + EXPECT_FALSE( + caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options))); +} + // The following parameterized test verifies that an offer/answer with varying // bundle policies and either bundle in the answer or not will produce the // expected RTP transports for audio and video. In particular, for bundling we @@ -393,16 +415,16 @@ TEST_P(PeerConnectionBundleMatrixTest, auto callee = CreatePeerConnectionWithAudioVideo(); ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); - bool equal_before = (caller->voice_rtp_transport_channel() == - caller->video_rtp_transport_channel()); + bool equal_before = + (caller->voice_rtp_transport() == caller->video_rtp_transport()); EXPECT_EQ(expected_same_before_, equal_before); RTCOfferAnswerOptions options; options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer); ASSERT_TRUE( caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options))); - bool equal_after = (caller->voice_rtp_transport_channel() == - caller->video_rtp_transport_channel()); + bool equal_after = + (caller->voice_rtp_transport() == caller->video_rtp_transport()); EXPECT_EQ(expected_same_after_, equal_after); } @@ -426,10 +448,6 @@ INSTANTIATE_TEST_CASE_P( BundleIncluded::kBundleInAnswer, true, true), - std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle, - BundleIncluded::kBundleNotInAnswer, - true, - true), std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat, BundleIncluded::kBundleInAnswer, false, @@ -454,13 +472,11 @@ TEST_P(PeerConnectionBundleTest, ASSERT_TRUE(callee->SetRemoteDescription( caller->CreateOfferAndSetAsLocal(options_with_bundle))); - EXPECT_EQ(callee->voice_rtp_transport_channel(), - callee->video_rtp_transport_channel()); + EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport()); ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer())); - EXPECT_EQ(callee->voice_rtp_transport_channel(), - callee->video_rtp_transport_channel()); + EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport()); } TEST_P(PeerConnectionBundleTest, @@ -496,8 +512,8 @@ TEST_P(PeerConnectionBundleTest, ASSERT_TRUE( caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options))); - EXPECT_FALSE(caller->voice_rtp_transport_channel()); - EXPECT_TRUE(caller->video_rtp_transport_channel()); + EXPECT_FALSE(caller->voice_rtp_transport()); + EXPECT_TRUE(caller->video_rtp_transport()); } // When requiring RTCP multiplexing, the PeerConnection never makes RTCP @@ -510,19 +526,18 @@ TEST_P(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) { ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); - EXPECT_FALSE(caller->voice_rtcp_transport_channel()); - EXPECT_FALSE(caller->video_rtcp_transport_channel()); + EXPECT_FALSE(caller->voice_rtcp_transport()); + EXPECT_FALSE(caller->video_rtcp_transport()); ASSERT_TRUE( caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal())); - EXPECT_FALSE(caller->voice_rtcp_transport_channel()); - EXPECT_FALSE(caller->video_rtcp_transport_channel()); + EXPECT_FALSE(caller->voice_rtcp_transport()); + EXPECT_FALSE(caller->video_rtcp_transport()); } -// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transport -// channels when the offer is sent, but will destroy them once the remote answer -// is set. +// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transports +// when the offer is sent, but will destroy them once the remote answer is set. TEST_P(PeerConnectionBundleTest, CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) { RTCConfiguration config; @@ -532,14 +547,14 @@ TEST_P(PeerConnectionBundleTest, ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); - EXPECT_TRUE(caller->voice_rtcp_transport_channel()); - EXPECT_TRUE(caller->video_rtcp_transport_channel()); + EXPECT_TRUE(caller->voice_rtcp_transport()); + EXPECT_TRUE(caller->video_rtcp_transport()); ASSERT_TRUE( caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal())); - EXPECT_FALSE(caller->voice_rtcp_transport_channel()); - EXPECT_FALSE(caller->video_rtcp_transport_channel()); + EXPECT_FALSE(caller->voice_rtcp_transport()); + EXPECT_FALSE(caller->video_rtcp_transport()); } TEST_P(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) { @@ -588,7 +603,7 @@ TEST_P(PeerConnectionBundleTest, ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); ASSERT_TRUE( - caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal())); + caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options))); // The way the *_WAIT checks work is they only wait if the condition fails, // which does not help in the case where state is not changing. This is @@ -624,7 +639,7 @@ TEST_P(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) { ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal())); - auto* old_video_transport = caller->video_rtp_transport_channel(); + auto* old_video_transport = caller->video_rtp_transport(); auto answer = callee->CreateAnswer(); auto* old_bundle_group = @@ -640,9 +655,8 @@ TEST_P(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) { ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer))); - EXPECT_EQ(old_video_transport, caller->video_rtp_transport_channel()); - EXPECT_EQ(caller->voice_rtp_transport_channel(), - caller->video_rtp_transport_channel()); + EXPECT_EQ(old_video_transport, caller->video_rtp_transport()); + EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport()); } INSTANTIATE_TEST_CASE_P(PeerConnectionBundleTest, diff --git a/pc/peerconnection_ice_unittest.cc b/pc/peerconnection_ice_unittest.cc index 9586236743..edf2bf8364 100644 --- a/pc/peerconnection_ice_unittest.cc +++ b/pc/peerconnection_ice_unittest.cc @@ -200,7 +200,9 @@ class PeerConnectionIceBaseTest : public ::testing::Test { if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) { cricket::BaseChannel* channel = transceiver->internal()->channel(); if (channel) { - return channel->rtp_dtls_transport()->ice_transport()->GetIceRole(); + auto dtls_transport = static_cast( + channel->rtp_packet_transport()); + return dtls_transport->ice_transport()->GetIceRole(); } } } diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc index 33bf267e18..6dbf32080d 100644 --- a/pc/peerconnection_integrationtest.cc +++ b/pc/peerconnection_integrationtest.cc @@ -2342,8 +2342,10 @@ TEST_P(PeerConnectionIntegrationTest, GetCaptureStartNtpTimeWithOldStatsApi) { // Get the audio output level stats. Note that the level is not available // until an RTCP packet has been received. - EXPECT_TRUE_WAIT(callee()->OldGetStatsForTrack(remote_audio_track)-> - CaptureStartNtpTime() > 0, 2 * kMaxWaitForFramesMs); + EXPECT_TRUE_WAIT( + callee()->OldGetStatsForTrack(remote_audio_track)->CaptureStartNtpTime() > + 0, + 2 * kMaxWaitForFramesMs); } // Test that we can get stats (using the new stats implemnetation) for diff --git a/pc/peerconnectionfactory.cc b/pc/peerconnectionfactory.cc index 70e8d19248..a7075efdd6 100644 --- a/pc/peerconnectionfactory.cc +++ b/pc/peerconnectionfactory.cc @@ -325,16 +325,6 @@ PeerConnectionFactory::CreateAudioTrack(const std::string& id, return AudioTrackProxy::Create(signaling_thread_, track); } -cricket::TransportController* PeerConnectionFactory::CreateTransportController( - cricket::PortAllocator* port_allocator, - bool redetermine_role_on_ice_restart, - RtcEventLog* event_log) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - return new cricket::TransportController( - signaling_thread_, network_thread_, port_allocator, - redetermine_role_on_ice_restart, options_.crypto_options, event_log); -} - std::unique_ptr PeerConnectionFactory::CreateSctpTransportInternalFactory() { #ifdef HAVE_SCTP diff --git a/pc/peerconnectionfactory.h b/pc/peerconnectionfactory.h index f0045f70d5..f58542f42e 100644 --- a/pc/peerconnectionfactory.h +++ b/pc/peerconnectionfactory.h @@ -88,11 +88,6 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface { bool StartAecDump(rtc::PlatformFile file, int64_t max_size_bytes) override; void StopAecDump() override; - virtual cricket::TransportController* CreateTransportController( - cricket::PortAllocator* port_allocator, - bool redetermine_role_on_ice_restart, - RtcEventLog* event_log = nullptr); - virtual std::unique_ptr CreateSctpTransportInternalFactory(); diff --git a/pc/peerconnectioninterface_unittest.cc b/pc/peerconnectioninterface_unittest.cc index 62fd3bfbb5..ad85d68c00 100644 --- a/pc/peerconnectioninterface_unittest.cc +++ b/pc/peerconnectioninterface_unittest.cc @@ -667,18 +667,7 @@ class PeerConnectionFactoryForTest : public webrtc::PeerConnectionFactory { std::move(call_factory), std::move(event_log_factory)) {} - cricket::TransportController* CreateTransportController( - cricket::PortAllocator* port_allocator, - bool redetermine_role_on_ice_restart, - webrtc::RtcEventLog* event_log = nullptr) override { - transport_controller = new cricket::TransportController( - rtc::Thread::Current(), rtc::Thread::Current(), port_allocator, - redetermine_role_on_ice_restart, rtc::CryptoOptions(), event_log); - return transport_controller; - } - rtc::scoped_refptr fake_audio_capture_module_; - cricket::TransportController* transport_controller; }; // TODO(steveanton): Convert to use the new PeerConnectionWrapper. @@ -2318,8 +2307,7 @@ TEST_P(PeerConnectionInterfaceTest, ReceiveFireFoxOffer) { content = cricket::GetFirstDataContent(pc_->local_description()->description()); ASSERT_TRUE(content != NULL); - // Expected to fail since it's using an incompatible format. - EXPECT_TRUE(content->rejected); + EXPECT_FALSE(content->rejected); #endif } @@ -2341,7 +2329,7 @@ TEST_P(PeerConnectionInterfaceTest, DtlsSdesFallbackNotSupported) { std::unique_ptr desc( webrtc::CreateSessionDescription(SdpType::kOffer, kDtlsSdesFallbackSdp, nullptr)); - EXPECT_FALSE(DoSetSessionDescription(std::move(desc), false)); + EXPECT_FALSE(DoSetSessionDescription(std::move(desc), /*local=*/false)); } // Test that we can create an audio only offer and receive an answer with a diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc index 279aba27af..69089a5dbb 100644 --- a/pc/rtpsenderreceiver_unittest.cc +++ b/pc/rtpsenderreceiver_unittest.cc @@ -16,6 +16,7 @@ #include "media/base/fakemediaengine.h" #include "media/base/rtpdataengine.h" #include "media/engine/fakewebrtccall.h" +#include "p2p/base/fakedtlstransport.h" #include "pc/audiotrack.h" #include "pc/channelmanager.h" #include "pc/localaudiosource.h" @@ -24,7 +25,6 @@ #include "pc/rtpreceiver.h" #include "pc/rtpsender.h" #include "pc/streamcollection.h" -#include "pc/test/faketransportcontroller.h" #include "pc/test/fakevideotracksource.h" #include "pc/videotrack.h" #include "pc/videotracksource.h" @@ -69,17 +69,18 @@ class RtpSenderReceiverTest : public testing::Test, // Create channels to be used by the RtpSenders and RtpReceivers. channel_manager_.Init(); bool srtp_required = true; - cricket::DtlsTransportInternal* rtp_transport = - fake_transport_controller_.CreateDtlsTransport( - cricket::CN_AUDIO, cricket::ICE_CANDIDATE_COMPONENT_RTP); + rtp_dtls_transport_ = rtc::MakeUnique( + "fake_dtls_transport", cricket::ICE_CANDIDATE_COMPONENT_RTP); + rtp_transport_ = CreateDtlsSrtpTransport(); + voice_channel_ = channel_manager_.CreateVoiceChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr, rtc::Thread::Current(), - cricket::CN_AUDIO, srtp_required, cricket::AudioOptions()); + &fake_call_, cricket::MediaConfig(), rtp_transport_.get(), + rtc::Thread::Current(), cricket::CN_AUDIO, srtp_required, + rtc::CryptoOptions(), cricket::AudioOptions()); video_channel_ = channel_manager_.CreateVideoChannel( - &fake_call_, cricket::MediaConfig(), - rtp_transport, nullptr, rtc::Thread::Current(), - cricket::CN_VIDEO, srtp_required, cricket::VideoOptions()); + &fake_call_, cricket::MediaConfig(), rtp_transport_.get(), + rtc::Thread::Current(), cricket::CN_VIDEO, srtp_required, + rtc::CryptoOptions(), cricket::VideoOptions()); voice_channel_->Enable(true); video_channel_->Enable(true); voice_media_channel_ = media_engine_->GetVoiceChannel(0); @@ -111,6 +112,18 @@ class RtpSenderReceiverTest : public testing::Test, cricket::StreamParams::CreateLegacy(kVideoSsrc2)); } + std::unique_ptr CreateDtlsSrtpTransport() { + auto rtp_transport = + rtc::MakeUnique(/*rtcp_mux_required=*/true); + auto srtp_transport = + rtc::MakeUnique(std::move(rtp_transport)); + auto dtls_srtp_transport = + rtc::MakeUnique(std::move(srtp_transport)); + dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(), + /*rtcp_dtls_transport=*/nullptr); + return dtls_srtp_transport; + } + // Needed to use DTMF sender. void AddDtmfCodec() { cricket::AudioSendParameters params; @@ -268,9 +281,12 @@ class RtpSenderReceiverTest : public testing::Test, rtc::Thread* const network_thread_; rtc::Thread* const worker_thread_; webrtc::RtcEventLogNullImpl event_log_; + // The |rtp_dtls_transport_| and |rtp_transport_| should be destroyed after + // the |channel_manager|. + std::unique_ptr rtp_dtls_transport_; + std::unique_ptr rtp_transport_; // |media_engine_| is actually owned by |channel_manager_|. cricket::FakeMediaEngine* media_engine_; - cricket::FakeTransportController fake_transport_controller_; cricket::ChannelManager channel_manager_; cricket::FakeCall fake_call_; cricket::VoiceChannel* voice_channel_; diff --git a/pc/rtptransport.cc b/pc/rtptransport.cc index 26f7e3e4c9..cab04e5f50 100644 --- a/pc/rtptransport.cc +++ b/pc/rtptransport.cc @@ -134,26 +134,6 @@ bool RtpTransport::SendPacket(bool rtcp, return true; } -bool RtpTransport::HandlesPacket(const uint8_t* data, size_t len) { - return bundle_filter_.DemuxPacket(data, len); -} - -bool RtpTransport::HandlesPayloadType(int payload_type) const { - return bundle_filter_.FindPayloadType(payload_type); -} - -void RtpTransport::AddHandledPayloadType(int payload_type) { - bundle_filter_.AddPayloadType(payload_type); -} - -PacketTransportInterface* RtpTransport::GetRtpPacketTransport() const { - return rtp_packet_transport_; -} - -PacketTransportInterface* RtpTransport::GetRtcpPacketTransport() const { - return rtcp_packet_transport_; -} - RTCError RtpTransport::SetParameters(const RtpTransportParameters& parameters) { if (parameters_.rtcp.mux && !parameters.rtcp.mux) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE, @@ -272,12 +252,7 @@ bool RtpTransport::WantsPacket(bool rtcp, << " packet: wrong size=" << packet->size(); return false; } - if (rtcp) { - // Permit all (seemingly valid) RTCP packets. - return true; - } - // Check whether we handle this payload. - return HandlesPacket(packet->data(), packet->size()); + return true; } } // namespace webrtc diff --git a/pc/rtptransport.h b/pc/rtptransport.h index 637d447454..f878980e00 100644 --- a/pc/rtptransport.h +++ b/pc/rtptransport.h @@ -13,7 +13,7 @@ #include -#include "pc/bundlefilter.h" +#include "api/ortc/rtptransportinterface.h" #include "pc/rtptransportinternal.h" #include "rtc_base/sigslot.h" @@ -49,13 +49,19 @@ class RtpTransport : public RtpTransportInternal { } void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) override; - PacketTransportInterface* GetRtpPacketTransport() const override; - PacketTransportInterface* GetRtcpPacketTransport() const override; + PacketTransportInterface* GetRtpPacketTransport() const override { + return rtp_packet_transport_; + } + PacketTransportInterface* GetRtcpPacketTransport() const override { + return rtcp_packet_transport_; + } // TODO(zstein): Use these RtcpParameters for configuration elsewhere. RTCError SetParameters(const RtpTransportParameters& parameters) override; RtpTransportParameters GetParameters() const override; + bool IsReadyToSend() const override { return ready_to_send_; } + bool IsWritable(bool rtcp) const override; bool SendRtpPacket(rtc::CopyOnWriteBuffer* packet, @@ -66,9 +72,7 @@ class RtpTransport : public RtpTransportInternal { const rtc::PacketOptions& options, int flags) override; - bool HandlesPayloadType(int payload_type) const override; - - void AddHandledPayloadType(int payload_type) override; + bool IsSrtpActive() const override { return false; } void SetMetricsObserver( rtc::scoped_refptr metrics_observer) override {} @@ -106,6 +110,15 @@ class RtpTransport : public RtpTransportInternal { bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet); + RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override { + RTC_NOTREACHED(); + return RTCError::OK(); + } + RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override { + RTC_NOTREACHED(); + return RTCError::OK(); + } + bool rtcp_mux_enabled_; rtc::PacketTransportInternal* rtp_packet_transport_ = nullptr; @@ -116,8 +129,6 @@ class RtpTransport : public RtpTransportInternal { bool rtcp_ready_to_send_ = false; RtpTransportParameters parameters_; - - cricket::BundleFilter bundle_filter_; }; } // namespace webrtc diff --git a/pc/rtptransport_unittest.cc b/pc/rtptransport_unittest.cc index 3876aa3998..0425942925 100644 --- a/pc/rtptransport_unittest.cc +++ b/pc/rtptransport_unittest.cc @@ -60,9 +60,19 @@ TEST(RtpTransportTest, SetRtpTransportKeepAliveNotSupported) { class SignalObserver : public sigslot::has_slots<> { public: explicit SignalObserver(RtpTransport* transport) { + transport_ = transport; transport->SignalReadyToSend.connect(this, &SignalObserver::OnReadyToSend); transport->SignalNetworkRouteChanged.connect( this, &SignalObserver::OnNetworkRouteChanged); + if (transport->rtp_packet_transport()) { + transport->rtp_packet_transport()->SignalSentPacket.connect( + this, &SignalObserver::OnSentPacket); + } + + if (transport->rtcp_packet_transport()) { + transport->rtcp_packet_transport()->SignalSentPacket.connect( + this, &SignalObserver::OnSentPacket); + } } bool ready() const { return ready_; } @@ -73,7 +83,24 @@ class SignalObserver : public sigslot::has_slots<> { network_route_ = std::move(network_route); } + void OnSentPacket(rtc::PacketTransportInternal* packet_transport, + const rtc::SentPacket& sent_packet) { + if (packet_transport == transport_->rtp_packet_transport()) { + rtp_transport_sent_count_++; + } else { + ASSERT_EQ(transport_->rtcp_packet_transport(), packet_transport); + rtcp_transport_sent_count_++; + } + } + + int rtp_transport_sent_count() { return rtp_transport_sent_count_; } + + int rtcp_transport_sent_count() { return rtcp_transport_sent_count_; } + private: + int rtp_transport_sent_count_ = 0; + int rtcp_transport_sent_count_ = 0; + RtpTransport* transport_ = nullptr; bool ready_ = false; rtc::Optional network_route_; }; @@ -197,6 +224,32 @@ TEST(RtpTransportTest, SetRtcpTransportWithNetworkRouteChanged) { EXPECT_FALSE(observer.network_route()); } +// Test that RTCP packets are sent over correct transport based on the RTCP-mux +// status. +TEST(RtpTransportTest, RtcpPacketSentOverCorrectTransport) { + // If the RTCP-mux is not enabled, RTCP packets are expected to be sent over + // the RtcpPacketTransport. + RtpTransport transport(kMuxDisabled); + rtc::FakePacketTransport fake_rtcp("fake_rtcp"); + rtc::FakePacketTransport fake_rtp("fake_rtp"); + transport.SetRtcpPacketTransport(&fake_rtcp); // rtcp ready + transport.SetRtpPacketTransport(&fake_rtp); // rtp ready + SignalObserver observer(&transport); + + fake_rtp.SetDestination(&fake_rtp, true); + fake_rtcp.SetDestination(&fake_rtcp, true); + + rtc::CopyOnWriteBuffer packet; + EXPECT_TRUE(transport.SendRtcpPacket(&packet, rtc::PacketOptions(), 0)); + EXPECT_EQ(1, observer.rtcp_transport_sent_count()); + + // The RTCP packets are expected to be sent over RtpPacketTransport if + // RTCP-mux is enabled. + transport.SetRtcpMuxEnabled(true); + EXPECT_TRUE(transport.SendRtcpPacket(&packet, rtc::PacketOptions(), 0)); + EXPECT_EQ(1, observer.rtp_transport_sent_count()); +} + class SignalCounter : public sigslot::has_slots<> { public: explicit SignalCounter(RtpTransport* transport) { @@ -263,7 +316,6 @@ TEST(RtpTransportTest, SignalHandledRtpPayloadType) { rtc::FakePacketTransport fake_rtp("fake_rtp"); fake_rtp.SetDestination(&fake_rtp, true); transport.SetRtpPacketTransport(&fake_rtp); - transport.AddHandledPayloadType(0x11); // An rtp packet. const rtc::PacketOptions options; @@ -274,21 +326,4 @@ TEST(RtpTransportTest, SignalHandledRtpPayloadType) { EXPECT_EQ(0, observer.rtcp_count()); } -// Test that SignalPacketReceived does not fire when a RTP packet with an -// unhandled payload type is received. -TEST(RtpTransportTest, DontSignalUnhandledRtpPayloadType) { - RtpTransport transport(kMuxDisabled); - SignalPacketReceivedCounter observer(&transport); - rtc::FakePacketTransport fake_rtp("fake_rtp"); - fake_rtp.SetDestination(&fake_rtp, true); - transport.SetRtpPacketTransport(&fake_rtp); - - const rtc::PacketOptions options; - const int flags = 0; - rtc::Buffer rtp_data(kRtpData, kRtpLen); - fake_rtp.SendPacket(rtp_data.data(), kRtpLen, options, flags); - EXPECT_EQ(0, observer.rtp_count()); - EXPECT_EQ(0, observer.rtcp_count()); -} - } // namespace webrtc diff --git a/pc/rtptransportinternal.h b/pc/rtptransportinternal.h index 0665fd76bc..a354936188 100644 --- a/pc/rtptransportinternal.h +++ b/pc/rtptransportinternal.h @@ -13,11 +13,12 @@ #include -#include "api/ortc/rtptransportinterface.h" +#include "api/ortc/srtptransportinterface.h" #include "api/umametrics.h" #include "p2p/base/icetransportinternal.h" #include "rtc_base/networkroute.h" #include "rtc_base/sigslot.h" +#include "rtc_base/sslstreamadapter.h" namespace rtc { class CopyOnWriteBuffer; @@ -27,11 +28,11 @@ struct PacketTime; namespace webrtc { -// This represents the internal interface beneath RtpTransportInterface; +// This represents the internal interface beneath SrtpTransportInterface; // it is not accessible to API consumers but is accessible to internal classes // in order to send and receive RTP and RTCP packets belonging to a single RTP // session. Additional convenience and configuration methods are also provided. -class RtpTransportInternal : public RtpTransportInterface, +class RtpTransportInternal : public SrtpTransportInterface, public sigslot::has_slots<> { public: virtual void SetRtcpMuxEnabled(bool enable) = 0; @@ -47,6 +48,8 @@ class RtpTransportInternal : public RtpTransportInterface, virtual rtc::PacketTransportInternal* rtcp_packet_transport() const = 0; virtual void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) = 0; + virtual bool IsReadyToSend() const = 0; + // Called whenever a transport's ready-to-send state changes. The argument // is true if all used transports are ready to send. This is more specific // than just "writable"; it means the last send didn't return ENOTCONN. @@ -80,9 +83,7 @@ class RtpTransportInternal : public RtpTransportInterface, const rtc::PacketOptions& options, int flags) = 0; - virtual bool HandlesPayloadType(int payload_type) const = 0; - - virtual void AddHandledPayloadType(int payload_type) = 0; + virtual bool IsSrtpActive() const = 0; virtual void SetMetricsObserver( rtc::scoped_refptr metrics_observer) = 0; diff --git a/pc/rtptransportinternaladapter.h b/pc/rtptransportinternaladapter.h index 6a2d7e2aa7..a1f4bfc02e 100644 --- a/pc/rtptransportinternaladapter.h +++ b/pc/rtptransportinternaladapter.h @@ -24,6 +24,8 @@ namespace webrtc { // methods. class RtpTransportInternalAdapter : public RtpTransportInternal { public: + RtpTransportInternalAdapter() {} + explicit RtpTransportInternalAdapter(RtpTransportInternal* transport) : transport_(transport) { RTC_DCHECK(transport_); @@ -51,6 +53,8 @@ class RtpTransportInternalAdapter : public RtpTransportInternal { transport_->SetRtcpPacketTransport(rtcp); } + bool IsReadyToSend() const override { return transport_->IsReadyToSend(); } + bool IsWritable(bool rtcp) const override { return transport_->IsWritable(rtcp); } @@ -67,14 +71,6 @@ class RtpTransportInternalAdapter : public RtpTransportInternal { return transport_->SendRtcpPacket(packet, options, flags); } - bool HandlesPayloadType(int payload_type) const override { - return transport_->HandlesPayloadType(payload_type); - } - - void AddHandledPayloadType(int payload_type) override { - return transport_->AddHandledPayloadType(payload_type); - } - // RtpTransportInterface overrides. PacketTransportInterface* GetRtpPacketTransport() const override { return transport_->GetRtpPacketTransport(); @@ -92,6 +88,8 @@ class RtpTransportInternalAdapter : public RtpTransportInternal { return transport_->GetParameters(); } + RtpTransportAdapter* GetInternal() override { return nullptr; } + void SetMetricsObserver( rtc::scoped_refptr metrics_observer) override { transport_->SetMetricsObserver(metrics_observer); @@ -99,7 +97,7 @@ class RtpTransportInternalAdapter : public RtpTransportInternal { protected: // Owned by the subclasses. - RtpTransportInternal* transport_; + RtpTransportInternal* transport_ = nullptr; }; } // namespace webrtc diff --git a/pc/srtptransport.cc b/pc/srtptransport.cc index 5eff3c932b..3e7b154fc0 100644 --- a/pc/srtptransport.cc +++ b/pc/srtptransport.cc @@ -21,19 +21,19 @@ #include "rtc_base/copyonwritebuffer.h" #include "rtc_base/ptr_util.h" #include "rtc_base/trace_event.h" +#include "rtc_base/zero_memory.h" namespace webrtc { SrtpTransport::SrtpTransport(bool rtcp_mux_enabled) : RtpTransportInternalAdapter(new RtpTransport(rtcp_mux_enabled)) { // Own the raw pointer |transport| from the base class. - rtp_transport_.reset(transport_); + rtp_transport_.reset(static_cast(transport_)); RTC_DCHECK(rtp_transport_); ConnectToRtpTransport(); } -SrtpTransport::SrtpTransport( - std::unique_ptr rtp_transport) +SrtpTransport::SrtpTransport(std::unique_ptr rtp_transport) : RtpTransportInternalAdapter(rtp_transport.get()), rtp_transport_(std::move(rtp_transport)) { RTC_DCHECK(rtp_transport_); @@ -52,6 +52,86 @@ void SrtpTransport::ConnectToRtpTransport() { rtp_transport_->SignalSentPacket.connect(this, &SrtpTransport::OnSentPacket); } +RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) { + if (send_params_) { + LOG_AND_RETURN_ERROR( + webrtc::RTCErrorType::UNSUPPORTED_OPERATION, + "Setting the SRTP send key twice is currently unsupported."); + } + if (recv_params_ && recv_params_->cipher_suite != params.cipher_suite) { + LOG_AND_RETURN_ERROR( + webrtc::RTCErrorType::UNSUPPORTED_OPERATION, + "The send key and receive key must have the same cipher suite."); + } + + send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite); + if (*send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Invalid SRTP crypto suite"); + } + + int send_key_len, send_salt_len; + if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len, + &send_salt_len)) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Could not get lengths for crypto suite(s):" + " send cipher_suite "); + } + + send_key_ = rtc::ZeroOnFreeBuffer(send_key_len + send_salt_len); + if (!ParseKeyParams(params.key_params, send_key_.data(), send_key_.size())) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Failed to parse the crypto key params"); + } + + if (!MaybeSetKeyParams()) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Failed to set the crypto key params"); + } + send_params_ = params; + return RTCError::OK(); +} + +RTCError SrtpTransport::SetSrtpReceiveKey(const cricket::CryptoParams& params) { + if (recv_params_) { + LOG_AND_RETURN_ERROR( + webrtc::RTCErrorType::UNSUPPORTED_OPERATION, + "Setting the SRTP send key twice is currently unsupported."); + } + if (send_params_ && send_params_->cipher_suite != params.cipher_suite) { + LOG_AND_RETURN_ERROR( + webrtc::RTCErrorType::UNSUPPORTED_OPERATION, + "The send key and receive key must have the same cipher suite."); + } + + recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite); + if (*recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Invalid SRTP crypto suite"); + } + + int recv_key_len, recv_salt_len; + if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len, + &recv_salt_len)) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Could not get lengths for crypto suite(s):" + " recv cipher_suite "); + } + + recv_key_ = rtc::ZeroOnFreeBuffer(recv_key_len + recv_salt_len); + if (!ParseKeyParams(params.key_params, recv_key_.data(), recv_key_.size())) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Failed to parse the crypto key params"); + } + + if (!MaybeSetKeyParams()) { + return RTCError(RTCErrorType::INVALID_PARAMETER, + "Failed to set the crypto key params"); + } + recv_params_ = params; + return RTCError::OK(); +} + bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options, int flags) { @@ -68,7 +148,7 @@ bool SrtpTransport::SendPacket(bool rtcp, rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options, int flags) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_ERROR) << "Failed to send the packet because SRTP transport is inactive."; return false; @@ -140,7 +220,7 @@ bool SrtpTransport::SendPacket(bool rtcp, void SrtpTransport::OnPacketReceived(bool rtcp, rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Inactive SRTP transport received a packet. Drop it."; return; @@ -181,7 +261,7 @@ void SrtpTransport::OnNetworkRouteChanged( // Only append the SRTP overhead when there is a selected network route. if (network_route) { int srtp_overhead = 0; - if (IsActive()) { + if (IsSrtpActive()) { GetSrtpOverhead(&srtp_overhead); } network_route->packet_overhead += srtp_overhead; @@ -271,7 +351,7 @@ bool SrtpTransport::SetRtcpParams(int send_cs, return true; } -bool SrtpTransport::IsActive() const { +bool SrtpTransport::IsSrtpActive() const { return send_session_ && recv_session_; } @@ -297,7 +377,7 @@ void SrtpTransport::CreateSrtpSessions() { } bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active"; return false; } @@ -310,7 +390,7 @@ bool SrtpTransport::ProtectRtp(void* p, int max_len, int* out_len, int64_t* index) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active"; return false; } @@ -322,7 +402,7 @@ bool SrtpTransport::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active"; return false; } @@ -335,7 +415,7 @@ bool SrtpTransport::ProtectRtcp(void* p, } bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active"; return false; } @@ -344,7 +424,7 @@ bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) { } bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active"; return false; } @@ -359,7 +439,7 @@ bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) { bool SrtpTransport::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active"; return false; } @@ -369,7 +449,7 @@ bool SrtpTransport::GetRtpAuthParams(uint8_t** key, } bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active"; return false; } @@ -380,7 +460,7 @@ bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const { } void SrtpTransport::EnableExternalAuth() { - RTC_DCHECK(!IsActive()); + RTC_DCHECK(!IsSrtpActive()); external_auth_enabled_ = true; } @@ -389,7 +469,7 @@ bool SrtpTransport::IsExternalAuthEnabled() const { } bool SrtpTransport::IsExternalAuthActive() const { - if (!IsActive()) { + if (!IsSrtpActive()) { RTC_LOG(LS_WARNING) << "Failed to check IsExternalAuthActive: SRTP not active"; return false; @@ -399,6 +479,42 @@ bool SrtpTransport::IsExternalAuthActive() const { return send_session_->IsExternalAuthActive(); } +bool SrtpTransport::MaybeSetKeyParams() { + if (!send_cipher_suite_ || !recv_cipher_suite_) { + return true; + } + + return SetRtpParams(*send_cipher_suite_, send_key_.data(), + static_cast(send_key_.size()), std::vector(), + *recv_cipher_suite_, recv_key_.data(), + static_cast(recv_key_.size()), std::vector()); +} + +bool SrtpTransport::ParseKeyParams(const std::string& key_params, + uint8_t* key, + size_t len) { + // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2" + + // Fail if key-method is wrong. + if (key_params.find("inline:") != 0) { + return false; + } + + // Fail if base64 decode fails, or the key is the wrong size. + std::string key_b64(key_params.substr(7)), key_str; + if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str, + nullptr) || + key_str.size() != len) { + return false; + } + + memcpy(key, key_str.c_str(), len); + // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing + // sensitive data. + rtc::ExplicitZeroMemory(&key_str[0], key_str.size()); + return true; +} + void SrtpTransport::SetMetricsObserver( rtc::scoped_refptr metrics_observer) { metrics_observer_ = metrics_observer; diff --git a/pc/srtptransport.h b/pc/srtptransport.h index 818aabb2a3..5bc9970530 100644 --- a/pc/srtptransport.h +++ b/pc/srtptransport.h @@ -16,10 +16,13 @@ #include #include +#include "api/ortc/srtptransportinterface.h" +#include "p2p/base/dtlstransportinternal.h" #include "p2p/base/icetransportinternal.h" +#include "pc/rtptransport.h" #include "pc/rtptransportinternaladapter.h" -#include "pc/srtpfilter.h" #include "pc/srtpsession.h" +#include "rtc_base/buffer.h" #include "rtc_base/checks.h" namespace webrtc { @@ -30,7 +33,29 @@ class SrtpTransport : public RtpTransportInternalAdapter { public: explicit SrtpTransport(bool rtcp_mux_enabled); - explicit SrtpTransport(std::unique_ptr rtp_transport); + explicit SrtpTransport(std::unique_ptr rtp_transport); + + virtual ~SrtpTransport() {} + + // SrtpTransportInterface overrides. + PacketTransportInterface* GetRtpPacketTransport() const override { + return rtp_transport_->GetRtpPacketTransport(); + } + PacketTransportInterface* GetRtcpPacketTransport() const override { + return rtp_transport_->GetRtcpPacketTransport(); + } + + // TODO(zstein): Use these RtcpParameters for configuration elsewhere. + RTCError SetParameters(const RtpTransportParameters& parameters) override { + return rtp_transport_->SetParameters(parameters); + } + RtpTransportParameters GetParameters() const override { + return rtp_transport_->GetParameters(); + } + + // SrtpTransportInterface specific implementation. + RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override; + RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override; bool SendRtpPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options, @@ -42,10 +67,7 @@ class SrtpTransport : public RtpTransportInternalAdapter { // The transport becomes active if the send_session_ and recv_session_ are // created. - bool IsActive() const; - - // TODO(zstein): Remove this when we remove RtpTransportAdapter. - RtpTransportAdapter* GetInternal() override { return nullptr; } + bool IsSrtpActive() const override; // Create new send/recv sessions and set the negotiated crypto keys for RTP // packet encryption. The keys can either come from SDES negotiation or DTLS @@ -138,14 +160,24 @@ class SrtpTransport : public RtpTransportInternalAdapter { bool UnprotectRtcp(void* data, int in_len, int* out_len); + bool MaybeSetKeyParams(); + bool ParseKeyParams(const std::string& key_params, uint8_t* key, size_t len); + const std::string content_name_; - std::unique_ptr rtp_transport_; + std::unique_ptr rtp_transport_; std::unique_ptr send_session_; std::unique_ptr recv_session_; std::unique_ptr send_rtcp_session_; std::unique_ptr recv_rtcp_session_; + rtc::Optional send_params_; + rtc::Optional recv_params_; + rtc::Optional send_cipher_suite_; + rtc::Optional recv_cipher_suite_; + rtc::ZeroOnFreeBuffer send_key_; + rtc::ZeroOnFreeBuffer recv_key_; + bool external_auth_enabled_ = false; int rtp_abs_sendtime_extn_id_ = -1; diff --git a/pc/srtptransport_unittest.cc b/pc/srtptransport_unittest.cc index e0b2302e6f..30e30f656f 100644 --- a/pc/srtptransport_unittest.cc +++ b/pc/srtptransport_unittest.cc @@ -57,12 +57,6 @@ class SrtpTransportTest : public testing::Test, public sigslot::has_slots<> { rtp_transport1->SetRtpPacketTransport(rtp_packet_transport1_.get()); rtp_transport2->SetRtpPacketTransport(rtp_packet_transport2_.get()); - // Add payload type for RTP packet and RTCP packet. - rtp_transport1->AddHandledPayloadType(0x00); - rtp_transport2->AddHandledPayloadType(0x00); - rtp_transport1->AddHandledPayloadType(0xc9); - rtp_transport2->AddHandledPayloadType(0xc9); - srtp_transport1_ = rtc::MakeUnique(std::move(rtp_transport1)); srtp_transport2_ = @@ -229,8 +223,8 @@ class SrtpTransportTest : public testing::Test, public sigslot::has_slots<> { cs, key1, key1_len, extension_ids, cs, key2, key2_len, extension_ids)); EXPECT_TRUE(srtp_transport2_->SetRtcpParams( cs, key2, key2_len, extension_ids, cs, key1, key1_len, extension_ids)); - EXPECT_TRUE(srtp_transport1_->IsActive()); - EXPECT_TRUE(srtp_transport2_->IsActive()); + EXPECT_TRUE(srtp_transport1_->IsSrtpActive()); + EXPECT_TRUE(srtp_transport2_->IsSrtpActive()); if (rtc::IsGcmCryptoSuite(cs)) { EXPECT_FALSE(srtp_transport1_->IsExternalAuthActive()); EXPECT_FALSE(srtp_transport2_->IsExternalAuthActive()); @@ -315,8 +309,8 @@ class SrtpTransportTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(srtp_transport2_->SetRtpParams(cs, key2, key2_len, encrypted_headers, cs, key1, key1_len, encrypted_headers)); - EXPECT_TRUE(srtp_transport1_->IsActive()); - EXPECT_TRUE(srtp_transport2_->IsActive()); + EXPECT_TRUE(srtp_transport1_->IsSrtpActive()); + EXPECT_TRUE(srtp_transport2_->IsSrtpActive()); EXPECT_FALSE(srtp_transport1_->IsExternalAuthActive()); EXPECT_FALSE(srtp_transport2_->IsExternalAuthActive()); TestSendRecvPacketWithEncryptedHeaderExtension(cs_name, encrypted_headers); diff --git a/pc/test/fakepeerconnectionforstats.h b/pc/test/fakepeerconnectionforstats.h index 1c2fb70543..733291fe82 100644 --- a/pc/test/fakepeerconnectionforstats.h +++ b/pc/test/fakepeerconnectionforstats.h @@ -124,8 +124,8 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase { auto* voice_media_channel_ptr = voice_media_channel.get(); voice_channel_ = rtc::MakeUnique( worker_thread_, network_thread_, signaling_thread_, nullptr, - std::move(voice_media_channel), mid, kDefaultRtcpMuxRequired, - kDefaultSrtpRequired); + std::move(voice_media_channel), mid, kDefaultSrtpRequired, + rtc::CryptoOptions()); voice_channel_->set_transport_name_for_testing(transport_name); GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_AUDIO) ->internal() @@ -141,8 +141,8 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase { auto video_media_channel_ptr = video_media_channel.get(); video_channel_ = rtc::MakeUnique( worker_thread_, network_thread_, signaling_thread_, - std::move(video_media_channel), mid, kDefaultRtcpMuxRequired, - kDefaultSrtpRequired); + std::move(video_media_channel), mid, kDefaultSrtpRequired, + rtc::CryptoOptions()); video_channel_->set_transport_name_for_testing(transport_name); GetOrCreateFirstTransceiverOfType(cricket::MEDIA_TYPE_VIDEO) ->internal() diff --git a/pc/test/faketransportcontroller.h b/pc/test/faketransportcontroller.h deleted file mode 100644 index 4a4cc96d8e..0000000000 --- a/pc/test/faketransportcontroller.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2009 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef PC_TEST_FAKETRANSPORTCONTROLLER_H_ -#define PC_TEST_FAKETRANSPORTCONTROLLER_H_ - -#include -#include -#include - -#include "p2p/base/fakedtlstransport.h" -#include "p2p/base/fakeicetransport.h" -#include "pc/transportcontroller.h" -#include "rtc_base/bind.h" -#include "rtc_base/sslfingerprint.h" -#include "rtc_base/thread.h" - -namespace cricket { - -// Fake TransportController class, which can be passed into a WebRtcSession -// object for test purposes. Can be connected to other FakeTransportControllers -// via Connect(). -// -// This fake is unusual in that for the most part, it's implemented with the -// real TransportController code, but with fake TransportChannels underneath. -class FakeTransportController : public TransportController { - public: - FakeTransportController() - : TransportController(rtc::Thread::Current(), - rtc::Thread::Current(), - nullptr, - /*redetermine_role_on_ice_restart=*/true, - rtc::CryptoOptions()) {} - - explicit FakeTransportController(bool redetermine_role_on_ice_restart) - : TransportController(rtc::Thread::Current(), - rtc::Thread::Current(), - nullptr, - redetermine_role_on_ice_restart, - rtc::CryptoOptions()) {} - - explicit FakeTransportController(IceRole role) - : TransportController(rtc::Thread::Current(), - rtc::Thread::Current(), - nullptr, - /*redetermine_role_on_ice_restart=*/true, - rtc::CryptoOptions()) { - SetIceRole(role); - } - - explicit FakeTransportController(rtc::Thread* network_thread) - : TransportController(rtc::Thread::Current(), - network_thread, - nullptr, - /*redetermine_role_on_ice_restart=*/true, - rtc::CryptoOptions()) {} - - FakeTransportController(rtc::Thread* network_thread, IceRole role) - : TransportController(rtc::Thread::Current(), - network_thread, - nullptr, - /*redetermine_role_on_ice_restart=*/true, - rtc::CryptoOptions()) { - SetIceRole(role); - } - - FakeDtlsTransport* GetFakeDtlsTransport_n(const std::string& transport_name, - int component) { - return static_cast( - get_channel_for_testing(transport_name, component)); - } - - // Simulate the exchange of transport descriptions, and the gathering and - // exchange of ICE candidates. - void Connect(FakeTransportController* dest) { - for (const std::string& transport_name : transport_names_for_testing()) { - std::unique_ptr local_fingerprint; - std::unique_ptr remote_fingerprint; - if (certificate_for_testing()) { - local_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate( - certificate_for_testing())); - } - if (dest->certificate_for_testing()) { - remote_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate( - dest->certificate_for_testing())); - } - TransportDescription local_desc( - std::vector(), - rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), - rtc::CreateRandomString(cricket::ICE_PWD_LENGTH), - cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE, - local_fingerprint.get()); - TransportDescription remote_desc( - std::vector(), - rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH), - rtc::CreateRandomString(cricket::ICE_PWD_LENGTH), - cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE, - remote_fingerprint.get()); - std::string err; - SetLocalTransportDescription(transport_name, local_desc, - webrtc::SdpType::kOffer, &err); - dest->SetRemoteTransportDescription(transport_name, local_desc, - webrtc::SdpType::kOffer, &err); - dest->SetLocalTransportDescription(transport_name, remote_desc, - webrtc::SdpType::kAnswer, &err); - SetRemoteTransportDescription(transport_name, remote_desc, - webrtc::SdpType::kAnswer, &err); - } - MaybeStartGathering(); - dest->MaybeStartGathering(); - network_thread()->Invoke( - RTC_FROM_HERE, - rtc::Bind(&FakeTransportController::SetChannelDestinations_n, this, - dest)); - } - - void DestroyRtcpTransport(const std::string& transport_name) { - DestroyDtlsTransport_n(transport_name, - cricket::ICE_CANDIDATE_COMPONENT_RTCP); - } - - protected: - IceTransportInternal* CreateIceTransportChannel_n( - const std::string& transport_name, - int component) override { - return new FakeIceTransport(transport_name, component); - } - - DtlsTransportInternal* CreateDtlsTransportChannel_n( - const std::string& transport_name, - int component, - IceTransportInternal* ice) override { - return new FakeDtlsTransport(static_cast(ice)); - } - - private: - void SetChannelDestinations_n(FakeTransportController* dest) { - for (DtlsTransportInternal* tc : channels_for_testing()) { - FakeDtlsTransport* local = static_cast(tc); - FakeDtlsTransport* remote = dest->GetFakeDtlsTransport_n( - local->transport_name(), local->component()); - if (remote) { - bool asymmetric = false; - local->SetDestination(remote, asymmetric); - } - } - } -}; - -} // namespace cricket - -#endif // PC_TEST_FAKETRANSPORTCONTROLLER_H_ diff --git a/pc/test/testsdpstrings.h b/pc/test/testsdpstrings.h index 0d751aac73..ea9935c6e3 100644 --- a/pc/test/testsdpstrings.h +++ b/pc/test/testsdpstrings.h @@ -61,7 +61,7 @@ static const char kFireFoxSdpOffer[] = "a=candidate:5 2 UDP 1694302206 74.95.2.170 33611 typ srflx raddr" " 10.0.254.2 rport 58890\r\n" #ifdef HAVE_SCTP - "m=application 45536 SCTP/DTLS 5000\r\n" + "m=application 45536 DTLS/SCTP 5000\r\n" "c=IN IP4 74.95.2.170\r\n" "a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n" "a=sendrecv\r\n" diff --git a/pc/transportcontroller.cc b/pc/transportcontroller.cc deleted file mode 100644 index 4e20981da6..0000000000 --- a/pc/transportcontroller.cc +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/transportcontroller.h" - -#include -#include -#include - -#include "p2p/base/port.h" -#include "rtc_base/bind.h" -#include "rtc_base/checks.h" -#include "rtc_base/ptr_util.h" -#include "rtc_base/thread.h" - -using webrtc::SdpType; - -namespace { - -enum { - MSG_ICECONNECTIONSTATE, - MSG_RECEIVING, - MSG_ICEGATHERINGSTATE, - MSG_CANDIDATESGATHERED, -}; - -struct CandidatesData : public rtc::MessageData { - CandidatesData(const std::string& transport_name, - const cricket::Candidates& candidates) - : transport_name(transport_name), candidates(candidates) {} - - std::string transport_name; - cricket::Candidates candidates; -}; - -bool VerifyCandidate(const cricket::Candidate& cand, std::string* error) { - // No address zero. - if (cand.address().IsNil() || cand.address().IsAnyIP()) { - *error = "candidate has address of zero"; - return false; - } - - // Disallow all ports below 1024, except for 80 and 443 on public addresses. - int port = cand.address().port(); - if (cand.protocol() == cricket::TCP_PROTOCOL_NAME && - (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) { - // Expected for active-only candidates per - // http://tools.ietf.org/html/rfc6544#section-4.5 so no error. - // Libjingle clients emit port 0, in "active" mode. - return true; - } - if (port < 1024) { - if ((port != 80) && (port != 443)) { - *error = "candidate has port below 1024, but not 80 or 443"; - return false; - } - - if (cand.address().IsPrivateIP()) { - *error = "candidate has port of 80 or 443 with private IP address"; - return false; - } - } - - return true; -} - -bool VerifyCandidates(const cricket::Candidates& candidates, - std::string* error) { - for (const cricket::Candidate& candidate : candidates) { - if (!VerifyCandidate(candidate, error)) { - return false; - } - } - return true; -} - -} // namespace - -namespace cricket { - -// This class groups the DTLS and ICE channels, and helps keep track of -// how many external objects (BaseChannels) reference each channel. -class TransportController::ChannelPair { - public: - // TODO(deadbeef): Change the types of |dtls| and |ice| to - // DtlsTransport and P2PTransportChannelWrapper, once TransportChannelImpl is - // removed. - ChannelPair(DtlsTransportInternal* dtls, IceTransportInternal* ice) - : ice_(ice), dtls_(dtls) {} - - // Currently, all ICE-related calls still go through this DTLS channel. But - // that will change once we get rid of TransportChannelImpl, and the DTLS - // channel interface no longer includes ICE-specific methods. - const DtlsTransportInternal* dtls() const { return dtls_.get(); } - DtlsTransportInternal* dtls() { return dtls_.get(); } - const IceTransportInternal* ice() const { return ice_.get(); } - IceTransportInternal* ice() { return ice_.get(); } - - private: - std::unique_ptr ice_; - std::unique_ptr dtls_; - - RTC_DISALLOW_COPY_AND_ASSIGN(ChannelPair); -}; - -TransportController::TransportController( - rtc::Thread* signaling_thread, - rtc::Thread* network_thread, - PortAllocator* port_allocator, - bool redetermine_role_on_ice_restart, - const rtc::CryptoOptions& crypto_options, - webrtc::RtcEventLog* event_log) - : signaling_thread_(signaling_thread), - network_thread_(network_thread), - port_allocator_(port_allocator), - redetermine_role_on_ice_restart_(redetermine_role_on_ice_restart), - crypto_options_(crypto_options), - event_log_(event_log) {} - -TransportController::~TransportController() { - // Channel destructors may try to send packets, so this needs to happen on - // the network thread. - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::DestroyAllChannels_n, this)); -} - -bool TransportController::SetSslMaxProtocolVersion( - rtc::SSLProtocolVersion version) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::SetSslMaxProtocolVersion_n, - this, version)); -} - -void TransportController::SetIceConfig(const IceConfig& config) { - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::SetIceConfig_n, this, config)); -} - -void TransportController::SetIceRole(IceRole ice_role) { - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::SetIceRole_n, this, ice_role)); -} - -void TransportController::SetNeedsIceRestartFlag() { - for (auto& kv : transports_) { - kv.second->SetNeedsIceRestartFlag(); - } -} - -bool TransportController::NeedsIceRestart( - const std::string& transport_name) const { - const JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - return false; - } - return transport->NeedsIceRestart(); -} - -bool TransportController::GetSslRole(const std::string& transport_name, - rtc::SSLRole* role) const { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::GetSslRole_n, this, - transport_name, role)); -} - -bool TransportController::SetLocalCertificate( - const rtc::scoped_refptr& certificate) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::SetLocalCertificate_n, - this, certificate)); -} - -bool TransportController::GetLocalCertificate( - const std::string& transport_name, - rtc::scoped_refptr* certificate) const { - if (network_thread_->IsCurrent()) { - return GetLocalCertificate_n(transport_name, certificate); - } - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::GetLocalCertificate_n, - this, transport_name, certificate)); -} - -std::unique_ptr TransportController::GetRemoteSSLCertChain( - const std::string& transport_name) const { - if (!network_thread_->IsCurrent()) { - return network_thread_->Invoke>( - RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); }); - } - - // Get the certificate from the RTP channel's DTLS handshake. Should be - // identical to the RTCP channel's, since they were given the same remote - // fingerprint. - const RefCountedChannel* ch = - GetChannel_n(transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - if (!ch) { - return nullptr; - } - return ch->dtls()->GetRemoteSSLCertChain(); -} - -bool TransportController::SetLocalTransportDescription( - const std::string& transport_name, - const TransportDescription& tdesc, - SdpType type, - std::string* err) { - return network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::SetLocalTransportDescription_n, this, - transport_name, tdesc, type, err)); -} - -bool TransportController::SetRemoteTransportDescription( - const std::string& transport_name, - const TransportDescription& tdesc, - SdpType type, - std::string* err) { - return network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::SetRemoteTransportDescription_n, this, - transport_name, tdesc, type, err)); -} - -void TransportController::MaybeStartGathering() { - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::MaybeStartGathering_n, this)); -} - -bool TransportController::AddRemoteCandidates(const std::string& transport_name, - const Candidates& candidates, - std::string* err) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::AddRemoteCandidates_n, - this, transport_name, candidates, err)); -} - -bool TransportController::RemoveRemoteCandidates(const Candidates& candidates, - std::string* err) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::RemoveRemoteCandidates_n, - this, candidates, err)); -} - -bool TransportController::ReadyForRemoteCandidates( - const std::string& transport_name) const { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::ReadyForRemoteCandidates_n, - this, transport_name)); -} - -bool TransportController::GetStats(const std::string& transport_name, - TransportStats* stats) { - if (network_thread_->IsCurrent()) { - return GetStats_n(transport_name, stats); - } - return network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportController::GetStats_n, this, transport_name, stats)); -} - -void TransportController::SetMetricsObserver( - webrtc::MetricsObserverInterface* metrics_observer) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::SetMetricsObserver_n, this, - metrics_observer)); -} - -DtlsTransportInternal* TransportController::CreateDtlsTransport( - const std::string& transport_name, - int component) { - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::CreateDtlsTransport_n, - this, transport_name, component)); -} - -DtlsTransportInternal* TransportController::CreateDtlsTransport_n( - const std::string& transport_name, - int component) { - RTC_DCHECK(network_thread_->IsCurrent()); - - RefCountedChannel* existing_channel = GetChannel_n(transport_name, component); - if (existing_channel) { - // Channel already exists; increment reference count and return. - existing_channel->AddRef(); - return existing_channel->dtls(); - } - - // Need to create a new channel. - JsepTransport* transport = GetOrCreateJsepTransport(transport_name); - - // Create DTLS channel wrapping ICE channel, and configure it. - IceTransportInternal* ice = - CreateIceTransportChannel_n(transport_name, component); - DtlsTransportInternal* dtls = - CreateDtlsTransportChannel_n(transport_name, component, ice); - dtls->ice_transport()->SetMetricsObserver(metrics_observer_); - dtls->ice_transport()->SetIceRole(ice_role_); - dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_); - dtls->ice_transport()->SetIceConfig(ice_config_); - if (certificate_) { - bool set_cert_success = dtls->SetLocalCertificate(certificate_); - RTC_DCHECK(set_cert_success); - } - - // Connect to signals offered by the channels. Currently, the DTLS channel - // forwards signals from the ICE channel, so we only need to connect to the - // DTLS channel. In the future this won't be the case. - dtls->SignalWritableState.connect( - this, &TransportController::OnChannelWritableState_n); - dtls->SignalReceivingState.connect( - this, &TransportController::OnChannelReceivingState_n); - dtls->SignalDtlsHandshakeError.connect( - this, &TransportController::OnDtlsHandshakeError); - dtls->ice_transport()->SignalGatheringState.connect( - this, &TransportController::OnChannelGatheringState_n); - dtls->ice_transport()->SignalCandidateGathered.connect( - this, &TransportController::OnChannelCandidateGathered_n); - dtls->ice_transport()->SignalCandidatesRemoved.connect( - this, &TransportController::OnChannelCandidatesRemoved_n); - dtls->ice_transport()->SignalRoleConflict.connect( - this, &TransportController::OnChannelRoleConflict_n); - dtls->ice_transport()->SignalStateChanged.connect( - this, &TransportController::OnChannelStateChanged_n); - RefCountedChannel* new_pair = new RefCountedChannel(dtls, ice); - new_pair->AddRef(); - channels_.insert(channels_.end(), new_pair); - bool channel_added = transport->AddChannel(dtls, component); - RTC_DCHECK(channel_added); - // Adding a channel could cause aggregate state to change. - UpdateAggregateStates_n(); - return dtls; -} - -void TransportController::DestroyDtlsTransport( - const std::string& transport_name, - int component) { - network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&TransportController::DestroyDtlsTransport_n, - this, transport_name, component)); -} - -void TransportController::DestroyDtlsTransport_n( - const std::string& transport_name, - int component) { - RTC_DCHECK(network_thread_->IsCurrent()); - auto it = GetChannelIterator_n(transport_name, component); - if (it == channels_.end()) { - RTC_LOG(LS_WARNING) << "Attempting to delete " << transport_name - << " TransportChannel " << component - << ", which doesn't exist."; - return; - } - // Release one reference to the RefCountedChannel, and do additional cleanup - // only if it was the last one. Matches the AddRef logic in - // CreateDtlsTransport_n. - if ((*it)->Release() == rtc::RefCountReleaseStatus::kOtherRefsRemained) { - return; - } - channels_.erase(it); - - JsepTransport* t = GetJsepTransport(transport_name); - bool channel_removed = t->RemoveChannel(component); - RTC_DCHECK(channel_removed); - // Just as we create a Transport when its first channel is created, - // we delete it when its last channel is deleted. - if (!t->HasChannels()) { - transports_.erase(transport_name); - } - // Removing a channel could cause aggregate state to change. - UpdateAggregateStates_n(); -} - -webrtc::SrtpTransport* TransportController::CreateSdesTransport( - const std::string& transport_name, - bool rtcp_mux_enabled) { - if (!network_thread_->IsCurrent()) { - return network_thread_->Invoke(RTC_FROM_HERE, [&] { - return CreateSdesTransport(transport_name, rtcp_mux_enabled); - }); - } - - auto existing_rtp_transport = FindRtpTransport(transport_name); - - if (existing_rtp_transport) { - // For SRTP transport wrapper, the |srtp_transport| is expected to be - // non-null and |dtls_srtp_transport| is expected to be a nullptr. - if (!existing_rtp_transport->srtp_transport || - existing_rtp_transport->dtls_srtp_transport) { - RTC_LOG(LS_ERROR) - << "Failed to create an RTP transport for SDES using name: " - << transport_name << " because the type doesn't match."; - return nullptr; - } - existing_rtp_transport->AddRef(); - return existing_rtp_transport->srtp_transport; - } - - auto new_srtp_transport = - rtc::MakeUnique(rtcp_mux_enabled); - - // The SDES should use an IceTransport rather than a DtlsTransport. We call - // |CreateDtlsTransport_n| here because the DtlsTransport will downgrade to an - // wrapper over IceTransport if we don't set the certificates and it will just - // forward the packets and signals without using DTLS. The support of SDES - // will be removed once all the downstream application stop using it. - new_srtp_transport->SetRtpPacketTransport(CreateDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP)); - if (!rtcp_mux_enabled) { - new_srtp_transport->SetRtcpPacketTransport(CreateDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP)); - } - -#if defined(ENABLE_EXTERNAL_AUTH) - new_srtp_transport->EnableExternalAuth(); -#endif - - auto new_rtp_transport_wrapper = new RefCountedRtpTransport(); - new_rtp_transport_wrapper->srtp_transport = new_srtp_transport.get(); - new_rtp_transport_wrapper->rtp_transport = std::move(new_srtp_transport); - new_rtp_transport_wrapper->AddRef(); - rtp_transports_[transport_name] = new_rtp_transport_wrapper; - return rtp_transports_[transport_name]->srtp_transport; -} - -webrtc::DtlsSrtpTransport* TransportController::CreateDtlsSrtpTransport( - const std::string& transport_name, - bool rtcp_mux_enabled) { - if (!network_thread_->IsCurrent()) { - return network_thread_->Invoke( - RTC_FROM_HERE, [&] { - return CreateDtlsSrtpTransport(transport_name, rtcp_mux_enabled); - }); - } - auto existing_rtp_transport = FindRtpTransport(transport_name); - - if (existing_rtp_transport) { - // For DTLS-SRTP transport wrapper, the |dtls_srtp_transport| is expected to - // be non-null and |srtp_transport| is expected to be a nullptr. - if (existing_rtp_transport->srtp_transport || - !existing_rtp_transport->dtls_srtp_transport) { - RTC_LOG(LS_ERROR) - << "Failed to create an RTP transport for DTLS-SRTP using name: " - << transport_name << " because the type doesn't match."; - return nullptr; - } - existing_rtp_transport->AddRef(); - return existing_rtp_transport->dtls_srtp_transport; - } - - auto new_srtp_transport = - rtc::MakeUnique(rtcp_mux_enabled); - -#if defined(ENABLE_EXTERNAL_AUTH) - new_srtp_transport->EnableExternalAuth(); -#endif - - auto new_dtls_srtp_transport = - rtc::MakeUnique(std::move(new_srtp_transport)); - - auto rtp_dtls_transport = CreateDtlsTransport_n( - transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP); - auto rtcp_dtls_transport = - rtcp_mux_enabled - ? nullptr - : CreateDtlsTransport_n(transport_name, - cricket::ICE_CANDIDATE_COMPONENT_RTCP); - - new_dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport, - rtcp_dtls_transport); - - auto new_rtp_transport_wrapper = new RefCountedRtpTransport(); - new_rtp_transport_wrapper->dtls_srtp_transport = - new_dtls_srtp_transport.get(); - new_rtp_transport_wrapper->rtp_transport = std::move(new_dtls_srtp_transport); - new_rtp_transport_wrapper->AddRef(); - rtp_transports_[transport_name] = new_rtp_transport_wrapper; - return rtp_transports_[transport_name]->dtls_srtp_transport; -} - -void TransportController::DestroyTransport(const std::string& transport_name) { - if (!network_thread_->IsCurrent()) { - network_thread_->Invoke(RTC_FROM_HERE, - [&] { DestroyTransport(transport_name); }); - return; - } - - auto existing_rtp_transport = FindRtpTransport(transport_name); - if (!existing_rtp_transport) { - RTC_LOG(LS_WARNING) << "Attempting to delete " << transport_name - << " transport , which doesn't exist."; - return; - } - if (existing_rtp_transport->Release() == - rtc::RefCountReleaseStatus::kDroppedLastRef) { - rtp_transports_.erase(transport_name); - } - return; -} - -std::vector TransportController::transport_names_for_testing() { - std::vector ret; - for (const auto& kv : transports_) { - ret.push_back(kv.first); - } - return ret; -} - -std::vector -TransportController::channels_for_testing() { - std::vector ret; - for (RefCountedChannel* channel : channels_) { - ret.push_back(channel->dtls()); - } - return ret; -} - -DtlsTransportInternal* TransportController::get_channel_for_testing( - const std::string& transport_name, - int component) { - RefCountedChannel* ch = GetChannel_n(transport_name, component); - return ch ? ch->dtls() : nullptr; -} - -IceTransportInternal* TransportController::CreateIceTransportChannel_n( - const std::string& transport_name, - int component) { - return new P2PTransportChannel(transport_name, component, port_allocator_, - event_log_); -} - -DtlsTransportInternal* TransportController::CreateDtlsTransportChannel_n( - const std::string&, - int, - IceTransportInternal* ice) { - DtlsTransport* dtls = new DtlsTransport(ice, crypto_options_); - dtls->SetSslMaxProtocolVersion(ssl_max_version_); - return dtls; -} - -void TransportController::OnMessage(rtc::Message* pmsg) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - - switch (pmsg->message_id) { - case MSG_ICECONNECTIONSTATE: { - rtc::TypedMessageData* data = - static_cast*>(pmsg->pdata); - SignalConnectionState(data->data()); - delete data; - break; - } - case MSG_RECEIVING: { - rtc::TypedMessageData* data = - static_cast*>(pmsg->pdata); - SignalReceiving(data->data()); - delete data; - break; - } - case MSG_ICEGATHERINGSTATE: { - rtc::TypedMessageData* data = - static_cast*>(pmsg->pdata); - SignalGatheringState(data->data()); - delete data; - break; - } - case MSG_CANDIDATESGATHERED: { - CandidatesData* data = static_cast(pmsg->pdata); - SignalCandidatesGathered(data->transport_name, data->candidates); - delete data; - break; - } - default: - RTC_NOTREACHED(); - } -} - -const TransportController::RefCountedRtpTransport* -TransportController::FindRtpTransport(const std::string& transport_name) { - auto it = rtp_transports_.find(transport_name); - return it == rtp_transports_.end() ? nullptr : it->second; -} - -std::vector::iterator -TransportController::GetChannelIterator_n(const std::string& transport_name, - int component) { - RTC_DCHECK(network_thread_->IsCurrent()); - return std::find_if(channels_.begin(), channels_.end(), - [transport_name, component](RefCountedChannel* channel) { - return channel->dtls()->transport_name() == - transport_name && - channel->dtls()->component() == component; - }); -} - -std::vector::const_iterator -TransportController::GetChannelIterator_n(const std::string& transport_name, - int component) const { - RTC_DCHECK(network_thread_->IsCurrent()); - return std::find_if( - channels_.begin(), channels_.end(), - [transport_name, component](const RefCountedChannel* channel) { - return channel->dtls()->transport_name() == transport_name && - channel->dtls()->component() == component; - }); -} - -const JsepTransport* TransportController::GetJsepTransport( - const std::string& transport_name) const { - auto it = transports_.find(transport_name); - return (it == transports_.end()) ? nullptr : it->second.get(); -} - -JsepTransport* TransportController::GetJsepTransport( - const std::string& transport_name) { - auto it = transports_.find(transport_name); - return (it == transports_.end()) ? nullptr : it->second.get(); -} - -const TransportController::RefCountedChannel* TransportController::GetChannel_n( - const std::string& transport_name, - int component) const { - RTC_DCHECK(network_thread_->IsCurrent()); - auto it = GetChannelIterator_n(transport_name, component); - return (it == channels_.end()) ? nullptr : *it; -} - -TransportController::RefCountedChannel* TransportController::GetChannel_n( - const std::string& transport_name, - int component) { - RTC_DCHECK(network_thread_->IsCurrent()); - auto it = GetChannelIterator_n(transport_name, component); - return (it == channels_.end()) ? nullptr : *it; -} - -JsepTransport* TransportController::GetOrCreateJsepTransport( - const std::string& transport_name) { - RTC_DCHECK(network_thread_->IsCurrent()); - - JsepTransport* transport = GetJsepTransport(transport_name); - if (transport) { - return transport; - } - - transport = new JsepTransport(transport_name, certificate_); - transports_[transport_name] = std::unique_ptr(transport); - return transport; -} - -void TransportController::DestroyAllChannels_n() { - RTC_DCHECK(network_thread_->IsCurrent()); - transports_.clear(); - // TODO(nisse): If |channels_| were a vector of scoped_refptr, we - // wouldn't need this strange hack. - for (RefCountedChannel* channel : channels_) { - // Even though these objects are normally ref-counted, if - // TransportController is deleted while they still have references, just - // remove all references. - while (channel->Release() == - rtc::RefCountReleaseStatus::kOtherRefsRemained) { - } - } - channels_.clear(); -} - -bool TransportController::SetSslMaxProtocolVersion_n( - rtc::SSLProtocolVersion version) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // Max SSL version can only be set before transports are created. - if (!transports_.empty()) { - return false; - } - - ssl_max_version_ = version; - return true; -} - -void TransportController::SetIceConfig_n(const IceConfig& config) { - RTC_DCHECK(network_thread_->IsCurrent()); - - ice_config_ = config; - for (auto& channel : channels_) { - channel->dtls()->ice_transport()->SetIceConfig(ice_config_); - } -} - -void TransportController::SetIceRole_n(IceRole ice_role) { - RTC_DCHECK(network_thread_->IsCurrent()); - - ice_role_ = ice_role; - for (auto& channel : channels_) { - channel->dtls()->ice_transport()->SetIceRole(ice_role_); - } -} - -bool TransportController::GetSslRole_n(const std::string& transport_name, - rtc::SSLRole* role) const { - RTC_DCHECK(network_thread_->IsCurrent()); - - const JsepTransport* t = GetJsepTransport(transport_name); - if (!t) { - return false; - } - rtc::Optional current_role = t->GetSslRole(); - if (!current_role) { - return false; - } - *role = *current_role; - return true; -} - -bool TransportController::SetLocalCertificate_n( - const rtc::scoped_refptr& certificate) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // Can't change a certificate, or set a null certificate. - if (certificate_ || !certificate) { - return false; - } - certificate_ = certificate; - - // Set certificate for JsepTransport, which verifies it matches the - // fingerprint in SDP, and DTLS transport. - // Fallback from DTLS to SDES is not supported. - for (auto& kv : transports_) { - kv.second->SetLocalCertificate(certificate_); - } - for (auto& channel : channels_) { - bool set_cert_success = channel->dtls()->SetLocalCertificate(certificate_); - RTC_DCHECK(set_cert_success); - } - return true; -} - -bool TransportController::GetLocalCertificate_n( - const std::string& transport_name, - rtc::scoped_refptr* certificate) const { - RTC_DCHECK(network_thread_->IsCurrent()); - - const JsepTransport* t = GetJsepTransport(transport_name); - if (!t) { - return false; - } - return t->GetLocalCertificate(certificate); -} - -bool TransportController::SetLocalTransportDescription_n( - const std::string& transport_name, - const TransportDescription& tdesc, - SdpType type, - std::string* err) { - RTC_DCHECK(network_thread_->IsCurrent()); - - JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - // If we didn't find a transport, that's not an error; - // it could have been deleted as a result of bundling. - // TODO(deadbeef): Make callers smarter so they won't attempt to set a - // description on a deleted transport. - return true; - } - - // The initial offer side may use ICE Lite, in which case, per RFC5245 Section - // 5.1.1, the answer side should take the controlling role if it is in the - // full ICE mode. - // - // When both sides use ICE Lite, the initial offer side must take the - // controlling role, and this is the default logic implemented in - // SetLocalDescription in PeerConnection. - if (transport->remote_description() && - transport->remote_description()->ice_mode == ICEMODE_LITE && - ice_role_ == ICEROLE_CONTROLLED && tdesc.ice_mode == ICEMODE_FULL) { - SetIceRole_n(ICEROLE_CONTROLLING); - } - - // Older versions of Chrome expect the ICE role to be re-determined when an - // ICE restart occurs, and also don't perform conflict resolution correctly, - // so for now we can't safely stop doing this, unless the application opts in - // by setting |redetermine_role_on_ice_restart_| to false. - // See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676 - // TODO(deadbeef): Remove this when these old versions of Chrome reach a low - // enough population. - if (redetermine_role_on_ice_restart_ && transport->local_description() && - IceCredentialsChanged(transport->local_description()->ice_ufrag, - transport->local_description()->ice_pwd, - tdesc.ice_ufrag, tdesc.ice_pwd) && - // Don't change the ICE role if the remote endpoint is ICE lite; we - // should always be controlling in that case. - (!transport->remote_description() || - transport->remote_description()->ice_mode != ICEMODE_LITE)) { - IceRole new_ice_role = - (type == SdpType::kOffer) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED; - SetIceRole(new_ice_role); - } - - RTC_LOG(LS_INFO) << "Set local transport description on " << transport_name; - return transport->SetLocalTransportDescription(tdesc, type, err); -} - -bool TransportController::SetRemoteTransportDescription_n( - const std::string& transport_name, - const TransportDescription& tdesc, - SdpType type, - std::string* err) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // If our role is ICEROLE_CONTROLLED and the remote endpoint supports only - // ice_lite, this local endpoint should take the CONTROLLING role. - // TODO(deadbeef): This is a session-level attribute, so it really shouldn't - // be in a TransportDescription in the first place... - if (ice_role_ == ICEROLE_CONTROLLED && tdesc.ice_mode == ICEMODE_LITE) { - SetIceRole_n(ICEROLE_CONTROLLING); - } - - JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - // If we didn't find a transport, that's not an error; - // it could have been deleted as a result of bundling. - // TODO(deadbeef): Make callers smarter so they won't attempt to set a - // description on a deleted transport. - return true; - } - - // If we use ICE Lite and the remote endpoint uses the full implementation of - // ICE, the local endpoint must take the controlled role, and the other side - // must be the controlling role. - if (transport->local_description() && - transport->local_description()->ice_mode == ICEMODE_LITE && - ice_role_ == ICEROLE_CONTROLLING && tdesc.ice_mode == ICEMODE_FULL) { - SetIceRole_n(ICEROLE_CONTROLLED); - } - - RTC_LOG(LS_INFO) << "Set remote transport description on " << transport_name; - return transport->SetRemoteTransportDescription(tdesc, type, err); -} - -void TransportController::MaybeStartGathering_n() { - for (auto& channel : channels_) { - channel->dtls()->ice_transport()->MaybeStartGathering(); - } -} - -bool TransportController::AddRemoteCandidates_n( - const std::string& transport_name, - const Candidates& candidates, - std::string* err) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // Verify each candidate before passing down to the transport layer. - if (!VerifyCandidates(candidates, err)) { - return false; - } - - JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - // If we didn't find a transport, that's not an error; - // it could have been deleted as a result of bundling. - return true; - } - - for (const Candidate& candidate : candidates) { - RefCountedChannel* channel = - GetChannel_n(transport_name, candidate.component()); - if (!channel) { - *err = "Candidate has an unknown component: " + candidate.ToString() + - " for content: " + transport_name; - return false; - } - channel->dtls()->ice_transport()->AddRemoteCandidate(candidate); - } - return true; -} - -bool TransportController::RemoveRemoteCandidates_n(const Candidates& candidates, - std::string* err) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // Verify each candidate before passing down to the transport layer. - if (!VerifyCandidates(candidates, err)) { - return false; - } - - std::map candidates_by_transport_name; - for (const Candidate& cand : candidates) { - if (!cand.transport_name().empty()) { - candidates_by_transport_name[cand.transport_name()].push_back(cand); - } else { - RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a " - "transport name set: " - << cand.ToString(); - } - } - - bool result = true; - for (const auto& kv : candidates_by_transport_name) { - const std::string& transport_name = kv.first; - const Candidates& candidates = kv.second; - JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - // If we didn't find a transport, that's not an error; - // it could have been deleted as a result of bundling. - continue; - } - for (const Candidate& candidate : candidates) { - RefCountedChannel* channel = - GetChannel_n(transport_name, candidate.component()); - if (channel) { - channel->dtls()->ice_transport()->RemoveRemoteCandidate(candidate); - } - } - } - return result; -} - -bool TransportController::ReadyForRemoteCandidates_n( - const std::string& transport_name) const { - RTC_DCHECK(network_thread_->IsCurrent()); - - const JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - return false; - } - return transport->ready_for_remote_candidates(); -} - -bool TransportController::GetStats_n(const std::string& transport_name, - TransportStats* stats) { - RTC_DCHECK(network_thread_->IsCurrent()); - - JsepTransport* transport = GetJsepTransport(transport_name); - if (!transport) { - return false; - } - return transport->GetStats(stats); -} - -void TransportController::SetMetricsObserver_n( - webrtc::MetricsObserverInterface* metrics_observer) { - RTC_DCHECK(network_thread_->IsCurrent()); - metrics_observer_ = metrics_observer; - for (auto& channel : channels_) { - channel->dtls()->ice_transport()->SetMetricsObserver(metrics_observer); - } -} - -void TransportController::OnChannelWritableState_n( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - RTC_LOG(LS_INFO) << " Transport " << transport->transport_name() - << " writability changed to " << transport->writable() - << "."; - UpdateAggregateStates_n(); -} - -void TransportController::OnChannelReceivingState_n( - rtc::PacketTransportInternal* transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - UpdateAggregateStates_n(); -} - -void TransportController::OnChannelGatheringState_n( - IceTransportInternal* channel) { - RTC_DCHECK(network_thread_->IsCurrent()); - UpdateAggregateStates_n(); -} - -void TransportController::OnChannelCandidateGathered_n( - IceTransportInternal* channel, - const Candidate& candidate) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // We should never signal peer-reflexive candidates. - if (candidate.type() == PRFLX_PORT_TYPE) { - RTC_NOTREACHED(); - return; - } - std::vector candidates; - candidates.push_back(candidate); - CandidatesData* data = - new CandidatesData(channel->transport_name(), candidates); - signaling_thread_->Post(RTC_FROM_HERE, this, MSG_CANDIDATESGATHERED, data); -} - -void TransportController::OnChannelCandidatesRemoved_n( - IceTransportInternal* channel, - const Candidates& candidates) { - invoker_.AsyncInvoke( - RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&TransportController::OnChannelCandidatesRemoved, this, - candidates)); -} - -void TransportController::OnChannelCandidatesRemoved( - const Candidates& candidates) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - SignalCandidatesRemoved(candidates); -} - -void TransportController::OnChannelRoleConflict_n( - IceTransportInternal* channel) { - RTC_DCHECK(network_thread_->IsCurrent()); - // Note: since the role conflict is handled entirely on the network thread, - // we don't need to worry about role conflicts occurring on two ports at once. - // The first one encountered should immediately reverse the role. - IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING) - ? ICEROLE_CONTROLLED - : ICEROLE_CONTROLLING; - RTC_LOG(LS_INFO) << "Got role conflict; switching to " - << (reversed_role == ICEROLE_CONTROLLING ? "controlling" - : "controlled") - << " role."; - SetIceRole_n(reversed_role); -} - -void TransportController::OnChannelStateChanged_n( - IceTransportInternal* channel) { - RTC_DCHECK(network_thread_->IsCurrent()); - RTC_LOG(LS_INFO) << channel->transport_name() << " TransportChannel " - << channel->component() - << " state changed. Check if state is complete."; - UpdateAggregateStates_n(); -} - -void TransportController::UpdateAggregateStates_n() { - RTC_DCHECK(network_thread_->IsCurrent()); - - IceConnectionState new_connection_state = kIceConnectionConnecting; - IceGatheringState new_gathering_state = kIceGatheringNew; - bool any_receiving = false; - bool any_failed = false; - bool all_connected = !channels_.empty(); - bool all_completed = !channels_.empty(); - bool any_gathering = false; - bool all_done_gathering = !channels_.empty(); - for (const auto& channel : channels_) { - any_receiving = any_receiving || channel->dtls()->receiving(); - any_failed = any_failed || channel->dtls()->ice_transport()->GetState() == - IceTransportState::STATE_FAILED; - all_connected = all_connected && channel->dtls()->writable(); - all_completed = - all_completed && channel->dtls()->writable() && - channel->dtls()->ice_transport()->GetState() == - IceTransportState::STATE_COMPLETED && - channel->dtls()->ice_transport()->GetIceRole() == ICEROLE_CONTROLLING && - channel->dtls()->ice_transport()->gathering_state() == - kIceGatheringComplete; - any_gathering = - any_gathering || - channel->dtls()->ice_transport()->gathering_state() != kIceGatheringNew; - all_done_gathering = all_done_gathering && - channel->dtls()->ice_transport()->gathering_state() == - kIceGatheringComplete; - } - if (any_failed) { - new_connection_state = kIceConnectionFailed; - } else if (all_completed) { - new_connection_state = kIceConnectionCompleted; - } else if (all_connected) { - new_connection_state = kIceConnectionConnected; - } - if (connection_state_ != new_connection_state) { - connection_state_ = new_connection_state; - signaling_thread_->Post( - RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE, - new rtc::TypedMessageData(new_connection_state)); - } - - if (receiving_ != any_receiving) { - receiving_ = any_receiving; - signaling_thread_->Post(RTC_FROM_HERE, this, MSG_RECEIVING, - new rtc::TypedMessageData(any_receiving)); - } - - if (all_done_gathering) { - new_gathering_state = kIceGatheringComplete; - } else if (any_gathering) { - new_gathering_state = kIceGatheringGathering; - } - if (gathering_state_ != new_gathering_state) { - gathering_state_ = new_gathering_state; - signaling_thread_->Post( - RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE, - new rtc::TypedMessageData(new_gathering_state)); - } -} - -void TransportController::OnDtlsHandshakeError(rtc::SSLHandshakeError error) { - SignalDtlsHandshakeError(error); -} - -} // namespace cricket diff --git a/pc/transportcontroller.h b/pc/transportcontroller.h deleted file mode 100644 index ea07dfe83f..0000000000 --- a/pc/transportcontroller.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef PC_TRANSPORTCONTROLLER_H_ -#define PC_TRANSPORTCONTROLLER_H_ - -#include -#include -#include -#include - -#include "api/candidate.h" -#include "p2p/base/dtlstransport.h" -#include "p2p/base/p2ptransportchannel.h" -#include "pc/dtlssrtptransport.h" -#include "pc/jseptransport.h" -#include "pc/rtptransport.h" -#include "pc/srtptransport.h" -#include "rtc_base/asyncinvoker.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/refcountedobject.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/sslstreamadapter.h" - -namespace rtc { -class Thread; -class PacketTransportInternal; -} // namespace rtc - -namespace webrtc { -class MetricsObserverInterface; -class RtcEventLog; -} // namespace webrtc - -namespace cricket { - -class TransportController : public sigslot::has_slots<>, - public rtc::MessageHandler { - public: - // If |redetermine_role_on_ice_restart| is true, ICE role is redetermined - // upon setting a local transport description that indicates an ICE restart. - // For the constructor that doesn't take this parameter, it defaults to true. - // - // |crypto_options| is used to determine if created DTLS transports negotiate - // GCM crypto suites or not. - TransportController(rtc::Thread* signaling_thread, - rtc::Thread* network_thread, - PortAllocator* port_allocator, - bool redetermine_role_on_ice_restart, - const rtc::CryptoOptions& crypto_options, - webrtc::RtcEventLog* event_log = nullptr); - - virtual ~TransportController(); - - rtc::Thread* signaling_thread() const { return signaling_thread_; } - rtc::Thread* network_thread() const { return network_thread_; } - - PortAllocator* port_allocator() const { return port_allocator_; } - - // Can only be set before transports are created. - // TODO(deadbeef): Make this an argument to the constructor once BaseSession - // and WebRtcSession are combined - bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version); - - void SetIceConfig(const IceConfig& config); - void SetIceRole(IceRole ice_role); - - // Set the "needs-ice-restart" flag as described in JSEP. After the flag is - // set, offers should generate new ufrags/passwords until an ICE restart - // occurs. - void SetNeedsIceRestartFlag(); - // Returns true if the ICE restart flag above was set, and no ICE restart has - // occurred yet for this transport (by applying a local description with - // changed ufrag/password). If the transport has been deleted as a result of - // bundling, returns false. - bool NeedsIceRestart(const std::string& transport_name) const; - - bool GetSslRole(const std::string& transport_name, rtc::SSLRole* role) const; - - // Specifies the identity to use in this session. - // Can only be called once. - bool SetLocalCertificate( - const rtc::scoped_refptr& certificate); - bool GetLocalCertificate( - const std::string& transport_name, - rtc::scoped_refptr* certificate) const; - // Caller owns returned certificate chain. This method mainly exists for - // stats reporting. - std::unique_ptr GetRemoteSSLCertChain( - const std::string& transport_name) const; - - bool SetLocalTransportDescription(const std::string& transport_name, - const TransportDescription& tdesc, - webrtc::SdpType type, - std::string* err); - bool SetRemoteTransportDescription(const std::string& transport_name, - const TransportDescription& tdesc, - webrtc::SdpType type, - std::string* err); - // Start gathering candidates for any new transports, or transports doing an - // ICE restart. - void MaybeStartGathering(); - bool AddRemoteCandidates(const std::string& transport_name, - const Candidates& candidates, - std::string* err); - bool RemoveRemoteCandidates(const Candidates& candidates, std::string* err); - bool ReadyForRemoteCandidates(const std::string& transport_name) const; - // TODO(deadbeef): GetStats isn't const because all the way down to - // OpenSSLStreamAdapter, - // GetSslCipherSuite and GetDtlsSrtpCryptoSuite are not const. Fix this. - bool GetStats(const std::string& transport_name, TransportStats* stats); - void SetMetricsObserver(webrtc::MetricsObserverInterface* metrics_observer); - - // Creates a channel if it doesn't exist. Otherwise, increments a reference - // count and returns an existing channel. - DtlsTransportInternal* CreateDtlsTransport(const std::string& transport_name, - int component); - virtual DtlsTransportInternal* CreateDtlsTransport_n( - const std::string& transport_name, - int component); - - // Decrements a channel's reference count, and destroys the channel if - // nothing is referencing it. - virtual void DestroyDtlsTransport(const std::string& transport_name, - int component); - virtual void DestroyDtlsTransport_n(const std::string& transport_name, - int component); - - // Create an SrtpTransport/DtlsSrtpTransport if it doesn't exist. - // Otherwise, increments a reference count and returns the existing one. - // These methods are not currently used but the plan is to transition - // PeerConnection and BaseChannel to use them instead of CreateDtlsTransport. - webrtc::SrtpTransport* CreateSdesTransport(const std::string& transport_name, - bool rtcp_mux_enabled); - webrtc::DtlsSrtpTransport* CreateDtlsSrtpTransport( - const std::string& transport_name, - bool rtcp_mux_enabled); - - // Destroy an RTP level transport which can be an RtpTransport, an - // SrtpTransport or a DtlsSrtpTransport. - void DestroyTransport(const std::string& transport_name); - - // TODO(deadbeef): Remove all for_testing methods! - const rtc::scoped_refptr& certificate_for_testing() - const { - return certificate_; - } - std::vector transport_names_for_testing(); - std::vector channels_for_testing(); - DtlsTransportInternal* get_channel_for_testing( - const std::string& transport_name, - int component); - - // All of these signals are fired on the signalling thread. - - // If any transport failed => failed, - // Else if all completed => completed, - // Else if all connected => connected, - // Else => connecting - sigslot::signal1 SignalConnectionState; - - // Receiving if any transport is receiving - sigslot::signal1 SignalReceiving; - - // If all transports done gathering => complete, - // Else if any are gathering => gathering, - // Else => new - sigslot::signal1 SignalGatheringState; - - // (transport_name, candidates) - sigslot::signal2 - SignalCandidatesGathered; - - sigslot::signal1 SignalCandidatesRemoved; - - sigslot::signal1 SignalDtlsHandshakeError; - - protected: - // TODO(deadbeef): Get rid of these virtual methods. Used by - // FakeTransportController currently, but FakeTransportController shouldn't - // even be functioning by subclassing TransportController. - virtual IceTransportInternal* CreateIceTransportChannel_n( - const std::string& transport_name, - int component); - virtual DtlsTransportInternal* CreateDtlsTransportChannel_n( - const std::string& transport_name, - int component, - IceTransportInternal* ice); - - private: - void OnMessage(rtc::Message* pmsg) override; - - class ChannelPair; - typedef rtc::RefCountedObject RefCountedChannel; - - // Wrapper for RtpTransport that keeps a reference count. - // When using SDES, |srtp_transport| is non-null, |dtls_srtp_transport| is - // null and |rtp_transport.get()| == |srtp_transport|, - // When using DTLS-SRTP, |dtls_srtp_transport| is non-null, |srtp_transport| - // is null and |rtp_transport.get()| == |dtls_srtp_transport|, - // When using unencrypted RTP, only |rtp_transport| is non-null. - struct RtpTransportWrapper { - // |rtp_transport| is always non-null. - std::unique_ptr rtp_transport; - webrtc::SrtpTransport* srtp_transport = nullptr; - webrtc::DtlsSrtpTransport* dtls_srtp_transport = nullptr; - }; - - typedef rtc::RefCountedObject RefCountedRtpTransport; - - const RefCountedRtpTransport* FindRtpTransport( - const std::string& transport_name); - - // Helper functions to get a channel or transport, or iterator to it (in case - // it needs to be erased). - std::vector::iterator GetChannelIterator_n( - const std::string& transport_name, - int component); - std::vector::const_iterator GetChannelIterator_n( - const std::string& transport_name, - int component) const; - const JsepTransport* GetJsepTransport( - const std::string& transport_name) const; - JsepTransport* GetJsepTransport(const std::string& transport_name); - const RefCountedChannel* GetChannel_n(const std::string& transport_name, - int component) const; - RefCountedChannel* GetChannel_n(const std::string& transport_name, - int component); - - JsepTransport* GetOrCreateJsepTransport(const std::string& transport_name); - void DestroyAllChannels_n(); - - bool SetSslMaxProtocolVersion_n(rtc::SSLProtocolVersion version); - void SetIceConfig_n(const IceConfig& config); - void SetIceRole_n(IceRole ice_role); - bool GetSslRole_n(const std::string& transport_name, - rtc::SSLRole* role) const; - bool SetLocalCertificate_n( - const rtc::scoped_refptr& certificate); - bool GetLocalCertificate_n( - const std::string& transport_name, - rtc::scoped_refptr* certificate) const; - bool SetLocalTransportDescription_n(const std::string& transport_name, - const TransportDescription& tdesc, - webrtc::SdpType type, - std::string* err); - bool SetRemoteTransportDescription_n(const std::string& transport_name, - const TransportDescription& tdesc, - webrtc::SdpType type, - std::string* err); - void MaybeStartGathering_n(); - bool AddRemoteCandidates_n(const std::string& transport_name, - const Candidates& candidates, - std::string* err); - bool RemoveRemoteCandidates_n(const Candidates& candidates, std::string* err); - bool ReadyForRemoteCandidates_n(const std::string& transport_name) const; - bool GetStats_n(const std::string& transport_name, TransportStats* stats); - void SetMetricsObserver_n(webrtc::MetricsObserverInterface* metrics_observer); - - // Handlers for signals from Transport. - void OnChannelWritableState_n(rtc::PacketTransportInternal* transport); - void OnChannelReceivingState_n(rtc::PacketTransportInternal* transport); - void OnChannelGatheringState_n(IceTransportInternal* channel); - void OnChannelCandidateGathered_n(IceTransportInternal* channel, - const Candidate& candidate); - void OnChannelCandidatesRemoved(const Candidates& candidates); - void OnChannelCandidatesRemoved_n(IceTransportInternal* channel, - const Candidates& candidates); - void OnChannelRoleConflict_n(IceTransportInternal* channel); - void OnChannelStateChanged_n(IceTransportInternal* channel); - - void UpdateAggregateStates_n(); - - void OnDtlsHandshakeError(rtc::SSLHandshakeError error); - - rtc::Thread* const signaling_thread_ = nullptr; - rtc::Thread* const network_thread_ = nullptr; - PortAllocator* const port_allocator_ = nullptr; - - std::map> transports_; - std::vector channels_; - - std::map rtp_transports_; - - // Aggregate state for TransportChannelImpls. - IceConnectionState connection_state_ = kIceConnectionConnecting; - bool receiving_ = false; - IceGatheringState gathering_state_ = kIceGatheringNew; - - IceConfig ice_config_; - IceRole ice_role_ = ICEROLE_CONTROLLING; - bool redetermine_role_on_ice_restart_; - uint64_t ice_tiebreaker_ = rtc::CreateRandomId64(); - rtc::CryptoOptions crypto_options_; - rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; - rtc::scoped_refptr certificate_; - rtc::AsyncInvoker invoker_; - - webrtc::MetricsObserverInterface* metrics_observer_ = nullptr; - - webrtc::RtcEventLog* event_log_; - - RTC_DISALLOW_COPY_AND_ASSIGN(TransportController); -}; - -} // namespace cricket - -#endif // PC_TRANSPORTCONTROLLER_H_ diff --git a/pc/transportcontroller_unittest.cc b/pc/transportcontroller_unittest.cc deleted file mode 100644 index 4f38c66b2c..0000000000 --- a/pc/transportcontroller_unittest.cc +++ /dev/null @@ -1,1019 +0,0 @@ -/* - * Copyright 2015 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include -#include - -#include "p2p/base/dtlstransport.h" -#include "p2p/base/fakeportallocator.h" -#include "p2p/base/p2ptransportchannel.h" -#include "p2p/base/portallocator.h" -#include "pc/test/faketransportcontroller.h" -#include "pc/transportcontroller.h" -#include "rtc_base/fakesslidentity.h" -#include "rtc_base/gunit.h" -#include "rtc_base/helpers.h" -#include "rtc_base/sslidentity.h" -#include "rtc_base/thread.h" -#include "test/gtest.h" - -using webrtc::SdpType; - -static const int kTimeout = 100; -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; -static const char kIceUfrag2[] = "TESTICEUFRAG0002"; -static const char kIcePwd2[] = "TESTICEPWD00000000000002"; -static const char kIceUfrag3[] = "TESTICEUFRAG0003"; -static const char kIcePwd3[] = "TESTICEPWD00000000000003"; -static const bool kRtcpMuxEnabled = true; - -namespace cricket { - -// Only subclassing from FakeTransportController because currently that's the -// only way to have a TransportController with fake ICE/DTLS transports. -// -// TODO(deadbeef): Pass a "TransportFactory" or something similar into -// TransportController, instead of using inheritance in this way for testing. -typedef FakeTransportController TransportControllerForTest; - -class TransportControllerTest : public testing::Test, - public sigslot::has_slots<> { - public: - TransportControllerTest() - : transport_controller_(new TransportControllerForTest()), - signaling_thread_(rtc::Thread::Current()) { - ConnectTransportControllerSignals(); - } - - void CreateTransportControllerWithNetworkThread() { - if (!network_thread_) { - network_thread_ = rtc::Thread::CreateWithSocketServer(); - network_thread_->Start(); - } - transport_controller_.reset( - new TransportControllerForTest(network_thread_.get())); - ConnectTransportControllerSignals(); - } - - void ConnectTransportControllerSignals() { - transport_controller_->SignalConnectionState.connect( - this, &TransportControllerTest::OnConnectionState); - transport_controller_->SignalReceiving.connect( - this, &TransportControllerTest::OnReceiving); - transport_controller_->SignalGatheringState.connect( - this, &TransportControllerTest::OnGatheringState); - transport_controller_->SignalCandidatesGathered.connect( - this, &TransportControllerTest::OnCandidatesGathered); - } - - FakeDtlsTransport* CreateFakeDtlsTransport(const std::string& content, - int component) { - DtlsTransportInternal* transport = - transport_controller_->CreateDtlsTransport_n(content, component); - return static_cast(transport); - } - - void DestroyFakeDtlsTransport(const std::string& content, int component) { - transport_controller_->DestroyDtlsTransport_n(content, component); - } - - Candidate CreateCandidate(int component) { - Candidate c; - c.set_address(rtc::SocketAddress("192.168.1.1", 8000)); - c.set_component(1); - c.set_protocol(UDP_PROTOCOL_NAME); - c.set_priority(1); - return c; - } - - // Used for thread hopping test. - void CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread() { - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&TransportControllerTest:: - CreateFakeDtlsTransportsAndCompleteConnection_w, - this)); - } - - void CreateFakeDtlsTransportsAndCompleteConnection_w() { - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - TransportDescription local_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - std::string err; - transport_controller_->SetLocalTransportDescription("audio", local_desc, - SdpType::kOffer, &err); - transport_controller_->SetLocalTransportDescription("video", local_desc, - SdpType::kOffer, &err); - transport_controller_->MaybeStartGathering(); - transport1->fake_ice_transport()->SignalCandidateGathered( - transport1->fake_ice_transport(), CreateCandidate(1)); - transport2->fake_ice_transport()->SignalCandidateGathered( - transport2->fake_ice_transport(), CreateCandidate(1)); - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport2->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport1->fake_ice_transport()->SetConnectionCount(2); - transport2->fake_ice_transport()->SetConnectionCount(2); - transport1->SetReceiving(true); - transport2->SetReceiving(true); - transport1->SetWritable(true); - transport2->SetWritable(true); - transport1->fake_ice_transport()->SetConnectionCount(1); - transport2->fake_ice_transport()->SetConnectionCount(1); - } - - IceConfig CreateIceConfig( - int receiving_timeout, - ContinualGatheringPolicy continual_gathering_policy) { - IceConfig config; - config.receiving_timeout = receiving_timeout; - config.continual_gathering_policy = continual_gathering_policy; - return config; - } - - protected: - void OnConnectionState(IceConnectionState state) { - if (!signaling_thread_->IsCurrent()) { - signaled_on_non_signaling_thread_ = true; - } - connection_state_ = state; - ++connection_state_signal_count_; - } - - void OnReceiving(bool receiving) { - if (!signaling_thread_->IsCurrent()) { - signaled_on_non_signaling_thread_ = true; - } - receiving_ = receiving; - ++receiving_signal_count_; - } - - void OnGatheringState(IceGatheringState state) { - if (!signaling_thread_->IsCurrent()) { - signaled_on_non_signaling_thread_ = true; - } - gathering_state_ = state; - ++gathering_state_signal_count_; - } - - void OnCandidatesGathered(const std::string& transport_name, - const Candidates& candidates) { - if (!signaling_thread_->IsCurrent()) { - signaled_on_non_signaling_thread_ = true; - } - candidates_[transport_name].insert(candidates_[transport_name].end(), - candidates.begin(), candidates.end()); - ++candidates_signal_count_; - } - - std::unique_ptr network_thread_; // Not used for most tests. - std::unique_ptr transport_controller_; - - // Information received from signals from transport controller. - IceConnectionState connection_state_ = kIceConnectionConnecting; - bool receiving_ = false; - IceGatheringState gathering_state_ = kIceGatheringNew; - // transport_name => candidates - std::map candidates_; - // Counts of each signal emitted. - int connection_state_signal_count_ = 0; - int receiving_signal_count_ = 0; - int gathering_state_signal_count_ = 0; - int candidates_signal_count_ = 0; - - // Used to make sure signals only come on signaling thread. - rtc::Thread* const signaling_thread_ = nullptr; - bool signaled_on_non_signaling_thread_ = false; -}; - -TEST_F(TransportControllerTest, TestSetIceConfig) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - - transport_controller_->SetIceConfig( - CreateIceConfig(1000, GATHER_CONTINUALLY)); - EXPECT_EQ(1000, transport1->fake_ice_transport()->receiving_timeout()); - EXPECT_TRUE(transport1->fake_ice_transport()->gather_continually()); - - transport_controller_->SetIceConfig( - CreateIceConfig(1000, GATHER_CONTINUALLY_AND_RECOVER)); - // Test that value stored in controller is applied to new transports. - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - EXPECT_EQ(1000, transport2->fake_ice_transport()->receiving_timeout()); - EXPECT_TRUE(transport2->fake_ice_transport()->gather_continually()); -} - -TEST_F(TransportControllerTest, TestSetSslMaxProtocolVersion) { - EXPECT_TRUE(transport_controller_->SetSslMaxProtocolVersion( - rtc::SSL_PROTOCOL_DTLS_12)); - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - - ASSERT_NE(nullptr, transport); - EXPECT_EQ(rtc::SSL_PROTOCOL_DTLS_12, transport->ssl_max_protocol_version()); - - // Setting max version after transport is created should fail. - EXPECT_FALSE(transport_controller_->SetSslMaxProtocolVersion( - rtc::SSL_PROTOCOL_DTLS_10)); -} - -TEST_F(TransportControllerTest, TestSetIceRole) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - EXPECT_EQ(ICEROLE_CONTROLLING, - transport1->fake_ice_transport()->GetIceRole()); - transport_controller_->SetIceRole(ICEROLE_CONTROLLED); - EXPECT_EQ(ICEROLE_CONTROLLED, transport1->fake_ice_transport()->GetIceRole()); - - // Test that value stored in controller is applied to new transports. - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - EXPECT_EQ(ICEROLE_CONTROLLED, transport2->fake_ice_transport()->GetIceRole()); -} - -// Test that when one transport encounters a role conflict, the ICE role is -// swapped on every transport. -TEST_F(TransportControllerTest, TestIceRoleConflict) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - EXPECT_EQ(ICEROLE_CONTROLLING, - transport1->fake_ice_transport()->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLING, - transport2->fake_ice_transport()->GetIceRole()); - - transport1->fake_ice_transport()->SignalRoleConflict( - transport1->fake_ice_transport()); - EXPECT_EQ(ICEROLE_CONTROLLED, transport1->fake_ice_transport()->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLED, transport2->fake_ice_transport()->GetIceRole()); - - // Should be able to handle a second role conflict. The remote endpoint can - // change its role/tie-breaker when it does an ICE restart. - transport2->fake_ice_transport()->SignalRoleConflict( - transport2->fake_ice_transport()); - EXPECT_EQ(ICEROLE_CONTROLLING, - transport1->fake_ice_transport()->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLING, - transport2->fake_ice_transport()->GetIceRole()); -} - -TEST_F(TransportControllerTest, TestGetSslRole) { - rtc::SSLRole role; - CreateFakeDtlsTransport("audio", 1); - - // Should return false before role has been negotiated. - EXPECT_FALSE(transport_controller_->GetSslRole("audio", &role)); - - // To negotiate an SSL role, need to set a local certificate, and - // local/remote transport descriptions with DTLS info. - rtc::scoped_refptr certificate = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("testing", rtc::KT_ECDSA))); - std::unique_ptr fingerprint( - rtc::SSLFingerprint::CreateFromCertificate(certificate)); - transport_controller_->SetLocalCertificate(certificate); - - // Set the same fingerprint on both sides since the remote fingerprint - // doesn't really matter for this test. - TransportDescription local_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, fingerprint.get()); - TransportDescription remote_desc(std::vector(), kIceUfrag2, - kIcePwd2, ICEMODE_FULL, - CONNECTIONROLE_ACTIVE, fingerprint.get()); - std::string err; - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kOffer, &err)); - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kAnswer, &err)); - - // Finally we can get the role. Should be "server" since the remote - // endpoint's role was "active". - EXPECT_TRUE(transport_controller_->GetSslRole("audio", &role)); - EXPECT_EQ(rtc::SSL_SERVER, role); - - // Lastly, test that GetSslRole returns false for a nonexistent transport. - EXPECT_FALSE(transport_controller_->GetSslRole("video", &role)); -} - -TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) { - rtc::scoped_refptr certificate1 = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))); - rtc::scoped_refptr certificate2 = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT))); - rtc::scoped_refptr returned_certificate; - - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - - EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1)); - EXPECT_TRUE(transport_controller_->GetLocalCertificate( - "audio", &returned_certificate)); - EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(), - returned_certificate->identity()->certificate().ToPEMString()); - - // Should fail if called for a nonexistant transport. - EXPECT_FALSE(transport_controller_->GetLocalCertificate( - "video", &returned_certificate)); - - // Test that identity stored in controller is applied to new transports. - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - EXPECT_TRUE(transport_controller_->GetLocalCertificate( - "video", &returned_certificate)); - EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(), - returned_certificate->identity()->certificate().ToPEMString()); - - // Shouldn't be able to change the identity once set. - EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2)); -} - -TEST_F(TransportControllerTest, TestGetRemoteSSLCertChain) { - rtc::FakeSSLCertificate fake_certificate("fake_data"); - - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - - transport->SetRemoteSSLCertificate(&fake_certificate); - std::unique_ptr returned_cert_chain = - transport_controller_->GetRemoteSSLCertChain("audio"); - EXPECT_TRUE(returned_cert_chain); - EXPECT_EQ(fake_certificate.ToPEMString(), - returned_cert_chain->Get(0).ToPEMString()); - - // Should fail if called for a nonexistant transport. - EXPECT_FALSE(transport_controller_->GetRemoteSSLCertChain("video")); -} - -TEST_F(TransportControllerTest, TestSetLocalTransportDescription) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - TransportDescription local_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - std::string err; - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kOffer, &err)); - // Check that ICE ufrag and pwd were propagated to transport. - EXPECT_EQ(kIceUfrag1, transport->fake_ice_transport()->ice_ufrag()); - EXPECT_EQ(kIcePwd1, transport->fake_ice_transport()->ice_pwd()); - // After setting local description, we should be able to start gathering - // candidates. - transport_controller_->MaybeStartGathering(); - EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); - EXPECT_EQ(1, gathering_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSetRemoteTransportDescription) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - std::string err; - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - // Check that ICE ufrag and pwd were propagated to transport. - EXPECT_EQ(kIceUfrag1, transport->fake_ice_transport()->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd1, transport->fake_ice_transport()->remote_ice_pwd()); -} - -TEST_F(TransportControllerTest, TestAddRemoteCandidates) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - Candidates candidates; - candidates.push_back(CreateCandidate(1)); - std::string err; - EXPECT_TRUE( - transport_controller_->AddRemoteCandidates("audio", candidates, &err)); - EXPECT_EQ(1U, transport->fake_ice_transport()->remote_candidates().size()); -} - -TEST_F(TransportControllerTest, TestReadyForRemoteCandidates) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - // We expect to be ready for remote candidates only after local and remote - // descriptions are set. - EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio")); - - std::string err; - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio")); - - TransportDescription local_desc(std::vector(), kIceUfrag2, - kIcePwd2, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, &err)); - EXPECT_TRUE(transport_controller_->ReadyForRemoteCandidates("audio")); -} - -TEST_F(TransportControllerTest, TestGetStats) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("audio", 2); - ASSERT_NE(nullptr, transport2); - FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport3); - - TransportStats stats; - EXPECT_TRUE(transport_controller_->GetStats("audio", &stats)); - EXPECT_EQ("audio", stats.transport_name); - EXPECT_EQ(2U, stats.channel_stats.size()); -} - -// Test that a "transport" from a stats perspective (combination of RTP/RTCP -// transports) goes away when all references to its transports are gone. -TEST_F(TransportControllerTest, TestCreateAndDestroyFakeDtlsTransport) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport2); - ASSERT_EQ(transport1, transport2); - FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("audio", 2); - ASSERT_NE(nullptr, transport3); - - // Using GetStats to check if transport is destroyed from an outside class's - // perspective. - TransportStats stats; - EXPECT_TRUE(transport_controller_->GetStats("audio", &stats)); - DestroyFakeDtlsTransport("audio", 2); - DestroyFakeDtlsTransport("audio", 1); - EXPECT_TRUE(transport_controller_->GetStats("audio", &stats)); - DestroyFakeDtlsTransport("audio", 1); - EXPECT_FALSE(transport_controller_->GetStats("audio", &stats)); -} - -TEST_F(TransportControllerTest, TestSignalConnectionStateFailed) { - // Need controlling ICE role to get in failed state. - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - // Should signal "failed" if any transport failed; transport is considered - // failed - // if it previously had a connection but now has none, and gathering is - // complete. - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport1->fake_ice_transport()->SetConnectionCount(1); - transport1->fake_ice_transport()->SetConnectionCount(0); - EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout); - EXPECT_EQ(1, connection_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalConnectionStateConnected) { - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 2); - ASSERT_NE(nullptr, transport3); - - // First, have one transport connect, and another fail, to ensure that - // the first transport connecting didn't trigger a "connected" state signal. - // We should only get a signal when all are connected. - transport1->fake_ice_transport()->SetConnectionCount(2); - transport1->SetWritable(true); - transport3->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport3->fake_ice_transport()->SetConnectionCount(1); - transport3->fake_ice_transport()->SetConnectionCount(0); - EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout); - // Signal count of 1 means that the only signal emitted was "failed". - EXPECT_EQ(1, connection_state_signal_count_); - - // Destroy the failed transport to return to "connecting" state. - DestroyFakeDtlsTransport("video", 2); - EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout); - EXPECT_EQ(2, connection_state_signal_count_); - - // Make the remaining transport reach a connected state. - transport2->fake_ice_transport()->SetConnectionCount(2); - transport2->SetWritable(true); - EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout); - EXPECT_EQ(3, connection_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalConnectionStateComplete) { - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("video", 2); - ASSERT_NE(nullptr, transport3); - - // Similar to above test, but we're now reaching the completed state, which - // means only one connection per FakeDtlsTransport. - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport1->fake_ice_transport()->SetConnectionCount(1); - transport1->SetWritable(true); - transport3->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport3->fake_ice_transport()->SetConnectionCount(1); - transport3->fake_ice_transport()->SetConnectionCount(0); - EXPECT_EQ_WAIT(kIceConnectionFailed, connection_state_, kTimeout); - // Signal count of 1 means that the only signal emitted was "failed". - EXPECT_EQ(1, connection_state_signal_count_); - - // Destroy the failed transport to return to "connecting" state. - DestroyFakeDtlsTransport("video", 2); - EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout); - EXPECT_EQ(2, connection_state_signal_count_); - - // Make the remaining transport reach a connected state. - transport2->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport2->fake_ice_transport()->SetConnectionCount(2); - transport2->SetWritable(true); - EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout); - EXPECT_EQ(3, connection_state_signal_count_); - - // Finally, transition to completed state. - transport2->fake_ice_transport()->SetConnectionCount(1); - EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); - EXPECT_EQ(4, connection_state_signal_count_); -} - -// Make sure that if we're "connected" and remove a transport, we stay in the -// "connected" state. -TEST_F(TransportControllerTest, TestDestroyTransportAndStayConnected) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport1->fake_ice_transport()->SetConnectionCount(2); - transport1->SetWritable(true); - transport2->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport2->fake_ice_transport()->SetConnectionCount(2); - transport2->SetWritable(true); - EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout); - EXPECT_EQ(1, connection_state_signal_count_); - - // Destroy one transport, then "complete" the other one, so we reach - // a known state. - DestroyFakeDtlsTransport("video", 1); - transport1->fake_ice_transport()->SetConnectionCount(1); - EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); - // Signal count of 2 means the deletion didn't cause any unexpected signals - EXPECT_EQ(2, connection_state_signal_count_); -} - -// If we destroy the last/only transport, we should simply transition to -// "connecting". -TEST_F(TransportControllerTest, TestDestroyLastTransportWhileConnected) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - - transport->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport->fake_ice_transport()->SetConnectionCount(2); - transport->SetWritable(true); - EXPECT_EQ_WAIT(kIceConnectionConnected, connection_state_, kTimeout); - EXPECT_EQ(1, connection_state_signal_count_); - - DestroyFakeDtlsTransport("audio", 1); - EXPECT_EQ_WAIT(kIceConnectionConnecting, connection_state_, kTimeout); - // Signal count of 2 means the deletion didn't cause any unexpected signals - EXPECT_EQ(2, connection_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalReceiving) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - // Should signal receiving as soon as any transport is receiving. - transport1->SetReceiving(true); - EXPECT_TRUE_WAIT(receiving_, kTimeout); - EXPECT_EQ(1, receiving_signal_count_); - - transport2->SetReceiving(true); - transport1->SetReceiving(false); - transport2->SetReceiving(false); - EXPECT_TRUE_WAIT(!receiving_, kTimeout); - EXPECT_EQ(2, receiving_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalGatheringStateGathering) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - transport->fake_ice_transport()->MaybeStartGathering(); - // Should be in the gathering state as soon as any transport starts gathering. - EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); - EXPECT_EQ(1, gathering_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalGatheringStateComplete) { - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - FakeDtlsTransport* transport3 = CreateFakeDtlsTransport("data", 1); - ASSERT_NE(nullptr, transport3); - - transport3->fake_ice_transport()->MaybeStartGathering(); - EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); - EXPECT_EQ(1, gathering_state_signal_count_); - - // Have one transport finish gathering, then destroy it, to make sure - // gathering - // completion wasn't signalled if only one transport finished gathering. - transport3->fake_ice_transport()->SetCandidatesGatheringComplete(); - DestroyFakeDtlsTransport("data", 1); - EXPECT_EQ_WAIT(kIceGatheringNew, gathering_state_, kTimeout); - EXPECT_EQ(2, gathering_state_signal_count_); - - // Make remaining transports start and then finish gathering. - transport1->fake_ice_transport()->MaybeStartGathering(); - transport2->fake_ice_transport()->MaybeStartGathering(); - EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); - EXPECT_EQ(3, gathering_state_signal_count_); - - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - transport2->fake_ice_transport()->SetCandidatesGatheringComplete(); - EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout); - EXPECT_EQ(4, gathering_state_signal_count_); -} - -// Test that when the last transport that hasn't finished connecting and/or -// gathering is destroyed, the aggregate state jumps to "completed". This can -// happen if, for example, we have an audio and video transport, the audio -// transport completes, then we start bundling video on the audio transport. -TEST_F(TransportControllerTest, - TestSignalingWhenLastIncompleteTransportDestroyed) { - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport1); - FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); - ASSERT_NE(nullptr, transport2); - - transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); - EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); - EXPECT_EQ(1, gathering_state_signal_count_); - - transport1->fake_ice_transport()->SetConnectionCount(1); - transport1->SetWritable(true); - DestroyFakeDtlsTransport("video", 1); - EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); - EXPECT_EQ(1, connection_state_signal_count_); - EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout); - EXPECT_EQ(2, gathering_state_signal_count_); -} - -TEST_F(TransportControllerTest, TestSignalCandidatesGathered) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - - // Transport won't signal candidates until it has a local description. - TransportDescription local_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - std::string err; - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kOffer, &err)); - transport_controller_->MaybeStartGathering(); - - transport->fake_ice_transport()->SignalCandidateGathered( - transport->fake_ice_transport(), CreateCandidate(1)); - EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout); - EXPECT_EQ(1U, candidates_["audio"].size()); -} - -TEST_F(TransportControllerTest, TestSignalingOccursOnSignalingThread) { - CreateTransportControllerWithNetworkThread(); - CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread(); - - // connecting --> connected --> completed - EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); - EXPECT_EQ(2, connection_state_signal_count_); - - EXPECT_TRUE_WAIT(receiving_, kTimeout); - EXPECT_EQ(1, receiving_signal_count_); - - // new --> gathering --> complete - EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout); - EXPECT_EQ(2, gathering_state_signal_count_); - - EXPECT_EQ_WAIT(1U, candidates_["audio"].size(), kTimeout); - EXPECT_EQ_WAIT(1U, candidates_["video"].size(), kTimeout); - EXPECT_EQ(2, candidates_signal_count_); - - EXPECT_TRUE(!signaled_on_non_signaling_thread_); -} - -// Older versions of Chrome expect the ICE role to be re-determined when an -// ICE restart occurs, and also don't perform conflict resolution correctly, -// so for now we can't safely stop doing this. -// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676 -// TODO(deadbeef): Remove this when these old versions of Chrome reach a low -// enough population. -TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - std::string err; - // Do an initial offer answer, so that the next offer is an ICE restart. - transport_controller_->SetIceRole(ICEROLE_CONTROLLED); - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - TransportDescription local_desc(std::vector(), kIceUfrag2, - kIcePwd2, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole()); - - // The endpoint that initiated an ICE restart should take the controlling - // role. - TransportDescription ice_restart_desc(std::vector(), kIceUfrag3, - kIcePwd3, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", ice_restart_desc, SdpType::kOffer, &err)); - EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); -} - -// Test that if the TransportController was created with the -// |redetermine_role_on_ice_restart| parameter set to false, the role is *not* -// redetermined on an ICE restart. -TEST_F(TransportControllerTest, IceRoleNotRedetermined) { - bool redetermine_role = false; - transport_controller_.reset(new TransportControllerForTest(redetermine_role)); - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - std::string err; - // Do an initial offer answer, so that the next offer is an ICE restart. - transport_controller_->SetIceRole(ICEROLE_CONTROLLED); - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - TransportDescription local_desc(std::vector(), kIceUfrag2, - kIcePwd2, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole()); - - // The endpoint that initiated an ICE restart should keep the existing role. - TransportDescription ice_restart_desc(std::vector(), kIceUfrag3, - kIcePwd3, ICEMODE_FULL, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", ice_restart_desc, SdpType::kOffer, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole()); -} - -// Tests ICE role is reversed after receiving ice-lite from remote. -TEST_F(TransportControllerTest, TestSetRemoteIceLiteInOffer) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - std::string err; - - transport_controller_->SetIceRole(ICEROLE_CONTROLLED); - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_LITE, - CONNECTIONROLE_ACTPASS, nullptr); - EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, nullptr)); - - EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); - EXPECT_EQ(ICEMODE_LITE, transport->fake_ice_transport()->remote_ice_mode()); -} - -// Tests ice-lite in remote answer. -TEST_F(TransportControllerTest, TestSetRemoteIceLiteInAnswer) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - std::string err; - - transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kOffer, nullptr)); - EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); - // Transports will be created in ICEFULL_MODE. - EXPECT_EQ(ICEMODE_FULL, transport->fake_ice_transport()->remote_ice_mode()); - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_LITE, CONNECTIONROLE_NONE, - nullptr); - ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kAnswer, nullptr)); - EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); - // After receiving remote description with ICEMODE_LITE, transport should - // have mode set to ICEMODE_LITE. - EXPECT_EQ(ICEMODE_LITE, transport->fake_ice_transport()->remote_ice_mode()); -} - -// Tests that the ICE role remains "controlling" if a subsequent offer that -// does an ICE restart is received from an ICE lite endpoint. Regression test -// for: https://crbug.com/710760 -TEST_F(TransportControllerTest, - IceRoleIsControllingAfterIceRestartFromIceLiteEndpoint) { - FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, transport); - std::string err; - - // Initial offer/answer. - TransportDescription remote_desc(std::vector(), kIceUfrag1, - kIcePwd1, ICEMODE_LITE, - CONNECTIONROLE_ACTPASS, nullptr); - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, nullptr)); - // Subsequent ICE restart offer/answer. - remote_desc.ice_ufrag = kIceUfrag2; - remote_desc.ice_pwd = kIcePwd2; - local_desc.ice_ufrag = kIceUfrag2; - local_desc.ice_pwd = kIcePwd2; - ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kOffer, &err)); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kAnswer, nullptr)); - - EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); -} - -// Tests SetNeedsIceRestartFlag and NeedsIceRestart, setting the flag and then -// initiating an ICE restart for one of the transports. -TEST_F(TransportControllerTest, NeedsIceRestart) { - CreateFakeDtlsTransport("audio", 1); - CreateFakeDtlsTransport("video", 1); - - // Do initial offer/answer so there's something to restart. - TransportDescription local_desc(kIceUfrag1, kIcePwd1); - TransportDescription remote_desc(kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "video", local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription( - "audio", remote_desc, SdpType::kAnswer, nullptr)); - ASSERT_TRUE(transport_controller_->SetRemoteTransportDescription( - "video", remote_desc, SdpType::kAnswer, nullptr)); - - // Initially NeedsIceRestart should return false. - EXPECT_FALSE(transport_controller_->NeedsIceRestart("audio")); - EXPECT_FALSE(transport_controller_->NeedsIceRestart("video")); - - // Set the needs-ice-restart flag and verify NeedsIceRestart starts returning - // true. - transport_controller_->SetNeedsIceRestartFlag(); - EXPECT_TRUE(transport_controller_->NeedsIceRestart("audio")); - EXPECT_TRUE(transport_controller_->NeedsIceRestart("video")); - // For a nonexistent transport, false should be returned. - EXPECT_FALSE(transport_controller_->NeedsIceRestart("deadbeef")); - - // Do ICE restart but only for audio. - TransportDescription ice_restart_local_desc(kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "audio", ice_restart_local_desc, SdpType::kOffer, nullptr)); - ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( - "video", local_desc, SdpType::kOffer, nullptr)); - // NeedsIceRestart should still be true for video. - EXPECT_FALSE(transport_controller_->NeedsIceRestart("audio")); - EXPECT_TRUE(transport_controller_->NeedsIceRestart("video")); -} - -enum class RTPTransportType { kSdes, kDtlsSrtp }; -std::ostream& operator<<(std::ostream& out, RTPTransportType value) { - switch (value) { - case RTPTransportType::kSdes: - return out << "SDES"; - case RTPTransportType::kDtlsSrtp: - return out << "DTLS-SRTP"; - } - return out; -} - -// Tests the TransportController can correctly create and destroy the RTP -// transports. -class TransportControllerRTPTransportTest - : public TransportControllerTest, - public ::testing::WithParamInterface { - protected: - // Helper function used to create an RTP layer transport. - webrtc::RtpTransportInternal* CreateRtpTransport( - const std::string& transport_name) { - RTPTransportType type = GetParam(); - switch (type) { - case RTPTransportType::kSdes: - return transport_controller_->CreateSdesTransport(transport_name, - kRtcpMuxEnabled); - case RTPTransportType::kDtlsSrtp: - return transport_controller_->CreateDtlsSrtpTransport(transport_name, - kRtcpMuxEnabled); - } - return nullptr; - } -}; - -// Tests that creating transports with the same name will cause the -// second call to re-use the transport created in the first call. -TEST_P(TransportControllerRTPTransportTest, CreateTransportsWithReference) { - const std::string transport_name = "transport"; - webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name); - webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name); - EXPECT_NE(nullptr, transport1); - EXPECT_NE(nullptr, transport2); - // The TransportController is expected to return the existing one when using - // the same transport name. - EXPECT_EQ(transport1, transport2); - transport_controller_->DestroyTransport(transport_name); - transport_controller_->DestroyTransport(transport_name); -} - -// Tests that creating different type of RTP transports with same name is not -// allowed. -TEST_P(TransportControllerRTPTransportTest, - CreateDifferentTypeOfTransportsWithSameName) { - const std::string transport_name = "transport"; - webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name); - EXPECT_NE(nullptr, transport1); - RTPTransportType type = GetParam(); - switch (type) { - case RTPTransportType::kSdes: - EXPECT_EQ(nullptr, transport_controller_->CreateDtlsSrtpTransport( - transport_name, kRtcpMuxEnabled)); - break; - case RTPTransportType::kDtlsSrtp: - EXPECT_EQ(nullptr, transport_controller_->CreateSdesTransport( - transport_name, kRtcpMuxEnabled)); - break; - default: - ASSERT_TRUE(false); - } - transport_controller_->DestroyTransport(transport_name); -} - -// Tests the RTP transport is not actually destroyed if references still exist. -TEST_P(TransportControllerRTPTransportTest, DestroyTransportWithReference) { - const std::string transport_name = "transport"; - webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name); - webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name); - EXPECT_NE(nullptr, transport1); - EXPECT_NE(nullptr, transport2); - transport_controller_->DestroyTransport(transport_name); - EXPECT_NE(nullptr, transport1->rtp_packet_transport()); - EXPECT_EQ(nullptr, transport1->rtcp_packet_transport()); - transport_controller_->DestroyTransport(transport_name); -} - -// Tests the RTP is actually destroyed if there is no reference to it. -// Disabled because of sometimes not working on Windows. -// https://bugs.webrtc.org/34942 -TEST_P(TransportControllerRTPTransportTest, - DISABLED_DestroyTransportWithNoReference) { - const std::string transport_name = "transport"; - webrtc::RtpTransportInternal* transport1 = CreateRtpTransport(transport_name); - webrtc::RtpTransportInternal* transport2 = CreateRtpTransport(transport_name); - EXPECT_NE(nullptr, transport1); - EXPECT_NE(nullptr, transport2); - transport_controller_->DestroyTransport(transport_name); - transport_controller_->DestroyTransport(transport_name); -#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) - EXPECT_DEATH(transport1->IsWritable(false), /*error_message=*/""); -#endif -} - -INSTANTIATE_TEST_CASE_P(TransportControllerTest, - TransportControllerRTPTransportTest, - ::testing::Values(RTPTransportType::kSdes, - RTPTransportType::kDtlsSrtp)); - -} // namespace cricket