diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc index eb6f606cf2..526f7cc3ab 100644 --- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc +++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc @@ -15,7 +15,6 @@ #include "webrtc/base/byteorder.h" #include "webrtc/base/gunit.h" #include "webrtc/call/call.h" -#include "webrtc/p2p/base/faketransportcontroller.h" #include "webrtc/test/field_trial.h" #include "webrtc/logging/rtc_event_log/rtc_event_log.h" #include "webrtc/media/base/fakemediaengine.h" diff --git a/webrtc/media/sctp/sctptransport_unittest.cc b/webrtc/media/sctp/sctptransport_unittest.cc index 2f34240fd6..4ccc24e27a 100644 --- a/webrtc/media/sctp/sctptransport_unittest.cc +++ b/webrtc/media/sctp/sctptransport_unittest.cc @@ -24,7 +24,7 @@ #include "webrtc/base/ssladapter.h" #include "webrtc/base/thread.h" #include "webrtc/media/sctp/sctptransport.h" -#include "webrtc/p2p/base/faketransportcontroller.h" +#include "webrtc/p2p/base/fakedtlstransport.h" namespace { static const int kDefaultTimeout = 10000; // 10 seconds. diff --git a/webrtc/p2p/BUILD.gn b/webrtc/p2p/BUILD.gn index 04e9b17908..9967b1212e 100644 --- a/webrtc/p2p/BUILD.gn +++ b/webrtc/p2p/BUILD.gn @@ -144,6 +144,9 @@ if (rtc_include_tests) { sources = [ "base/asyncstuntcpsocket_unittest.cc", "base/dtlstransportchannel_unittest.cc", + "base/fakedtlstransport.h", + "base/fakeicetransport.h", + "base/fakepackettransport.h", "base/fakeportallocator.h", "base/faketransportcontroller.h", "base/jseptransport_unittest.cc", diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc index 7034343174..4473d32893 100644 --- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc +++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc @@ -12,7 +12,7 @@ #include #include "webrtc/p2p/base/dtlstransportchannel.h" -#include "webrtc/p2p/base/faketransportcontroller.h" +#include "webrtc/p2p/base/fakeicetransport.h" #include "webrtc/p2p/base/packettransportinterface.h" #include "webrtc/base/checks.h" #include "webrtc/base/common.h" diff --git a/webrtc/p2p/base/fakecandidatepair.h b/webrtc/p2p/base/fakecandidatepair.h new file mode 100644 index 0000000000..73e6c6794d --- /dev/null +++ b/webrtc/p2p/base/fakecandidatepair.h @@ -0,0 +1,54 @@ +/* + * Copyright 2017 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 WEBRTC_P2P_BASE_FAKECANDIDATEPAIR_H_ +#define WEBRTC_P2P_BASE_FAKECANDIDATEPAIR_H_ + +#include + +#include "webrtc/p2p/base/candidate.h" +#include "webrtc/p2p/base/candidatepairinterface.h" + +namespace cricket { + +// Fake candidate pair class, which can be passed to BaseChannel for testing +// purposes. +class FakeCandidatePair : public CandidatePairInterface { + public: + FakeCandidatePair(const Candidate& local_candidate, + const Candidate& remote_candidate) + : local_candidate_(local_candidate), + remote_candidate_(remote_candidate) {} + const Candidate& local_candidate() const override { return local_candidate_; } + const Candidate& remote_candidate() const override { + return remote_candidate_; + } + + static std::unique_ptr Create( + const rtc::SocketAddress& local_address, + int16_t local_network_id, + const rtc::SocketAddress& remote_address, + int16_t remote_network_id) { + Candidate local_candidate(0, "udp", local_address, 0u, "", "", "local", 0, + "foundation", local_network_id, 0); + Candidate remote_candidate(0, "udp", remote_address, 0u, "", "", "local", 0, + "foundation", remote_network_id, 0); + return std::unique_ptr( + new FakeCandidatePair(local_candidate, remote_candidate)); + } + + private: + Candidate local_candidate_; + Candidate remote_candidate_; +}; + +} // namespace cricket + +#endif // WEBRTC_P2P_BASE_FAKECANDIDATEPAIR_H_ diff --git a/webrtc/p2p/base/fakedtlstransport.h b/webrtc/p2p/base/fakedtlstransport.h new file mode 100644 index 0000000000..1fe66ec1b2 --- /dev/null +++ b/webrtc/p2p/base/fakedtlstransport.h @@ -0,0 +1,270 @@ +/* + * Copyright 2017 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 WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ +#define WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ + +#include +#include +#include + +#include "webrtc/base/fakesslidentity.h" +#include "webrtc/p2p/base/dtlstransportinternal.h" +#include "webrtc/p2p/base/fakeicetransport.h" + +namespace cricket { + +// Fake DTLS transport which is implemented by wrapping a fake ICE transport. +// Doesn't interact directly with fake ICE transport for anything other than +// sending packets. +class FakeDtlsTransport : public DtlsTransportInternal { + public: + explicit FakeDtlsTransport(FakeIceTransport* ice_transport) + : ice_transport_(ice_transport), + transport_name_(ice_transport->transport_name()), + component_(ice_transport->component()), + dtls_fingerprint_("", nullptr, 0) { + ice_transport_->SignalReadPacket.connect( + this, &FakeDtlsTransport::OnIceTransportReadPacket); + } + + // If this constructor is called, a new fake ICE transport will be created, + // and this FakeDtlsTransport will take the ownership. + explicit FakeDtlsTransport(const std::string& name, int component) + : owned_ice_transport_(new FakeIceTransport(name, component)), + transport_name_(owned_ice_transport_->transport_name()), + component_(owned_ice_transport_->component()), + dtls_fingerprint_("", nullptr, 0) { + ice_transport_ = owned_ice_transport_.get(); + ice_transport_->SignalReadPacket.connect( + this, &FakeDtlsTransport::OnIceTransportReadPacket); + } + + ~FakeDtlsTransport() override { + if (dest_ && dest_->dest_ == this) { + dest_->dest_ = nullptr; + } + } + + // Get inner fake ICE transport. + FakeIceTransport* fake_ice_transport() { return ice_transport_; } + + // If async, will send packets by "Post"-ing to message queue instead of + // synchronously "Send"-ing. + void SetAsync(bool async) { ice_transport_->SetAsync(async); } + void SetAsyncDelay(int delay_ms) { ice_transport_->SetAsyncDelay(delay_ms); } + + // SetWritable, SetReceiving and SetDestination are the main methods that can + // be used for testing, to simulate connectivity or lack thereof. + void SetWritable(bool writable) { + ice_transport_->SetWritable(writable); + set_writable(writable); + } + void SetReceiving(bool receiving) { + ice_transport_->SetReceiving(receiving); + set_receiving(receiving); + } + + // Simulates the two DTLS transports connecting to each other. + // If |asymmetric| is true this method only affects this FakeDtlsTransport. + // If false, it affects |dest| as well. + void SetDestination(FakeDtlsTransport* dest, bool asymmetric = false) { + if (dest == dest_) { + return; + } + RTC_DCHECK(!dest || !dest_) + << "Changing fake destination from one to another is not supported."; + if (dest && !dest_) { + // This simulates the DTLS handshake. + dest_ = dest; + if (local_cert_ && dest_->local_cert_) { + do_dtls_ = true; + NegotiateSrtpCiphers(); + } + SetWritable(true); + if (!asymmetric) { + dest->SetDestination(this, true); + } + ice_transport_->SetDestination( + static_cast(dest->ice_transport()), asymmetric); + } else { + // Simulates loss of connectivity, by asymmetrically forgetting dest_. + dest_ = nullptr; + SetWritable(false); + ice_transport_->SetDestination(nullptr, asymmetric); + } + } + + // Fake DtlsTransportInternal implementation. + DtlsTransportState dtls_state() const override { return dtls_state_; } + const std::string& transport_name() const override { return transport_name_; } + int component() const override { return component_; } + const rtc::SSLFingerprint& dtls_fingerprint() const { + return dtls_fingerprint_; + } + bool SetRemoteFingerprint(const std::string& alg, + const uint8_t* digest, + size_t digest_len) override { + dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); + return true; + } + bool SetSslRole(rtc::SSLRole role) override { + ssl_role_ = role; + return true; + } + bool GetSslRole(rtc::SSLRole* role) const override { + *role = ssl_role_; + return true; + } + bool SetLocalCertificate( + const rtc::scoped_refptr& certificate) override { + local_cert_ = certificate; + return true; + } + void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { + remote_cert_ = cert; + } + bool IsDtlsActive() const override { return do_dtls_; } + bool SetSrtpCryptoSuites(const std::vector& ciphers) override { + srtp_ciphers_ = ciphers; + return true; + } + bool GetSrtpCryptoSuite(int* crypto_suite) override { + if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { + *crypto_suite = chosen_crypto_suite_; + return true; + } + return false; + } + bool GetSslCipherSuite(int* cipher_suite) override { return false; } + rtc::scoped_refptr GetLocalCertificate() const override { + return local_cert_; + } + std::unique_ptr GetRemoteSSLCertificate() + const override { + return remote_cert_ ? std::unique_ptr( + remote_cert_->GetReference()) + : nullptr; + } + bool ExportKeyingMaterial(const std::string& label, + const uint8_t* context, + size_t context_len, + bool use_context, + uint8_t* result, + size_t result_len) override { + if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { + memset(result, 0xff, result_len); + return true; + } + + return false; + } + void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { + ssl_max_version_ = version; + } + rtc::SSLProtocolVersion ssl_max_protocol_version() const { + return ssl_max_version_; + } + bool SetSrtpCiphers(const std::vector& ciphers) override { + std::vector crypto_suites; + for (const auto cipher : ciphers) { + crypto_suites.push_back(rtc::SrtpCryptoSuiteFromName(cipher)); + } + return SetSrtpCryptoSuites(crypto_suites); + } + + IceTransportInternal* ice_transport() override { return ice_transport_; } + + // PacketTransportInterface implementation, which passes through to fake ICE + // transport for sending actual packets. + bool writable() const override { return writable_; } + bool receiving() const override { return receiving_; } + int SendPacket(const char* data, + size_t len, + const rtc::PacketOptions& options, + int flags) override { + // We expect only SRTP packets to be sent through this interface. + if (flags != PF_SRTP_BYPASS && flags != 0) { + return -1; + } + return ice_transport_->SendPacket(data, len, options, flags); + } + int SetOption(rtc::Socket::Option opt, int value) override { + return ice_transport_->SetOption(opt, value); + } + bool GetOption(rtc::Socket::Option opt, int* value) override { + return ice_transport_->GetOption(opt, value); + } + int GetError() override { return ice_transport_->GetError(); } + + private: + void OnIceTransportReadPacket(PacketTransportInterface* ice_, + const char* data, + size_t len, + const rtc::PacketTime& time, + int flags) { + SignalReadPacket(this, data, len, time, flags); + } + + void NegotiateSrtpCiphers() { + for (std::vector::const_iterator it1 = srtp_ciphers_.begin(); + it1 != srtp_ciphers_.end(); ++it1) { + for (std::vector::const_iterator it2 = dest_->srtp_ciphers_.begin(); + it2 != dest_->srtp_ciphers_.end(); ++it2) { + if (*it1 == *it2) { + chosen_crypto_suite_ = *it1; + return; + } + } + } + } + + void set_receiving(bool receiving) { + if (receiving_ == receiving) { + return; + } + receiving_ = receiving; + SignalReceivingState(this); + } + + void set_writable(bool writable) { + if (writable_ == writable) { + return; + } + writable_ = writable; + if (writable_) { + SignalReadyToSend(this); + } + SignalWritableState(this); + } + + FakeIceTransport* ice_transport_; + std::unique_ptr owned_ice_transport_; + std::string transport_name_; + int component_; + FakeDtlsTransport* dest_ = nullptr; + rtc::scoped_refptr local_cert_; + rtc::FakeSSLCertificate* remote_cert_ = nullptr; + bool do_dtls_ = false; + std::vector srtp_ciphers_; + int chosen_crypto_suite_ = rtc::SRTP_INVALID_CRYPTO_SUITE; + rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; + rtc::SSLFingerprint dtls_fingerprint_; + rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; + + DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; + + bool receiving_ = false; + bool writable_ = false; +}; + +} // namespace cricket + +#endif // WEBRTC_P2P_BASE_FAKEDTLSTRANSPORT_H_ diff --git a/webrtc/p2p/base/fakeicetransport.h b/webrtc/p2p/base/fakeicetransport.h new file mode 100644 index 0000000000..8daf33b803 --- /dev/null +++ b/webrtc/p2p/base/fakeicetransport.h @@ -0,0 +1,236 @@ +/* + * Copyright 2017 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 WEBRTC_P2P_BASE_FAKEICETRANSPORT_H_ +#define WEBRTC_P2P_BASE_FAKEICETRANSPORT_H_ + +#include + +#include "webrtc/base/asyncinvoker.h" +#include "webrtc/base/copyonwritebuffer.h" +#include "webrtc/p2p/base/icetransportinternal.h" + +namespace cricket { + +class FakeIceTransport : public IceTransportInternal { + public: + explicit FakeIceTransport(const std::string& name, int component) + : name_(name), component_(component) {} + ~FakeIceTransport() override { + if (dest_ && dest_->dest_ == this) { + dest_->dest_ = nullptr; + } + } + + // If async, will send packets by "Post"-ing to message queue instead of + // synchronously "Send"-ing. + void SetAsync(bool async) { async_ = async; } + void SetAsyncDelay(int delay_ms) { async_delay_ms_ = delay_ms; } + + // SetWritable, SetReceiving and SetDestination are the main methods that can + // be used for testing, to simulate connectivity or lack thereof. + void SetWritable(bool writable) { set_writable(writable); } + void SetReceiving(bool receiving) { set_receiving(receiving); } + + // Simulates the two transports connecting to each other. + // If |asymmetric| is true this method only affects this FakeIceTransport. + // If false, it affects |dest| as well. + void SetDestination(FakeIceTransport* dest, bool asymmetric = false) { + if (dest == dest_) { + return; + } + RTC_DCHECK(!dest || !dest_) + << "Changing fake destination from one to another is not supported."; + if (dest) { + // This simulates the delivery of candidates. + dest_ = dest; + set_writable(true); + if (!asymmetric) { + dest->SetDestination(this, true); + } + } else { + // Simulates loss of connectivity, by asymmetrically forgetting dest_. + dest_ = nullptr; + set_writable(false); + } + } + + void SetConnectionCount(size_t connection_count) { + size_t old_connection_count = connection_count_; + connection_count_ = connection_count; + if (connection_count) { + had_connection_ = true; + } + // In this fake transport channel, |connection_count_| determines the + // transport state. + if (connection_count_ < old_connection_count) { + SignalStateChanged(this); + } + } + + void SetCandidatesGatheringComplete() { + if (gathering_state_ != kIceGatheringComplete) { + gathering_state_ = kIceGatheringComplete; + SignalGatheringState(this); + } + } + + // Convenience functions for accessing ICE config and other things. + int receiving_timeout() const { return ice_config_.receiving_timeout; } + bool gather_continually() const { return ice_config_.gather_continually(); } + const Candidates& remote_candidates() const { return remote_candidates_; } + + // Fake IceTransportInternal implementation. + const std::string& transport_name() const override { return name_; } + int component() const override { return component_; } + uint64_t IceTiebreaker() const { return tiebreaker_; } + IceMode remote_ice_mode() const { return remote_ice_mode_; } + const std::string& ice_ufrag() const { return ice_ufrag_; } + const std::string& ice_pwd() const { return ice_pwd_; } + const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; } + const std::string& remote_ice_pwd() const { return remote_ice_pwd_; } + + IceTransportState GetState() const override { + if (connection_count_ == 0) { + return had_connection_ ? IceTransportState::STATE_FAILED + : IceTransportState::STATE_INIT; + } + + if (connection_count_ == 1) { + return IceTransportState::STATE_COMPLETED; + } + + return IceTransportState::STATE_CONNECTING; + } + + void SetIceRole(IceRole role) override { role_ = role; } + IceRole GetIceRole() const override { return role_; } + void SetIceTiebreaker(uint64_t tiebreaker) override { + tiebreaker_ = tiebreaker; + } + void SetIceParameters(const IceParameters& ice_params) override { + ice_ufrag_ = ice_params.ufrag; + ice_pwd_ = ice_params.pwd; + } + void SetRemoteIceParameters(const IceParameters& params) override { + remote_ice_ufrag_ = params.ufrag; + remote_ice_pwd_ = params.pwd; + } + + void SetRemoteIceMode(IceMode mode) override { remote_ice_mode_ = mode; } + + void MaybeStartGathering() override { + if (gathering_state_ == kIceGatheringNew) { + gathering_state_ = kIceGatheringGathering; + SignalGatheringState(this); + } + } + + IceGatheringState gathering_state() const override { + return gathering_state_; + } + + void SetIceConfig(const IceConfig& config) override { ice_config_ = config; } + + void AddRemoteCandidate(const Candidate& candidate) override { + remote_candidates_.push_back(candidate); + } + void RemoveRemoteCandidate(const Candidate& candidate) override {} + + bool GetStats(ConnectionInfos* infos) override { + ConnectionInfo info; + infos->clear(); + infos->push_back(info); + return true; + } + + void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override { + } + + // Fake PacketTransportInterface implementation. + bool writable() const override { return writable_; } + bool receiving() const override { return receiving_; } + int SendPacket(const char* data, + size_t len, + const rtc::PacketOptions& options, + int flags) override { + if (!dest_) { + return -1; + } + rtc::CopyOnWriteBuffer packet(data, len); + if (async_) { + invoker_.AsyncInvokeDelayed( + RTC_FROM_HERE, rtc::Thread::Current(), + rtc::Bind(&FakeIceTransport::SendPacketInternal, this, packet), + async_delay_ms_); + } else { + SendPacketInternal(packet); + } + rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); + SignalSentPacket(this, sent_packet); + return static_cast(len); + } + int SetOption(rtc::Socket::Option opt, int value) override { return true; } + bool GetOption(rtc::Socket::Option opt, int* value) override { return true; } + int GetError() override { return 0; } + + private: + void set_writable(bool writable) { + if (writable_ == writable) { + return; + } + LOG(INFO) << "set_writable from:" << writable_ << " to " << writable; + writable_ = writable; + if (writable_) { + SignalReadyToSend(this); + } + SignalWritableState(this); + } + + void set_receiving(bool receiving) { + if (receiving_ == receiving) { + return; + } + receiving_ = receiving; + SignalReceivingState(this); + } + + void SendPacketInternal(const rtc::CopyOnWriteBuffer& packet) { + if (dest_) { + dest_->SignalReadPacket(dest_, packet.data(), packet.size(), + rtc::CreatePacketTime(0), 0); + } + } + + rtc::AsyncInvoker invoker_; + std::string name_; + int component_; + FakeIceTransport* dest_ = nullptr; + bool async_ = false; + int async_delay_ms_ = 0; + Candidates remote_candidates_; + IceConfig ice_config_; + IceRole role_ = ICEROLE_UNKNOWN; + uint64_t tiebreaker_ = 0; + std::string ice_ufrag_; + std::string ice_pwd_; + std::string remote_ice_ufrag_; + std::string remote_ice_pwd_; + IceMode remote_ice_mode_ = ICEMODE_FULL; + size_t connection_count_ = 0; + IceGatheringState gathering_state_ = kIceGatheringNew; + bool had_connection_ = false; + bool writable_ = false; + bool receiving_ = false; +}; + +} // namespace cricket + +#endif // WEBRTC_P2P_BASE_FAKEICETRANSPORT_H_ diff --git a/webrtc/p2p/base/fakepackettransport.h b/webrtc/p2p/base/fakepackettransport.h new file mode 100644 index 0000000000..c8fc9bb1e9 --- /dev/null +++ b/webrtc/p2p/base/fakepackettransport.h @@ -0,0 +1,126 @@ +/* + * Copyright 2017 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 WEBRTC_P2P_BASE_FAKEPACKETTRANSPORT_H_ +#define WEBRTC_P2P_BASE_FAKEPACKETTRANSPORT_H_ + +#include + +#include "webrtc/base/asyncinvoker.h" +#include "webrtc/base/copyonwritebuffer.h" +#include "webrtc/p2p/base/packettransportinterface.h" + +namespace rtc { + +// Used to simulate a packet-based transport. +class FakePacketTransport : public PacketTransportInterface { + public: + explicit FakePacketTransport(const std::string& debug_name) + : debug_name_(debug_name) {} + ~FakePacketTransport() override { + if (dest_ && dest_->dest_ == this) { + dest_->dest_ = nullptr; + } + } + + // If async, will send packets by "Post"-ing to message queue instead of + // synchronously "Send"-ing. + void SetAsync(bool async) { async_ = async; } + void SetAsyncDelay(int delay_ms) { async_delay_ms_ = delay_ms; } + + // SetWritable, SetReceiving and SetDestination are the main methods that can + // be used for testing, to simulate connectivity or lack thereof. + void SetWritable(bool writable) { set_writable(writable); } + void SetReceiving(bool receiving) { set_receiving(receiving); } + + // Simulates the two transports connecting to each other. + // If |asymmetric| is true this method only affects this FakePacketTransport. + // If false, it affects |dest| as well. + void SetDestination(FakePacketTransport* dest, bool asymmetric) { + if (dest) { + dest_ = dest; + set_writable(true); + if (!asymmetric) { + dest->SetDestination(this, true); + } + } else { + // Simulates loss of connectivity, by asymmetrically forgetting dest_. + dest_ = nullptr; + set_writable(false); + } + } + + // Fake PacketTransportInterface implementation. + std::string debug_name() const override { return debug_name_; } + bool writable() const override { return writable_; } + bool receiving() const override { return receiving_; } + int SendPacket(const char* data, + size_t len, + const PacketOptions& options, + int flags) override { + if (!dest_) { + return -1; + } + CopyOnWriteBuffer packet(data, len); + if (async_) { + invoker_.AsyncInvokeDelayed( + RTC_FROM_HERE, Thread::Current(), + Bind(&FakePacketTransport::SendPacketInternal, this, packet), + async_delay_ms_); + } else { + SendPacketInternal(packet); + } + SentPacket sent_packet(options.packet_id, TimeMillis()); + SignalSentPacket(this, sent_packet); + return static_cast(len); + } + int SetOption(Socket::Option opt, int value) override { return true; } + bool GetOption(Socket::Option opt, int* value) override { return true; } + int GetError() override { return 0; } + + private: + void set_writable(bool writable) { + if (writable_ == writable) { + return; + } + writable_ = writable; + if (writable_) { + SignalReadyToSend(this); + } + SignalWritableState(this); + } + + void set_receiving(bool receiving) { + if (receiving_ == receiving) { + return; + } + receiving_ = receiving; + SignalReceivingState(this); + } + + void SendPacketInternal(const CopyOnWriteBuffer& packet) { + if (dest_) { + dest_->SignalReadPacket(dest_, packet.data(), packet.size(), + CreatePacketTime(0), 0); + } + } + + AsyncInvoker invoker_; + std::string debug_name_; + FakePacketTransport* dest_ = nullptr; + bool async_ = false; + int async_delay_ms_ = 0; + bool writable_ = false; + bool receiving_ = false; +}; + +} // namespace rtc + +#endif // WEBRTC_P2P_BASE_FAKEPACKETTRANSPORT_H_ diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h index 76ed370656..35af390d81 100644 --- a/webrtc/p2p/base/faketransportcontroller.h +++ b/webrtc/p2p/base/faketransportcontroller.h @@ -11,567 +11,22 @@ #ifndef WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ #define WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_ -#include #include #include #include #include "webrtc/base/bind.h" -#include "webrtc/base/buffer.h" -#include "webrtc/base/fakesslidentity.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" #include "webrtc/base/sslfingerprint.h" #include "webrtc/base/thread.h" -#include "webrtc/p2p/base/candidatepairinterface.h" -#include "webrtc/p2p/base/dtlstransportinternal.h" -#include "webrtc/p2p/base/icetransportinternal.h" - +#include "webrtc/p2p/base/fakedtlstransport.h" +#include "webrtc/p2p/base/fakeicetransport.h" #include "webrtc/p2p/base/transportcontroller.h" -#ifdef HAVE_QUIC -#include "webrtc/p2p/quic/quictransport.h" -#endif - namespace cricket { -namespace { -struct PacketMessageData : public rtc::MessageData { - PacketMessageData(const char* data, size_t len) : packet(data, len) {} - rtc::Buffer packet; -}; -} // namespace - -class FakeIceTransport : public IceTransportInternal, - public rtc::MessageHandler { - public: - explicit FakeIceTransport(const std::string& name, int component) - : name_(name), component_(component) {} - ~FakeIceTransport() { Reset(); } - - const std::string& transport_name() const override { return name_; } - int component() const override { return component_; } - uint64_t IceTiebreaker() const { return tiebreaker_; } - IceMode remote_ice_mode() const { return remote_ice_mode_; } - const std::string& ice_ufrag() const { return ice_ufrag_; } - const std::string& ice_pwd() const { return ice_pwd_; } - const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; } - const std::string& remote_ice_pwd() const { return remote_ice_pwd_; } - - // If async, will send packets by "Post"-ing to message queue instead of - // synchronously "Send"-ing. - void SetAsync(bool async) { async_ = async; } - void SetAsyncDelay(int delay_ms) { async_delay_ms_ = delay_ms; } - - IceTransportState GetState() const override { - if (connection_count_ == 0) { - return had_connection_ ? IceTransportState::STATE_FAILED - : IceTransportState::STATE_INIT; - } - - if (connection_count_ == 1) { - return IceTransportState::STATE_COMPLETED; - } - - return IceTransportState::STATE_CONNECTING; - } - - void SetIceRole(IceRole role) override { role_ = role; } - IceRole GetIceRole() const override { return role_; } - void SetIceTiebreaker(uint64_t tiebreaker) override { - tiebreaker_ = tiebreaker; - } - void SetIceParameters(const IceParameters& ice_params) override { - ice_ufrag_ = ice_params.ufrag; - ice_pwd_ = ice_params.pwd; - } - void SetRemoteIceParameters(const IceParameters& params) override { - remote_ice_ufrag_ = params.ufrag; - remote_ice_pwd_ = params.pwd; - } - - void SetRemoteIceMode(IceMode mode) override { remote_ice_mode_ = mode; } - - void MaybeStartGathering() override { - if (gathering_state_ == kIceGatheringNew) { - gathering_state_ = kIceGatheringGathering; - SignalGatheringState(this); - } - } - - IceGatheringState gathering_state() const override { - return gathering_state_; - } - - void Reset() { - if (state_ != STATE_INIT) { - state_ = STATE_INIT; - if (dest_) { - dest_->state_ = STATE_INIT; - dest_->dest_ = nullptr; - dest_ = nullptr; - } - } - } - - void SetWritable(bool writable) { set_writable(writable); } - - void set_writable(bool writable) { - if (writable_ == writable) { - return; - } - LOG(INFO) << "set_writable from:" << writable_ << " to " << writable; - writable_ = writable; - if (writable_) { - SignalReadyToSend(this); - } - SignalWritableState(this); - } - bool writable() const override { return writable_; } - - // Simulates the two transports connecting to each other. - // If |asymmetric| is true this method only affects this FakeIceTransport. - // If false, it affects |dest| as well. - void SetDestination(FakeIceTransport* dest, bool asymmetric = false) { - if (state_ == STATE_INIT && dest) { - // This simulates the delivery of candidates. - dest_ = dest; - state_ = STATE_CONNECTED; - set_writable(true); - if (!asymmetric) { - dest->SetDestination(this, true); - } - } else if (state_ == STATE_CONNECTED && !dest) { - // Simulates loss of connectivity, by asymmetrically forgetting dest_. - dest_ = nullptr; - state_ = STATE_INIT; - set_writable(false); - } - } - - void SetConnectionCount(size_t connection_count) { - size_t old_connection_count = connection_count_; - connection_count_ = connection_count; - if (connection_count) - had_connection_ = true; - // In this fake transport channel, |connection_count_| determines the - // transport channel state. - if (connection_count_ < old_connection_count) - SignalStateChanged(this); - } - - void SetCandidatesGatheringComplete() { - if (gathering_state_ != kIceGatheringComplete) { - gathering_state_ = kIceGatheringComplete; - SignalGatheringState(this); - } - } - - void SetReceiving(bool receiving) { set_receiving(receiving); } - - void set_receiving(bool receiving) { - if (receiving_ == receiving) { - return; - } - receiving_ = receiving; - SignalReceivingState(this); - } - bool receiving() const override { return receiving_; } - - void SetIceConfig(const IceConfig& config) override { ice_config_ = config; } - - int receiving_timeout() const { return ice_config_.receiving_timeout; } - bool gather_continually() const { return ice_config_.gather_continually(); } - - int SendPacket(const char* data, - size_t len, - const rtc::PacketOptions& options, - int flags) override { - if (state_ != STATE_CONNECTED) { - return -1; - } - - if (flags != PF_SRTP_BYPASS && flags != 0) { - return -1; - } - - PacketMessageData* packet = new PacketMessageData(data, len); - if (async_) { - if (async_delay_ms_) { - rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, async_delay_ms_, - this, 0, packet); - } else { - rtc::Thread::Current()->Post(RTC_FROM_HERE, this, 0, packet); - } - } else { - rtc::Thread::Current()->Send(RTC_FROM_HERE, this, 0, packet); - } - rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); - SignalSentPacket(this, sent_packet); - return static_cast(len); - } - int SetOption(rtc::Socket::Option opt, int value) override { return true; } - bool GetOption(rtc::Socket::Option opt, int* value) override { return true; } - int GetError() override { return 0; } - - void AddRemoteCandidate(const Candidate& candidate) override { - remote_candidates_.push_back(candidate); - } - - void RemoveRemoteCandidate(const Candidate& candidate) override {} - - const Candidates& remote_candidates() const { return remote_candidates_; } - - void OnMessage(rtc::Message* msg) override { - PacketMessageData* data = static_cast(msg->pdata); - dest_->SignalReadPacket(dest_, data->packet.data(), - data->packet.size(), rtc::CreatePacketTime(0), 0); - delete data; - } - - bool GetStats(ConnectionInfos* infos) override { - ConnectionInfo info; - infos->clear(); - infos->push_back(info); - return true; - } - - void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override { - } - - private: - std::string name_; - int component_; - enum State { STATE_INIT, STATE_CONNECTED }; - FakeIceTransport* dest_ = nullptr; - State state_ = STATE_INIT; - bool async_ = false; - int async_delay_ms_ = 0; - Candidates remote_candidates_; - IceConfig ice_config_; - IceRole role_ = ICEROLE_UNKNOWN; - uint64_t tiebreaker_ = 0; - std::string ice_ufrag_; - std::string ice_pwd_; - std::string remote_ice_ufrag_; - std::string remote_ice_pwd_; - IceMode remote_ice_mode_ = ICEMODE_FULL; - size_t connection_count_ = 0; - IceGatheringState gathering_state_ = kIceGatheringNew; - bool had_connection_ = false; - bool writable_ = false; - bool receiving_ = false; -}; - -class FakeDtlsTransport : public DtlsTransportInternal { - public: - explicit FakeDtlsTransport(FakeIceTransport* ice_transport) - : ice_transport_(ice_transport), - transport_name_(ice_transport->transport_name()), - component_(ice_transport->component()), - dtls_fingerprint_("", nullptr, 0) { - ice_transport_->SignalReadPacket.connect( - this, &FakeDtlsTransport::OnIceTransportReadPacket); - } - - // If this constructor is called, a new fake ice transport will be created, - // and this FakeDtlsTransport will take the ownership. - explicit FakeDtlsTransport(const std::string& name, int component) - : owned_ice_transport_(new FakeIceTransport(name, component)), - transport_name_(owned_ice_transport_->transport_name()), - component_(owned_ice_transport_->component()), - dtls_fingerprint_("", nullptr, 0) { - ice_transport_ = owned_ice_transport_.get(); - ice_transport_->SignalReadPacket.connect( - this, &FakeDtlsTransport::OnIceTransportReadPacket); - } - - ~FakeDtlsTransport() override { Reset(); } - - uint64_t IceTiebreaker() const { return ice_transport_->IceTiebreaker(); } - IceMode remote_ice_mode() const { return ice_transport_->remote_ice_mode(); } - const std::string& ice_ufrag() const { return ice_transport_->ice_ufrag(); } - const std::string& ice_pwd() const { return ice_transport_->ice_pwd(); } - const std::string& remote_ice_ufrag() const { - return ice_transport_->remote_ice_ufrag(); - } - const std::string& remote_ice_pwd() const { - return ice_transport_->remote_ice_pwd(); - } - - DtlsTransportState dtls_state() const override { return dtls_state_; } - - const std::string& transport_name() const override { return transport_name_; } - - int component() const override { return component_; } - - const rtc::SSLFingerprint& dtls_fingerprint() const { - return dtls_fingerprint_; - } - - // If async, will send packets by "Post"-ing to message queue instead of - // synchronously "Send"-ing. - void SetAsync(bool async) { ice_transport_->SetAsync(async); } - void SetAsyncDelay(int delay_ms) { ice_transport_->SetAsyncDelay(delay_ms); } - - IceRole GetIceRole() const { return ice_transport_->GetIceRole(); } - - bool SetRemoteFingerprint(const std::string& alg, - const uint8_t* digest, - size_t digest_len) override { - dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); - return true; - } - - bool SetSslRole(rtc::SSLRole role) override { - ssl_role_ = role; - return true; - } - - bool GetSslRole(rtc::SSLRole* role) const override { - *role = ssl_role_; - return true; - } - - IceGatheringState gathering_state() const { - return ice_transport_->gathering_state(); - } - - void Reset() { - if (state_ != STATE_INIT) { - state_ = STATE_INIT; - if (dest_) { - dest_->state_ = STATE_INIT; - dest_->dest_ = nullptr; - dest_ = nullptr; - } - } - } - - void SetWritable(bool writable) { set_writable(writable); } - - // Simulates the two transport channels connecting to each other. - // If |asymmetric| is true this method only affects this FakeDtlsTransport. - // If false, it affects |dest| as well. - void SetDestination(FakeDtlsTransport* dest, bool asymmetric = false) { - if (state_ == STATE_INIT && dest) { - // This simulates the delivery of candidates. - dest_ = dest; - if (local_cert_ && dest_->local_cert_) { - do_dtls_ = true; - NegotiateSrtpCiphers(); - } - state_ = STATE_CONNECTED; - SetWritable(true); - if (!asymmetric) { - dest->SetDestination(this, true); - } - ice_transport_->SetDestination( - static_cast(dest->ice_transport()), asymmetric); - } else if (state_ == STATE_CONNECTED && !dest) { - // Simulates loss of connectivity, by asymmetrically forgetting dest_. - dest_ = nullptr; - state_ = STATE_INIT; - SetWritable(false); - ice_transport_->SetDestination(nullptr, asymmetric); - } - } - - void SetConnectionCount(size_t connection_count) { - ice_transport_->SetConnectionCount(connection_count); - } - - void SetCandidatesGatheringComplete() { - ice_transport_->SetCandidatesGatheringComplete(); - } - - void SetReceiving(bool receiving) { - ice_transport_->SetReceiving(receiving); - set_receiving(receiving); - } - - int receiving_timeout() const { return ice_transport_->receiving_timeout(); } - bool gather_continually() const { - return ice_transport_->gather_continually(); - } - - int SendPacket(const char* data, - size_t len, - const rtc::PacketOptions& options, - int flags) override { - return ice_transport_->SendPacket(data, len, options, flags); - } - - bool GetOption(rtc::Socket::Option opt, int* value) override { return true; } - - const Candidates& remote_candidates() const { - return ice_transport_->remote_candidates(); - } - - void OnIceTransportReadPacket(PacketTransportInterface* ice_, - const char* data, - size_t len, - const rtc::PacketTime& time, - int flags) { - SignalReadPacket(this, data, len, time, flags); - } - - bool SetLocalCertificate( - const rtc::scoped_refptr& certificate) override { - local_cert_ = certificate; - return true; - } - - void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) { - remote_cert_ = cert; - } - - bool IsDtlsActive() const override { return do_dtls_; } - - bool SetSrtpCryptoSuites(const std::vector& ciphers) override { - srtp_ciphers_ = ciphers; - return true; - } - - bool GetSrtpCryptoSuite(int* crypto_suite) override { - if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { - *crypto_suite = chosen_crypto_suite_; - return true; - } - return false; - } - - bool GetSslCipherSuite(int* cipher_suite) override { return false; } - - rtc::scoped_refptr GetLocalCertificate() const override { - return local_cert_; - } - - std::unique_ptr GetRemoteSSLCertificate() - const override { - return remote_cert_ ? std::unique_ptr( - remote_cert_->GetReference()) - : nullptr; - } - - bool ExportKeyingMaterial(const std::string& label, - const uint8_t* context, - size_t context_len, - bool use_context, - uint8_t* result, - size_t result_len) override { - if (chosen_crypto_suite_ != rtc::SRTP_INVALID_CRYPTO_SUITE) { - memset(result, 0xff, result_len); - return true; - } - - return false; - } - - void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) { - ssl_max_version_ = version; - } - rtc::SSLProtocolVersion ssl_max_protocol_version() const { - return ssl_max_version_; - } - - IceTransportInternal* ice_transport() override { return ice_transport_; } - - bool writable() const override { return writable_; } - - bool receiving() const override { return receiving_; } - - int GetError() override { return ice_transport_->GetError(); } - - int SetOption(rtc::Socket::Option opt, int value) override { - return ice_transport_->SetOption(opt, value); - } - - bool SetSrtpCiphers(const std::vector& ciphers) override { - std::vector crypto_suites; - for (const auto cipher : ciphers) { - crypto_suites.push_back(rtc::SrtpCryptoSuiteFromName(cipher)); - } - return SetSrtpCryptoSuites(crypto_suites); - } - - private: - void NegotiateSrtpCiphers() { - for (std::vector::const_iterator it1 = srtp_ciphers_.begin(); - it1 != srtp_ciphers_.end(); ++it1) { - for (std::vector::const_iterator it2 = dest_->srtp_ciphers_.begin(); - it2 != dest_->srtp_ciphers_.end(); ++it2) { - if (*it1 == *it2) { - chosen_crypto_suite_ = *it1; - return; - } - } - } - } - - void set_receiving(bool receiving) { - if (receiving_ == receiving) { - return; - } - receiving_ = receiving; - SignalReceivingState(this); - } - - void set_writable(bool writable) { - if (writable_ == writable) { - return; - } - writable_ = writable; - if (writable_) { - SignalReadyToSend(this); - } - SignalWritableState(this); - } - - enum State { STATE_INIT, STATE_CONNECTED }; - FakeIceTransport* ice_transport_; - std::unique_ptr owned_ice_transport_; - std::string transport_name_; - int component_; - FakeDtlsTransport* dest_ = nullptr; - State state_ = STATE_INIT; - Candidates remote_candidates_; - rtc::scoped_refptr local_cert_; - rtc::FakeSSLCertificate* remote_cert_ = nullptr; - bool do_dtls_ = false; - std::vector srtp_ciphers_; - int chosen_crypto_suite_ = rtc::SRTP_INVALID_CRYPTO_SUITE; - rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; - rtc::SSLFingerprint dtls_fingerprint_; - rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT; - - DtlsTransportState dtls_state_ = DTLS_TRANSPORT_NEW; - - bool receiving_ = false; - bool writable_ = false; -}; - -// Fake candidate pair class, which can be passed to BaseChannel for testing -// purposes. -class FakeCandidatePair : public CandidatePairInterface { - public: - FakeCandidatePair(const Candidate& local_candidate, - const Candidate& remote_candidate) - : local_candidate_(local_candidate), - remote_candidate_(remote_candidate) {} - const Candidate& local_candidate() const override { return local_candidate_; } - const Candidate& remote_candidate() const override { - return remote_candidate_; - } - - private: - Candidate local_candidate_; - Candidate remote_candidate_; -}; - -// Fake TransportController class, which can be passed into a BaseChannel object -// for test purposes. Can be connected to other FakeTransportControllers via -// Connect(). +// 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. @@ -653,27 +108,12 @@ class FakeTransportController : public TransportController { dest)); } - FakeCandidatePair* CreateFakeCandidatePair( - const rtc::SocketAddress& local_address, - int16_t local_network_id, - const rtc::SocketAddress& remote_address, - int16_t remote_network_id) { - Candidate local_candidate(0, "udp", local_address, 0u, "", "", "local", 0, - "foundation", local_network_id, 0); - Candidate remote_candidate(0, "udp", remote_address, 0u, "", "", "local", 0, - "foundation", remote_network_id, 0); - return new FakeCandidatePair(local_candidate, remote_candidate); - } - void DestroyRtcpTransport(const std::string& transport_name) { DestroyDtlsTransport_n(transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP); } protected: - // The ICE channel is never actually used by TransportController directly, - // since (currently) the DTLS channel pretends to be both ICE + DTLS. This - // will change when we get rid of TransportChannelImpl. IceTransportInternal* CreateIceTransportChannel_n( const std::string& transport_name, int component) override { diff --git a/webrtc/p2p/base/jseptransport_unittest.cc b/webrtc/p2p/base/jseptransport_unittest.cc index 74ed35e145..ccb7016e05 100644 --- a/webrtc/p2p/base/jseptransport_unittest.cc +++ b/webrtc/p2p/base/jseptransport_unittest.cc @@ -13,7 +13,8 @@ #include "webrtc/base/fakesslidentity.h" #include "webrtc/base/gunit.h" #include "webrtc/base/network.h" -#include "webrtc/p2p/base/faketransportcontroller.h" +#include "webrtc/p2p/base/fakedtlstransport.h" +#include "webrtc/p2p/base/fakeicetransport.h" using cricket::JsepTransport; using cricket::TransportChannel; @@ -34,15 +35,16 @@ class JsepTransportTest : public testing::Test, public sigslot::has_slots<> { JsepTransportTest() : transport_(new JsepTransport("test content name", nullptr)) {} bool SetupChannel() { - fake_ice_channel_.reset(new FakeIceTransport(transport_->mid(), 1)); - fake_dtls_transport_.reset(new FakeDtlsTransport(fake_ice_channel_.get())); + fake_ice_transport_.reset(new FakeIceTransport(transport_->mid(), 1)); + fake_dtls_transport_.reset( + new FakeDtlsTransport(fake_ice_transport_.get())); return transport_->AddChannel(fake_dtls_transport_.get(), 1); } void DestroyChannel() { transport_->RemoveChannel(1); } protected: std::unique_ptr fake_dtls_transport_; - std::unique_ptr fake_ice_channel_; + std::unique_ptr fake_ice_transport_; std::unique_ptr transport_; }; @@ -53,16 +55,16 @@ TEST_F(JsepTransportTest, TestChannelIceParameters) { ASSERT_TRUE(transport_->SetLocalTransportDescription( local_desc, cricket::CA_OFFER, NULL)); EXPECT_TRUE(SetupChannel()); - EXPECT_EQ(cricket::ICEMODE_FULL, fake_dtls_transport_->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, fake_dtls_transport_->ice_ufrag()); - EXPECT_EQ(kIcePwd1, fake_dtls_transport_->ice_pwd()); + EXPECT_EQ(cricket::ICEMODE_FULL, fake_ice_transport_->remote_ice_mode()); + EXPECT_EQ(kIceUfrag1, fake_ice_transport_->ice_ufrag()); + EXPECT_EQ(kIcePwd1, fake_ice_transport_->ice_pwd()); cricket::TransportDescription remote_desc(kIceUfrag1, kIcePwd1); ASSERT_TRUE(transport_->SetRemoteTransportDescription( remote_desc, cricket::CA_ANSWER, NULL)); - EXPECT_EQ(cricket::ICEMODE_FULL, fake_dtls_transport_->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, fake_dtls_transport_->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd1, fake_dtls_transport_->remote_ice_pwd()); + EXPECT_EQ(cricket::ICEMODE_FULL, fake_ice_transport_->remote_ice_mode()); + EXPECT_EQ(kIceUfrag1, fake_ice_transport_->remote_ice_ufrag()); + EXPECT_EQ(kIcePwd1, fake_ice_transport_->remote_ice_pwd()); } // Verifies that IceCredentialsChanged returns true when either ufrag or pwd diff --git a/webrtc/p2p/base/transportcontroller_unittest.cc b/webrtc/p2p/base/transportcontroller_unittest.cc index 1fc71f1274..6ea83a4809 100644 --- a/webrtc/p2p/base/transportcontroller_unittest.cc +++ b/webrtc/p2p/base/transportcontroller_unittest.cc @@ -34,11 +34,10 @@ static const char kIcePwd3[] = "TESTICEPWD00000000000003"; namespace cricket { // Only subclassing from FakeTransportController because currently that's the -// only way to have a TransportController with fake TransportChannels. +// only way to have a TransportController with fake ICE/DTLS transports. // -// TODO(deadbeef): Change this once the Transport/TransportChannel class -// heirarchy is cleaned up, and we can pass a "TransportChannelFactory" or -// something similar into TransportController. +// 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, @@ -71,13 +70,14 @@ class TransportControllerTest : public testing::Test, this, &TransportControllerTest::OnCandidatesGathered); } - FakeDtlsTransport* CreateChannel(const std::string& content, int component) { - DtlsTransportInternal* channel = + FakeDtlsTransport* CreateFakeDtlsTransport(const std::string& content, + int component) { + DtlsTransportInternal* transport = transport_controller_->CreateDtlsTransport_n(content, component); - return static_cast(channel); + return static_cast(transport); } - void DestroyChannel(const std::string& content, int component) { + void DestroyFakeDtlsTransport(const std::string& content, int component) { transport_controller_->DestroyDtlsTransport_n(content, component); } @@ -91,20 +91,20 @@ class TransportControllerTest : public testing::Test, } // Used for thread hopping test. - void CreateChannelsAndCompleteConnectionOnNetworkThread() { + void CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread() { network_thread_->Invoke( RTC_FROM_HERE, - rtc::Bind( - &TransportControllerTest::CreateChannelsAndCompleteConnection_w, - this)); + rtc::Bind(&TransportControllerTest:: + CreateFakeDtlsTransportsAndCompleteConnection_w, + this)); } - void CreateChannelsAndCompleteConnection_w() { + void CreateFakeDtlsTransportsAndCompleteConnection_w() { transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + 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, @@ -115,20 +115,20 @@ class TransportControllerTest : public testing::Test, transport_controller_->SetLocalTransportDescription("video", local_desc, CA_OFFER, &err); transport_controller_->MaybeStartGathering(); - channel1->ice_transport()->SignalCandidateGathered( - channel1->ice_transport(), CreateCandidate(1)); - channel2->ice_transport()->SignalCandidateGathered( - channel2->ice_transport(), CreateCandidate(1)); - channel1->SetCandidatesGatheringComplete(); - channel2->SetCandidatesGatheringComplete(); - channel1->SetConnectionCount(2); - channel2->SetConnectionCount(2); - channel1->SetReceiving(true); - channel2->SetReceiving(true); - channel1->SetWritable(true); - channel2->SetWritable(true); - channel1->SetConnectionCount(1); - channel2->SetConnectionCount(1); + 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( @@ -196,30 +196,30 @@ class TransportControllerTest : public testing::Test, }; TEST_F(TransportControllerTest, TestSetIceConfig) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); transport_controller_->SetIceConfig( CreateIceConfig(1000, GATHER_CONTINUALLY)); - EXPECT_EQ(1000, channel1->receiving_timeout()); - EXPECT_TRUE(channel1->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 channels. - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); - EXPECT_EQ(1000, channel2->receiving_timeout()); - EXPECT_TRUE(channel2->gather_continually()); + // 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* channel = CreateChannel("audio", 1); + FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); - ASSERT_NE(nullptr, channel); - EXPECT_EQ(rtc::SSL_PROTOCOL_DTLS_12, channel->ssl_max_protocol_version()); + 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( @@ -227,47 +227,54 @@ TEST_F(TransportControllerTest, TestSetSslMaxProtocolVersion) { } TEST_F(TransportControllerTest, TestSetIceRole) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - EXPECT_EQ(ICEROLE_CONTROLLING, channel1->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLING, + transport1->fake_ice_transport()->GetIceRole()); transport_controller_->SetIceRole(ICEROLE_CONTROLLED); - EXPECT_EQ(ICEROLE_CONTROLLED, channel1->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLED, transport1->fake_ice_transport()->GetIceRole()); - // Test that value stored in controller is applied to new channels. - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); - EXPECT_EQ(ICEROLE_CONTROLLED, channel2->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 channel encounters a role conflict, the ICE role is -// swapped on every channel. +// Test that when one transport encounters a role conflict, the ICE role is +// swapped on every transport. TEST_F(TransportControllerTest, TestIceRoleConflict) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + 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, channel1->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLING, channel2->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLING, + transport1->fake_ice_transport()->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLING, + transport2->fake_ice_transport()->GetIceRole()); - channel1->ice_transport()->SignalRoleConflict(channel1->ice_transport()); - EXPECT_EQ(ICEROLE_CONTROLLED, channel1->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLED, channel2->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. - channel2->ice_transport()->SignalRoleConflict(channel2->ice_transport()); - EXPECT_EQ(ICEROLE_CONTROLLING, channel1->GetIceRole()); - EXPECT_EQ(ICEROLE_CONTROLLING, channel2->GetIceRole()); + 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) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); - ASSERT_TRUE(channel->SetSslRole(rtc::SSL_CLIENT)); + FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport); + ASSERT_TRUE(transport->SetSslRole(rtc::SSL_CLIENT)); rtc::SSLRole role; EXPECT_FALSE(transport_controller_->GetSslRole("video", &role)); EXPECT_TRUE(transport_controller_->GetSslRole("audio", &role)); @@ -283,8 +290,8 @@ TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) { rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT))); rtc::scoped_refptr returned_certificate; - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1)); EXPECT_TRUE(transport_controller_->GetLocalCertificate( @@ -296,9 +303,9 @@ TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) { EXPECT_FALSE(transport_controller_->GetLocalCertificate( "video", &returned_certificate)); - // Test that identity stored in controller is applied to new channels. - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + // 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(), @@ -311,10 +318,10 @@ TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) { TEST_F(TransportControllerTest, TestGetRemoteSSLCertificate) { rtc::FakeSSLCertificate fake_certificate("fake_data"); - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport); - channel->SetRemoteSSLCertificate(&fake_certificate); + transport->SetRemoteSSLCertificate(&fake_certificate); std::unique_ptr returned_certificate = transport_controller_->GetRemoteSSLCertificate("audio"); EXPECT_TRUE(returned_certificate); @@ -326,17 +333,17 @@ TEST_F(TransportControllerTest, TestGetRemoteSSLCertificate) { } TEST_F(TransportControllerTest, TestSetLocalTransportDescription) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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, CA_OFFER, &err)); - // Check that ICE ufrag and pwd were propagated to channel. - EXPECT_EQ(kIceUfrag1, channel->ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel->ice_pwd()); + // 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(); @@ -345,33 +352,33 @@ TEST_F(TransportControllerTest, TestSetLocalTransportDescription) { } TEST_F(TransportControllerTest, TestSetRemoteTransportDescription) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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, CA_OFFER, &err)); - // Check that ICE ufrag and pwd were propagated to channel. - EXPECT_EQ(kIceUfrag1, channel->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel->remote_ice_pwd()); + // 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* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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, channel->remote_candidates().size()); + EXPECT_EQ(1U, transport->fake_ice_transport()->remote_candidates().size()); } TEST_F(TransportControllerTest, TestReadyForRemoteCandidates) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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")); @@ -393,12 +400,12 @@ TEST_F(TransportControllerTest, TestReadyForRemoteCandidates) { } TEST_F(TransportControllerTest, TestGetStats) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("audio", 2); - ASSERT_NE(nullptr, channel2); - FakeDtlsTransport* channel3 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel3); + 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)); @@ -406,113 +413,115 @@ TEST_F(TransportControllerTest, TestGetStats) { EXPECT_EQ(2U, stats.channel_stats.size()); } -// Test that transport gets destroyed when it has no more channels. -TEST_F(TransportControllerTest, TestCreateAndDestroyChannel) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel2); - ASSERT_EQ(channel1, channel2); - FakeDtlsTransport* channel3 = CreateChannel("audio", 2); - ASSERT_NE(nullptr, channel3); +// 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)); - DestroyChannel("audio", 2); - DestroyChannel("audio", 1); + DestroyFakeDtlsTransport("audio", 2); + DestroyFakeDtlsTransport("audio", 1); EXPECT_TRUE(transport_controller_->GetStats("audio", &stats)); - DestroyChannel("audio", 1); + 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* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); + FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); + ASSERT_NE(nullptr, transport2); - // Should signal "failed" if any channel failed; channel is considered failed + // 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. - channel1->SetCandidatesGatheringComplete(); - channel1->SetConnectionCount(1); - channel1->SetConnectionCount(0); + 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* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); - FakeDtlsTransport* channel3 = CreateChannel("video", 2); - ASSERT_NE(nullptr, channel3); + 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 channel connect, and another fail, to ensure that - // the first channel connecting didn't trigger a "connected" state signal. + // 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. - channel1->SetConnectionCount(2); - channel1->SetWritable(true); - channel3->SetCandidatesGatheringComplete(); - channel3->SetConnectionCount(1); - channel3->SetConnectionCount(0); + 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 channel to return to "connecting" state. - DestroyChannel("video", 2); + // 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 channel reach a connected state. - channel2->SetConnectionCount(2); - channel2->SetWritable(true); + // 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* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); - FakeDtlsTransport* channel3 = CreateChannel("video", 2); - ASSERT_NE(nullptr, channel3); + 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. - channel1->SetCandidatesGatheringComplete(); - channel1->SetConnectionCount(1); - channel1->SetWritable(true); - channel3->SetCandidatesGatheringComplete(); - channel3->SetConnectionCount(1); - channel3->SetConnectionCount(0); + 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 channel to return to "connecting" state. - DestroyChannel("video", 2); + // 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 channel reach a connected state. - channel2->SetCandidatesGatheringComplete(); - channel2->SetConnectionCount(2); - channel2->SetWritable(true); + // 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. - channel2->SetConnectionCount(1); + transport2->fake_ice_transport()->SetConnectionCount(1); EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); EXPECT_EQ(4, connection_state_signal_count_); } @@ -520,24 +529,24 @@ TEST_F(TransportControllerTest, TestSignalConnectionStateComplete) { // Make sure that if we're "connected" and remove a transport, we stay in the // "connected" state. TEST_F(TransportControllerTest, TestDestroyTransportAndStayConnected) { - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); + FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); + ASSERT_NE(nullptr, transport2); - channel1->SetCandidatesGatheringComplete(); - channel1->SetConnectionCount(2); - channel1->SetWritable(true); - channel2->SetCandidatesGatheringComplete(); - channel2->SetConnectionCount(2); - channel2->SetWritable(true); + 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 channel, then "complete" the other one, so we reach + // Destroy one transport, then "complete" the other one, so we reach // a known state. - DestroyChannel("video", 1); - channel1->SetConnectionCount(1); + 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_); @@ -546,75 +555,76 @@ TEST_F(TransportControllerTest, TestDestroyTransportAndStayConnected) { // If we destroy the last/only transport, we should simply transition to // "connecting". TEST_F(TransportControllerTest, TestDestroyLastTransportWhileConnected) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport); - channel->SetCandidatesGatheringComplete(); - channel->SetConnectionCount(2); - channel->SetWritable(true); + 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_); - DestroyChannel("audio", 1); + 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* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + 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 channel is receiving. - channel1->SetReceiving(true); + // Should signal receiving as soon as any transport is receiving. + transport1->SetReceiving(true); EXPECT_TRUE_WAIT(receiving_, kTimeout); EXPECT_EQ(1, receiving_signal_count_); - channel2->SetReceiving(true); - channel1->SetReceiving(false); - channel2->SetReceiving(false); + 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* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); - channel->ice_transport()->MaybeStartGathering(); + 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* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); - FakeDtlsTransport* channel3 = CreateChannel("data", 1); - ASSERT_NE(nullptr, channel3); + 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); - channel3->ice_transport()->MaybeStartGathering(); + transport3->fake_ice_transport()->MaybeStartGathering(); EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); EXPECT_EQ(1, gathering_state_signal_count_); - // Have one channel finish gathering, then destroy it, to make sure gathering + // Have one transport finish gathering, then destroy it, to make sure + // gathering // completion wasn't signalled if only one transport finished gathering. - channel3->SetCandidatesGatheringComplete(); - DestroyChannel("data", 1); + transport3->fake_ice_transport()->SetCandidatesGatheringComplete(); + DestroyFakeDtlsTransport("data", 1); EXPECT_EQ_WAIT(kIceGatheringNew, gathering_state_, kTimeout); EXPECT_EQ(2, gathering_state_signal_count_); - // Make remaining channels start and then finish gathering. - channel1->ice_transport()->MaybeStartGathering(); - channel2->ice_transport()->MaybeStartGathering(); + // 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_); - channel1->SetCandidatesGatheringComplete(); - channel2->SetCandidatesGatheringComplete(); + transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); + transport2->fake_ice_transport()->SetCandidatesGatheringComplete(); EXPECT_EQ_WAIT(kIceGatheringComplete, gathering_state_, kTimeout); EXPECT_EQ(4, gathering_state_signal_count_); } @@ -626,18 +636,18 @@ TEST_F(TransportControllerTest, TestSignalGatheringStateComplete) { TEST_F(TransportControllerTest, TestSignalingWhenLastIncompleteTransportDestroyed) { transport_controller_->SetIceRole(ICEROLE_CONTROLLING); - FakeDtlsTransport* channel1 = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel1); - FakeDtlsTransport* channel2 = CreateChannel("video", 1); - ASSERT_NE(nullptr, channel2); + FakeDtlsTransport* transport1 = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport1); + FakeDtlsTransport* transport2 = CreateFakeDtlsTransport("video", 1); + ASSERT_NE(nullptr, transport2); - channel1->SetCandidatesGatheringComplete(); + transport1->fake_ice_transport()->SetCandidatesGatheringComplete(); EXPECT_EQ_WAIT(kIceGatheringGathering, gathering_state_, kTimeout); EXPECT_EQ(1, gathering_state_signal_count_); - channel1->SetConnectionCount(1); - channel1->SetWritable(true); - DestroyChannel("video", 1); + 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); @@ -645,8 +655,8 @@ TEST_F(TransportControllerTest, } TEST_F(TransportControllerTest, TestSignalCandidatesGathered) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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, @@ -657,15 +667,15 @@ TEST_F(TransportControllerTest, TestSignalCandidatesGathered) { "audio", local_desc, CA_OFFER, &err)); transport_controller_->MaybeStartGathering(); - channel->ice_transport()->SignalCandidateGathered(channel->ice_transport(), - CreateCandidate(1)); + 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(); - CreateChannelsAndCompleteConnectionOnNetworkThread(); + CreateFakeDtlsTransportsAndCompleteConnectionOnNetworkThread(); // connecting --> connected --> completed EXPECT_EQ_WAIT(kIceConnectionCompleted, connection_state_, kTimeout); @@ -692,8 +702,8 @@ TEST_F(TransportControllerTest, TestSignalingOccursOnSignalingThread) { // TODO(deadbeef): Remove this when these old versions of Chrome reach a low // enough population. TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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); @@ -707,7 +717,7 @@ TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) { CONNECTIONROLE_ACTPASS, nullptr); EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( "audio", local_desc, CA_ANSWER, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, channel->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole()); // The endpoint that initiated an ICE restart should take the controlling // role. @@ -716,7 +726,7 @@ TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) { CONNECTIONROLE_ACTPASS, nullptr); EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( "audio", ice_restart_desc, CA_OFFER, &err)); - EXPECT_EQ(ICEROLE_CONTROLLING, channel->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLING, transport->fake_ice_transport()->GetIceRole()); } // Test that if the TransportController was created with the @@ -725,8 +735,8 @@ TEST_F(TransportControllerTest, IceRoleRedeterminedOnIceRestartByDefault) { TEST_F(TransportControllerTest, IceRoleNotRedetermined) { bool redetermine_role = false; transport_controller_.reset(new TransportControllerForTest(redetermine_role)); - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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); @@ -740,7 +750,7 @@ TEST_F(TransportControllerTest, IceRoleNotRedetermined) { CONNECTIONROLE_ACTPASS, nullptr); EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( "audio", local_desc, CA_ANSWER, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, channel->GetIceRole()); + 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, @@ -748,13 +758,13 @@ TEST_F(TransportControllerTest, IceRoleNotRedetermined) { CONNECTIONROLE_ACTPASS, nullptr); EXPECT_TRUE(transport_controller_->SetLocalTransportDescription( "audio", ice_restart_desc, CA_OFFER, &err)); - EXPECT_EQ(ICEROLE_CONTROLLED, channel->GetIceRole()); + EXPECT_EQ(ICEROLE_CONTROLLED, transport->fake_ice_transport()->GetIceRole()); } -// Tests channel role is reversed after receiving ice-lite from remote. +// Tests ICE role is reversed after receiving ice-lite from remote. TEST_F(TransportControllerTest, TestSetRemoteIceLiteInOffer) { - FakeDtlsTransport* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + FakeDtlsTransport* transport = CreateFakeDtlsTransport("audio", 1); + ASSERT_NE(nullptr, transport); std::string err; transport_controller_->SetIceRole(ICEROLE_CONTROLLED); @@ -767,39 +777,39 @@ TEST_F(TransportControllerTest, TestSetRemoteIceLiteInOffer) { ASSERT_TRUE(transport_controller_->SetLocalTransportDescription( "audio", local_desc, CA_ANSWER, nullptr)); - EXPECT_EQ(ICEROLE_CONTROLLING, channel->GetIceRole()); - EXPECT_EQ(ICEMODE_LITE, channel->remote_ice_mode()); + 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* channel = CreateChannel("audio", 1); - ASSERT_NE(nullptr, channel); + 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, CA_OFFER, nullptr)); - EXPECT_EQ(ICEROLE_CONTROLLING, channel->GetIceRole()); - // Channels will be created in ICEFULL_MODE. - EXPECT_EQ(ICEMODE_FULL, channel->remote_ice_mode()); + 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, CA_ANSWER, nullptr)); - EXPECT_EQ(ICEROLE_CONTROLLING, channel->GetIceRole()); - // After receiving remote description with ICEMODE_LITE, channel should + 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, channel->remote_ice_mode()); + EXPECT_EQ(ICEMODE_LITE, transport->fake_ice_transport()->remote_ice_mode()); } // Tests SetNeedsIceRestartFlag and NeedsIceRestart, setting the flag and then // initiating an ICE restart for one of the transports. TEST_F(TransportControllerTest, NeedsIceRestart) { - CreateChannel("audio", 1); - CreateChannel("video", 1); + CreateFakeDtlsTransport("audio", 1); + CreateFakeDtlsTransport("video", 1); // Do initial offer/answer so there's something to restart. TransportDescription local_desc(kIceUfrag1, kIcePwd1); diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc index a34e9434eb..3c438f63ef 100644 --- a/webrtc/pc/channel.cc +++ b/webrtc/pc/channel.cc @@ -198,10 +198,14 @@ void BaseChannel::DisconnectTransportChannels_n() { // Stop signals from transport channels, but keep them alive because // media_channel may use them from a different thread. if (rtp_dtls_transport_) { - DisconnectFromTransport(rtp_dtls_transport_); + DisconnectFromDtlsTransport(rtp_dtls_transport_); + } else if (rtp_packet_transport_) { + DisconnectFromPacketTransport(rtp_packet_transport_); } if (rtcp_dtls_transport_) { - DisconnectFromTransport(rtcp_dtls_transport_); + DisconnectFromDtlsTransport(rtcp_dtls_transport_); + } else if (rtcp_packet_transport_) { + DisconnectFromPacketTransport(rtcp_packet_transport_); } // Clear pending read packets/messages. @@ -210,26 +214,33 @@ void BaseChannel::DisconnectTransportChannels_n() { } bool BaseChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport) { if (!network_thread_->Invoke( RTC_FROM_HERE, Bind(&BaseChannel::InitNetwork_n, this, - rtp_dtls_transport, rtcp_dtls_transport))) { + rtp_dtls_transport, rtcp_dtls_transport, + rtp_packet_transport, rtcp_packet_transport))) { return false; } - - // Both RTP and RTCP channels are set, we can call SetInterface on - // media channel and it can set network options. - RTC_DCHECK(worker_thread_->IsCurrent()); + // Both RTP and RTCP channels should be set, we can call SetInterface on + // the media channel and it can set network options. + RTC_DCHECK_RUN_ON(worker_thread_); media_channel_->SetInterface(this); return true; } -bool BaseChannel::InitNetwork_n(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { +bool BaseChannel::InitNetwork_n( + DtlsTransportInternal* rtp_dtls_transport, + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport) { RTC_DCHECK(network_thread_->IsCurrent()); - SetTransports_n(rtp_dtls_transport, rtcp_dtls_transport); + SetTransports_n(rtp_dtls_transport, rtcp_dtls_transport, rtp_packet_transport, + rtcp_packet_transport); - if (!SetDtlsSrtpCryptoSuites_n(rtp_dtls_transport_, false)) { + if (rtp_dtls_transport_ && + !SetDtlsSrtpCryptoSuites_n(rtp_dtls_transport_, false)) { return false; } if (rtcp_dtls_transport_ && @@ -254,35 +265,56 @@ void BaseChannel::Deinit() { 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)); + 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_n(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { - RTC_DCHECK(network_thread_->IsCurrent()); - if (!rtp_dtls_transport && !rtcp_dtls_transport) { - LOG(LS_ERROR) << "Setting nullptr to RTP Transport and RTCP Transport."; - return; - } +void BaseChannel::SetTransports( + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* 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::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* 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_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()); - RTC_DCHECK(NeedsRtcpTransport()); } - - std::string transport_name = rtp_dtls_transport - ? rtp_dtls_transport->transport_name() - : rtcp_dtls_transport->transport_name(); - if (transport_name == transport_name_) { - // Nothing to do if transport name isn't changing. + 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->debug_name(); + } + if (rtp_packet_transport == rtp_packet_transport_) { + // Nothing to do if transport isn't changing. return; } - transport_name_ = transport_name; - // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport // changes and wait until the DTLS handshake is complete to set the newly // negotiated parameters. @@ -295,17 +327,15 @@ void BaseChannel::SetTransports_n(DtlsTransportInternal* rtp_dtls_transport, // If this BaseChannel doesn't require RTCP mux and we haven't fully // negotiated RTCP mux, we need an RTCP transport. - if (NeedsRtcpTransport()) { + if (rtcp_packet_transport) { LOG(LS_INFO) << "Setting RTCP Transport for " << content_name() << " on " - << transport_name << " transport " << rtcp_dtls_transport; - SetTransport_n(true, rtcp_dtls_transport); - RTC_DCHECK(rtcp_dtls_transport_); + << debug_name << " transport " << rtcp_packet_transport; + SetTransport_n(true, rtcp_dtls_transport, rtcp_packet_transport); } - LOG(LS_INFO) << "Setting non-RTCP Transport for " << content_name() << " on " - << transport_name << " transport " << rtp_dtls_transport; - SetTransport_n(false, rtp_dtls_transport); - RTC_DCHECK(rtp_dtls_transport_); + LOG(LS_INFO) << "Setting RTP Transport for " << content_name() << " on " + << debug_name << " transport " << rtp_packet_transport; + SetTransport_n(false, rtp_dtls_transport, rtp_packet_transport); // Update aggregate writable/ready-to-send state between RTP and RTCP upon // setting new transport channels. @@ -320,44 +350,58 @@ void BaseChannel::SetTransports_n(DtlsTransportInternal* rtp_dtls_transport, // BaseChannel could have resulted in an error), but even so, we'll just // encounter the error again and update "ready to send" accordingly. SetTransportChannelReadyToSend( - false, rtp_dtls_transport_ && rtp_dtls_transport_->writable()); + false, rtp_packet_transport_ && rtp_packet_transport_->writable()); SetTransportChannelReadyToSend( - true, rtcp_dtls_transport_ && rtcp_dtls_transport_->writable()); + true, rtcp_packet_transport_ && rtcp_packet_transport_->writable()); } -void BaseChannel::SetTransport_n(bool rtcp, - DtlsTransportInternal* new_transport) { +void BaseChannel::SetTransport_n( + bool rtcp, + DtlsTransportInternal* new_dtls_transport, + rtc::PacketTransportInterface* new_packet_transport) { RTC_DCHECK(network_thread_->IsCurrent()); - DtlsTransportInternal*& old_transport = + DtlsTransportInternal*& old_dtls_transport = rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_; + rtc::PacketTransportInterface*& old_packet_transport = + rtcp ? rtcp_packet_transport_ : rtp_packet_transport_; - if (!old_transport && !new_transport) { + if (!old_packet_transport && !new_packet_transport) { // Nothing to do. return; } - RTC_DCHECK(old_transport != new_transport); - if (old_transport) { - DisconnectFromTransport(old_transport); + RTC_DCHECK(old_packet_transport != new_packet_transport); + if (old_dtls_transport) { + DisconnectFromDtlsTransport(old_dtls_transport); + } else if (old_packet_transport) { + DisconnectFromPacketTransport(old_packet_transport); } - old_transport = new_transport; + old_packet_transport = new_packet_transport; + old_dtls_transport = new_dtls_transport; - if (new_transport) { - if (rtcp) { - RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_filter_.IsActive())) - << "Setting RTCP for DTLS/SRTP after SrtpFilter is active " - << "should never happen."; - } - ConnectToTransport(new_transport); - auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; - for (const auto& pair : socket_options) { - new_transport->SetOption(pair.first, pair.second); - } + // If there's no new transport, we're done after disconnecting from old one. + if (!new_packet_transport) { + return; + } + + if (rtcp && new_dtls_transport) { + RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_filter_.IsActive())) + << "Setting RTCP for DTLS/SRTP after SrtpFilter is active " + << "should never happen."; + } + if (new_dtls_transport) { + ConnectToDtlsTransport(new_dtls_transport); + } else { + ConnectToPacketTransport(new_packet_transport); + } + auto& socket_options = rtcp ? rtcp_socket_options_ : socket_options_; + for (const auto& pair : socket_options) { + new_packet_transport->SetOption(pair.first, pair.second); } } -void BaseChannel::ConnectToTransport(DtlsTransportInternal* transport) { +void BaseChannel::ConnectToDtlsTransport(DtlsTransportInternal* transport) { RTC_DCHECK(network_thread_->IsCurrent()); transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState); @@ -369,7 +413,8 @@ void BaseChannel::ConnectToTransport(DtlsTransportInternal* transport) { this, &BaseChannel::OnSelectedCandidatePairChanged); } -void BaseChannel::DisconnectFromTransport(DtlsTransportInternal* transport) { +void BaseChannel::DisconnectFromDtlsTransport( + DtlsTransportInternal* transport) { RTC_DCHECK(network_thread_->IsCurrent()); OnSelectedCandidatePairChanged(transport->ice_transport(), nullptr, -1, false); @@ -383,6 +428,24 @@ void BaseChannel::DisconnectFromTransport(DtlsTransportInternal* transport) { this); } +void BaseChannel::ConnectToPacketTransport( + rtc::PacketTransportInterface* transport) { + RTC_DCHECK_RUN_ON(network_thread_); + transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState); + transport->SignalReadPacket.connect(this, &BaseChannel::OnPacketRead); + transport->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend); + transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n); +} + +void BaseChannel::DisconnectFromPacketTransport( + rtc::PacketTransportInterface* transport) { + RTC_DCHECK_RUN_ON(network_thread_); + transport->SignalWritableState.disconnect(this); + transport->SignalReadPacket.disconnect(this); + transport->SignalReadyToSend.disconnect(this); + transport->SignalSentPacket.disconnect(this); +} + bool BaseChannel::Enable(bool enable) { worker_thread_->Invoke( RTC_FROM_HERE, @@ -450,6 +513,9 @@ void BaseChannel::StopConnectionMonitor() { bool BaseChannel::GetConnectionStats(ConnectionInfos* infos) { RTC_DCHECK(network_thread_->IsCurrent()); + if (!rtp_dtls_transport_) { + return false; + } return rtp_dtls_transport_->ice_transport()->GetStats(infos); } @@ -499,20 +565,20 @@ int BaseChannel::SetOption_n(SocketType type, rtc::Socket::Option opt, int value) { RTC_DCHECK(network_thread_->IsCurrent()); - DtlsTransportInternal* transport = nullptr; + rtc::PacketTransportInterface* transport = nullptr; switch (type) { case ST_RTP: - transport = rtp_dtls_transport_; + transport = rtp_packet_transport_; socket_options_.push_back( std::pair(opt, value)); break; case ST_RTCP: - transport = rtcp_dtls_transport_; + transport = rtcp_packet_transport_; rtcp_socket_options_.push_back( std::pair(opt, value)); break; } - return transport ? transport->ice_transport()->SetOption(opt, value) : -1; + return transport ? transport->SetOption(opt, value) : -1; } bool BaseChannel::SetCryptoOptions(const rtc::CryptoOptions& crypto_options) { @@ -521,8 +587,8 @@ bool BaseChannel::SetCryptoOptions(const rtc::CryptoOptions& crypto_options) { } void BaseChannel::OnWritableState(rtc::PacketTransportInterface* transport) { - RTC_DCHECK(transport == rtp_dtls_transport_ || - transport == rtcp_dtls_transport_); + RTC_DCHECK(transport == rtp_packet_transport_ || + transport == rtcp_packet_transport_); RTC_DCHECK(network_thread_->IsCurrent()); UpdateWritableState_n(); } @@ -544,9 +610,9 @@ void BaseChannel::OnPacketRead(rtc::PacketTransportInterface* transport, } void BaseChannel::OnReadyToSend(rtc::PacketTransportInterface* transport) { - RTC_DCHECK(transport == rtp_dtls_transport_ || - transport == rtcp_dtls_transport_); - SetTransportChannelReadyToSend(transport == rtcp_dtls_transport_, true); + RTC_DCHECK(transport == rtp_packet_transport_ || + transport == rtcp_packet_transport_); + SetTransportChannelReadyToSend(transport == rtcp_packet_transport_, true); } void BaseChannel::OnDtlsState(DtlsTransportInternal* transport, @@ -570,8 +636,10 @@ void BaseChannel::OnSelectedCandidatePairChanged( CandidatePairInterface* selected_candidate_pair, int last_sent_packet_id, bool ready_to_send) { - RTC_DCHECK(ice_transport == rtp_dtls_transport_->ice_transport() || - ice_transport == rtcp_dtls_transport_->ice_transport()); + RTC_DCHECK((rtp_dtls_transport_ && + ice_transport == rtp_dtls_transport_->ice_transport()) || + (rtcp_dtls_transport_ && + ice_transport == rtcp_dtls_transport_->ice_transport())); RTC_DCHECK(network_thread_->IsCurrent()); selected_candidate_pair_ = selected_candidate_pair; std::string transport_name = ice_transport->transport_name(); @@ -600,8 +668,8 @@ void BaseChannel::SetTransportChannelReadyToSend(bool rtcp, bool ready) { bool ready_to_send = (rtp_ready_to_send_ && - // In the case of rtcp mux |rtcp_dtls_transport_| will be null. - (rtcp_ready_to_send_ || !rtcp_dtls_transport_)); + // In the case of rtcp mux |rtcp_packet_transport_| will be null. + (rtcp_ready_to_send_ || !rtcp_packet_transport_)); invoker_.AsyncInvoke( RTC_FROM_HERE, worker_thread_, @@ -611,7 +679,7 @@ void BaseChannel::SetTransportChannelReadyToSend(bool rtcp, bool ready) { bool BaseChannel::PacketIsRtcp(const rtc::PacketTransportInterface* transport, const char* data, size_t len) { - return (transport == rtcp_dtls_transport_ || + return (transport == rtcp_packet_transport_ || rtcp_mux_filter_.DemuxRtcp(data, static_cast(len))); } @@ -640,9 +708,9 @@ bool BaseChannel::SendPacket(bool rtcp, // 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. - DtlsTransportInternal* transport = (!rtcp || rtcp_mux_filter_.IsActive()) - ? rtp_dtls_transport_ - : rtcp_dtls_transport_; + rtc::PacketTransportInterface* transport = + (!rtcp || rtcp_mux_filter_.IsActive()) ? rtp_packet_transport_ + : rtcp_packet_transport_; if (!transport || !transport->writable()) { return false; } @@ -891,8 +959,8 @@ void BaseChannel::DisableMedia_w() { } void BaseChannel::UpdateWritableState_n() { - if (rtp_dtls_transport_ && rtp_dtls_transport_->writable() && - (!rtcp_dtls_transport_ || rtcp_dtls_transport_->writable())) { + if (rtp_packet_transport_ && rtp_packet_transport_->writable() && + (!rtcp_packet_transport_ || rtcp_packet_transport_->writable())) { ChannelWritable_n(); } else { ChannelNotWritable_n(); @@ -959,7 +1027,7 @@ bool BaseChannel::SetupDtlsSrtp_n(bool rtcp) { DtlsTransportInternal* transport = rtcp ? rtcp_dtls_transport_ : rtp_dtls_transport_; - + RTC_DCHECK(transport); RTC_DCHECK(transport->IsDtlsActive()); int selected_crypto_suite; @@ -1110,7 +1178,7 @@ bool BaseChannel::SetRtpTransportParameters_n( bool BaseChannel::CheckSrtpConfig_n(const std::vector& cryptos, bool* dtls, std::string* error_desc) { - *dtls = rtp_dtls_transport_->IsDtlsActive(); + *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; @@ -1195,9 +1263,9 @@ bool BaseChannel::SetRtcpMux_n(bool enable, LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name() << " by destroying RTCP transport for " << transport_name(); - if (rtcp_dtls_transport()) { - SetTransport_n(true, nullptr); - SignalRtcpMuxFullyActive(rtp_dtls_transport()->transport_name()); + if (rtcp_packet_transport_) { + SetTransport_n(true, nullptr, nullptr); + SignalRtcpMuxFullyActive(transport_name_); } UpdateWritableState_n(); SetTransportChannelReadyToSend(true, false); @@ -1219,7 +1287,7 @@ bool BaseChannel::SetRtcpMux_n(bool enable, // a final answer. if (rtcp_mux_filter_.IsActive()) { // If the RTP transport is already writable, then so are we. - if (rtp_dtls_transport_->writable()) { + if (rtp_packet_transport_->writable()) { ChannelWritable_n(); } } @@ -1479,11 +1547,6 @@ VoiceChannel::~VoiceChannel() { Deinit(); } -bool VoiceChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { - return BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport); -} - bool VoiceChannel::SetAudioSend(uint32_t ssrc, bool enable, const AudioOptions* options, @@ -1881,11 +1944,6 @@ VideoChannel::VideoChannel(rtc::Thread* worker_thread, rtcp_mux_required, srtp_required) {} -bool VideoChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { - return BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport); -} - VideoChannel::~VideoChannel() { TRACE_EVENT0("webrtc", "VideoChannel::~VideoChannel"); StopMediaMonitor(); @@ -2151,9 +2209,13 @@ RtpDataChannel::~RtpDataChannel() { Deinit(); } -bool RtpDataChannel::Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport) { - if (!BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport)) { +bool RtpDataChannel::Init_w( + DtlsTransportInternal* rtp_dtls_transport, + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport) { + if (!BaseChannel::Init_w(rtp_dtls_transport, rtcp_dtls_transport, + rtp_packet_transport, rtcp_packet_transport)) { return false; } media_channel()->SignalDataReceived.connect(this, diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h index e4848b2334..0c95d936e5 100644 --- a/webrtc/pc/channel.h +++ b/webrtc/pc/channel.h @@ -30,6 +30,8 @@ #include "webrtc/media/base/streamparams.h" #include "webrtc/media/base/videosinkinterface.h" #include "webrtc/media/base/videosourceinterface.h" +#include "webrtc/p2p/base/dtlstransportinternal.h" +#include "webrtc/p2p/base/packettransportinterface.h" #include "webrtc/p2p/base/transportcontroller.h" #include "webrtc/p2p/client/socketmonitor.h" #include "webrtc/pc/audiomonitor.h" @@ -39,10 +41,6 @@ #include "webrtc/pc/rtcpmuxfilter.h" #include "webrtc/pc/srtpfilter.h" -namespace rtc { -class PacketTransportInterface; -} - namespace webrtc { class AudioSinkInterface; } // namespace webrtc @@ -75,7 +73,6 @@ class BaseChannel public MediaChannel::NetworkInterface, public ConnectionStatsGetter { public: - // |rtcp| represents whether or not this channel uses RTCP. // 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). BaseChannel(rtc::Thread* worker_thread, @@ -87,7 +84,9 @@ class BaseChannel bool srtp_required); virtual ~BaseChannel(); bool Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport); // Deinit may be called multiple times and is simply ignored if it's already // done. void Deinit(); @@ -95,6 +94,7 @@ class BaseChannel rtc::Thread* worker_thread() const { return worker_thread_; } rtc::Thread* network_thread() const { return network_thread_; } const std::string& content_name() const { return content_name_; } + // TODO(deadbeef): This is redundant; remove this. const std::string& transport_name() const { return transport_name_; } bool enabled() const { return enabled_; } @@ -113,8 +113,12 @@ class BaseChannel // 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::PacketTransportInterface" and switch to + // "DtlsTransportInternal", or vice-versa. void SetTransports(DtlsTransportInternal* rtp_dtls_transport, DtlsTransportInternal* rtcp_dtls_transport); + void SetTransports(rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport); bool PushdownLocalDescription(const SessionDescription* local_desc, ContentAction action, std::string* error_desc); @@ -206,11 +210,15 @@ class BaseChannel virtual MediaChannel* media_channel() const { return media_channel_; } void SetTransports_n(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* 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. - void SetTransport_n(bool rtcp, DtlsTransportInternal* new_transport); + void SetTransport_n(bool rtcp, + DtlsTransportInternal* new_dtls_transport, + rtc::PacketTransportInterface* new_packet_transport); bool was_ever_writable() const { return was_ever_writable_; } void set_local_content_direction(MediaContentDirection direction) { @@ -233,8 +241,10 @@ class BaseChannel bool IsReadyToSendMedia_w() const; rtc::Thread* signaling_thread() { return signaling_thread_; } - void ConnectToTransport(DtlsTransportInternal* transport); - void DisconnectFromTransport(DtlsTransportInternal* transport); + void ConnectToDtlsTransport(DtlsTransportInternal* transport); + void DisconnectFromDtlsTransport(DtlsTransportInternal* transport); + void ConnectToPacketTransport(rtc::PacketTransportInterface* transport); + void DisconnectFromPacketTransport(rtc::PacketTransportInterface* transport); void FlushRtcpMessages_n(); @@ -366,7 +376,9 @@ class BaseChannel private: bool InitNetwork_n(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport); void DisconnectTransportChannels_n(); void SignalSentPacket_n(rtc::PacketTransportInterface* transport, const rtc::SentPacket& sent_packet); @@ -384,14 +396,20 @@ class BaseChannel const std::string content_name_; std::unique_ptr connection_monitor_; + // Won't be set when using raw packet transports. SDP-specific thing. std::string transport_name_; // True if RTCP-multiplexing is required. In other words, no standalone RTCP // transport will ever be used for this channel. const bool rtcp_mux_required_; + // 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; - std::vector > socket_options_; DtlsTransportInternal* rtcp_dtls_transport_ = nullptr; + rtc::PacketTransportInterface* rtp_packet_transport_ = nullptr; + rtc::PacketTransportInterface* rtcp_packet_transport_ = nullptr; + std::vector > socket_options_; std::vector > rtcp_socket_options_; SrtpFilter srtp_filter_; RtcpMuxFilter rtcp_mux_filter_; @@ -433,8 +451,6 @@ class VoiceChannel : public BaseChannel { bool rtcp_mux_required, bool srtp_required); ~VoiceChannel(); - bool Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); // Configure sending media on the stream with SSRC |ssrc| // If there is only one sending stream SSRC 0 can be used. @@ -552,8 +568,6 @@ class VideoChannel : public BaseChannel { bool rtcp_mux_required, bool srtp_required); ~VideoChannel(); - bool Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); // downcasts a MediaChannel VideoMediaChannel* media_channel() const override { @@ -633,7 +647,9 @@ class RtpDataChannel : public BaseChannel { bool srtp_required); ~RtpDataChannel(); bool Init_w(DtlsTransportInternal* rtp_dtls_transport, - DtlsTransportInternal* rtcp_dtls_transport); + DtlsTransportInternal* rtcp_dtls_transport, + rtc::PacketTransportInterface* rtp_packet_transport, + rtc::PacketTransportInterface* rtcp_packet_transport); virtual bool SendData(const SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc index d6401a5935..57e7afb179 100644 --- a/webrtc/pc/channel_unittest.cc +++ b/webrtc/pc/channel_unittest.cc @@ -21,8 +21,9 @@ #include "webrtc/media/base/fakertp.h" #include "webrtc/media/base/mediachannel.h" #include "webrtc/media/base/testutils.h" -#include "webrtc/p2p/base/dtlstransportinternal.h" -#include "webrtc/p2p/base/faketransportcontroller.h" +#include "webrtc/p2p/base/fakecandidatepair.h" +#include "webrtc/p2p/base/fakedtlstransport.h" +#include "webrtc/p2p/base/fakepackettransport.h" #include "webrtc/pc/channel.h" using cricket::CA_OFFER; @@ -96,7 +97,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { SECURE = 0x4, SSRC_MUX = 0x8, DTLS = 0x10, - GCM_CIPHER = 0x20 + GCM_CIPHER = 0x20, + // Use BaseChannel with PacketTransportInterface rather than + // DtlsTransportInternal. + RAW_PACKET_TRANSPORT = 0x40, }; ChannelTest(bool verify_playout, @@ -104,24 +108,15 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { rtc::ArrayView rtcp_data, NetworkIsWorker network_is_worker) : verify_playout_(verify_playout), - media_channel1_(NULL), - media_channel2_(NULL), rtp_packet_(rtp_data.data(), rtp_data.size()), - rtcp_packet_(rtcp_data.data(), rtcp_data.size()), - media_info_callbacks1_(), - media_info_callbacks2_() { + rtcp_packet_(rtcp_data.data(), rtcp_data.size()) { if (network_is_worker == NetworkIsWorker::Yes) { network_thread_ = rtc::Thread::Current(); } else { network_thread_keeper_ = rtc::Thread::Create(); network_thread_keeper_->SetName("Network", nullptr); - network_thread_keeper_->Start(); network_thread_ = network_thread_keeper_.get(); } - transport_controller1_.reset(new cricket::FakeTransportController( - network_thread_, cricket::ICEROLE_CONTROLLING)); - transport_controller2_.reset(new cricket::FakeTransportController( - network_thread_, cricket::ICEROLE_CONTROLLED)); } void CreateChannels(int flags1, int flags2) { @@ -133,28 +128,101 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { typename T::MediaChannel* ch2, int flags1, int flags2) { + // Network thread is started in CreateChannels, to allow the test to + // configure a fake clock before any threads are spawned and attempt to + // access the time. + if (network_thread_keeper_) { + network_thread_keeper_->Start(); + } // Make sure RTCP_MUX_REQUIRED isn't set without RTCP_MUX. - ASSERT_NE(RTCP_MUX_REQUIRED, flags1 & (RTCP_MUX | RTCP_MUX_REQUIRED)); - ASSERT_NE(RTCP_MUX_REQUIRED, flags2 & (RTCP_MUX | RTCP_MUX_REQUIRED)); + 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); rtc::Thread* worker_thread = rtc::Thread::Current(); media_channel1_ = ch1; media_channel2_ = ch2; + rtc::PacketTransportInterface* rtp1 = nullptr; + rtc::PacketTransportInterface* rtcp1 = nullptr; + rtc::PacketTransportInterface* rtp2 = nullptr; + rtc::PacketTransportInterface* rtcp2 = nullptr; + // Based on flags, create fake DTLS or raw packet transports. + if (flags1 & RAW_PACKET_TRANSPORT) { + fake_rtp_packet_transport1_.reset( + new rtc::FakePacketTransport("channel1_rtp")); + rtp1 = fake_rtp_packet_transport1_.get(); + if (!(flags1 & RTCP_MUX_REQUIRED)) { + fake_rtcp_packet_transport1_.reset( + new rtc::FakePacketTransport("channel1_rtcp")); + rtcp1 = fake_rtcp_packet_transport1_.get(); + } + } else { + // Confirmed to work with KT_RSA and KT_ECDSA. + 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)) { + fake_rtcp_dtls_transport1_.reset(new cricket::FakeDtlsTransport( + "channel1", cricket::ICE_CANDIDATE_COMPONENT_RTCP)); + rtcp1 = fake_rtcp_dtls_transport1_.get(); + } + if (flags1 & DTLS) { + auto cert1 = + rtc::RTCCertificate::Create(std::unique_ptr( + rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))); + fake_rtp_dtls_transport1_->SetLocalCertificate(cert1); + if (fake_rtcp_dtls_transport1_) { + fake_rtcp_dtls_transport1_->SetLocalCertificate(cert1); + } + } + } + // 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)) { + fake_rtcp_packet_transport2_.reset( + new rtc::FakePacketTransport("channel2_rtcp")); + rtcp2 = fake_rtcp_packet_transport2_.get(); + } + } else { + // Confirmed to work with KT_RSA and KT_ECDSA. + 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)) { + fake_rtcp_dtls_transport2_.reset(new cricket::FakeDtlsTransport( + "channel2", cricket::ICE_CANDIDATE_COMPONENT_RTCP)); + rtcp2 = fake_rtcp_dtls_transport2_.get(); + } + if (flags2 & DTLS) { + auto cert2 = + rtc::RTCCertificate::Create(std::unique_ptr( + rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT))); + fake_rtp_dtls_transport2_->SetLocalCertificate(cert2); + if (fake_rtcp_dtls_transport2_) { + fake_rtcp_dtls_transport2_->SetLocalCertificate(cert2); + } + } + } channel1_.reset( CreateChannel(worker_thread, network_thread_, &media_engine_, ch1, - transport_controller1_.get(), flags1)); + fake_rtp_dtls_transport1_.get(), + fake_rtcp_dtls_transport1_.get(), rtp1, rtcp1, flags1)); channel2_.reset( CreateChannel(worker_thread, network_thread_, &media_engine_, ch2, - transport_controller2_.get(), flags2)); + fake_rtp_dtls_transport2_.get(), + fake_rtcp_dtls_transport2_.get(), rtp2, rtcp2, flags2)); channel1_->SignalMediaMonitor.connect(this, &ChannelTest::OnMediaMonitor1); channel2_->SignalMediaMonitor.connect(this, &ChannelTest::OnMediaMonitor2); channel1_->SignalRtcpMuxFullyActive.connect( - transport_controller1_.get(), - &cricket::FakeTransportController::DestroyRtcpTransport); + this, &ChannelTest::OnRtcpMuxFullyActive1); channel2_->SignalRtcpMuxFullyActive.connect( - transport_controller2_.get(), - &cricket::FakeTransportController::DestroyRtcpTransport); + this, &ChannelTest::OnRtcpMuxFullyActive2); if ((flags1 & DTLS) && (flags2 & DTLS)) { flags1 = (flags1 & ~SECURE); flags2 = (flags2 & ~SECURE); @@ -166,19 +234,6 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CopyContent(local_media_content1_, &remote_media_content1_); CopyContent(local_media_content2_, &remote_media_content2_); - if (flags1 & DTLS) { - // Confirmed to work with KT_RSA and KT_ECDSA. - transport_controller1_->SetLocalCertificate( - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT)))); - } - if (flags2 & DTLS) { - // Confirmed to work with KT_RSA and KT_ECDSA. - transport_controller2_->SetLocalCertificate( - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT)))); - } - // Add stream information (SSRC) to the local content but not to the remote // content. This means that we per default know the SSRC of what we send but // not what we receive. @@ -198,11 +253,12 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, typename T::MediaChannel* ch, - cricket::TransportController* transport_controller, + cricket::DtlsTransportInternal* fake_rtp_dtls_transport, + cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, + rtc::PacketTransportInterface* fake_rtp_packet_transport, + rtc::PacketTransportInterface* fake_rtcp_packet_transport, int flags) { - rtc::Thread* signaling_thread = - transport_controller ? transport_controller->signaling_thread() - : nullptr; + rtc::Thread* signaling_thread = rtc::Thread::Current(); typename T::Channel* channel = new typename T::Channel( worker_thread, network_thread, signaling_thread, engine, ch, cricket::CN_AUDIO, (flags & RTCP_MUX_REQUIRED) != 0, @@ -210,21 +266,41 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { rtc::CryptoOptions crypto_options; crypto_options.enable_gcm_crypto_suites = (flags & GCM_CIPHER) != 0; channel->SetCryptoOptions(crypto_options); - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (channel->NeedsRtcpTransport()) { - rtcp_dtls_transport = transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTCP); + if (!channel->NeedsRtcpTransport()) { + fake_rtcp_dtls_transport = nullptr; } - if (!channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport)) { + if (!channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, + fake_rtp_packet_transport, + fake_rtcp_packet_transport)) { delete channel; channel = NULL; } return channel; } + void ConnectFakeTransports() { + network_thread_->Invoke(RTC_FROM_HERE, [this] { + bool asymmetric = false; + // Depending on test flags, could be using DTLS or raw packet transport. + if (fake_rtp_dtls_transport1_ && fake_rtp_dtls_transport2_) { + fake_rtp_dtls_transport1_->SetDestination( + fake_rtp_dtls_transport2_.get(), asymmetric); + } + if (fake_rtcp_dtls_transport1_ && fake_rtcp_dtls_transport2_) { + fake_rtcp_dtls_transport1_->SetDestination( + fake_rtcp_dtls_transport2_.get(), asymmetric); + } + if (fake_rtp_packet_transport1_ && fake_rtp_packet_transport2_) { + fake_rtp_packet_transport1_->SetDestination( + fake_rtp_packet_transport2_.get(), asymmetric); + } + if (fake_rtcp_packet_transport1_ && fake_rtcp_packet_transport2_) { + fake_rtcp_packet_transport1_->SetDestination( + fake_rtcp_packet_transport2_.get(), asymmetric); + } + }); + } + bool SendInitiate() { bool result = channel1_->SetLocalContent(&local_media_content1_, CA_OFFER, NULL); @@ -233,8 +309,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { result = channel2_->SetRemoteContent(&remote_media_content1_, CA_OFFER, NULL); if (result) { - transport_controller1_->Connect(transport_controller2_.get()); - + ConnectFakeTransports(); result = channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER, NULL); } @@ -266,7 +341,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { channel2_->Enable(true); result = channel1_->SetRemoteContent(&remote_media_content2_, CA_PRANSWER, NULL); - transport_controller1_->Connect(transport_controller2_.get()); + ConnectFakeTransports(); } return result; } @@ -280,9 +355,20 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { return result; } - bool SendTerminate() { + bool Terminate() { channel1_.reset(); channel2_.reset(); + fake_rtp_dtls_transport1_.reset(); + fake_rtcp_dtls_transport1_.reset(); + fake_rtp_dtls_transport2_.reset(); + fake_rtcp_dtls_transport2_.reset(); + fake_rtp_packet_transport1_.reset(); + fake_rtcp_packet_transport1_.reset(); + fake_rtp_packet_transport2_.reset(); + fake_rtcp_packet_transport2_.reset(); + if (network_thread_keeper_) { + network_thread_keeper_.reset(); + } return true; } @@ -293,24 +379,6 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { return channel1_->RemoveRecvStream(id); } - std::vector GetChannels1() { - return transport_controller1_->channels_for_testing(); - } - - std::vector GetChannels2() { - return transport_controller2_->channels_for_testing(); - } - - cricket::FakeDtlsTransport* GetFakeChannel1(int component) { - return transport_controller1_->GetFakeDtlsTransport_n( - channel1_->content_name(), component); - } - - cricket::FakeDtlsTransport* GetFakeChannel2(int component) { - return transport_controller2_->GetFakeDtlsTransport_n( - channel2_->content_name(), component); - } - void SendRtp1() { media_channel1_->SendRtp(rtp_packet_.data(), rtp_packet_.size(), rtc::PacketOptions()); @@ -405,7 +473,11 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Returns true if so. bool CheckGcmCipher(typename T::Channel* channel, int flags) { int suite; - if (!channel->rtp_dtls_transport()->GetSrtpCryptoSuite(&suite)) { + cricket::FakeDtlsTransport* transport = + (channel == channel1_.get()) ? fake_rtp_dtls_transport1_.get() + : fake_rtp_dtls_transport2_.get(); + RTC_DCHECK(transport); + if (!transport->GetSrtpCryptoSuite(&suite)) { return false; } @@ -476,6 +548,12 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { RTC_DCHECK_EQ(channel, channel2_.get()); media_info_callbacks2_++; } + void OnRtcpMuxFullyActive1(const std::string&) { + rtcp_mux_activated_callbacks1_++; + } + void OnRtcpMuxFullyActive2(const std::string&) { + rtcp_mux_activated_callbacks2_++; + } cricket::CandidatePairInterface* last_selected_candidate_pair() { return last_selected_candidate_pair_; @@ -535,43 +613,37 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // mux. void TestSetContentsRtcpMux() { CreateChannels(0, 0); - EXPECT_TRUE(channel1_->rtcp_dtls_transport() != NULL); - EXPECT_TRUE(channel2_->rtcp_dtls_transport() != NULL); typename T::Content content; CreateContent(0, kPcmuCodec, kH264Codec, &content); // Both sides agree on mux. Should no longer be a separate RTCP channel. content.set_rtcp_mux(true); EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL)); EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL)); - EXPECT_TRUE(channel1_->rtcp_dtls_transport() == NULL); // Only initiator supports mux. Should still have a separate RTCP channel. EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER, NULL)); content.set_rtcp_mux(false); EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER, NULL)); - EXPECT_TRUE(channel2_->rtcp_dtls_transport() != NULL); } // Test that SetLocalContent and SetRemoteContent properly set RTCP // mux when a provisional answer is received. void TestSetContentsRtcpMuxWithPrAnswer() { CreateChannels(0, 0); - EXPECT_TRUE(channel1_->rtcp_dtls_transport() != NULL); - EXPECT_TRUE(channel2_->rtcp_dtls_transport() != NULL); typename T::Content content; CreateContent(0, kPcmuCodec, kH264Codec, &content); content.set_rtcp_mux(true); EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL)); EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_PRANSWER, NULL)); - EXPECT_TRUE(channel1_->rtcp_dtls_transport() != NULL); + // Both sides agree on mux. Should signal RTCP mux as fully activated. + EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL)); - // Both sides agree on mux. Should no longer be a separate RTCP channel. - EXPECT_TRUE(channel1_->rtcp_dtls_transport() == NULL); + EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); // Only initiator supports mux. Should still have a separate RTCP channel. EXPECT_TRUE(channel2_->SetLocalContent(&content, CA_OFFER, NULL)); content.set_rtcp_mux(false); EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_PRANSWER, NULL)); EXPECT_TRUE(channel2_->SetRemoteContent(&content, CA_ANSWER, NULL)); - EXPECT_TRUE(channel2_->rtcp_dtls_transport() != NULL); + EXPECT_EQ(0, rtcp_mux_activated_callbacks2_); } // Test that SetRemoteContent properly deals with a content update. @@ -777,7 +849,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL)); EXPECT_EQ(1u, media_channel2_->recv_streams().size()); - transport_controller1_->Connect(transport_controller2_.get()); + ConnectFakeTransports(); // Channel 2 do not send anything. typename T::Content content2; @@ -854,7 +926,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_FALSE(media_channel2_->playout()); } EXPECT_FALSE(media_channel2_->sending()); - transport_controller1_->Connect(transport_controller2_.get()); + ConnectFakeTransports(); if (verify_playout_) { EXPECT_TRUE(media_channel1_->playout()); } @@ -902,7 +974,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL)); EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER, NULL)); EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER, NULL)); - transport_controller1_->Connect(transport_controller2_.get()); + ConnectFakeTransports(); if (verify_playout_) { EXPECT_TRUE(media_channel1_->playout()); @@ -951,36 +1023,34 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); - cricket::DtlsTransportInternal* transport_channel1 = - channel1_->rtp_dtls_transport(); - ASSERT_TRUE(transport_channel1); typename T::MediaChannel* media_channel1 = static_cast(channel1_->media_channel()); ASSERT_TRUE(media_channel1); media_channel1->set_num_network_route_changes(0); - network_thread_->Invoke(RTC_FROM_HERE, [transport_channel1] { + network_thread_->Invoke(RTC_FROM_HERE, [this] { // The transport channel becomes disconnected. - transport_channel1->ice_transport()->SignalSelectedCandidatePairChanged( - transport_channel1->ice_transport(), nullptr, -1, false); + fake_rtp_dtls_transport1_->ice_transport() + ->SignalSelectedCandidatePairChanged( + fake_rtp_dtls_transport1_->ice_transport(), nullptr, -1, false); }); WaitForThreads(); EXPECT_EQ(1, media_channel1->num_network_route_changes()); EXPECT_FALSE(media_channel1->last_network_route().connected); media_channel1->set_num_network_route_changes(0); - network_thread_->Invoke(RTC_FROM_HERE, [this, transport_channel1, - media_channel1, kLocalNetId, - kRemoteNetId, kLastPacketId] { + network_thread_->Invoke(RTC_FROM_HERE, [this, media_channel1, + kLocalNetId, kRemoteNetId, + kLastPacketId] { // The transport channel becomes connected. rtc::SocketAddress local_address("192.168.1.1", 1000 /* port number */); rtc::SocketAddress remote_address("192.168.1.2", 2000 /* port number */); - std::unique_ptr candidate_pair( - transport_controller1_->CreateFakeCandidatePair( - local_address, kLocalNetId, remote_address, kRemoteNetId)); - transport_channel1->ice_transport()->SignalSelectedCandidatePairChanged( - transport_channel1->ice_transport(), candidate_pair.get(), - kLastPacketId, true); + auto candidate_pair = cricket::FakeCandidatePair::Create( + local_address, kLocalNetId, remote_address, kRemoteNetId); + fake_rtp_dtls_transport1_->ice_transport() + ->SignalSelectedCandidatePairChanged( + fake_rtp_dtls_transport1_->ice_transport(), candidate_pair.get(), + kLastPacketId, true); }); WaitForThreads(); EXPECT_EQ(1, media_channel1->num_network_route_changes()); @@ -1032,7 +1102,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { RTCP_MUX, RTCP_MUX); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_TRUE(SendTerminate()); + EXPECT_TRUE(Terminate()); } // Send voice RTP data to the other side and ensure it gets there. @@ -1040,8 +1110,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); SendRtp1(); SendRtp2(); WaitForThreads(); @@ -1069,8 +1139,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_TRUE(channel2_->NeedsRtcpTransport()); SendRtcp1(); SendRtcp2(); WaitForThreads(); @@ -1085,8 +1155,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(RTCP_MUX, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_TRUE(channel2_->NeedsRtcpTransport()); SendRtcp1(); SendRtcp2(); WaitForThreads(); @@ -1100,10 +1170,12 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendRtcpMuxToRtcpMux() { CreateChannels(RTCP_MUX, RTCP_MUX); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); + EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); SendRtp1(); SendRtp2(); SendRtcp1(); @@ -1124,8 +1196,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendRequireRtcpMuxToRtcpMux() { CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(1U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); EXPECT_TRUE(SendAccept()); SendRtp1(); SendRtp2(); @@ -1147,10 +1219,12 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendRtcpMuxToRequireRtcpMux() { CreateChannels(RTCP_MUX, RTCP_MUX | RTCP_MUX_REQUIRED); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); + EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); SendRtp1(); SendRtp2(); SendRtcp1(); @@ -1171,10 +1245,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendRequireRtcpMuxToRequireRtcpMux() { CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(1U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); SendRtp1(); SendRtp2(); SendRtcp1(); @@ -1195,8 +1269,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendRequireRtcpMuxToNoRtcpMux() { CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, 0); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(1U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_TRUE(channel2_->NeedsRtcpTransport()); EXPECT_FALSE(SendAccept()); } @@ -1204,8 +1278,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendEarlyRtcpMuxToRtcp() { CreateChannels(RTCP_MUX, 0); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + 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. @@ -1222,7 +1296,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Complete call setup and ensure everything is still OK. EXPECT_TRUE(SendAccept()); - EXPECT_EQ(2U, GetChannels1().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); SendRtcp1(); SendRtcp2(); WaitForThreads(); @@ -1237,8 +1311,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { void SendEarlyRtcpMuxToRtcpMux() { CreateChannels(RTCP_MUX, RTCP_MUX); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + 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. @@ -1253,8 +1327,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckRtcp1()); // Complete call setup and ensure everything is still OK. + EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_EQ(1, rtcp_mux_activated_callbacks1_); SendRtcp1(); SendRtcp2(); WaitForThreads(); @@ -1263,10 +1339,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { } // Test that we properly send SRTP with RTCP in both directions. - // You can pass in DTLS and/or RTCP_MUX as flags. + // You can pass in DTLS, RTCP_MUX, GCM_CIPHER and RAW_PACKET_TRANSPORT as + // flags. void SendSrtpToSrtp(int flags1_in = 0, int flags2_in = 0) { - RTC_CHECK((flags1_in & ~(RTCP_MUX | DTLS | GCM_CIPHER)) == 0); - RTC_CHECK((flags2_in & ~(RTCP_MUX | DTLS | GCM_CIPHER)) == 0); + RTC_CHECK((flags1_in & + ~(RTCP_MUX | DTLS | GCM_CIPHER | RAW_PACKET_TRANSPORT)) == 0); + RTC_CHECK((flags2_in & + ~(RTCP_MUX | DTLS | GCM_CIPHER | RAW_PACKET_TRANSPORT)) == 0); int flags1 = SECURE | flags1_in; int flags2 = SECURE | flags2_in; @@ -1342,8 +1421,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(SendProvisionalAnswer()); EXPECT_TRUE(channel1_->secure()); EXPECT_TRUE(channel2_->secure()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_TRUE(channel2_->NeedsRtcpTransport()); WaitForThreads(); // Wait for 'sending' flag go through network thread. SendCustomRtcp1(kSsrc1); SendCustomRtp1(kSsrc1, ++sequence_number1_1); @@ -1359,9 +1438,13 @@ 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_EQ(1U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + 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_->secure()); EXPECT_TRUE(channel2_->secure()); SendCustomRtcp1(kSsrc1); @@ -1427,8 +1510,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(RTCP_MUX | RTCP_MUX_REQUIRED, RTCP_MUX | RTCP_MUX_REQUIRED); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(1U, GetChannels1().size()); - EXPECT_EQ(1U, GetChannels2().size()); + EXPECT_FALSE(channel1_->NeedsRtcpTransport()); + EXPECT_FALSE(channel2_->NeedsRtcpTransport()); SendRtp1(); SendRtp2(); WaitForThreads(); @@ -1438,8 +1521,9 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtp2()); // Lose writability, which should fail. - network_thread_->Invoke( - RTC_FROM_HERE, [this] { GetFakeChannel1(1)->SetWritable(false); }); + network_thread_->Invoke(RTC_FROM_HERE, [this] { + fake_rtp_dtls_transport1_->SetWritable(false); + }); SendRtp1(); SendRtp2(); WaitForThreads(); @@ -1447,8 +1531,9 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtp2()); // Regain writability - network_thread_->Invoke( - RTC_FROM_HERE, [this] { GetFakeChannel1(1)->SetWritable(true); }); + network_thread_->Invoke(RTC_FROM_HERE, [this] { + fake_rtp_dtls_transport1_->SetWritable(true); + }); EXPECT_TRUE(media_channel1_->sending()); SendRtp1(); SendRtp2(); @@ -1459,8 +1544,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(CheckNoRtp2()); // Lose writability completely - network_thread_->Invoke( - RTC_FROM_HERE, [this] { GetFakeChannel1(1)->SetDestination(nullptr); }); + network_thread_->Invoke(RTC_FROM_HERE, [this] { + bool asymmetric = true; + fake_rtp_dtls_transport1_->SetDestination(nullptr, asymmetric); + }); EXPECT_TRUE(media_channel1_->sending()); // Should fail also. @@ -1473,7 +1560,9 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Gain writability back network_thread_->Invoke(RTC_FROM_HERE, [this] { - GetFakeChannel1(1)->SetDestination(GetFakeChannel2(1)); + bool asymmetric = true; + fake_rtp_dtls_transport1_->SetDestination(fake_rtp_dtls_transport2_.get(), + asymmetric); }); EXPECT_TRUE(media_channel1_->sending()); SendRtp1(); @@ -1495,18 +1584,16 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { int pl_type2 = pl_types[1]; int flags = SSRC_MUX; if (secure) flags |= SECURE; - uint32_t expected_channels = 2U; if (rtcp_mux) { flags |= RTCP_MUX; - expected_channels = 1U; } CreateChannels(flags, flags); EXPECT_TRUE(SendInitiate()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(expected_channels, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(expected_channels, GetChannels1().size()); - EXPECT_EQ(expected_channels, GetChannels2().size()); + EXPECT_EQ(rtcp_mux, !channel1_->NeedsRtcpTransport()); + EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport()); EXPECT_TRUE(channel1_->bundle_filter()->FindPayloadType(pl_type1)); EXPECT_TRUE(channel2_->bundle_filter()->FindPayloadType(pl_type1)); EXPECT_FALSE(channel1_->bundle_filter()->FindPayloadType(pl_type2)); @@ -1686,8 +1773,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); - EXPECT_EQ(2U, GetChannels1().size()); - EXPECT_EQ(2U, GetChannels2().size()); + EXPECT_TRUE(channel1_->NeedsRtcpTransport()); + EXPECT_TRUE(channel2_->NeedsRtcpTransport()); // Send RTCP1 from a different thread. ScopedCallThread send_rtcp([this] { SendRtcp1(); }); @@ -1733,12 +1820,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Using fake clock because this tests that SRTP errors are signaled at // specific times based on set_signal_silent_time. rtc::ScopedFakeClock fake_clock; + + CreateChannels(SECURE, SECURE); // Some code uses a time of 0 as a special value, so we must start with // a non-zero time. // TODO(deadbeef): Fix this. fake_clock.AdvanceTime(rtc::TimeDelta::FromSeconds(1)); - CreateChannels(SECURE, SECURE); EXPECT_FALSE(channel1_->secure()); EXPECT_FALSE(channel2_->secure()); EXPECT_TRUE(SendInitiate()); @@ -1779,22 +1867,21 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { error_handler.mode_ = cricket::SrtpFilter::UNPROTECT; network_thread_->Invoke(RTC_FROM_HERE, [this] { - cricket::DtlsTransportInternal* transport_channel = - channel2_->rtp_dtls_transport(); - transport_channel->SignalReadPacket( - transport_channel, reinterpret_cast(kBadPacket), - sizeof(kBadPacket), rtc::PacketTime(), 0); + fake_rtp_dtls_transport2_->SignalReadPacket( + fake_rtp_dtls_transport2_.get(), + reinterpret_cast(kBadPacket), sizeof(kBadPacket), + rtc::PacketTime(), 0); }); EXPECT_EQ(cricket::SrtpFilter::ERROR_FAIL, error_handler.error_); EXPECT_EQ(cricket::SrtpFilter::UNPROTECT, error_handler.mode_); - // Terminate channels before the fake clock is destroyed. - EXPECT_TRUE(SendTerminate()); + // Terminate channels/threads before the fake clock is destroyed. + EXPECT_TRUE(Terminate()); } void TestOnReadyToSend() { CreateChannels(0, 0); - DtlsTransportInternal* rtp = channel1_->rtp_dtls_transport(); - DtlsTransportInternal* rtcp = channel1_->rtcp_dtls_transport(); + cricket::FakeDtlsTransport* rtp = fake_rtp_dtls_transport1_.get(); + cricket::FakeDtlsTransport* rtcp = fake_rtcp_dtls_transport1_.get(); EXPECT_FALSE(media_channel1_->ready_to_send()); network_thread_->Invoke(RTC_FROM_HERE, @@ -1840,12 +1927,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { CreateChannels(0, 0); typename T::Content content; CreateContent(0, kPcmuCodec, kH264Codec, &content); - // Both sides agree on mux. Should no longer be a separate RTCP channel. + // Both sides agree on mux. Should signal that RTCP mux is fully active. content.set_rtcp_mux(true); EXPECT_TRUE(channel1_->SetLocalContent(&content, CA_OFFER, NULL)); + EXPECT_EQ(0, rtcp_mux_activated_callbacks1_); EXPECT_TRUE(channel1_->SetRemoteContent(&content, CA_ANSWER, NULL)); - EXPECT_TRUE(channel1_->rtcp_dtls_transport() == NULL); - DtlsTransportInternal* rtp = channel1_->rtp_dtls_transport(); + 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. @@ -1936,12 +2024,18 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { const bool verify_playout_; std::unique_ptr network_thread_keeper_; rtc::Thread* network_thread_; - std::unique_ptr transport_controller1_; - std::unique_ptr transport_controller2_; + std::unique_ptr fake_rtp_dtls_transport1_; + std::unique_ptr fake_rtcp_dtls_transport1_; + std::unique_ptr fake_rtp_dtls_transport2_; + std::unique_ptr fake_rtcp_dtls_transport2_; + std::unique_ptr fake_rtp_packet_transport1_; + std::unique_ptr fake_rtcp_packet_transport1_; + std::unique_ptr fake_rtp_packet_transport2_; + std::unique_ptr fake_rtcp_packet_transport2_; cricket::FakeMediaEngine media_engine_; // The media channels are owned by the voice channel objects below. - typename T::MediaChannel* media_channel1_; - typename T::MediaChannel* media_channel2_; + typename T::MediaChannel* media_channel1_ = nullptr; + typename T::MediaChannel* media_channel2_ = nullptr; std::unique_ptr channel1_; std::unique_ptr channel2_; typename T::Content local_media_content1_; @@ -1951,8 +2045,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // The RTP and RTCP packets to send in the tests. rtc::Buffer rtp_packet_; rtc::Buffer rtcp_packet_; - int media_info_callbacks1_; - int media_info_callbacks2_; + int media_info_callbacks1_ = 0; + int media_info_callbacks2_ = 0; + int rtcp_mux_activated_callbacks1_ = 0; + int rtcp_mux_activated_callbacks2_ = 0; cricket::CandidatePairInterface* last_selected_candidate_pair_; }; @@ -2014,25 +2110,23 @@ cricket::VideoChannel* ChannelTest::CreateChannel( rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, cricket::FakeVideoMediaChannel* ch, - cricket::TransportController* transport_controller, + cricket::DtlsTransportInternal* fake_rtp_dtls_transport, + cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, + rtc::PacketTransportInterface* fake_rtp_packet_transport, + rtc::PacketTransportInterface* fake_rtcp_packet_transport, int flags) { - rtc::Thread* signaling_thread = - transport_controller ? transport_controller->signaling_thread() : nullptr; + rtc::Thread* signaling_thread = rtc::Thread::Current(); cricket::VideoChannel* channel = new cricket::VideoChannel( worker_thread, network_thread, signaling_thread, ch, cricket::CN_VIDEO, (flags & RTCP_MUX_REQUIRED) != 0, (flags & SECURE) != 0); rtc::CryptoOptions crypto_options; crypto_options.enable_gcm_crypto_suites = (flags & GCM_CIPHER) != 0; channel->SetCryptoOptions(crypto_options); - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (channel->NeedsRtcpTransport()) { - rtcp_dtls_transport = transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTCP); + if (!channel->NeedsRtcpTransport()) { + fake_rtcp_dtls_transport = nullptr; } - if (!channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport)) { + if (!channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, + fake_rtp_packet_transport, fake_rtcp_packet_transport)) { delete channel; channel = NULL; } @@ -2260,6 +2354,12 @@ 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); +} + TEST_F(VoiceChannelSingleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { Base::SendEarlyMediaUsingRtcpMuxSrtp(); } @@ -2587,6 +2687,12 @@ 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); +} + TEST_F(VoiceChannelDoubleThreadTest, SendEarlyMediaUsingRtcpMuxSrtp) { Base::SendEarlyMediaUsingRtcpMuxSrtp(); } @@ -2894,6 +3000,12 @@ 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); } @@ -3123,6 +3235,12 @@ 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); } @@ -3230,25 +3348,23 @@ cricket::RtpDataChannel* ChannelTest::CreateChannel( rtc::Thread* network_thread, cricket::MediaEngineInterface* engine, cricket::FakeDataMediaChannel* ch, - cricket::TransportController* transport_controller, + cricket::DtlsTransportInternal* fake_rtp_dtls_transport, + cricket::DtlsTransportInternal* fake_rtcp_dtls_transport, + rtc::PacketTransportInterface* fake_rtp_packet_transport, + rtc::PacketTransportInterface* fake_rtcp_packet_transport, int flags) { - rtc::Thread* signaling_thread = - transport_controller ? transport_controller->signaling_thread() : nullptr; + rtc::Thread* signaling_thread = rtc::Thread::Current(); cricket::RtpDataChannel* channel = new cricket::RtpDataChannel( worker_thread, network_thread, signaling_thread, ch, cricket::CN_DATA, (flags & RTCP_MUX_REQUIRED) != 0, (flags & SECURE) != 0); rtc::CryptoOptions crypto_options; crypto_options.enable_gcm_crypto_suites = (flags & GCM_CIPHER) != 0; channel->SetCryptoOptions(crypto_options); - cricket::DtlsTransportInternal* rtp_dtls_transport = - transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr; - if (channel->NeedsRtcpTransport()) { - rtcp_dtls_transport = transport_controller->CreateDtlsTransport( - channel->content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTCP); + if (!channel->NeedsRtcpTransport()) { + fake_rtcp_dtls_transport = nullptr; } - if (!channel->Init_w(rtp_dtls_transport, rtcp_dtls_transport)) { + if (!channel->Init_w(fake_rtp_dtls_transport, fake_rtcp_dtls_transport, + fake_rtp_packet_transport, fake_rtcp_packet_transport)) { delete channel; channel = NULL; } @@ -3565,7 +3681,9 @@ TEST_F(RtpDataChannelDoubleThreadTest, TestSendData) { class BaseChannelDeathTest : public testing::Test { public: BaseChannelDeathTest() - : // RTCP mux not required, SRTP required. + : 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(), @@ -3575,66 +3693,89 @@ class BaseChannelDeathTest : public testing::Test { cricket::AudioOptions()), cricket::CN_AUDIO, false, - true) { - rtp_transport_ = fake_transport_controller_.CreateDtlsTransport( - "foo", cricket::ICE_CANDIDATE_COMPONENT_RTP); - rtcp_transport_ = fake_transport_controller_.CreateDtlsTransport( - "foo", cricket::ICE_CANDIDATE_COMPONENT_RTCP); - EXPECT_TRUE(voice_channel_.Init_w(rtp_transport_, rtcp_transport_)); - } + true) {} protected: - cricket::FakeTransportController fake_transport_controller_; cricket::FakeMediaEngine fake_media_engine_; + cricket::FakeDtlsTransport fake_rtp_dtls_transport_; + cricket::FakeDtlsTransport fake_rtcp_dtls_transport_; cricket::VoiceChannel voice_channel_; - // Will be cleaned up by FakeTransportController, don't need to worry about - // deleting them in this test. - cricket::DtlsTransportInternal* rtp_transport_; - cricket::DtlsTransportInternal* rtcp_transport_; }; -TEST_F(BaseChannelDeathTest, SetTransportWithNullRtpTransport) { - cricket::DtlsTransportInternal* new_rtcp_transport = - fake_transport_controller_.CreateDtlsTransport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP); - EXPECT_DEATH(voice_channel_.SetTransports(nullptr, new_rtcp_transport), ""); +TEST_F(BaseChannelDeathTest, SetTransportsWithNullRtpTransport) { + ASSERT_TRUE(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, SetTransportWithMissingRtcpTransport) { - cricket::DtlsTransportInternal* new_rtp_transport = - fake_transport_controller_.CreateDtlsTransport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - EXPECT_DEATH(voice_channel_.SetTransports(new_rtp_transport, nullptr), ""); +TEST_F(BaseChannelDeathTest, SetTransportsWithMissingRtcpTransport) { + ASSERT_TRUE(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, SetTransportWithUnneededRtcpTransport) { +TEST_F(BaseChannelDeathTest, SetTransportsWithUnneededRtcpTransport) { + ASSERT_TRUE(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, CA_OFFER, nullptr)); ASSERT_TRUE(voice_channel_.SetRemoteContent(&content, CA_ANSWER, nullptr)); - cricket::DtlsTransportInternal* new_rtp_transport = - fake_transport_controller_.CreateDtlsTransport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* new_rtcp_transport = - fake_transport_controller_.CreateDtlsTransport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTCP); + 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), ""); + 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, SetTransportWithMismatchingTransportNames) { - cricket::DtlsTransportInternal* new_rtp_transport = - fake_transport_controller_.CreateDtlsTransport( - "bar", cricket::ICE_CANDIDATE_COMPONENT_RTP); - cricket::DtlsTransportInternal* new_rtcp_transport = - fake_transport_controller_.CreateDtlsTransport( - "baz", cricket::ICE_CANDIDATE_COMPONENT_RTCP); +TEST_F(BaseChannelDeathTest, SetTransportsWithMismatchingTransportNames) { + ASSERT_TRUE(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), ""); + voice_channel_.SetTransports(&new_rtp_transport, &new_rtcp_transport), + ""); +} + +// Not expected to support going from DtlsTransportInternal to +// PacketTransportInterface. +TEST_F(BaseChannelDeathTest, SetTransportsDtlsToNonDtls) { + ASSERT_TRUE(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 PacketTransportInterface to +// DtlsTransportInternal. +TEST_F(BaseChannelDeathTest, SetTransportsNonDtlsToDtls) { + ASSERT_TRUE(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) diff --git a/webrtc/pc/channelmanager.cc b/webrtc/pc/channelmanager.cc index f667900d3e..965719193e 100644 --- a/webrtc/pc/channelmanager.cc +++ b/webrtc/pc/channelmanager.cc @@ -246,7 +246,8 @@ VoiceChannel* ChannelManager::CreateVoiceChannel_w( media_channel, content_name, rtcp_mux_required, srtp_required); voice_channel->SetCryptoOptions(crypto_options_); - if (!voice_channel->Init_w(rtp_transport, rtcp_transport)) { + if (!voice_channel->Init_w(rtp_transport, rtcp_transport, rtp_transport, + rtcp_transport)) { delete voice_channel; return nullptr; } @@ -317,7 +318,8 @@ VideoChannel* ChannelManager::CreateVideoChannel_w( worker_thread_, network_thread_, signaling_thread, media_channel, content_name, rtcp_mux_required, srtp_required); video_channel->SetCryptoOptions(crypto_options_); - if (!video_channel->Init_w(rtp_transport, rtcp_transport)) { + if (!video_channel->Init_w(rtp_transport, rtcp_transport, rtp_transport, + rtcp_transport)) { delete video_channel; return NULL; } @@ -390,7 +392,8 @@ RtpDataChannel* ChannelManager::CreateRtpDataChannel_w( worker_thread_, network_thread_, signaling_thread, media_channel, content_name, rtcp_mux_required, srtp_required); data_channel->SetCryptoOptions(crypto_options_); - if (!data_channel->Init_w(rtp_transport, rtcp_transport)) { + if (!data_channel->Init_w(rtp_transport, rtcp_transport, rtp_transport, + rtcp_transport)) { LOG(LS_WARNING) << "Failed to init data channel."; delete data_channel; return nullptr; diff --git a/webrtc/pc/peerconnectioninterface_unittest.cc b/webrtc/pc/peerconnectioninterface_unittest.cc index ba3529335f..dc75ba17b3 100644 --- a/webrtc/pc/peerconnectioninterface_unittest.cc +++ b/webrtc/pc/peerconnectioninterface_unittest.cc @@ -27,7 +27,6 @@ #include "webrtc/media/base/fakevideocapturer.h" #include "webrtc/media/sctp/sctptransportinternal.h" #include "webrtc/p2p/base/fakeportallocator.h" -#include "webrtc/p2p/base/faketransportcontroller.h" #include "webrtc/pc/audiotrack.h" #include "webrtc/pc/mediasession.h" #include "webrtc/pc/mediastream.h" diff --git a/webrtc/pc/statscollector_unittest.cc b/webrtc/pc/statscollector_unittest.cc index ef218c00c6..e89da1c8ae 100644 --- a/webrtc/pc/statscollector_unittest.cc +++ b/webrtc/pc/statscollector_unittest.cc @@ -24,7 +24,6 @@ #include "webrtc/logging/rtc_event_log/rtc_event_log.h" #include "webrtc/media/base/fakemediaengine.h" #include "webrtc/media/base/test/mock_mediachannel.h" -#include "webrtc/p2p/base/faketransportcontroller.h" #include "webrtc/pc/channelmanager.h" #include "webrtc/pc/mediastream.h" #include "webrtc/pc/mediastreamtrack.h"