diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h index 4ebb614b37..5b9df680a0 100644 --- a/api/peerconnectioninterface.h +++ b/api/peerconnectioninterface.h @@ -436,11 +436,6 @@ class PeerConnectionInterface : public rtc::RefCountInterface { struct cricket::MediaConfig media_config; - // This doesn't currently work. For a while we were working on adding QUIC - // data channel support to PeerConnection, but decided on a different - // approach, and that code hasn't been updated for a while. - bool enable_quic = false; - // If set to true, only one preferred TURN allocation will be used per // network interface. UDP is preferred over TCP and IPv6 over IPv4. This // can be used to cut down on the number of candidate pairings. @@ -469,7 +464,6 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // (STUN pings), in milliseconds. rtc::Optional ice_check_min_interval; - // ICE Periodic Regathering // If set, WebRTC will periodically create and propose candidates without // starting a new ICE generation. The regathering happens continuously with diff --git a/media/base/mediaengine.h b/media/base/mediaengine.h index 5dd42d7490..5fa05c6dd9 100644 --- a/media/base/mediaengine.h +++ b/media/base/mediaengine.h @@ -170,7 +170,7 @@ class CompositeMediaEngine : public MediaEngineInterface { std::pair engines_; }; -enum DataChannelType { DCT_NONE = 0, DCT_RTP = 1, DCT_SCTP = 2, DCT_QUIC = 3 }; +enum DataChannelType { DCT_NONE = 0, DCT_RTP = 1, DCT_SCTP = 2 }; class DataEngineInterface { public: diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index eba6b68778..ff558a9ac4 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -116,28 +116,6 @@ rtc_static_library("rtc_p2p") { suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] } } - - # TODO(deadbeef): code under p2p/quic and base/transportchannelimpl.h should be - # removed. See bugs.webrtc.org/8385. - if (rtc_use_quic) { - deps = [ - "//third_party/libquic", - ] - sources += [ - "base/transportchannelimpl.h", - "quic/quicconnectionhelper.cc", - "quic/quicconnectionhelper.h", - "quic/quicsession.cc", - "quic/quicsession.h", - "quic/quictransport.cc", - "quic/quictransport.h", - "quic/quictransportchannel.cc", - "quic/quictransportchannel.h", - "quic/reliablequicstream.cc", - "quic/reliablequicstream.h", - ] - public_deps += [ "//third_party/libquic" ] - } } if (rtc_include_tests) { @@ -197,15 +175,6 @@ if (rtc_include_tests) { "base/udptransport_unittest.cc", "client/basicportallocator_unittest.cc", ] - if (rtc_use_quic) { - sources += [ - "quic/quicconnectionhelper_unittest.cc", - "quic/quicsession_unittest.cc", - "quic/quictransport_unittest.cc", - "quic/quictransportchannel_unittest.cc", - "quic/reliablequicstream_unittest.cc", - ] - } deps = [ ":p2p_test_utils", ":rtc_p2p", diff --git a/p2p/quic/quicconnectionhelper.cc b/p2p/quic/quicconnectionhelper.cc deleted file mode 100644 index 015d3f202b..0000000000 --- a/p2p/quic/quicconnectionhelper.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quicconnectionhelper.h" - -namespace cricket { - -QuicAlarm* QuicConnectionHelper::CreateAlarm( - net::QuicAlarm::Delegate* delegate) { - return new QuicAlarm(GetClock(), thread_, - net::QuicArenaScopedPtr(delegate)); -} - -net::QuicArenaScopedPtr QuicConnectionHelper::CreateAlarm( - net::QuicArenaScopedPtr delegate, - net::QuicConnectionArena* arena) { - return net::QuicArenaScopedPtr( - new QuicAlarm(GetClock(), thread_, std::move(delegate))); -} - -QuicAlarm::QuicAlarm(const net::QuicClock* clock, - rtc::Thread* thread, - net::QuicArenaScopedPtr delegate) - : net::QuicAlarm(std::move(delegate)), clock_(clock), thread_(thread) {} - -QuicAlarm::~QuicAlarm() {} - -void QuicAlarm::OnMessage(rtc::Message* msg) { - // The alarm may have been cancelled. - if (!deadline().IsInitialized()) { - return; - } - - // The alarm may have been re-set to a later time. - if (clock_->Now() < deadline()) { - SetImpl(); - return; - } - - Fire(); -} - -int64_t QuicAlarm::GetDelay() const { - return deadline().Subtract(clock_->Now()).ToMilliseconds(); -} - -void QuicAlarm::SetImpl() { - DCHECK(deadline().IsInitialized()); - CancelImpl(); // Unregister if already posted. - - int64_t delay_ms = GetDelay(); - if (delay_ms < 0) { - delay_ms = 0; - } - thread_->PostDelayed(RTC_FROM_HERE, delay_ms, this); -} - -void QuicAlarm::CancelImpl() { - thread_->Clear(this); -} - -QuicConnectionHelper::QuicConnectionHelper(rtc::Thread* thread) - : thread_(thread) {} - -QuicConnectionHelper::~QuicConnectionHelper() {} - -const net::QuicClock* QuicConnectionHelper::GetClock() const { - return &clock_; -} - -net::QuicRandom* QuicConnectionHelper::GetRandomGenerator() { - return net::QuicRandom::GetInstance(); -} - -net::QuicBufferAllocator* QuicConnectionHelper::GetBufferAllocator() { - return &buffer_allocator_; -} - -} // namespace cricket diff --git a/p2p/quic/quicconnectionhelper.h b/p2p/quic/quicconnectionhelper.h deleted file mode 100644 index 964fabb54b..0000000000 --- a/p2p/quic/quicconnectionhelper.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2016 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 P2P_QUIC_QUICCONNECTIONHELPER_H_ -#define P2P_QUIC_QUICCONNECTIONHELPER_H_ - -#include "net/quic/crypto/quic_random.h" -#include "net/quic/quic_alarm.h" -#include "net/quic/quic_clock.h" -#include "net/quic/quic_connection.h" -#include "net/quic/quic_simple_buffer_allocator.h" -#include "rtc_base/thread.h" - -namespace cricket { - -// An alarm which will go off at a scheduled time, and execute the |OnAlarm| -// method of the delegate. -class QuicAlarm : public net::QuicAlarm, public rtc::MessageHandler { - public: - QuicAlarm(const net::QuicClock* clock, - rtc::Thread* thread, - net::QuicArenaScopedPtr delegate); - - ~QuicAlarm() override; - - // rtc::MessageHandler override. - void OnMessage(rtc::Message* msg) override; - - // Helper method to get the delay in ms for posting task. - int64_t GetDelay() const; - - protected: - // net::QuicAlarm overrides. - void SetImpl() override; - void CancelImpl() override; - - private: - const net::QuicClock* clock_; - rtc::Thread* thread_; -}; - -// Helper methods for QuicConnection timing and random number generation. -class QuicConnectionHelper : public net::QuicConnectionHelperInterface { - public: - explicit QuicConnectionHelper(rtc::Thread* thread); - ~QuicConnectionHelper() override; - - // QuicConnectionHelperInterface overrides. - const net::QuicClock* GetClock() const override; - net::QuicRandom* GetRandomGenerator() override; - QuicAlarm* CreateAlarm(net::QuicAlarm::Delegate* delegate) override; - net::QuicArenaScopedPtr CreateAlarm( - net::QuicArenaScopedPtr delegate, - net::QuicConnectionArena* arena) override; - net::QuicBufferAllocator* GetBufferAllocator() override; - - private: - net::QuicClock clock_; - net::SimpleBufferAllocator buffer_allocator_; - rtc::Thread* thread_; -}; - -} // namespace cricket - -#endif // P2P_QUIC_QUICCONNECTIONHELPER_H_ diff --git a/p2p/quic/quicconnectionhelper_unittest.cc b/p2p/quic/quicconnectionhelper_unittest.cc deleted file mode 100644 index 8b1b14abfe..0000000000 --- a/p2p/quic/quicconnectionhelper_unittest.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include - -#include "p2p/quic/quicconnectionhelper.h" - -#include "net/quic/quic_time.h" -#include "rtc_base/gunit.h" - -using cricket::QuicAlarm; -using cricket::QuicConnectionHelper; - -using net::QuicClock; -using net::QuicTime; -using net::QuicWallTime; - -// Clock that can be set to arbitrary times. -class MockClock : public QuicClock { - public: - MockClock() : now_(QuicTime::Zero()) {} - - void AdvanceTime(QuicTime::Delta delta) { now_ = now_.Add(delta); } - - QuicTime Now() const override { return now_; } - - QuicTime ApproximateNow() const override { return now_; } - - QuicWallTime WallNow() const override { - return QuicWallTime::FromUNIXSeconds( - now_.Subtract(QuicTime::Zero()).ToSeconds()); - } - - base::TimeTicks NowInTicks() const { - base::TimeTicks ticks; - return ticks + base::TimeDelta::FromMicroseconds( - now_.Subtract(QuicTime::Zero()).ToMicroseconds()); - } - - private: - QuicTime now_; -}; - -// Implements OnAlarm() event which alarm triggers. -class MockAlarmDelegate : public QuicAlarm::Delegate { - public: - MockAlarmDelegate() : fired_(false) {} - - void OnAlarm() override { fired_ = true; } - - bool fired() const { return fired_; } - void Clear() { fired_ = false; } - - private: - bool fired_; -}; - -class QuicAlarmTest : public ::testing::Test { - public: - QuicAlarmTest() - : delegate_(new MockAlarmDelegate()), - alarm_(new QuicAlarm( - &clock_, - rtc::Thread::Current(), - net::QuicArenaScopedPtr(delegate_))) {} - - // Make the alarm fire after the given microseconds (us). Negative values - // imply the alarm should fire immediately. - void SetTime(int us) { - QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(us); - alarm_->Set(clock_.Now().Add(delta)); - } - - // Make rtc::Thread::Current() process the next message. - void ProcessNextMessage() { rtc::Thread::Current()->ProcessMessages(0); } - - protected: - // Handles event that alarm fires. - MockAlarmDelegate* delegate_; - // Used for setting clock time relative to alarm. - MockClock clock_; - - std::unique_ptr alarm_; -}; - -// Test that the alarm is fired. -TEST_F(QuicAlarmTest, FireAlarm) { - SetTime(-1); - ProcessNextMessage(); - ASSERT_TRUE(delegate_->fired()); - ASSERT_EQ(QuicTime::Zero(), alarm_->deadline()); -} - -// Test cancellation of alarm when it is set to fire. -TEST_F(QuicAlarmTest, CancelAlarmAfterSet) { - // TODO(mikescarlett): Test will fail in the future if - // rtc::Thread::PostDelayed calls the delegate synchronously for times <= 0. - // Rewrite this when rtc::Thread is able to use a mock clock. - SetTime(-1); - alarm_->Cancel(); - ProcessNextMessage(); - ASSERT_FALSE(delegate_->fired()); -} - -// Test cancellation of alarm when it is not set to fire. -TEST_F(QuicAlarmTest, CancelAlarmBeforeSet) { - alarm_->Cancel(); - ProcessNextMessage(); - ASSERT_FALSE(delegate_->fired()); -} - -// Test that timing for posting task is accurate. -TEST_F(QuicAlarmTest, AlarmGetDelay) { - SetTime(1000000); - EXPECT_EQ(1000, alarm_->GetDelay()); - clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(300000)); - EXPECT_EQ(700, alarm_->GetDelay()); -} diff --git a/p2p/quic/quicsession.cc b/p2p/quic/quicsession.cc deleted file mode 100644 index 36583dddeb..0000000000 --- a/p2p/quic/quicsession.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quicsession.h" - -#include -#include - -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" -#include "rtc_base/messagehandler.h" -#include "rtc_base/messagequeue.h" - -namespace cricket { - -// Default priority for incoming QUIC streams. -// TODO(mikescarlett): Determine if this value is correct. -static const net::SpdyPriority kDefaultPriority = 3; - -QuicSession::QuicSession(std::unique_ptr connection, - const net::QuicConfig& config) - : net::QuicSession(connection.release(), config) {} - -QuicSession::~QuicSession() {} - -void QuicSession::StartClientHandshake( - net::QuicCryptoClientStream* crypto_stream) { - SetCryptoStream(crypto_stream); - net::QuicSession::Initialize(); - crypto_stream->CryptoConnect(); -} - -void QuicSession::StartServerHandshake( - net::QuicCryptoServerStream* crypto_stream) { - SetCryptoStream(crypto_stream); - net::QuicSession::Initialize(); -} - -void QuicSession::SetCryptoStream(net::QuicCryptoStream* crypto_stream) { - crypto_stream_.reset(crypto_stream); -} - -bool QuicSession::ExportKeyingMaterial(base::StringPiece label, - base::StringPiece context, - size_t result_len, - std::string* result) { - return crypto_stream_->ExportKeyingMaterial(label, context, result_len, - result); -} - -void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { - net::QuicSession::OnCryptoHandshakeEvent(event); - if (event == HANDSHAKE_CONFIRMED) { - LOG(LS_INFO) << "QuicSession handshake complete"; - RTC_DCHECK(IsEncryptionEstablished()); - RTC_DCHECK(IsCryptoHandshakeConfirmed()); - - SignalHandshakeComplete(); - } -} - -void QuicSession::CloseStream(net::QuicStreamId stream_id) { - if (IsClosedStream(stream_id)) { - // When CloseStream has been called recursively (via - // ReliableQuicStream::OnClose), the stream is already closed so return. - return; - } - write_blocked_streams()->UnregisterStream(stream_id); - net::QuicSession::CloseStream(stream_id); -} - -ReliableQuicStream* QuicSession::CreateIncomingDynamicStream( - net::QuicStreamId id) { - ReliableQuicStream* stream = CreateDataStream(id, kDefaultPriority); - if (stream) { - SignalIncomingStream(stream); - } - return stream; -} - -ReliableQuicStream* QuicSession::CreateOutgoingDynamicStream( - net::SpdyPriority priority) { - return CreateDataStream(GetNextOutgoingStreamId(), priority); -} - -ReliableQuicStream* QuicSession::CreateDataStream(net::QuicStreamId id, - net::SpdyPriority priority) { - if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) { - // Encryption not active so no stream created - return nullptr; - } - ReliableQuicStream* stream = new ReliableQuicStream(id, this); - if (stream) { - // Make QuicSession take ownership of the stream. - ActivateStream(stream); - // Register the stream to the QuicWriteBlockedList. |priority| is clamped - // between 0 and 7, with 0 being the highest priority and 7 the lowest - // priority. - write_blocked_streams()->RegisterStream(stream->id(), priority); - } - return stream; -} - -void QuicSession::OnConnectionClosed(net::QuicErrorCode error, - const std::string& error_details, - net::ConnectionCloseSource source) { - net::QuicSession::OnConnectionClosed(error, error_details, source); - SignalConnectionClosed(error, - source == net::ConnectionCloseSource::FROM_PEER); -} - -bool QuicSession::OnReadPacket(const char* data, size_t data_len) { - net::QuicReceivedPacket packet(data, data_len, clock_.Now()); - ProcessUdpPacket(connection()->self_address(), connection()->peer_address(), - packet); - return true; -} - -} // namespace cricket diff --git a/p2p/quic/quicsession.h b/p2p/quic/quicsession.h deleted file mode 100644 index 9f6839a73e..0000000000 --- a/p2p/quic/quicsession.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2016 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 P2P_QUIC_QUICSESSION_H_ -#define P2P_QUIC_QUICSESSION_H_ - -#include -#include - -#include "net/quic/quic_crypto_client_stream.h" -#include "net/quic/quic_crypto_server_stream.h" -#include "net/quic/quic_crypto_stream.h" -#include "net/quic/quic_session.h" -#include "p2p/quic/reliablequicstream.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/sslidentity.h" - -namespace cricket { - -// This class provides a QUIC session over peer-to-peer transport that -// negotiates the crypto handshake (using QuicCryptoHandshake) and provides -// reading/writing of data using QUIC packets. -class QuicSession : public net::QuicSession, public sigslot::has_slots<> { - public: - QuicSession(std::unique_ptr connection, - const net::QuicConfig& config); - ~QuicSession() override; - - // Initiates client crypto handshake by sending client hello. - void StartClientHandshake(net::QuicCryptoClientStream* crypto_stream); - - // Responds to a client who has inititated the crypto handshake. - void StartServerHandshake(net::QuicCryptoServerStream* crypto_stream); - - // QuicSession overrides. - net::QuicCryptoStream* GetCryptoStream() override { - return crypto_stream_.get(); - } - ReliableQuicStream* CreateOutgoingDynamicStream( - net::SpdyPriority priority) override; - - // QuicSession optional overrides. - void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; - void CloseStream(net::QuicStreamId stream_id) override; - - // QuicConnectionVisitorInterface overrides. - void OnConnectionClosed(net::QuicErrorCode error, - const std::string& error_details, - net::ConnectionCloseSource source) override; - - // Exports keying material for SRTP. - bool ExportKeyingMaterial(base::StringPiece label, - base::StringPiece context, - size_t result_len, - std::string* result); - - // Decrypts an incoming QUIC packet to a data stream. - bool OnReadPacket(const char* data, size_t data_len); - - // Called when peers have established forward-secure encryption - sigslot::signal0<> SignalHandshakeComplete; - // Called when connection closes locally, or remotely by peer. - sigslot::signal2 SignalConnectionClosed; - // Called when an incoming QUIC stream is created so we can process data - // from it by registering a listener to - // ReliableQuicStream::SignalDataReceived. - sigslot::signal1 SignalIncomingStream; - - protected: - // Sets the QUIC crypto stream and takes ownership of it. - void SetCryptoStream(net::QuicCryptoStream* crypto_stream); - - // QuicSession override. - ReliableQuicStream* CreateIncomingDynamicStream( - net::QuicStreamId id) override; - - virtual ReliableQuicStream* CreateDataStream(net::QuicStreamId id, - net::SpdyPriority priority); - - private: - std::unique_ptr crypto_stream_; - net::QuicClock clock_; // For recording packet receipt time - - RTC_DISALLOW_COPY_AND_ASSIGN(QuicSession); -}; - -} // namespace cricket - -#endif // P2P_QUIC_QUICSESSION_H_ diff --git a/p2p/quic/quicsession_unittest.cc b/p2p/quic/quicsession_unittest.cc deleted file mode 100644 index 7762ba0e85..0000000000 --- a/p2p/quic/quicsession_unittest.cc +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quicsession.h" - -#include -#include -#include - -#include "net/base/ip_endpoint.h" -#include "net/quic/crypto/crypto_server_config_protobuf.h" -#include "net/quic/crypto/proof_source.h" -#include "net/quic/crypto/proof_verifier.h" -#include "net/quic/crypto/quic_crypto_client_config.h" -#include "net/quic/crypto/quic_crypto_server_config.h" -#include "net/quic/crypto/quic_random.h" -#include "net/quic/quic_crypto_client_stream.h" -#include "net/quic/quic_crypto_server_stream.h" -#include "p2p/base/faketransportcontroller.h" -#include "p2p/quic/quicconnectionhelper.h" -#include "p2p/quic/reliablequicstream.h" -#include "rtc_base/gunit.h" - -using net::IPAddress; -using net::IPEndPoint; -using net::PerPacketOptions; -using net::Perspective; -using net::ProofVerifyContext; -using net::ProofVerifyDetails; -using net::QuicByteCount; -using net::QuicClock; -using net::QuicCompressedCertsCache; -using net::QuicConfig; -using net::QuicConnection; -using net::QuicCryptoClientConfig; -using net::QuicCryptoServerConfig; -using net::QuicCryptoClientStream; -using net::QuicCryptoServerStream; -using net::QuicCryptoStream; -using net::QuicErrorCode; -using net::QuicPacketWriter; -using net::QuicRandom; -using net::QuicServerConfigProtobuf; -using net::QuicServerId; -using net::QuicStreamId; -using net::WriteResult; -using net::WriteStatus; - -using cricket::FakeTransportChannel; -using cricket::QuicConnectionHelper; -using cricket::QuicSession; -using cricket::ReliableQuicStream; -using cricket::TransportChannel; - -using rtc::Thread; - -// Timeout for running asynchronous operations within unit tests. -static const int kTimeoutMs = 1000; -// Testing SpdyPriority value for creating outgoing ReliableQuicStream. -static const uint8_t kDefaultPriority = 3; -// TExport keying material function -static const char kExporterLabel[] = "label"; -static const char kExporterContext[] = "context"; -static const size_t kExporterContextLen = sizeof(kExporterContext); -// Identifies QUIC server session -static const QuicServerId kServerId("www.google.com", 443); - -// Used by QuicCryptoServerConfig to provide server credentials, returning a -// canned response equal to |success|. -class FakeProofSource : public net::ProofSource { - public: - explicit FakeProofSource(bool success) : success_(success) {} - - // ProofSource override. - bool GetProof(const IPAddress& server_ip, - const std::string& hostname, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - bool ecdsa_ok, - scoped_refptr* out_certs, - std::string* out_signature, - std::string* out_leaf_cert_sct) override { - if (success_) { - std::vector certs; - certs.push_back("Required to establish handshake"); - *out_certs = new ProofSource::Chain(certs); - *out_signature = "Signature"; - *out_leaf_cert_sct = "Time"; - } - return success_; - } - - private: - // Whether or not obtaining proof source succeeds. - bool success_; -}; - -// Used by QuicCryptoClientConfig to verify server credentials, returning a -// canned response of QUIC_SUCCESS if |success| is true. -class FakeProofVerifier : public net::ProofVerifier { - public: - explicit FakeProofVerifier(bool success) : success_(success) {} - - // ProofVerifier override - net::QuicAsyncStatus VerifyProof( - const std::string& hostname, - const uint16_t port, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - const std::vector& certs, - const std::string& cert_sct, - const std::string& signature, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr* verify_details, - net::ProofVerifierCallback* callback) override { - return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE; - } - - private: - // Whether or not proof verification succeeds. - bool success_; -}; - -// Writes QUIC packets to a fake transport channel that simulates a network. -class FakeQuicPacketWriter : public QuicPacketWriter { - public: - explicit FakeQuicPacketWriter(FakeTransportChannel* fake_channel) - : fake_channel_(fake_channel) {} - - // Sends packets across the network. - WriteResult WritePacket(const char* buffer, - size_t buf_len, - const IPAddress& self_address, - const IPEndPoint& peer_address, - PerPacketOptions* options) override { - rtc::PacketOptions packet_options; - int rv = fake_channel_->SendPacket(buffer, buf_len, packet_options, 0); - net::WriteStatus status; - if (rv > 0) { - status = net::WRITE_STATUS_OK; - } else if (fake_channel_->GetError() == EWOULDBLOCK) { - status = net::WRITE_STATUS_BLOCKED; - } else { - status = net::WRITE_STATUS_ERROR; - } - return net::WriteResult(status, rv); - } - - // Returns true if the writer buffers and subsequently rewrites data - // when an attempt to write results in the underlying socket becoming - // write blocked. - bool IsWriteBlockedDataBuffered() const override { return true; } - - // Returns true if the network socket is not writable. - bool IsWriteBlocked() const override { return !fake_channel_->writable(); } - - // Records that the socket has become writable, for example when an EPOLLOUT - // is received or an asynchronous write completes. - void SetWritable() override { fake_channel_->SetWritable(true); } - - // Returns the maximum size of the packet which can be written using this - // writer for the supplied peer address. This size may actually exceed the - // size of a valid QUIC packet. - QuicByteCount GetMaxPacketSize( - const IPEndPoint& peer_address) const override { - return net::kMaxPacketSize; - } - - private: - FakeTransportChannel* fake_channel_; -}; - -// Wrapper for QuicSession and transport channel that stores incoming data. -class QuicSessionForTest : public QuicSession { - public: - QuicSessionForTest(std::unique_ptr connection, - const net::QuicConfig& config, - std::unique_ptr channel) - : QuicSession(std::move(connection), config), - channel_(std::move(channel)) { - channel_->SignalReadPacket.connect( - this, &QuicSessionForTest::OnChannelReadPacket); - } - - // Called when channel has packets to read. - void OnChannelReadPacket(TransportChannel* channel, - const char* data, - size_t size, - const rtc::PacketTime& packet_time, - int flags) { - OnReadPacket(data, size); - } - - // Called when peer receives incoming stream from another peer. - void OnIncomingStream(ReliableQuicStream* stream) { - stream->SignalDataReceived.connect(this, - &QuicSessionForTest::OnDataReceived); - last_incoming_stream_ = stream; - } - - // Called when peer has data to read from incoming stream. - void OnDataReceived(net::QuicStreamId id, const char* data, size_t length) { - last_received_data_ = std::string(data, length); - } - - std::string data() { return last_received_data_; } - - bool has_data() { return data().size() > 0; } - - FakeTransportChannel* channel() { return channel_.get(); } - - ReliableQuicStream* incoming_stream() { return last_incoming_stream_; } - - private: - // Transports QUIC packets to/from peer. - std::unique_ptr channel_; - // Stores data received by peer once it is sent from the other peer. - std::string last_received_data_; - // Handles incoming streams from sender. - ReliableQuicStream* last_incoming_stream_ = nullptr; -}; - -// Simulates data transfer between two peers using QUIC. -class QuicSessionTest : public ::testing::Test, - public QuicCryptoClientStream::ProofHandler { - public: - QuicSessionTest() - : quic_helper_(rtc::Thread::Current()), - quic_compressed_certs_cache_( - QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {} - - // Instantiates |client_peer_| and |server_peer_|. - void CreateClientAndServerSessions(); - - std::unique_ptr CreateSession( - std::unique_ptr channel, - Perspective perspective); - - QuicCryptoClientStream* CreateCryptoClientStream(QuicSessionForTest* session, - bool handshake_success); - QuicCryptoServerStream* CreateCryptoServerStream(QuicSessionForTest* session, - bool handshake_success); - - std::unique_ptr CreateConnection( - FakeTransportChannel* channel, - Perspective perspective); - - void StartHandshake(bool client_handshake_success, - bool server_handshake_success); - - // Test handshake establishment and sending/receiving of data. - void TestStreamConnection(QuicSessionForTest* from_session, - QuicSessionForTest* to_session); - // Test that client and server are not connected after handshake failure. - void TestDisconnectAfterFailedHandshake(); - - // QuicCryptoClientStream::ProofHelper overrides. - void OnProofValid( - const QuicCryptoClientConfig::CachedState& cached) override {} - void OnProofVerifyDetailsAvailable( - const ProofVerifyDetails& verify_details) override {} - - protected: - QuicConnectionHelper quic_helper_; - QuicConfig config_; - QuicClock clock_; - QuicCompressedCertsCache quic_compressed_certs_cache_; - - std::unique_ptr client_peer_; - std::unique_ptr server_peer_; -}; - -// Initializes "client peer" who begins crypto handshake and "server peer" who -// establishes encryption with client. -void QuicSessionTest::CreateClientAndServerSessions() { - std::unique_ptr channel1( - new FakeTransportChannel("channel1", 0)); - std::unique_ptr channel2( - new FakeTransportChannel("channel2", 0)); - - // Prevent channel1->OnReadPacket and channel2->OnReadPacket from calling - // themselves in a loop, which causes to future packets to be recursively - // consumed while the current thread blocks consumption of current ones. - channel2->SetAsync(true); - - // Configure peers to send packets to each other. - channel1->SetDestination(channel2.get()); - - client_peer_ = CreateSession(std::move(channel1), Perspective::IS_CLIENT); - server_peer_ = CreateSession(std::move(channel2), Perspective::IS_SERVER); -} - -std::unique_ptr QuicSessionTest::CreateSession( - std::unique_ptr channel, - Perspective perspective) { - std::unique_ptr quic_connection = - CreateConnection(channel.get(), perspective); - return std::unique_ptr(new QuicSessionForTest( - std::move(quic_connection), config_, std::move(channel))); -} - -QuicCryptoClientStream* QuicSessionTest::CreateCryptoClientStream( - QuicSessionForTest* session, - bool handshake_success) { - QuicCryptoClientConfig* client_config = - new QuicCryptoClientConfig(new FakeProofVerifier(handshake_success)); - return new QuicCryptoClientStream( - kServerId, session, new ProofVerifyContext(), client_config, this); -} - -QuicCryptoServerStream* QuicSessionTest::CreateCryptoServerStream( - QuicSessionForTest* session, - bool handshake_success) { - QuicCryptoServerConfig* server_config = - new QuicCryptoServerConfig("TESTING", QuicRandom::GetInstance(), - new FakeProofSource(handshake_success)); - // Provide server with serialized config string to prove ownership. - QuicCryptoServerConfig::ConfigOptions options; - QuicServerConfigProtobuf* primary_config = server_config->GenerateConfig( - QuicRandom::GetInstance(), &clock_, options); - server_config->AddConfig(primary_config, clock_.WallNow()); - bool use_stateless_rejects_if_peer_supported = false; - return new QuicCryptoServerStream( - server_config, &quic_compressed_certs_cache_, - use_stateless_rejects_if_peer_supported, session); -} - -std::unique_ptr QuicSessionTest::CreateConnection( - FakeTransportChannel* channel, - Perspective perspective) { - FakeQuicPacketWriter* writer = new FakeQuicPacketWriter(channel); - - IPAddress ip(0, 0, 0, 0); - bool owns_writer = true; - - return std::unique_ptr(new QuicConnection( - 0, net::IPEndPoint(ip, 0), &quic_helper_, writer, owns_writer, - perspective, net::QuicSupportedVersions())); -} - -void QuicSessionTest::StartHandshake(bool client_handshake_success, - bool server_handshake_success) { - server_peer_->StartServerHandshake( - CreateCryptoServerStream(server_peer_.get(), server_handshake_success)); - client_peer_->StartClientHandshake( - CreateCryptoClientStream(client_peer_.get(), client_handshake_success)); -} - -void QuicSessionTest::TestStreamConnection(QuicSessionForTest* from_session, - QuicSessionForTest* to_session) { - // Wait for crypto handshake to finish then check if encryption established. - ASSERT_TRUE_WAIT(from_session->IsCryptoHandshakeConfirmed() && - to_session->IsCryptoHandshakeConfirmed(), - kTimeoutMs); - - ASSERT_TRUE(from_session->IsEncryptionEstablished()); - ASSERT_TRUE(to_session->IsEncryptionEstablished()); - - std::string from_key; - std::string to_key; - - bool from_success = from_session->ExportKeyingMaterial( - kExporterLabel, kExporterContext, kExporterContextLen, &from_key); - ASSERT_TRUE(from_success); - bool to_success = to_session->ExportKeyingMaterial( - kExporterLabel, kExporterContext, kExporterContextLen, &to_key); - ASSERT_TRUE(to_success); - - EXPECT_EQ(from_key.size(), kExporterContextLen); - EXPECT_EQ(from_key, to_key); - - // Now we can establish encrypted outgoing stream. - ReliableQuicStream* outgoing_stream = - from_session->CreateOutgoingDynamicStream(kDefaultPriority); - ASSERT_NE(nullptr, outgoing_stream); - EXPECT_TRUE(from_session->HasOpenDynamicStreams()); - - outgoing_stream->SignalDataReceived.connect( - from_session, &QuicSessionForTest::OnDataReceived); - to_session->SignalIncomingStream.connect( - to_session, &QuicSessionForTest::OnIncomingStream); - - // Send a test message from peer 1 to peer 2. - const char kTestMessage[] = "Hello, World!"; - outgoing_stream->Write(kTestMessage, strlen(kTestMessage)); - - // Wait for peer 2 to receive messages. - ASSERT_TRUE_WAIT(to_session->has_data(), kTimeoutMs); - - ReliableQuicStream* incoming = to_session->incoming_stream(); - ASSERT_TRUE(incoming); - EXPECT_TRUE(to_session->HasOpenDynamicStreams()); - - EXPECT_EQ(to_session->data(), kTestMessage); - - // Send a test message from peer 2 to peer 1. - const char kTestResponse[] = "Response"; - incoming->Write(kTestResponse, strlen(kTestResponse)); - - // Wait for peer 1 to receive messages. - ASSERT_TRUE_WAIT(from_session->has_data(), kTimeoutMs); - - EXPECT_EQ(from_session->data(), kTestResponse); -} - -// Client and server should disconnect when proof verification fails. -void QuicSessionTest::TestDisconnectAfterFailedHandshake() { - EXPECT_TRUE_WAIT(!client_peer_->connection()->connected(), kTimeoutMs); - EXPECT_TRUE_WAIT(!server_peer_->connection()->connected(), kTimeoutMs); - - EXPECT_FALSE(client_peer_->IsEncryptionEstablished()); - EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed()); - - EXPECT_FALSE(server_peer_->IsEncryptionEstablished()); - EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed()); -} - -// Establish encryption then send message from client to server. -TEST_F(QuicSessionTest, ClientToServer) { - CreateClientAndServerSessions(); - StartHandshake(true, true); - TestStreamConnection(client_peer_.get(), server_peer_.get()); -} - -// Establish encryption then send message from server to client. -TEST_F(QuicSessionTest, ServerToClient) { - CreateClientAndServerSessions(); - StartHandshake(true, true); - TestStreamConnection(server_peer_.get(), client_peer_.get()); -} - -// Make client fail to verify proof from server. -TEST_F(QuicSessionTest, ClientRejection) { - CreateClientAndServerSessions(); - StartHandshake(false, true); - TestDisconnectAfterFailedHandshake(); -} - -// Make server fail to give proof to client. -TEST_F(QuicSessionTest, ServerRejection) { - CreateClientAndServerSessions(); - StartHandshake(true, false); - TestDisconnectAfterFailedHandshake(); -} - -// Test that data streams are not created before handshake. -TEST_F(QuicSessionTest, CannotCreateDataStreamBeforeHandshake) { - CreateClientAndServerSessions(); - EXPECT_EQ(nullptr, server_peer_->CreateOutgoingDynamicStream(5)); - EXPECT_EQ(nullptr, client_peer_->CreateOutgoingDynamicStream(5)); -} - -// Test that closing a QUIC stream causes the QuicSession to remove it. -TEST_F(QuicSessionTest, CloseQuicStream) { - CreateClientAndServerSessions(); - StartHandshake(true, true); - ASSERT_TRUE_WAIT(client_peer_->IsCryptoHandshakeConfirmed() && - server_peer_->IsCryptoHandshakeConfirmed(), - kTimeoutMs); - ReliableQuicStream* stream = client_peer_->CreateOutgoingDynamicStream(5); - ASSERT_NE(nullptr, stream); - EXPECT_FALSE(client_peer_->IsClosedStream(stream->id())); - stream->Close(); - EXPECT_TRUE(client_peer_->IsClosedStream(stream->id())); -} diff --git a/p2p/quic/quictransport.cc b/p2p/quic/quictransport.cc deleted file mode 100644 index 714c2676f2..0000000000 --- a/p2p/quic/quictransport.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quictransport.h" - -#include "p2p/base/p2ptransportchannel.h" -#include "rtc_base/checks.h" - -namespace cricket { - -QuicTransport::QuicTransport( - const std::string& name, - PortAllocator* allocator, - const rtc::scoped_refptr& certificate) - : Transport(name, allocator), local_certificate_(certificate) {} - -QuicTransport::~QuicTransport() { - DestroyAllChannels(); -} - -void QuicTransport::SetLocalCertificate( - const rtc::scoped_refptr& certificate) { - local_certificate_ = certificate; -} -bool QuicTransport::GetLocalCertificate( - rtc::scoped_refptr* certificate) { - if (!local_certificate_) { - return false; - } - *certificate = local_certificate_; - return true; -} - -bool QuicTransport::ApplyLocalTransportDescription( - TransportChannelImpl* channel, - std::string* error_desc) { - rtc::SSLFingerprint* local_fp = - local_description()->identity_fingerprint.get(); - if (!VerifyCertificateFingerprint(local_certificate_.get(), local_fp, - error_desc)) { - return false; - } - if (!channel->SetLocalCertificate(local_certificate_)) { - return BadTransportDescription("Failed to set local identity.", error_desc); - } - return Transport::ApplyLocalTransportDescription(channel, error_desc); -} - -bool QuicTransport::NegotiateTransportDescription(ContentAction action, - std::string* error_desc) { - if (!local_description() || !remote_description()) { - const std::string msg = - "Local and Remote description must be set before " - "transport descriptions are negotiated"; - return BadTransportDescription(msg, error_desc); - } - rtc::SSLFingerprint* local_fp = - local_description()->identity_fingerprint.get(); - rtc::SSLFingerprint* remote_fp = - remote_description()->identity_fingerprint.get(); - if (!local_fp || !remote_fp) { - return BadTransportDescription("Fingerprints must be supplied for QUIC.", - error_desc); - } - remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp)); - if (!NegotiateRole(action, &local_role_, error_desc)) { - return false; - } - // Now run the negotiation for the Transport class. - return Transport::NegotiateTransportDescription(action, error_desc); -} - -QuicTransportChannel* QuicTransport::CreateTransportChannel(int component) { - P2PTransportChannel* ice_channel = - new P2PTransportChannel(name(), component, port_allocator()); - return new QuicTransportChannel(ice_channel); -} - -void QuicTransport::DestroyTransportChannel(TransportChannelImpl* channel) { - delete channel; -} - -bool QuicTransport::GetSslRole(rtc::SSLRole* ssl_role) const { - RTC_DCHECK(ssl_role != NULL); - *ssl_role = local_role_; - return true; -} - -bool QuicTransport::ApplyNegotiatedTransportDescription( - TransportChannelImpl* channel, - std::string* error_desc) { - // Set ssl role and remote fingerprint. These are required for QUIC setup. - if (!channel->SetSslRole(local_role_)) { - return BadTransportDescription("Failed to set ssl role for the channel.", - error_desc); - } - // Apply remote fingerprint. - if (!channel->SetRemoteFingerprint( - remote_fingerprint_->algorithm, - reinterpret_cast(remote_fingerprint_->digest.data()), - remote_fingerprint_->digest.size())) { - return BadTransportDescription("Failed to apply remote fingerprint.", - error_desc); - } - return Transport::ApplyNegotiatedTransportDescription(channel, error_desc); -} - -} // namespace cricket diff --git a/p2p/quic/quictransport.h b/p2p/quic/quictransport.h deleted file mode 100644 index 6f81d0e273..0000000000 --- a/p2p/quic/quictransport.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2016 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 P2P_QUIC_QUICTRANSPORT_H_ -#define P2P_QUIC_QUICTRANSPORT_H_ - -#include -#include -#include - -#include "p2p/base/jseptransport.h" -#include "p2p/quic/quictransportchannel.h" - -namespace cricket { - -class P2PTransportChannel; -class PortAllocator; - -// TODO(deadbeef): To get QUIC working with TransportController again, would -// need to merge this class with Transport (or make separate DTLS/QUIC -// subclasses). The only difference between the two (as of typing this) is that -// the QUIC channel *requires* a fingerprint, whereas the DTLS channel can -// operate in a passthrough mode when SDES is used. -class QuicTransport : public Transport { - public: - QuicTransport(const std::string& name, - PortAllocator* allocator, - const rtc::scoped_refptr& certificate); - - ~QuicTransport() override; - - // Transport overrides. - void SetLocalCertificate( - const rtc::scoped_refptr& certificate) override; - bool GetLocalCertificate( - rtc::scoped_refptr* certificate) override; - bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override { - return true; // Not needed by QUIC - } - bool GetSslRole(rtc::SSLRole* ssl_role) const override; - - protected: - // Transport overrides. - QuicTransportChannel* CreateTransportChannel(int component) override; - void DestroyTransportChannel(TransportChannelImpl* channel) override; - bool ApplyLocalTransportDescription(TransportChannelImpl* channel, - std::string* error_desc) override; - bool NegotiateTransportDescription(ContentAction action, - std::string* error_desc) override; - bool ApplyNegotiatedTransportDescription(TransportChannelImpl* channel, - std::string* error_desc) override; - - private: - rtc::scoped_refptr local_certificate_; - rtc::SSLRole local_role_ = rtc::SSL_CLIENT; - std::unique_ptr remote_fingerprint_; -}; - -} // namespace cricket - -#endif // P2P_QUIC_QUICTRANSPORT_H_ diff --git a/p2p/quic/quictransport_unittest.cc b/p2p/quic/quictransport_unittest.cc deleted file mode 100644 index 4fb566d07b..0000000000 --- a/p2p/quic/quictransport_unittest.cc +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quictransport.h" - -#include -#include -#include - -#include "rtc_base/gunit.h" -#include "rtc_base/rtccertificate.h" -#include "rtc_base/sslidentity.h" - -using cricket::TransportChannelImpl; -using cricket::QuicTransport; -using cricket::Transport; -using cricket::TransportDescription; - -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; - -static const char kIceUfrag2[] = "TESTICEUFRAG0002"; -static const char kIcePwd2[] = "TESTICEPWD00000000000002"; - -static rtc::scoped_refptr CreateCertificate( - std::string name) { - return rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate(name, rtc::KT_DEFAULT))); -} - -static std::unique_ptr CreateFingerprint( - rtc::RTCCertificate* cert) { - std::string digest_algorithm; - cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); - return std::unique_ptr( - rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); -} - -class QuicTransportTest : public testing::Test { - public: - QuicTransportTest() : transport_("testing", nullptr, nullptr) {} - - void SetTransportDescription(cricket::ConnectionRole local_role, - cricket::ConnectionRole remote_role, - cricket::ContentAction local_action, - cricket::ContentAction remote_action, - rtc::SSLRole expected_ssl_role) { - TransportChannelImpl* channel = transport_.CreateChannel(1); - ASSERT_NE(nullptr, channel); - - rtc::scoped_refptr local_certificate( - CreateCertificate("local")); - ASSERT_NE(nullptr, local_certificate); - transport_.SetLocalCertificate(local_certificate); - - std::unique_ptr local_fingerprint = - CreateFingerprint(local_certificate.get()); - ASSERT_NE(nullptr, local_fingerprint); - TransportDescription local_desc(std::vector(), kIceUfrag1, - kIcePwd1, cricket::ICEMODE_FULL, local_role, - local_fingerprint.get()); - ASSERT_TRUE(transport_.SetLocalTransportDescription(local_desc, - local_action, nullptr)); - // The certificate is applied to QuicTransportChannel when the local - // description is set. - rtc::scoped_refptr channel_local_certificate = - channel->GetLocalCertificate(); - ASSERT_NE(nullptr, channel_local_certificate); - EXPECT_EQ(local_certificate, channel_local_certificate); - std::unique_ptr remote_fingerprint = - CreateFingerprint(CreateCertificate("remote").get()); - // NegotiateTransportDescription was not called yet. The SSL role should - // not be set and neither should the remote fingerprint. - std::unique_ptr role(new rtc::SSLRole()); - EXPECT_FALSE(channel->GetSslRole(role.get())); - // Setting the remote description should set the SSL role. - ASSERT_NE(nullptr, remote_fingerprint); - TransportDescription remote_desc(std::vector(), kIceUfrag2, - kIcePwd2, cricket::ICEMODE_FULL, - remote_role, remote_fingerprint.get()); - ASSERT_TRUE(transport_.SetRemoteTransportDescription( - remote_desc, remote_action, nullptr)); - ASSERT_TRUE(channel->GetSslRole(role.get())); - // SSL role should be client because the remote description is an ANSWER. - EXPECT_EQ(expected_ssl_role, *role); - } - - protected: - QuicTransport transport_; -}; - -// Test setting the local certificate. -TEST_F(QuicTransportTest, SetLocalCertificate) { - rtc::scoped_refptr local_certificate( - CreateCertificate("local")); - ASSERT_NE(nullptr, local_certificate); - rtc::scoped_refptr transport_local_certificate; - EXPECT_FALSE(transport_.GetLocalCertificate(&transport_local_certificate)); - transport_.SetLocalCertificate(local_certificate); - ASSERT_TRUE(transport_.GetLocalCertificate(&transport_local_certificate)); - ASSERT_NE(nullptr, transport_local_certificate); - EXPECT_EQ(local_certificate, transport_local_certificate); -} - -// Test setting the ICE role. -TEST_F(QuicTransportTest, SetIceRole) { - TransportChannelImpl* channel1 = transport_.CreateChannel(1); - ASSERT_NE(nullptr, channel1); - transport_.SetIceRole(cricket::ICEROLE_CONTROLLING); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_.ice_role()); - TransportChannelImpl* channel2 = transport_.CreateChannel(2); - ASSERT_NE(nullptr, channel2); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole()); -} - -// Test setting the ICE tie breaker. -TEST_F(QuicTransportTest, SetIceTiebreaker) { - transport_.SetIceTiebreaker(1u); - EXPECT_EQ(1u, transport_.IceTiebreaker()); -} - -// Test setting the local and remote descriptions for a SSL client. -TEST_F(QuicTransportTest, SetLocalAndRemoteTransportDescriptionClient) { - SetTransportDescription(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_PASSIVE, cricket::CA_OFFER, - cricket::CA_ANSWER, rtc::SSL_CLIENT); -} - -// Test setting the local and remote descriptions for a SSL server. -TEST_F(QuicTransportTest, SetLocalAndRemoteTransportDescriptionServer) { - SetTransportDescription(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE, cricket::CA_OFFER, - cricket::CA_ANSWER, rtc::SSL_SERVER); -} - -// Test creation and destruction of channels. -TEST_F(QuicTransportTest, CreateAndDestroyChannels) { - TransportChannelImpl* channel1 = transport_.CreateChannel(1); - ASSERT_NE(nullptr, channel1); - EXPECT_TRUE(transport_.HasChannel(1)); - EXPECT_EQ(channel1, transport_.GetChannel(1)); - TransportChannelImpl* channel2 = transport_.CreateChannel(2); - ASSERT_NE(nullptr, channel2); - EXPECT_TRUE(transport_.HasChannel(2)); - EXPECT_EQ(channel2, transport_.GetChannel(2)); - transport_.DestroyChannel(1); - EXPECT_FALSE(transport_.HasChannel(1)); - EXPECT_EQ(nullptr, transport_.GetChannel(1)); - transport_.DestroyChannel(2); - EXPECT_FALSE(transport_.HasChannel(2)); - EXPECT_EQ(nullptr, transport_.GetChannel(2)); -} diff --git a/p2p/quic/quictransportchannel.cc b/p2p/quic/quictransportchannel.cc deleted file mode 100644 index 1f32e2a794..0000000000 --- a/p2p/quic/quictransportchannel.cc +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quictransportchannel.h" - -#include - -#include "net/quic/crypto/proof_source.h" -#include "net/quic/crypto/proof_verifier.h" -#include "net/quic/crypto/quic_crypto_client_config.h" -#include "net/quic/crypto/quic_crypto_server_config.h" -#include "net/quic/quic_connection.h" -#include "net/quic/quic_crypto_client_stream.h" -#include "net/quic/quic_crypto_server_stream.h" -#include "net/quic/quic_packet_writer.h" -#include "net/quic/quic_protocol.h" -#include "p2p/base/common.h" -#include "rtc_base/checks.h" -#include "rtc_base/helpers.h" -#include "rtc_base/logging.h" -#include "rtc_base/socket.h" -#include "rtc_base/thread.h" - -namespace { - -// QUIC public header constants for net::QuicConnection. These are arbitrary -// given that |channel_| only receives packets specific to this channel, -// in which case we already know the QUIC packets have the correct destination. -const net::QuicConnectionId kConnectionId = 0; -const net::IPAddress kConnectionIpAddress(0, 0, 0, 0); -const net::IPEndPoint kConnectionIpEndpoint(kConnectionIpAddress, 0); - -// Arbitrary server port number for net::QuicCryptoClientConfig. -const int kQuicServerPort = 0; - -// QUIC connection timeout. This is large so that |channel_| can -// be responsible for connection timeout. -const int kIdleConnectionStateLifetime = 1000; // seconds - -// Length of HKDF input keying material, equal to its number of bytes. -// https://tools.ietf.org/html/rfc5869#section-2.2. -// TODO(mikescarlett): Verify that input keying material length is correct. -const size_t kInputKeyingMaterialLength = 32; - -// We don't pull the RTP constants from rtputils.h, to avoid a layer violation. -const size_t kMinRtpPacketLen = 12; - -bool IsRtpPacket(const char* data, size_t len) { - const uint8_t* u = reinterpret_cast(data); - return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80); -} - -// Function for detecting QUIC packets based off -// https://tools.ietf.org/html/draft-tsvwg-quic-protocol-02#section-6. -const size_t kMinQuicPacketLen = 2; - -bool IsQuicPacket(const char* data, size_t len) { - const uint8_t* u = reinterpret_cast(data); - return (len >= kMinQuicPacketLen && (u[0] & 0x80) == 0); -} - -// Used by QuicCryptoServerConfig to provide dummy proof credentials. -// TODO(mikescarlett): Remove when secure P2P QUIC handshake is possible. -class DummyProofSource : public net::ProofSource { - public: - DummyProofSource() {} - ~DummyProofSource() override {} - - // ProofSource override. - bool GetProof(const net::IPAddress& server_ip, - const std::string& hostname, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - bool ecdsa_ok, - scoped_refptr* out_chain, - std::string* out_signature, - std::string* out_leaf_cert_sct) override { - LOG(LS_INFO) << "GetProof() providing dummy credentials for insecure QUIC"; - std::vector certs; - certs.push_back("Dummy cert"); - *out_chain = new ProofSource::Chain(certs); - *out_signature = "Dummy signature"; - *out_leaf_cert_sct = "Dummy timestamp"; - return true; - } -}; - -// Used by QuicCryptoClientConfig to ignore the peer's credentials -// and establish an insecure QUIC connection. -// TODO(mikescarlett): Remove when secure P2P QUIC handshake is possible. -class InsecureProofVerifier : public net::ProofVerifier { - public: - InsecureProofVerifier() {} - ~InsecureProofVerifier() override {} - - // ProofVerifier override. - net::QuicAsyncStatus VerifyProof( - const std::string& hostname, - const uint16_t port, - const std::string& server_config, - net::QuicVersion quic_version, - base::StringPiece chlo_hash, - const std::vector& certs, - const std::string& cert_sct, - const std::string& signature, - const net::ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr* verify_details, - net::ProofVerifierCallback* callback) override { - LOG(LS_INFO) << "VerifyProof() ignoring credentials and returning success"; - return net::QUIC_SUCCESS; - } -}; - -} // namespace - -namespace cricket { - -QuicTransportChannel::QuicTransportChannel(TransportChannelImpl* channel) - : TransportChannelImpl(channel->transport_name(), channel->component()), - network_thread_(rtc::Thread::Current()), - channel_(channel), - helper_(network_thread_) { - channel_->SignalWritableState.connect(this, - &QuicTransportChannel::OnWritableState); - channel_->SignalReadPacket.connect(this, &QuicTransportChannel::OnReadPacket); - channel_->SignalSentPacket.connect(this, &QuicTransportChannel::OnSentPacket); - channel_->SignalReadyToSend.connect(this, - &QuicTransportChannel::OnReadyToSend); - channel_->SignalGatheringState.connect( - this, &QuicTransportChannel::OnGatheringState); - channel_->SignalCandidateGathered.connect( - this, &QuicTransportChannel::OnCandidateGathered); - channel_->SignalRoleConflict.connect(this, - &QuicTransportChannel::OnRoleConflict); - channel_->SignalRouteChange.connect(this, - &QuicTransportChannel::OnRouteChange); - channel_->SignalSelectedCandidatePairChanged.connect( - this, &QuicTransportChannel::OnSelectedCandidatePairChanged); - channel_->SignalStateChanged.connect( - this, &QuicTransportChannel::OnChannelStateChanged); - channel_->SignalReceivingState.connect( - this, &QuicTransportChannel::OnReceivingState); - - // Set the QUIC connection timeout. - config_.SetIdleConnectionStateLifetime( - net::QuicTime::Delta::FromSeconds(kIdleConnectionStateLifetime), - net::QuicTime::Delta::FromSeconds(kIdleConnectionStateLifetime)); - // Set the bytes reserved for the QUIC connection ID to zero. - config_.SetBytesForConnectionIdToSend(0); -} - -QuicTransportChannel::~QuicTransportChannel() {} - -bool QuicTransportChannel::SetLocalCertificate( - const rtc::scoped_refptr& certificate) { - if (!certificate) { - LOG_J(LS_ERROR, this) - << "No local certificate was supplied. Not doing QUIC."; - return false; - } - if (!local_certificate_) { - local_certificate_ = certificate; - return true; - } - if (certificate == local_certificate_) { - // This may happen during renegotiation. - LOG_J(LS_INFO, this) << "Ignoring identical certificate"; - return true; - } - LOG_J(LS_ERROR, this) - << "Local certificate of the QUIC connection already set. " - "Can't change the local certificate once it's active."; - return false; -} - -rtc::scoped_refptr -QuicTransportChannel::GetLocalCertificate() const { - return local_certificate_; -} - -bool QuicTransportChannel::SetSslRole(rtc::SSLRole role) { - if (ssl_role_ && *ssl_role_ == role) { - LOG_J(LS_WARNING, this) << "Ignoring SSL Role identical to current role."; - return true; - } - if (quic_state_ != QUIC_TRANSPORT_CONNECTED) { - ssl_role_ = rtc::Optional(role); - return true; - } - LOG_J(LS_ERROR, this) - << "SSL Role can't be reversed after the session is setup."; - return false; -} - -bool QuicTransportChannel::GetSslRole(rtc::SSLRole* role) const { - if (!ssl_role_) { - return false; - } - *role = *ssl_role_; - return true; -} - -bool QuicTransportChannel::SetRemoteFingerprint(const std::string& digest_alg, - const uint8_t* digest, - size_t digest_len) { - if (digest_alg.empty()) { - RTC_DCHECK(!digest_len); - LOG_J(LS_ERROR, this) << "Remote peer doesn't support digest algorithm."; - return false; - } - std::string remote_fingerprint_value(reinterpret_cast(digest), - digest_len); - // Once we have the local certificate, the same remote fingerprint can be set - // multiple times. This may happen during renegotiation. - if (remote_fingerprint_ && - remote_fingerprint_->value == remote_fingerprint_value && - remote_fingerprint_->algorithm == digest_alg) { - LOG_J(LS_INFO, this) - << "Ignoring identical remote fingerprint and algorithm"; - return true; - } - remote_fingerprint_ = rtc::Optional(RemoteFingerprint()); - remote_fingerprint_->value = remote_fingerprint_value; - remote_fingerprint_->algorithm = digest_alg; - return true; -} - -bool QuicTransportChannel::ExportKeyingMaterial(const std::string& label, - const uint8_t* context, - size_t context_len, - bool use_context, - uint8_t* result, - size_t result_len) { - std::string quic_context(reinterpret_cast(context), context_len); - std::string quic_result; - if (!quic_->ExportKeyingMaterial(label, quic_context, result_len, - &quic_result)) { - return false; - } - quic_result.copy(reinterpret_cast(result), result_len); - return true; -} - -bool QuicTransportChannel::GetSrtpCryptoSuite(int* cipher) { - *cipher = rtc::SRTP_AES128_CM_SHA1_80; - return true; -} - -// Called from upper layers to send a media packet. -int QuicTransportChannel::SendPacket(const char* data, - size_t size, - const rtc::PacketOptions& options, - int flags) { - if ((flags & PF_SRTP_BYPASS) && IsRtpPacket(data, size)) { - return channel_->SendPacket(data, size, options); - } - LOG(LS_ERROR) << "Failed to send an invalid SRTP bypass packet using QUIC."; - return -1; -} - -// The state transition logic here is as follows: -// - Before the QUIC handshake is complete, the QUIC channel is unwritable. -// - When |channel_| goes writable we start the QUIC handshake. -// - Once the QUIC handshake completes, the state is that of the -// |channel_| again. -void QuicTransportChannel::OnWritableState(TransportChannel* channel) { - RTC_DCHECK(rtc::Thread::Current() == network_thread_); - RTC_DCHECK(channel == channel_.get()); - LOG_J(LS_VERBOSE, this) - << "QuicTransportChannel: channel writable state changed to " - << channel_->writable(); - switch (quic_state_) { - case QUIC_TRANSPORT_NEW: - // Start the QUIC handshake when |channel_| is writable. - // This will fail if the SSL role or remote fingerprint are not set. - // Otherwise failure could result from network or QUIC errors. - MaybeStartQuic(); - break; - case QUIC_TRANSPORT_CONNECTED: - // Note: SignalWritableState fired by set_writable. - set_writable(channel_->writable()); - if (HasDataToWrite()) { - OnCanWrite(); - } - break; - case QUIC_TRANSPORT_CONNECTING: - // This channel is not writable until the QUIC handshake finishes. It - // might have been write blocked. - if (HasDataToWrite()) { - OnCanWrite(); - } - break; - case QUIC_TRANSPORT_CLOSED: - // TODO(mikescarlett): Allow the QUIC connection to be reset if it drops - // due to a non-failure. - break; - } -} - -void QuicTransportChannel::OnReceivingState(TransportChannel* channel) { - RTC_DCHECK(rtc::Thread::Current() == network_thread_); - RTC_DCHECK(channel == channel_.get()); - LOG_J(LS_VERBOSE, this) - << "QuicTransportChannel: channel receiving state changed to " - << channel_->receiving(); - if (quic_state_ == QUIC_TRANSPORT_CONNECTED) { - // Note: SignalReceivingState fired by set_receiving. - set_receiving(channel_->receiving()); - } -} - -void QuicTransportChannel::OnReadPacket(TransportChannel* channel, - const char* data, - size_t size, - const rtc::PacketTime& packet_time, - int flags) { - RTC_DCHECK(rtc::Thread::Current() == network_thread_); - RTC_DCHECK(channel == channel_.get()); - RTC_DCHECK(flags == 0); - - switch (quic_state_) { - case QUIC_TRANSPORT_NEW: - // This would occur if other peer is ready to start QUIC but this peer - // hasn't started QUIC. - LOG_J(LS_INFO, this) << "Dropping packet received before QUIC started."; - break; - case QUIC_TRANSPORT_CONNECTING: - case QUIC_TRANSPORT_CONNECTED: - // We should only get QUIC or SRTP packets; STUN's already been demuxed. - // Is this potentially a QUIC packet? - if (IsQuicPacket(data, size)) { - if (!HandleQuicPacket(data, size)) { - LOG_J(LS_ERROR, this) << "Failed to handle QUIC packet."; - return; - } - } else { - // If this is an RTP packet, signal upwards as a bypass packet. - if (!IsRtpPacket(data, size)) { - LOG_J(LS_ERROR, this) - << "Received unexpected non-QUIC, non-RTP packet."; - return; - } - SignalReadPacket(this, data, size, packet_time, PF_SRTP_BYPASS); - } - break; - case QUIC_TRANSPORT_CLOSED: - // This shouldn't be happening. Drop the packet. - break; - } -} - -void QuicTransportChannel::OnSentPacket(TransportChannel* channel, - const rtc::SentPacket& sent_packet) { - RTC_DCHECK(rtc::Thread::Current() == network_thread_); - SignalSentPacket(this, sent_packet); -} - -void QuicTransportChannel::OnReadyToSend(TransportChannel* channel) { - if (writable()) { - SignalReadyToSend(this); - } -} - -void QuicTransportChannel::OnGatheringState(TransportChannelImpl* channel) { - RTC_DCHECK(channel == channel_.get()); - SignalGatheringState(this); -} - -void QuicTransportChannel::OnCandidateGathered(TransportChannelImpl* channel, - const Candidate& c) { - RTC_DCHECK(channel == channel_.get()); - SignalCandidateGathered(this, c); -} - -void QuicTransportChannel::OnRoleConflict(TransportChannelImpl* channel) { - RTC_DCHECK(channel == channel_.get()); - SignalRoleConflict(this); -} - -void QuicTransportChannel::OnRouteChange(TransportChannel* channel, - const Candidate& candidate) { - RTC_DCHECK(channel == channel_.get()); - SignalRouteChange(this, candidate); -} - -void QuicTransportChannel::OnSelectedCandidatePairChanged( - TransportChannel* channel, - CandidatePairInterface* selected_candidate_pair, - int last_sent_packet_id, - bool ready_to_send) { - RTC_DCHECK(channel == channel_.get()); - SignalSelectedCandidatePairChanged(this, selected_candidate_pair, - last_sent_packet_id, ready_to_send); -} - -void QuicTransportChannel::OnChannelStateChanged( - TransportChannelImpl* channel) { - RTC_DCHECK(channel == channel_.get()); - SignalStateChanged(this); -} - -bool QuicTransportChannel::MaybeStartQuic() { - if (!channel_->writable()) { - LOG_J(LS_ERROR, this) << "Couldn't start QUIC handshake."; - return false; - } - if (!CreateQuicSession() || !StartQuicHandshake()) { - LOG_J(LS_WARNING, this) - << "Underlying channel is writable but cannot start " - "the QUIC handshake."; - return false; - } - // Verify connection is not closed due to QUIC bug or network failure. - // A closed connection should not happen since |channel_| is writable. - if (!quic_->connection()->connected()) { - LOG_J(LS_ERROR, this) - << "QUIC connection should not be closed if underlying " - "channel is writable."; - return false; - } - // Indicate that |quic_| is ready to receive QUIC packets. - set_quic_state(QUIC_TRANSPORT_CONNECTING); - return true; -} - -bool QuicTransportChannel::CreateQuicSession() { - if (!ssl_role_ || !remote_fingerprint_) { - return false; - } - net::Perspective perspective = (*ssl_role_ == rtc::SSL_CLIENT) - ? net::Perspective::IS_CLIENT - : net::Perspective::IS_SERVER; - bool owns_writer = false; - std::unique_ptr connection(new net::QuicConnection( - kConnectionId, kConnectionIpEndpoint, &helper_, this, owns_writer, - perspective, net::QuicSupportedVersions())); - quic_.reset(new QuicSession(std::move(connection), config_)); - quic_->SignalHandshakeComplete.connect( - this, &QuicTransportChannel::OnHandshakeComplete); - quic_->SignalConnectionClosed.connect( - this, &QuicTransportChannel::OnConnectionClosed); - quic_->SignalIncomingStream.connect(this, - &QuicTransportChannel::OnIncomingStream); - return true; -} - -bool QuicTransportChannel::StartQuicHandshake() { - if (*ssl_role_ == rtc::SSL_CLIENT) { - // Unique identifier for remote peer. - net::QuicServerId server_id(remote_fingerprint_->value, kQuicServerPort); - // Perform authentication of remote peer; owned by QuicCryptoClientConfig. - // TODO(mikescarlett): Actually verify proof. - net::ProofVerifier* proof_verifier = new InsecureProofVerifier(); - quic_crypto_client_config_.reset( - new net::QuicCryptoClientConfig(proof_verifier)); - net::QuicCryptoClientStream* crypto_stream = - new net::QuicCryptoClientStream(server_id, quic_.get(), - new net::ProofVerifyContext(), - quic_crypto_client_config_.get(), this); - quic_->StartClientHandshake(crypto_stream); - LOG_J(LS_INFO, this) << "QuicTransportChannel: Started client handshake."; - } else { - RTC_DCHECK_EQ(*ssl_role_, rtc::SSL_SERVER); - // Provide credentials to remote peer; owned by QuicCryptoServerConfig. - // TODO(mikescarlett): Actually provide credentials. - net::ProofSource* proof_source = new DummyProofSource(); - // Input keying material to HKDF, per http://tools.ietf.org/html/rfc5869. - // This is pseudorandom so that HKDF-Extract outputs a pseudorandom key, - // since QuicCryptoServerConfig does not use a salt value. - std::string source_address_token_secret; - if (!rtc::CreateRandomString(kInputKeyingMaterialLength, - &source_address_token_secret)) { - LOG_J(LS_ERROR, this) - << "Error generating input keying material for HKDF."; - return false; - } - quic_crypto_server_config_.reset(new net::QuicCryptoServerConfig( - source_address_token_secret, helper_.GetRandomGenerator(), - proof_source)); - // Provide server with serialized config string to prove ownership. - net::QuicCryptoServerConfig::ConfigOptions options; - quic_crypto_server_config_->AddDefaultConfig(helper_.GetRandomGenerator(), - helper_.GetClock(), options); - quic_compressed_certs_cache_.reset(new net::QuicCompressedCertsCache( - net::QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)); - // TODO(mikescarlett): Add support for stateless rejects. - bool use_stateless_rejects_if_peer_supported = false; - net::QuicCryptoServerStream* crypto_stream = - new net::QuicCryptoServerStream(quic_crypto_server_config_.get(), - quic_compressed_certs_cache_.get(), - use_stateless_rejects_if_peer_supported, - quic_.get()); - quic_->StartServerHandshake(crypto_stream); - LOG_J(LS_INFO, this) << "QuicTransportChannel: Started server handshake."; - } - return true; -} - -bool QuicTransportChannel::HandleQuicPacket(const char* data, size_t size) { - RTC_DCHECK(rtc::Thread::Current() == network_thread_); - return quic_->OnReadPacket(data, size); -} - -net::WriteResult QuicTransportChannel::WritePacket( - const char* buffer, - size_t buf_len, - const net::IPAddress& self_address, - const net::IPEndPoint& peer_address, - net::PerPacketOptions* options) { - // QUIC should never call this if IsWriteBlocked, but just in case... - if (IsWriteBlocked()) { - return net::WriteResult(net::WRITE_STATUS_BLOCKED, EWOULDBLOCK); - } - // TODO(mikescarlett): Figure out how to tell QUIC "I dropped your packet, but - // don't block" without the QUIC connection tearing itself down. - int sent = channel_->SendPacket(buffer, buf_len, rtc::PacketOptions()); - int bytes_written = sent > 0 ? sent : 0; - return net::WriteResult(net::WRITE_STATUS_OK, bytes_written); -} - -// TODO(mikescarlett): Implement check for whether |channel_| is currently -// write blocked so that |quic_| does not try to write packet. This is -// necessary because |channel_| can be writable yet write blocked and -// channel_->GetError() is not flushed when there is no error. -bool QuicTransportChannel::IsWriteBlocked() const { - return !channel_->writable(); -} - -void QuicTransportChannel::OnHandshakeComplete() { - set_quic_state(QUIC_TRANSPORT_CONNECTED); - set_writable(true); - // OnReceivingState might have been called before the QUIC channel was - // connected, in which case the QUIC channel is now receiving. - if (channel_->receiving()) { - set_receiving(true); - } -} - -void QuicTransportChannel::OnConnectionClosed(net::QuicErrorCode error, - bool from_peer) { - LOG_J(LS_INFO, this) << "Connection closed by " - << (from_peer ? "other" : "this") << " peer " - << "with QUIC error " << error; - // TODO(mikescarlett): Allow the QUIC session to be reset when the connection - // does not close due to failure. - set_quic_state(QUIC_TRANSPORT_CLOSED); - set_writable(false); - SignalClosed(); -} - -void QuicTransportChannel::OnProofValid( - const net::QuicCryptoClientConfig::CachedState& cached) { - LOG_J(LS_INFO, this) << "Cached proof marked valid"; -} - -void QuicTransportChannel::OnProofVerifyDetailsAvailable( - const net::ProofVerifyDetails& verify_details) { - LOG_J(LS_INFO, this) << "Proof verify details available from" - << " QuicCryptoClientStream"; -} - -bool QuicTransportChannel::HasDataToWrite() const { - return quic_ && quic_->HasDataToWrite(); -} - -void QuicTransportChannel::OnCanWrite() { - RTC_DCHECK(quic_ != nullptr); - quic_->connection()->OnCanWrite(); -} - -void QuicTransportChannel::set_quic_state(QuicTransportState state) { - LOG_J(LS_VERBOSE, this) << "set_quic_state from:" << quic_state_ << " to " - << state; - quic_state_ = state; -} - -ReliableQuicStream* QuicTransportChannel::CreateQuicStream() { - if (quic_) { - net::SpdyPriority priority = 0; // Priority of the QUIC stream - return quic_->CreateOutgoingDynamicStream(priority); - } - return nullptr; -} - -void QuicTransportChannel::OnIncomingStream(ReliableQuicStream* stream) { - SignalIncomingStream(stream); -} - -} // namespace cricket diff --git a/p2p/quic/quictransportchannel.h b/p2p/quic/quictransportchannel.h deleted file mode 100644 index 2099bf9f4b..0000000000 --- a/p2p/quic/quictransportchannel.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2016 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 P2P_QUIC_QUICTRANSPORTCHANNEL_H_ -#define P2P_QUIC_QUICTRANSPORTCHANNEL_H_ - -#include -#include -#include - -#include "net/quic/quic_crypto_client_stream.h" -#include "net/quic/quic_packet_writer.h" -#include "api/optional.h" -#include "p2p/base/transportchannelimpl.h" -#include "p2p/quic/quicconnectionhelper.h" -#include "p2p/quic/quicsession.h" -#include "rtc_base/constructormagic.h" - -namespace cricket { - -enum QuicTransportState { - // Haven't started QUIC handshake. - QUIC_TRANSPORT_NEW = 0, - // Started QUIC handshake. - QUIC_TRANSPORT_CONNECTING, - // Negotiated, and has an encrypted connection. - QUIC_TRANSPORT_CONNECTED, - // QUIC connection closed due to handshake failure or explicit shutdown. - QUIC_TRANSPORT_CLOSED, -}; - -// QuicTransportChannel uses the QUIC protocol to establish encryption with -// another peer, wrapping an existing TransportChannelImpl instance -// (e.g a P2PTransportChannel) responsible for connecting peers. -// Once the wrapped transport channel is connected, QuicTransportChannel -// negotiates the crypto handshake and establishes SRTP keying material. -// -// How it works: -// -// QuicTransportChannel { -// QuicSession* quic_; -// TransportChannelImpl* channel_; -// } -// -// - Data written to SendPacket() is passed directly to |channel_| if it is -// an SRTP packet with the PF_SRTP_BYPASS flag. -// -// - |quic_| passes outgoing packets to WritePacket(), which transfers them -// to |channel_| to be sent across the network. -// -// - Data which comes into QuicTransportChannel::OnReadPacket is checked to -// see if it is QUIC, and if it is, passed to |quic_|. SRTP packets are -// signaled upwards as bypass packets. -// -// - When the QUIC handshake is completed, quic_state() returns -// QUIC_TRANSPORT_CONNECTED and SRTP keying material can be exported. -// -// - CreateQuicStream() creates an outgoing QUIC stream. Once the local peer -// sends data from this stream, the remote peer emits SignalIncomingStream -// with a QUIC stream of the same id to handle received data. -// -// TODO(mikescarlett): Implement secure QUIC handshake and 0-RTT handshakes. -class QuicTransportChannel : public TransportChannelImpl, - public net::QuicPacketWriter, - public net::QuicCryptoClientStream::ProofHandler { - public: - // |channel| - the TransportChannelImpl we are wrapping. - explicit QuicTransportChannel(TransportChannelImpl* channel); - ~QuicTransportChannel() override; - - // TransportChannel overrides. - // TODO(mikescarlett): Implement certificate authentication. - bool SetLocalCertificate( - const rtc::scoped_refptr& certificate) override; - rtc::scoped_refptr GetLocalCertificate() const override; - // TODO(mikescarlett): Implement fingerprint authentication. - bool SetRemoteFingerprint(const std::string& digest_alg, - const uint8_t* digest, - size_t digest_len) override; - // TODO(mikescarlett): Remove this DTLS-specific method when TransportChannel - // does not require defining it. - bool IsDtlsActive() const override { return true; } - // Sends a RTP packet if the PF_SRTP_BYPASS flag is set. - int SendPacket(const char* data, - size_t size, - const rtc::PacketOptions& options, - int flags) override; - // Sets up the ciphers to use for SRTP. - // TODO(mikescarlett): Use SRTP ciphers for negotiation. - bool SetSrtpCryptoSuites(const std::vector& ciphers) override { - return true; - } - // Determines which SRTP cipher was negotiated. - // TODO(mikescarlett): Implement QUIC cipher negotiation. This currently - // returns SRTP_AES128_CM_SHA1_80. - bool GetSrtpCryptoSuite(int* cipher) override; - bool SetSslRole(rtc::SSLRole role) override; - bool GetSslRole(rtc::SSLRole* role) const override; - // Determines which SSL cipher was negotiated. - // TODO(mikescarlett): Implement QUIC cipher negotiation. - bool GetSslCipherSuite(int* cipher) override { return false; } - // Once QUIC is established (i.e., |quic_state_| is QUIC_TRANSPORT_CONNECTED), - // this extracts the keys negotiated during the QUIC handshake, for use - // in external encryption such as for extracting SRTP keys. - 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; - // TODO(mikescarlett): Remove this method once TransportChannel does not - // require defining it. - std::unique_ptr GetRemoteSSLCertificate() - const override { - return nullptr; - } - - // TransportChannelImpl overrides that we forward to the wrapped transport. - void SetIceRole(IceRole role) override { channel_->SetIceRole(role); } - IceRole GetIceRole() const override { return channel_->GetIceRole(); } - int SetOption(rtc::Socket::Option opt, int value) override { - return channel_->SetOption(opt, value); - } - bool GetOption(rtc::Socket::Option opt, int* value) override { - return channel_->GetOption(opt, value); - } - int GetError() override { return channel_->GetError(); } - bool GetStats(ConnectionInfos* infos) override { - return channel_->GetStats(infos); - } - const std::string SessionId() const override { return channel_->SessionId(); } - TransportChannelState GetState() const override { - return channel_->GetState(); - } - void SetIceTiebreaker(uint64_t tiebreaker) override { - channel_->SetIceTiebreaker(tiebreaker); - } - void SetIceParameters(const IceParameters& ice_params) override { - channel_->SetIceParameters(ice_params); - } - void SetRemoteIceParameters(const IceParameters& ice_params) override { - channel_->SetRemoteIceParameters(ice_params); - } - void SetRemoteIceMode(IceMode mode) override { - channel_->SetRemoteIceMode(mode); - } - void MaybeStartGathering() override { channel_->MaybeStartGathering(); } - IceGatheringState gathering_state() const override { - return channel_->gathering_state(); - } - void AddRemoteCandidate(const Candidate& candidate) override { - channel_->AddRemoteCandidate(candidate); - } - void RemoveRemoteCandidate(const Candidate& candidate) override { - channel_->RemoveRemoteCandidate(candidate); - } - void SetIceConfig(const IceConfig& config) override { - channel_->SetIceConfig(config); - } - - // QuicPacketWriter overrides. - // Called from net::QuicConnection when |quic_| has packets to write. - net::WriteResult WritePacket(const char* buffer, - size_t buf_len, - const net::IPAddress& self_address, - const net::IPEndPoint& peer_address, - net::PerPacketOptions* options) override; - // Whether QuicTransportChannel buffers data when unable to write. If this is - // set to false, then net::QuicConnection buffers unsent packets. - bool IsWriteBlockedDataBuffered() const override { return false; } - // Whether QuicTransportChannel is write blocked. If this returns true, - // outgoing QUIC packets are queued by net::QuicConnection until - // QuicTransportChannel::OnCanWrite() is called. - bool IsWriteBlocked() const override; - // Maximum size of the QUIC packet which can be written. - net::QuicByteCount GetMaxPacketSize( - const net::IPEndPoint& peer_address) const override { - return net::kMaxPacketSize; - } - // This method is not used -- call set_writable(bool writable) instead. - // TODO(miekscarlett): Remove this method once QuicPacketWriter does not - // require defining it. - void SetWritable() override {} - - // QuicCryptoClientStream::ProofHandler overrides. - // Called by client crypto handshake when cached proof is marked valid. - void OnProofValid( - const net::QuicCryptoClientConfig::CachedState& cached) override; - // Called by the client crypto handshake when proof verification details - // become available, either because proof verification is complete, or when - // cached details are used. - void OnProofVerifyDetailsAvailable( - const net::ProofVerifyDetails& verify_details) override; - - void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override { - channel_->SetMetricsObserver(observer); - } - - // Returns true if |quic_| has queued data which wasn't written due - // to |channel_| being write blocked. - bool HasDataToWrite() const; - // Writes queued data for |quic_| when |channel_| is no longer write blocked. - void OnCanWrite(); - // Connectivity state of QuicTransportChannel. - QuicTransportState quic_state() const { return quic_state_; } - // Creates a new QUIC stream that can send data. - ReliableQuicStream* CreateQuicStream(); - - TransportChannelImpl* ice_transport_channel() { return channel_.get(); } - - // Emitted when |quic_| creates a QUIC stream to receive data from the remote - // peer, when the stream did not exist previously. - sigslot::signal1 SignalIncomingStream; - // Emitted when the QuicTransportChannel state becomes QUIC_TRANSPORT_CLOSED. - sigslot::signal0<> SignalClosed; - - private: - // Fingerprint of remote peer. - struct RemoteFingerprint { - std::string value; - std::string algorithm; - }; - - // Callbacks for |channel_|. - void OnReadableState(TransportChannel* channel); - void OnWritableState(TransportChannel* channel); - void OnReadPacket(TransportChannel* channel, - const char* data, - size_t size, - const rtc::PacketTime& packet_time, - int flags); - void OnSentPacket(TransportChannel* channel, - const rtc::SentPacket& sent_packet); - void OnReadyToSend(TransportChannel* channel); - void OnReceivingState(TransportChannel* channel); - void OnGatheringState(TransportChannelImpl* channel); - void OnCandidateGathered(TransportChannelImpl* channel, const Candidate& c); - void OnRoleConflict(TransportChannelImpl* channel); - void OnRouteChange(TransportChannel* channel, const Candidate& candidate); - void OnSelectedCandidatePairChanged( - TransportChannel* channel, - CandidatePairInterface* selected_candidate_pair, - int last_sent_packet_id, - bool ready_to_send); - void OnChannelStateChanged(TransportChannelImpl* channel); - - // Callbacks for |quic_|. - // Called when |quic_| has established the crypto handshake. - void OnHandshakeComplete(); - // Called when |quic_| has closed the connection. - void OnConnectionClosed(net::QuicErrorCode error, bool from_peer); - // Called when |quic_| has created a new QUIC stream for incoming data. - void OnIncomingStream(ReliableQuicStream* stream); - - // Called by OnReadPacket() when a QUIC packet is received. - bool HandleQuicPacket(const char* data, size_t size); - // Sets up the QUIC handshake. - bool MaybeStartQuic(); - // Creates the QUIC connection and |quic_|. - bool CreateQuicSession(); - // Creates the crypto stream and initializes the handshake. - bool StartQuicHandshake(); - // Sets the QuicTransportChannel connectivity state. - void set_quic_state(QuicTransportState state); - - // Everything should occur on this thread. - rtc::Thread* network_thread_; - // Underlying channel which is responsible for connecting with the remote peer - // and sending/receiving packets across the network. - std::unique_ptr channel_; - // Connectivity state of QuicTransportChannel. - QuicTransportState quic_state_ = QUIC_TRANSPORT_NEW; - // QUIC session which establishes the crypto handshake and converts data - // to/from QUIC packets. - std::unique_ptr quic_; - // Non-crypto config for |quic_|. - net::QuicConfig config_; - // Helper for net::QuicConnection that provides timing and - // random number generation. - QuicConnectionHelper helper_; - // This peer's role in the QUIC crypto handshake. SSL_CLIENT implies this peer - // initiates the handshake, while SSL_SERVER implies the remote peer initiates - // the handshake. This must be set before we start QUIC. - rtc::Optional ssl_role_; - // Config for QUIC crypto client stream, used when |ssl_role_| is SSL_CLIENT. - std::unique_ptr quic_crypto_client_config_; - // Config for QUIC crypto server stream, used when |ssl_role_| is SSL_SERVER. - std::unique_ptr quic_crypto_server_config_; - // Used by QUIC crypto server stream to track most recently compressed certs. - std::unique_ptr quic_compressed_certs_cache_; - // This peer's certificate. - rtc::scoped_refptr local_certificate_; - // Fingerprint of the remote peer. This must be set before we start QUIC. - rtc::Optional remote_fingerprint_; - - RTC_DISALLOW_COPY_AND_ASSIGN(QuicTransportChannel); -}; - -} // namespace cricket - -#endif // P2P_QUIC_QUICTRANSPORTCHANNEL_H_ diff --git a/p2p/quic/quictransportchannel_unittest.cc b/p2p/quic/quictransportchannel_unittest.cc deleted file mode 100644 index 4e583b5ab1..0000000000 --- a/p2p/quic/quictransportchannel_unittest.cc +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/quictransportchannel.h" - -#include -#include -#include -#include - -#include "p2p/base/faketransportcontroller.h" -#include "rtc_base/gunit.h" -#include "rtc_base/sslidentity.h" - -using cricket::ConnectionRole; -using cricket::IceRole; -using cricket::QuicTransportChannel; -using cricket::ReliableQuicStream; -using cricket::TransportChannel; -using cricket::TransportDescription; - -// Timeout in milliseconds for asynchronous operations in unit tests. -static const int kTimeoutMs = 1000; - -// Export keying material parameters. -static const char kExporterLabel[] = "label"; -static const uint8_t kExporterContext[] = "context"; -static const size_t kExporterContextLength = sizeof(kExporterContext); -static const size_t kOutputKeyLength = 20; - -// Packet size for SRTP. -static const size_t kPacketSize = 100; - -// Indicates ICE channel has no write error. -static const int kNoWriteError = 0; - -// ICE parameters. -static const char kIceUfrag[] = "TESTICEUFRAG0001"; -static const char kIcePwd[] = "TESTICEPWD00000000000001"; - -// QUIC packet parameters. -static const net::IPAddress kIpAddress(0, 0, 0, 0); -static const net::IPEndPoint kIpEndpoint(kIpAddress, 0); - -// Detects incoming RTP packets. -static bool IsRtpLeadByte(uint8_t b) { - return (b & 0xC0) == 0x80; -} - -// Maps SSL role to ICE connection role. The peer with a client role is assumed -// to be the one who initiates the connection. -static ConnectionRole SslRoleToConnectionRole(rtc::SSLRole ssl_role) { - return (ssl_role == rtc::SSL_CLIENT) ? cricket::CONNECTIONROLE_ACTIVE - : cricket::CONNECTIONROLE_PASSIVE; -} - -// Allows cricket::FakeTransportChannel to simulate write blocked -// and write error states. -// TODO(mikescarlett): Add this functionality to cricket::FakeTransportChannel. -class FailableTransportChannel : public cricket::FakeTransportChannel { - public: - FailableTransportChannel(const std::string& name, int component) - : cricket::FakeTransportChannel(name, component), error_(kNoWriteError) {} - int GetError() override { return error_; } - void SetError(int error) { error_ = error; } - int SendPacket(const char* data, - size_t len, - const rtc::PacketOptions& options, - int flags) override { - if (error_ == kNoWriteError) { - return cricket::FakeTransportChannel::SendPacket(data, len, options, - flags); - } - return -1; - } - - private: - int error_; -}; - -// Peer who establishes a handshake using a QuicTransportChannel, which wraps -// a FailableTransportChannel to simulate network connectivity and ICE -// negotiation. -class QuicTestPeer : public sigslot::has_slots<> { - public: - explicit QuicTestPeer(const std::string& name) - : name_(name), - bytes_sent_(0), - ice_channel_(new FailableTransportChannel(name_, 0)), - quic_channel_(ice_channel_), - incoming_stream_count_(0) { - quic_channel_.SignalReadPacket.connect( - this, &QuicTestPeer::OnTransportChannelReadPacket); - quic_channel_.SignalIncomingStream.connect(this, - &QuicTestPeer::OnIncomingStream); - quic_channel_.SignalClosed.connect(this, &QuicTestPeer::OnClosed); - ice_channel_->SetAsync(true); - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate(name_, rtc::KT_DEFAULT))); - quic_channel_.SetLocalCertificate(local_cert); - local_fingerprint_.reset(CreateFingerprint(local_cert.get())); - } - - // Connects |ice_channel_| to that of the other peer. - void Connect(QuicTestPeer* other_peer) { - ice_channel_->SetDestination(other_peer->ice_channel_); - } - - // Disconnects |ice_channel_|. - void Disconnect() { ice_channel_->SetDestination(nullptr); } - - // Generates ICE credentials and passes them to |quic_channel_|. - void SetIceParameters(IceRole local_ice_role, - ConnectionRole local_connection_role, - ConnectionRole remote_connection_role, - rtc::SSLFingerprint* remote_fingerprint) { - quic_channel_.SetIceRole(local_ice_role); - quic_channel_.SetIceTiebreaker( - (local_ice_role == cricket::ICEROLE_CONTROLLING) ? 1 : 2); - - TransportDescription local_desc( - std::vector(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL, - local_connection_role, local_fingerprint_.get()); - TransportDescription remote_desc( - std::vector(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL, - remote_connection_role, remote_fingerprint); - - quic_channel_.SetIceParameters(local_desc.GetIceParameters()); - quic_channel_.SetRemoteIceParameters(remote_desc.GetIceParameters()); - } - - // Creates fingerprint from certificate. - rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { - std::string digest_algorithm; - bool get_digest_algorithm = - cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); - if (!get_digest_algorithm || digest_algorithm.empty()) { - return nullptr; - } - std::unique_ptr fingerprint( - rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); - if (digest_algorithm != rtc::DIGEST_SHA_256) { - return nullptr; - } - return fingerprint.release(); - } - - // Sends SRTP packet to the other peer via |quic_channel_|. - int SendSrtpPacket() { - char packet[kPacketSize]; - packet[0] = 0x80; // Make the packet header look like RTP. - int rv = quic_channel_.SendPacket( - &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS); - bytes_sent_ += rv; - return rv; - } - - // Sends a non-SRTP packet with the PF_SRTP_BYPASS flag via |quic_channel_|. - int SendInvalidSrtpPacket() { - char packet[kPacketSize]; - // Fill the packet with 0 to form an invalid SRTP packet. - memset(packet, 0, kPacketSize); - return quic_channel_.SendPacket( - &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS); - } - - // Sends an RTP packet to the other peer via |quic_channel_|, without the SRTP - // bypass flag. - int SendRtpPacket() { - char packet[kPacketSize]; - packet[0] = 0x80; // Make the packet header look like RTP. - return quic_channel_.SendPacket(&packet[0], kPacketSize, - rtc::PacketOptions(), 0); - } - - void ClearBytesSent() { bytes_sent_ = 0; } - - void ClearBytesReceived() { bytes_received_ = 0; } - - void SetWriteError(int error) { ice_channel_->SetError(error); } - - size_t bytes_received() const { return bytes_received_; } - - size_t bytes_sent() const { return bytes_sent_; } - - FailableTransportChannel* ice_channel() { return ice_channel_; } - - QuicTransportChannel* quic_channel() { return &quic_channel_; } - - std::unique_ptr& local_fingerprint() { - return local_fingerprint_; - } - - ReliableQuicStream* incoming_quic_stream() { return incoming_quic_stream_; } - - size_t incoming_stream_count() const { return incoming_stream_count_; } - - bool signal_closed_emitted() const { return signal_closed_emitted_; } - - private: - // QuicTransportChannel callbacks. - void OnTransportChannelReadPacket(TransportChannel* channel, - const char* data, - size_t size, - const rtc::PacketTime& packet_time, - int flags) { - bytes_received_ += size; - // Only SRTP packets should have the bypass flag set. - int expected_flags = IsRtpLeadByte(data[0]) ? cricket::PF_SRTP_BYPASS : 0; - ASSERT_EQ(expected_flags, flags); - } - void OnIncomingStream(ReliableQuicStream* stream) { - incoming_quic_stream_ = stream; - ++incoming_stream_count_; - } - void OnClosed() { signal_closed_emitted_ = true; } - - std::string name_; // Channel name. - size_t bytes_sent_; // Bytes sent by QUIC channel. - size_t bytes_received_; // Bytes received by QUIC channel. - FailableTransportChannel* ice_channel_; // Simulates an ICE channel. - QuicTransportChannel quic_channel_; // QUIC channel to test. - std::unique_ptr local_fingerprint_; - ReliableQuicStream* incoming_quic_stream_ = nullptr; - size_t incoming_stream_count_; - bool signal_closed_emitted_ = false; -}; - -class QuicTransportChannelTest : public testing::Test { - public: - QuicTransportChannelTest() : peer1_("P1"), peer2_("P2") {} - - // Performs negotiation before QUIC handshake, then connects the fake - // transport channels of each peer. As a side effect, the QUIC channels - // start sending handshake messages. |peer1_| has a client role and |peer2_| - // has server role in the QUIC handshake. - void Connect() { - SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER); - peer1_.Connect(&peer2_); - } - - // Disconnects the fake transport channels. - void Disconnect() { - peer1_.Disconnect(); - peer2_.Disconnect(); - } - - // Sets up ICE parameters and exchanges fingerprints before QUIC handshake. - void SetIceAndCryptoParameters(rtc::SSLRole peer1_ssl_role, - rtc::SSLRole peer2_ssl_role) { - peer1_.quic_channel()->SetSslRole(peer1_ssl_role); - peer2_.quic_channel()->SetSslRole(peer2_ssl_role); - - std::unique_ptr& peer1_fingerprint = - peer1_.local_fingerprint(); - std::unique_ptr& peer2_fingerprint = - peer2_.local_fingerprint(); - - peer1_.quic_channel()->SetRemoteFingerprint( - peer2_fingerprint->algorithm, - reinterpret_cast(peer2_fingerprint->digest.data()), - peer2_fingerprint->digest.size()); - peer2_.quic_channel()->SetRemoteFingerprint( - peer1_fingerprint->algorithm, - reinterpret_cast(peer1_fingerprint->digest.data()), - peer1_fingerprint->digest.size()); - - ConnectionRole peer1_connection_role = - SslRoleToConnectionRole(peer1_ssl_role); - ConnectionRole peer2_connection_role = - SslRoleToConnectionRole(peer2_ssl_role); - - peer1_.SetIceParameters(cricket::ICEROLE_CONTROLLED, peer1_connection_role, - peer2_connection_role, peer2_fingerprint.get()); - peer2_.SetIceParameters(cricket::ICEROLE_CONTROLLING, peer2_connection_role, - peer1_connection_role, peer1_fingerprint.get()); - } - - // Checks if QUIC handshake is done. - bool quic_connected() { - return peer1_.quic_channel()->quic_state() == - cricket::QUIC_TRANSPORT_CONNECTED && - peer2_.quic_channel()->quic_state() == - cricket::QUIC_TRANSPORT_CONNECTED; - } - - // Checks if QUIC channels are writable. - bool quic_writable() { - return peer1_.quic_channel()->writable() && - peer2_.quic_channel()->writable(); - } - - protected: - // QUIC peer with a client role, who initiates the QUIC handshake. - QuicTestPeer peer1_; - // QUIC peer with a server role, who responds to the client peer. - QuicTestPeer peer2_; -}; - -// Test that the QUIC channel passes ICE parameters to the underlying ICE -// channel. -TEST_F(QuicTransportChannelTest, ChannelSetupIce) { - SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER); - FailableTransportChannel* channel1 = peer1_.ice_channel(); - FailableTransportChannel* channel2 = peer2_.ice_channel(); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole()); - EXPECT_EQ(2u, channel1->IceTiebreaker()); - EXPECT_EQ(kIceUfrag, channel1->ice_ufrag()); - EXPECT_EQ(kIcePwd, channel1->ice_pwd()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole()); - EXPECT_EQ(1u, channel2->IceTiebreaker()); -} - -// Test that export keying material generates identical keys for both peers -// after the QUIC handshake. -TEST_F(QuicTransportChannelTest, ExportKeyingMaterial) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - uint8_t key1[kOutputKeyLength]; - uint8_t key2[kOutputKeyLength]; - - bool from_success = peer1_.quic_channel()->ExportKeyingMaterial( - kExporterLabel, kExporterContext, kExporterContextLength, true, key1, - kOutputKeyLength); - ASSERT_TRUE(from_success); - bool to_success = peer2_.quic_channel()->ExportKeyingMaterial( - kExporterLabel, kExporterContext, kExporterContextLength, true, key2, - kOutputKeyLength); - ASSERT_TRUE(to_success); - - EXPECT_EQ(0, memcmp(key1, key2, sizeof(key1))); -} - -// Test that the QUIC channel is not writable before the QUIC handshake. -TEST_F(QuicTransportChannelTest, NotWritableBeforeHandshake) { - Connect(); - EXPECT_FALSE(quic_writable()); - Disconnect(); - EXPECT_FALSE(quic_writable()); - Connect(); - EXPECT_FALSE(quic_writable()); -} - -// Test that once handshake begins, QUIC is not writable until its completion. -TEST_F(QuicTransportChannelTest, QuicHandshake) { - Connect(); - EXPECT_FALSE(quic_writable()); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - EXPECT_TRUE(quic_writable()); -} - -// Test that Non-SRTP data is not sent using SendPacket(), regardless of QUIC -// channel state. -TEST_F(QuicTransportChannelTest, TransferNonSrtp) { - // Send data before ICE channel is connected. - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - ASSERT_EQ(-1, peer1_.SendRtpPacket()); - EXPECT_EQ(0u, peer1_.bytes_sent()); - // Send data after ICE channel is connected, before QUIC handshake. - Connect(); - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - ASSERT_EQ(-1, peer1_.SendRtpPacket()); - EXPECT_EQ(0u, peer1_.bytes_sent()); - // Send data after QUIC handshake. - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - ASSERT_EQ(-1, peer1_.SendRtpPacket()); - EXPECT_EQ(0u, peer1_.bytes_sent()); -} - -// Test that SRTP data is always be sent, regardless of QUIC channel state, when -// the ICE channel is connected. -TEST_F(QuicTransportChannelTest, TransferSrtp) { - // Send data after ICE channel is connected, before QUIC handshake. - Connect(); - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - ASSERT_EQ(kPacketSize, static_cast(peer1_.SendSrtpPacket())); - EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs); - EXPECT_EQ(kPacketSize, peer1_.bytes_sent()); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - // Send data after QUIC handshake. - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - ASSERT_EQ(kPacketSize, static_cast(peer1_.SendSrtpPacket())); - EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs); - EXPECT_EQ(kPacketSize, peer1_.bytes_sent()); -} - -// Test that invalid SRTP (non-SRTP data with -// PF_SRTP_BYPASS flag) fails to send with return value -1. -TEST_F(QuicTransportChannelTest, TransferInvalidSrtp) { - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket()); - EXPECT_EQ(0u, peer2_.bytes_received()); - Connect(); - peer1_.ClearBytesSent(); - peer2_.ClearBytesReceived(); - EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket()); - EXPECT_EQ(0u, peer2_.bytes_received()); -} - -// Test that QuicTransportChannel::WritePacket blocks when the ICE -// channel is not writable, and otherwise succeeds. -TEST_F(QuicTransportChannelTest, QuicWritePacket) { - peer1_.ice_channel()->SetDestination(peer2_.ice_channel()); - std::string packet = "FAKEQUICPACKET"; - - // QUIC should be write blocked when the ICE channel is not writable. - peer1_.ice_channel()->SetWritable(false); - EXPECT_TRUE(peer1_.quic_channel()->IsWriteBlocked()); - net::WriteResult write_blocked_result = peer1_.quic_channel()->WritePacket( - packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); - EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_blocked_result.status); - EXPECT_EQ(EWOULDBLOCK, write_blocked_result.error_code); - - // QUIC should ignore errors when the ICE channel is writable. - peer1_.ice_channel()->SetWritable(true); - EXPECT_FALSE(peer1_.quic_channel()->IsWriteBlocked()); - peer1_.SetWriteError(EWOULDBLOCK); - net::WriteResult ignore_error_result = peer1_.quic_channel()->WritePacket( - packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); - EXPECT_EQ(net::WRITE_STATUS_OK, ignore_error_result.status); - EXPECT_EQ(0, ignore_error_result.bytes_written); - - peer1_.SetWriteError(kNoWriteError); - net::WriteResult no_error_result = peer1_.quic_channel()->WritePacket( - packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); - EXPECT_EQ(net::WRITE_STATUS_OK, no_error_result.status); - EXPECT_EQ(static_cast(packet.size()), no_error_result.bytes_written); -} - -// Test that SSL roles can be reversed before QUIC handshake. -TEST_F(QuicTransportChannelTest, QuicRoleReversalBeforeQuic) { - EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); - EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); - EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); -} - -// Test that SSL roles cannot be reversed after the QUIC handshake. SetSslRole -// returns true if the current SSL role equals the proposed SSL role. -TEST_F(QuicTransportChannelTest, QuicRoleReversalAfterQuic) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - EXPECT_FALSE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); - EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); - EXPECT_FALSE(peer2_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); - EXPECT_TRUE(peer2_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); -} - -// Set the SSL role, then test that GetSslRole returns the same value. -TEST_F(QuicTransportChannelTest, SetGetSslRole) { - ASSERT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); - std::unique_ptr role(new rtc::SSLRole()); - ASSERT_TRUE(peer1_.quic_channel()->GetSslRole(role.get())); - EXPECT_EQ(rtc::SSL_SERVER, *role); -} - -// Test that after the QUIC handshake is complete, the QUIC handshake remains -// confirmed even if the ICE channel reconnects. -TEST_F(QuicTransportChannelTest, HandshakeConfirmedAfterReconnect) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - Disconnect(); - EXPECT_TRUE(quic_connected()); - Connect(); - EXPECT_TRUE(quic_connected()); -} - -// Test that if the ICE channel becomes receiving after the QUIC channel is -// connected, then the QUIC channel becomes receiving. -TEST_F(QuicTransportChannelTest, IceReceivingAfterConnected) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - ASSERT_FALSE(peer1_.ice_channel()->receiving()); - EXPECT_FALSE(peer1_.quic_channel()->receiving()); - peer1_.ice_channel()->SetReceiving(true); - EXPECT_TRUE(peer1_.quic_channel()->receiving()); -} - -// Test that if the ICE channel becomes receiving before the QUIC channel is -// connected, then the QUIC channel becomes receiving. -TEST_F(QuicTransportChannelTest, IceReceivingBeforeConnected) { - Connect(); - peer1_.ice_channel()->SetReceiving(true); - ASSERT_TRUE(peer1_.ice_channel()->receiving()); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - EXPECT_TRUE(peer1_.quic_channel()->receiving()); -} - -// Test that when peer 1 creates an outgoing stream, peer 2 creates an incoming -// QUIC stream with the same ID and fires OnIncomingStream. -TEST_F(QuicTransportChannelTest, CreateOutgoingAndIncomingQuicStream) { - Connect(); - EXPECT_EQ(nullptr, peer1_.quic_channel()->CreateQuicStream()); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - ReliableQuicStream* stream = peer1_.quic_channel()->CreateQuicStream(); - ASSERT_NE(nullptr, stream); - stream->Write("Hi", 2); - EXPECT_TRUE_WAIT(peer2_.incoming_quic_stream() != nullptr, kTimeoutMs); - EXPECT_EQ(stream->id(), peer2_.incoming_quic_stream()->id()); -} - -// Test that if the QuicTransportChannel is unwritable, then all outgoing QUIC -// streams can send data once the QuicTransprotChannel becomes writable again. -TEST_F(QuicTransportChannelTest, OutgoingQuicStreamSendsDataAfterReconnect) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - ReliableQuicStream* stream1 = peer1_.quic_channel()->CreateQuicStream(); - ASSERT_NE(nullptr, stream1); - ReliableQuicStream* stream2 = peer1_.quic_channel()->CreateQuicStream(); - ASSERT_NE(nullptr, stream2); - - peer1_.ice_channel()->SetWritable(false); - stream1->Write("First", 5); - EXPECT_EQ(5u, stream1->queued_data_bytes()); - stream2->Write("Second", 6); - EXPECT_EQ(6u, stream2->queued_data_bytes()); - EXPECT_EQ(0u, peer2_.incoming_stream_count()); - - peer1_.ice_channel()->SetWritable(true); - EXPECT_EQ_WAIT(0u, stream1->queued_data_bytes(), kTimeoutMs); - EXPECT_EQ_WAIT(0u, stream2->queued_data_bytes(), kTimeoutMs); - EXPECT_EQ_WAIT(2u, peer2_.incoming_stream_count(), kTimeoutMs); -} - -// Test that SignalClosed is emitted when the QuicConnection closes. -TEST_F(QuicTransportChannelTest, SignalClosedEmitted) { - Connect(); - ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); - ASSERT_FALSE(peer1_.signal_closed_emitted()); - ReliableQuicStream* stream = peer1_.quic_channel()->CreateQuicStream(); - ASSERT_NE(nullptr, stream); - stream->CloseConnectionWithDetails(net::QuicErrorCode::QUIC_NO_ERROR, - "Closing QUIC for testing"); - EXPECT_TRUE(peer1_.signal_closed_emitted()); - EXPECT_TRUE_WAIT(peer2_.signal_closed_emitted(), kTimeoutMs); -} diff --git a/p2p/quic/reliablequicstream.cc b/p2p/quic/reliablequicstream.cc deleted file mode 100644 index 3dadf337ef..0000000000 --- a/p2p/quic/reliablequicstream.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/reliablequicstream.h" - -#include - -#include "net/quic/quic_session.h" -#include "rtc_base/checks.h" - -namespace cricket { - -ReliableQuicStream::ReliableQuicStream(net::QuicStreamId id, - net::QuicSession* session) - : net::ReliableQuicStream(id, session) { - RTC_DCHECK_NE(net::kCryptoStreamId, id); -} - -ReliableQuicStream::~ReliableQuicStream() {} - -void ReliableQuicStream::OnDataAvailable() { - struct iovec iov; - while (sequencer()->GetReadableRegions(&iov, 1) == 1) { - SignalDataReceived(id(), reinterpret_cast(iov.iov_base), - iov.iov_len); - sequencer()->MarkConsumed(iov.iov_len); - } -} - -void ReliableQuicStream::OnClose() { - net::ReliableQuicStream::OnClose(); - SignalClosed(id(), connection_error()); -} - -rtc::StreamResult ReliableQuicStream::Write(const char* data, - size_t len, - bool fin) { - // Writes the data, or buffers it. - WriteOrBufferData(base::StringPiece(data, len), fin, nullptr); - if (HasBufferedData()) { - return rtc::StreamResult(rtc::SR_BLOCK); - } - return rtc::StreamResult(rtc::SR_SUCCESS); -} - -void ReliableQuicStream::Close() { - net::ReliableQuicStream::session()->CloseStream(id()); -} - -void ReliableQuicStream::OnCanWrite() { - uint64_t prev_queued_bytes = queued_data_bytes(); - net::ReliableQuicStream::OnCanWrite(); - uint64_t queued_bytes_written = prev_queued_bytes - queued_data_bytes(); - SignalQueuedBytesWritten(id(), queued_bytes_written); -} - -} // namespace cricket diff --git a/p2p/quic/reliablequicstream.h b/p2p/quic/reliablequicstream.h deleted file mode 100644 index 2fcc701a4d..0000000000 --- a/p2p/quic/reliablequicstream.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2016 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 P2P_QUIC_RELIABLEQUICSTREAM_H_ -#define P2P_QUIC_RELIABLEQUICSTREAM_H_ - -#include "net/quic/reliable_quic_stream.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/stream.h" - -namespace cricket { - -// Streams created by QuicSession. -class ReliableQuicStream : public net::ReliableQuicStream, - public sigslot::has_slots<> { - public: - ReliableQuicStream(net::QuicStreamId id, net::QuicSession* session); - - ~ReliableQuicStream() override; - - // ReliableQuicStream overrides. - void OnDataAvailable() override; - void OnClose() override; - void OnCanWrite() override; - - // Process decrypted data into encrypted QUIC packets, which get sent to the - // QuicPacketWriter. rtc::SR_BLOCK is returned if the operation blocks instead - // of writing, in which case the data is queued until OnCanWrite() is called. - // If |fin| == true, then this stream closes after sending data. - rtc::StreamResult Write(const char* data, size_t len, bool fin = false); - // Removes this stream from the QuicSession's stream map. - void Close(); - - // Called when decrypted data is ready to be read. - sigslot::signal3 SignalDataReceived; - // Called when the stream is closed. - sigslot::signal2 SignalClosed; - // Emits the number of queued bytes that were written by OnCanWrite(), after - // the stream was previously write blocked. - sigslot::signal2 SignalQueuedBytesWritten; - - private: - RTC_DISALLOW_COPY_AND_ASSIGN(ReliableQuicStream); -}; - -} // namespace cricket - -#endif // P2P_QUIC_RELIABLEQUICSTREAM_H_ diff --git a/p2p/quic/reliablequicstream_unittest.cc b/p2p/quic/reliablequicstream_unittest.cc deleted file mode 100644 index 3f24001bff..0000000000 --- a/p2p/quic/reliablequicstream_unittest.cc +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2016 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "p2p/quic/reliablequicstream.h" - -#include -#include - -#include "net/base/ip_address_number.h" -#include "net/quic/quic_connection.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/quic_session.h" -#include "p2p/quic/quicconnectionhelper.h" -#include "rtc_base/buffer.h" -#include "rtc_base/gunit.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/stream.h" - -using cricket::QuicConnectionHelper; -using cricket::ReliableQuicStream; - -using net::IPAddress; -using net::IPEndPoint; -using net::PerPacketOptions; -using net::Perspective; -using net::QuicAckListenerInterface; -using net::QuicConfig; -using net::QuicConnection; -using net::QuicConsumedData; -using net::QuicCryptoStream; -using net::QuicErrorCode; -using net::QuicIOVector; -using net::QuicPacketWriter; -using net::QuicRstStreamErrorCode; -using net::QuicSession; -using net::QuicStreamId; -using net::QuicStreamOffset; -using net::SpdyPriority; - -using rtc::SR_SUCCESS; -using rtc::SR_BLOCK; - -// Arbitrary number for a stream's write blocked priority. -static const SpdyPriority kDefaultPriority = 3; -static const net::QuicStreamId kStreamId = 5; - -// QuicSession that does not create streams and writes data from -// ReliableQuicStream to a string. -class MockQuicSession : public QuicSession { - public: - MockQuicSession(QuicConnection* connection, - const QuicConfig& config, - std::string* write_buffer) - : QuicSession(connection, config), write_buffer_(write_buffer) {} - - // Writes outgoing data from ReliableQuicStream to a string. - QuicConsumedData WritevData( - QuicStreamId id, - QuicIOVector iovector, - QuicStreamOffset offset, - bool fin, - QuicAckListenerInterface* ack_notifier_delegate) override { - if (!writable_) { - return QuicConsumedData(0, false); - } - - const char* data = reinterpret_cast(iovector.iov->iov_base); - size_t len = iovector.total_length; - write_buffer_->append(data, len); - return QuicConsumedData(len, false); - } - - net::ReliableQuicStream* CreateIncomingDynamicStream( - QuicStreamId id) override { - return new ReliableQuicStream(kStreamId, this); - } - - net::ReliableQuicStream* CreateOutgoingDynamicStream( - SpdyPriority priority) override { - return nullptr; - } - - QuicCryptoStream* GetCryptoStream() override { return nullptr; } - - // Called by ReliableQuicStream when they want to close stream. - void SendRstStream(QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written) override {} - - // Sets whether data is written to buffer, or else if this is write blocked. - void set_writable(bool writable) { writable_ = writable; } - - // Tracks whether the stream is write blocked and its priority. - void register_write_blocked_stream(QuicStreamId stream_id, - SpdyPriority priority) { - write_blocked_streams()->RegisterStream(stream_id, priority); - } - - private: - // Stores written data from ReliableQuicStream. - std::string* write_buffer_; - // Whether data is written to write_buffer_. - bool writable_ = true; -}; - -// Packet writer that does nothing. This is required for QuicConnection but -// isn't used for writing data. -class DummyPacketWriter : public QuicPacketWriter { - public: - DummyPacketWriter() {} - - // QuicPacketWriter overrides. - net::WriteResult WritePacket(const char* buffer, - size_t buf_len, - const IPAddress& self_address, - const IPEndPoint& peer_address, - PerPacketOptions* options) override { - return net::WriteResult(net::WRITE_STATUS_ERROR, 0); - } - - bool IsWriteBlockedDataBuffered() const override { return false; } - - bool IsWriteBlocked() const override { return false; }; - - void SetWritable() override {} - - net::QuicByteCount GetMaxPacketSize( - const net::IPEndPoint& peer_address) const override { - return 0; - } -}; - -class ReliableQuicStreamTest : public ::testing::Test, - public sigslot::has_slots<> { - public: - ReliableQuicStreamTest() {} - - void CreateReliableQuicStream() { - - // Arbitrary values for QuicConnection. - QuicConnectionHelper* quic_helper = - new QuicConnectionHelper(rtc::Thread::Current()); - Perspective perspective = Perspective::IS_SERVER; - net::IPAddress ip(0, 0, 0, 0); - - bool owns_writer = true; - - QuicConnection* connection = new QuicConnection( - 0, IPEndPoint(ip, 0), quic_helper, new DummyPacketWriter(), owns_writer, - perspective, net::QuicSupportedVersions()); - - session_.reset( - new MockQuicSession(connection, QuicConfig(), &write_buffer_)); - stream_.reset(new ReliableQuicStream(kStreamId, session_.get())); - stream_->SignalDataReceived.connect( - this, &ReliableQuicStreamTest::OnDataReceived); - stream_->SignalClosed.connect(this, &ReliableQuicStreamTest::OnClosed); - stream_->SignalQueuedBytesWritten.connect( - this, &ReliableQuicStreamTest::OnQueuedBytesWritten); - - session_->register_write_blocked_stream(stream_->id(), kDefaultPriority); - } - - void OnDataReceived(QuicStreamId id, const char* data, size_t length) { - ASSERT_EQ(id, stream_->id()); - read_buffer_.append(data, length); - } - - void OnClosed(QuicStreamId id, int err) { closed_ = true; } - - void OnQueuedBytesWritten(QuicStreamId id, uint64_t queued_bytes_written) { - queued_bytes_written_ = queued_bytes_written; - } - - protected: - std::unique_ptr stream_; - std::unique_ptr session_; - - // Data written by the ReliableQuicStream. - std::string write_buffer_; - // Data read by the ReliableQuicStream. - std::string read_buffer_; - // Whether the ReliableQuicStream is closed. - bool closed_ = false; - // Bytes written by OnCanWrite(). - uint64_t queued_bytes_written_; -}; - -// Write an entire string. -TEST_F(ReliableQuicStreamTest, WriteDataWhole) { - CreateReliableQuicStream(); - EXPECT_EQ(SR_SUCCESS, stream_->Write("Foo bar", 7)); - - EXPECT_EQ("Foo bar", write_buffer_); -} - -// Write part of a string. -TEST_F(ReliableQuicStreamTest, WriteDataPartial) { - CreateReliableQuicStream(); - EXPECT_EQ(SR_SUCCESS, stream_->Write("Hello, World!", 8)); - EXPECT_EQ("Hello, W", write_buffer_); -} - -// Test that strings are buffered correctly. -TEST_F(ReliableQuicStreamTest, BufferData) { - CreateReliableQuicStream(); - - session_->set_writable(false); - EXPECT_EQ(SR_BLOCK, stream_->Write("Foo bar", 7)); - - EXPECT_EQ(0ul, write_buffer_.size()); - EXPECT_TRUE(stream_->HasBufferedData()); - - session_->set_writable(true); - stream_->OnCanWrite(); - EXPECT_EQ(7ul, queued_bytes_written_); - - EXPECT_FALSE(stream_->HasBufferedData()); - EXPECT_EQ("Foo bar", write_buffer_); - - EXPECT_EQ(SR_SUCCESS, stream_->Write("xyzzy", 5)); - EXPECT_EQ("Foo barxyzzy", write_buffer_); -} - -// Read an entire string. -TEST_F(ReliableQuicStreamTest, ReadDataWhole) { - CreateReliableQuicStream(); - net::QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); - stream_->OnStreamFrame(frame); - - EXPECT_EQ("Hello, World!", read_buffer_); -} - -// Read part of a string. -TEST_F(ReliableQuicStreamTest, ReadDataPartial) { - CreateReliableQuicStream(); - net::QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!"); - frame.frame_length = 5; - stream_->OnStreamFrame(frame); - - EXPECT_EQ("Hello", read_buffer_); -} - -// Test that closing the stream results in a callback. -TEST_F(ReliableQuicStreamTest, CloseStream) { - CreateReliableQuicStream(); - EXPECT_FALSE(closed_); - stream_->OnClose(); - EXPECT_TRUE(closed_); -} diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 25effcd08f..116c1acec1 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -232,19 +232,6 @@ rtc_source_set("libjingle_peerconnection") { ":peerconnection", "../api:libjingle_peerconnection_api", ] - - if (rtc_use_quic) { - sources += [ - "quicdatachannel.cc", - "quicdatachannel.h", - "quicdatatransport.cc", - "quicdatatransport.h", - ] - deps += [ "//third_party/libquic" ] - public_deps = [ - "//third_party/libquic", - ] - } } if (rtc_include_tests) { @@ -440,16 +427,6 @@ if (rtc_include_tests) { ] } - if (rtc_use_quic) { - public_deps = [ - "//third_party/libquic", - ] - sources += [ - "quicdatachannel_unittest.cc", - "quicdatatransport_unittest.cc", - ] - } - deps = [] if (is_android) { deps += [ ":android_black_magic" ] diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index b96818f48b..5007f3351c 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -270,7 +270,6 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( ContinualGatheringPolicy continual_gathering_policy; bool prioritize_most_likely_ice_candidate_pairs; struct cricket::MediaConfig media_config; - bool enable_quic; bool prune_turn_ports; bool presume_writable_when_fully_relayed; bool enable_ice_renomination; @@ -302,7 +301,6 @@ bool PeerConnectionInterface::RTCConfiguration::operator==( disable_ipv6_on_wifi == o.disable_ipv6_on_wifi && max_ipv6_networks == o.max_ipv6_networks && enable_rtp_data_channel == o.enable_rtp_data_channel && - enable_quic == o.enable_quic && screencast_min_bitrate == o.screencast_min_bitrate && combined_audio_video_bwe == o.combined_audio_video_bwe && enable_dtls_srtp == o.enable_dtls_srtp && @@ -781,22 +779,6 @@ PeerConnection::CreateDataChannel( const std::string& label, const DataChannelInit* config) { TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel"); -#ifdef HAVE_QUIC - if (session_->data_channel_type() == cricket::DCT_QUIC) { - // TODO(zhihuang): Handle case when config is NULL. - if (!config) { - LOG(LS_ERROR) << "Missing config for QUIC data channel."; - return nullptr; - } - // TODO(zhihuang): Allow unreliable or ordered QUIC data channels. - if (!config->reliable || config->ordered) { - LOG(LS_ERROR) << "QUIC data channel does not implement unreliable or " - "ordered delivery."; - return nullptr; - } - return session_->quic_data_transport()->CreateDataChannel(label, config); - } -#endif // HAVE_QUIC bool first_datachannel = !HasDataChannels(); @@ -2356,13 +2338,7 @@ rtc::scoped_refptr PeerConnection::InternalCreateDataChannel( } bool PeerConnection::HasDataChannels() const { -#ifdef HAVE_QUIC - return !rtp_data_channels_.empty() || !sctp_data_channels_.empty() || - (session_->quic_data_transport() && - session_->quic_data_transport()->HasDataChannels()); -#else return !rtp_data_channels_.empty() || !sctp_data_channels_.empty(); -#endif // HAVE_QUIC } void PeerConnection::AllocateSctpSids(rtc::SSLRole role) { diff --git a/pc/peerconnectionendtoend_unittest.cc b/pc/peerconnectionendtoend_unittest.cc index cfd0755ae4..bc80e1e6e2 100644 --- a/pc/peerconnectionendtoend_unittest.cc +++ b/pc/peerconnectionendtoend_unittest.cc @@ -495,85 +495,7 @@ TEST_F(PeerConnectionEndToEndTest, EXPECT_EQ(1U, dc_1_observer->received_message_count()); EXPECT_EQ(1U, dc_2_observer->received_message_count()); } -#endif // HAVE_SCTP -#ifdef HAVE_QUIC -// Test that QUIC data channels can be used and that messages go to the correct -// remote data channel when both peers want to use QUIC. It is assumed that the -// application has externally negotiated the data channel parameters. -TEST_F(PeerConnectionEndToEndTest, MessageTransferBetweenQuicDataChannels) { - config_.enable_quic = true; - CreatePcs(); - - webrtc::DataChannelInit init_1; - init_1.id = 0; - init_1.ordered = false; - init_1.reliable = true; - - webrtc::DataChannelInit init_2; - init_2.id = 1; - init_2.ordered = false; - init_2.reliable = true; - - rtc::scoped_refptr caller_dc_1( - caller_->CreateDataChannel("data", init_1)); - ASSERT_NE(nullptr, caller_dc_1); - rtc::scoped_refptr caller_dc_2( - caller_->CreateDataChannel("data", init_2)); - ASSERT_NE(nullptr, caller_dc_2); - rtc::scoped_refptr callee_dc_1( - callee_->CreateDataChannel("data", init_1)); - ASSERT_NE(nullptr, callee_dc_1); - rtc::scoped_refptr callee_dc_2( - callee_->CreateDataChannel("data", init_2)); - ASSERT_NE(nullptr, callee_dc_2); - - Negotiate(); - WaitForConnection(); - EXPECT_TRUE_WAIT(caller_dc_1->state() == webrtc::DataChannelInterface::kOpen, - kMaxWait); - EXPECT_TRUE_WAIT(callee_dc_1->state() == webrtc::DataChannelInterface::kOpen, - kMaxWait); - EXPECT_TRUE_WAIT(caller_dc_2->state() == webrtc::DataChannelInterface::kOpen, - kMaxWait); - EXPECT_TRUE_WAIT(callee_dc_2->state() == webrtc::DataChannelInterface::kOpen, - kMaxWait); - - std::unique_ptr dc_1_observer( - new webrtc::MockDataChannelObserver(callee_dc_1.get())); - - std::unique_ptr dc_2_observer( - new webrtc::MockDataChannelObserver(callee_dc_2.get())); - - const std::string message_1 = "hello 1"; - const std::string message_2 = "hello 2"; - - // Send data from caller to callee. - caller_dc_1->Send(webrtc::DataBuffer(message_1)); - EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait); - - caller_dc_2->Send(webrtc::DataBuffer(message_2)); - EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait); - - EXPECT_EQ(1U, dc_1_observer->received_message_count()); - EXPECT_EQ(1U, dc_2_observer->received_message_count()); - - // Send data from callee to caller. - dc_1_observer.reset(new webrtc::MockDataChannelObserver(caller_dc_1.get())); - dc_2_observer.reset(new webrtc::MockDataChannelObserver(caller_dc_2.get())); - - callee_dc_1->Send(webrtc::DataBuffer(message_1)); - EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait); - - callee_dc_2->Send(webrtc::DataBuffer(message_2)); - EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait); - - EXPECT_EQ(1U, dc_1_observer->received_message_count()); - EXPECT_EQ(1U, dc_2_observer->received_message_count()); -} -#endif // HAVE_QUIC - -#ifdef HAVE_SCTP // Verifies that a DataChannel added from an OPEN message functions after // a channel has been previously closed (webrtc issue 3778). // This previously failed because the new channel re-uses the ID of the closed diff --git a/pc/quicdatachannel.cc b/pc/quicdatachannel.cc deleted file mode 100644 index 3f09b5ab98..0000000000 --- a/pc/quicdatachannel.cc +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/quicdatachannel.h" - -#include "p2p/quic/quictransportchannel.h" -#include "p2p/quic/reliablequicstream.h" -#include "rtc_base/bind.h" -#include "rtc_base/bytebuffer.h" -#include "rtc_base/copyonwritebuffer.h" -#include "rtc_base/logging.h" - -namespace webrtc { - -void WriteQuicDataChannelMessageHeader(int data_channel_id, - uint64_t message_id, - rtc::CopyOnWriteBuffer* header) { - RTC_DCHECK(header); - // 64-bit varints require at most 10 bytes (7*10 == 70), and 32-bit varints - // require at most 5 bytes (7*5 == 35). - size_t max_length = 15; - rtc::ByteBufferWriter byte_buffer(nullptr, max_length, - rtc::ByteBuffer::ByteOrder::ORDER_HOST); - byte_buffer.WriteUVarint(data_channel_id); - byte_buffer.WriteUVarint(message_id); - header->SetData(byte_buffer.Data(), byte_buffer.Length()); -} - -bool ParseQuicDataMessageHeader(const char* data, - size_t len, - int* data_channel_id, - uint64_t* message_id, - size_t* bytes_read) { - RTC_DCHECK(data_channel_id); - RTC_DCHECK(message_id); - RTC_DCHECK(bytes_read); - - rtc::ByteBufferReader byte_buffer(data, len, rtc::ByteBuffer::ORDER_HOST); - uint64_t dcid; - if (!byte_buffer.ReadUVarint(&dcid)) { - LOG(LS_ERROR) << "Could not read the data channel ID"; - return false; - } - *data_channel_id = dcid; - if (!byte_buffer.ReadUVarint(message_id)) { - LOG(LS_ERROR) << "Could not read message ID for data channel " - << *data_channel_id; - return false; - } - size_t remaining_bytes = byte_buffer.Length(); - *bytes_read = len - remaining_bytes; - return true; -} - -QuicDataChannel::QuicDataChannel(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - rtc::Thread* network_thread, - const std::string& label, - const DataChannelInit& config) - : signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - network_thread_(network_thread), - id_(config.id), - state_(kConnecting), - buffered_amount_(0), - next_message_id_(0), - label_(label), - protocol_(config.protocol) {} - -QuicDataChannel::~QuicDataChannel() {} - -void QuicDataChannel::RegisterObserver(DataChannelObserver* observer) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - observer_ = observer; -} - -void QuicDataChannel::UnregisterObserver() { - RTC_DCHECK(signaling_thread_->IsCurrent()); - observer_ = nullptr; -} - -bool QuicDataChannel::Send(const DataBuffer& buffer) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - if (state_ != kOpen) { - LOG(LS_ERROR) << "QUIC data channel " << id_ - << " is not open so cannot send."; - return false; - } - return network_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&QuicDataChannel::Send_n, this, buffer)); -} - -bool QuicDataChannel::Send_n(const DataBuffer& buffer) { - RTC_DCHECK(network_thread_->IsCurrent()); - - // Encode and send the header containing the data channel ID and message ID. - rtc::CopyOnWriteBuffer header; - WriteQuicDataChannelMessageHeader(id_, ++next_message_id_, &header); - RTC_DCHECK(quic_transport_channel_); - cricket::ReliableQuicStream* stream = - quic_transport_channel_->CreateQuicStream(); - RTC_DCHECK(stream); - - // Send the header with a FIN if the message is empty. - bool header_fin = (buffer.size() == 0); - rtc::StreamResult header_result = - stream->Write(header.data(), header.size(), header_fin); - - if (header_result == rtc::SR_BLOCK) { - // The header is write blocked but we should try sending the message. Since - // the ReliableQuicStream queues data in order, if the header is write - // blocked then the message will be write blocked. Otherwise if the message - // is sent then the header is sent. - LOG(LS_INFO) << "Stream " << stream->id() - << " header is write blocked for QUIC data channel " << id_; - } else if (header_result != rtc::SR_SUCCESS) { - LOG(LS_ERROR) << "Stream " << stream->id() - << " failed to write header for QUIC data channel " << id_ - << ". Unexpected error " << header_result; - return false; - } - - // If the message is not empty, then send the message with a FIN. - bool message_fin = true; - rtc::StreamResult message_result = - header_fin ? header_result : stream->Write(buffer.data.data(), - buffer.size(), message_fin); - - if (message_result == rtc::SR_SUCCESS) { - // The message is sent and we don't need this QUIC stream. - LOG(LS_INFO) << "Stream " << stream->id() - << " successfully wrote message for QUIC data channel " << id_; - stream->Close(); - return true; - } - // TODO(mikescarlett): Register the ReliableQuicStream's priority to the - // QuicWriteBlockedList so that the QUIC session doesn't drop messages when - // the QUIC transport channel becomes unwritable. - if (message_result == rtc::SR_BLOCK) { - // The QUIC stream is write blocked, so the message is queued by the QUIC - // session. If this is due to the QUIC not being writable, it will be sent - // once QUIC becomes writable again. Otherwise it may be due to exceeding - // the QUIC flow control limit, in which case the remote peer's QUIC session - // will tell the QUIC stream to send more data. - LOG(LS_INFO) << "Stream " << stream->id() - << " message is write blocked for QUIC data channel " << id_; - SetBufferedAmount_w(buffered_amount_ + stream->queued_data_bytes()); - stream->SignalQueuedBytesWritten.connect( - this, &QuicDataChannel::OnQueuedBytesWritten); - write_blocked_quic_streams_[stream->id()] = stream; - // The QUIC stream will be removed from |write_blocked_quic_streams_| once - // it closes. - stream->SignalClosed.connect(this, - &QuicDataChannel::OnWriteBlockedStreamClosed); - return true; - } - LOG(LS_ERROR) << "Stream " << stream->id() - << " failed to write message for QUIC data channel " << id_ - << ". Unexpected error: " << message_result; - return false; -} - -void QuicDataChannel::OnQueuedBytesWritten(net::QuicStreamId stream_id, - uint64_t queued_bytes_written) { - RTC_DCHECK(worker_thread_->IsCurrent()); - SetBufferedAmount_w(buffered_amount_ - queued_bytes_written); - const auto& kv = write_blocked_quic_streams_.find(stream_id); - if (kv == write_blocked_quic_streams_.end()) { - RTC_NOTREACHED(); - return; - } - cricket::ReliableQuicStream* stream = kv->second; - // True if the QUIC stream is done sending data. - if (stream->fin_sent()) { - LOG(LS_INFO) << "Stream " << stream->id() - << " successfully wrote data for QUIC data channel " << id_; - stream->Close(); - } -} - -void QuicDataChannel::SetBufferedAmount_w(uint64_t buffered_amount) { - RTC_DCHECK(worker_thread_->IsCurrent()); - buffered_amount_ = buffered_amount; - invoker_.AsyncInvoke( - RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&QuicDataChannel::OnBufferedAmountChange_s, this, - buffered_amount)); -} - -void QuicDataChannel::Close() { - RTC_DCHECK(signaling_thread_->IsCurrent()); - if (state_ == kClosed || state_ == kClosing) { - return; - } - LOG(LS_INFO) << "Closing QUIC data channel."; - SetState_s(kClosing); - worker_thread_->Invoke(RTC_FROM_HERE, - rtc::Bind(&QuicDataChannel::Close_w, this)); - SetState_s(kClosed); -} - -void QuicDataChannel::Close_w() { - RTC_DCHECK(worker_thread_->IsCurrent()); - for (auto& kv : incoming_quic_messages_) { - Message& message = kv.second; - cricket::ReliableQuicStream* stream = message.stream; - stream->Close(); - } - - for (auto& kv : write_blocked_quic_streams_) { - cricket::ReliableQuicStream* stream = kv.second; - stream->Close(); - } -} - -bool QuicDataChannel::SetTransportChannel( - cricket::QuicTransportChannel* channel) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - - if (!channel) { - LOG(LS_ERROR) << "|channel| is NULL. Cannot set transport channel."; - return false; - } - if (quic_transport_channel_) { - if (channel == quic_transport_channel_) { - LOG(LS_WARNING) << "Ignoring duplicate transport channel."; - return true; - } - LOG(LS_ERROR) << "|channel| does not match existing transport channel."; - return false; - } - - quic_transport_channel_ = channel; - LOG(LS_INFO) << "Setting QuicTransportChannel for QUIC data channel " << id_; - DataState data_channel_state = worker_thread_->Invoke( - RTC_FROM_HERE, rtc::Bind(&QuicDataChannel::SetTransportChannel_w, this)); - SetState_s(data_channel_state); - return true; -} - -DataChannelInterface::DataState QuicDataChannel::SetTransportChannel_w() { - RTC_DCHECK(worker_thread_->IsCurrent()); - quic_transport_channel_->SignalReadyToSend.connect( - this, &QuicDataChannel::OnReadyToSend); - quic_transport_channel_->SignalClosed.connect( - this, &QuicDataChannel::OnConnectionClosed); - if (quic_transport_channel_->writable()) { - return kOpen; - } - return kConnecting; -} - -void QuicDataChannel::OnIncomingMessage(Message&& message) { - RTC_DCHECK(network_thread_->IsCurrent()); - RTC_DCHECK(message.stream); - if (!observer_) { - LOG(LS_WARNING) << "QUIC data channel " << id_ - << " received a message but has no observer."; - message.stream->Close(); - return; - } - // A FIN is received if the message fits into a single QUIC stream frame and - // the remote peer is done sending. - if (message.stream->fin_received()) { - LOG(LS_INFO) << "Stream " << message.stream->id() - << " has finished receiving data for QUIC data channel " - << id_; - DataBuffer final_message(message.buffer, false); - invoker_.AsyncInvoke(RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&QuicDataChannel::OnMessage_s, this, - std::move(final_message))); - message.stream->Close(); - return; - } - // Otherwise the message is divided across multiple QUIC stream frames, so - // queue the data. OnDataReceived() will be called each time the remaining - // QUIC stream frames arrive. - LOG(LS_INFO) << "QUIC data channel " << id_ - << " is queuing incoming data for stream " - << message.stream->id(); - incoming_quic_messages_[message.stream->id()] = std::move(message); - message.stream->SignalDataReceived.connect(this, - &QuicDataChannel::OnDataReceived); - // The QUIC stream will be removed from |incoming_quic_messages_| once it - // closes. - message.stream->SignalClosed.connect( - this, &QuicDataChannel::OnIncomingQueuedStreamClosed); -} - -void QuicDataChannel::OnDataReceived(net::QuicStreamId stream_id, - const char* data, - size_t len) { - RTC_DCHECK(network_thread_->IsCurrent()); - RTC_DCHECK(data); - const auto& kv = incoming_quic_messages_.find(stream_id); - if (kv == incoming_quic_messages_.end()) { - RTC_NOTREACHED(); - return; - } - Message& message = kv->second; - cricket::ReliableQuicStream* stream = message.stream; - rtc::CopyOnWriteBuffer& received_data = message.buffer; - // If the QUIC stream has not received a FIN, then the remote peer is not - // finished sending data. - if (!stream->fin_received()) { - received_data.AppendData(data, len); - return; - } - // Otherwise we are done receiving and can provide the data channel observer - // with the message. - LOG(LS_INFO) << "Stream " << stream_id - << " has finished receiving data for QUIC data channel " << id_; - received_data.AppendData(data, len); - DataBuffer final_message(std::move(received_data), false); - invoker_.AsyncInvoke( - RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&QuicDataChannel::OnMessage_s, this, std::move(final_message))); - // Once the stream is closed, OnDataReceived will not fire for the stream. - stream->Close(); -} - -void QuicDataChannel::OnReadyToSend(cricket::TransportChannel* channel) { - RTC_DCHECK(network_thread_->IsCurrent()); - RTC_DCHECK(channel == quic_transport_channel_); - LOG(LS_INFO) << "QuicTransportChannel is ready to send"; - invoker_.AsyncInvoke( - RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&QuicDataChannel::SetState_s, this, kOpen)); -} - -void QuicDataChannel::OnWriteBlockedStreamClosed(net::QuicStreamId stream_id, - int error) { - RTC_DCHECK(worker_thread_->IsCurrent()); - LOG(LS_VERBOSE) << "Write blocked stream " << stream_id << " is closed."; - write_blocked_quic_streams_.erase(stream_id); -} - -void QuicDataChannel::OnIncomingQueuedStreamClosed(net::QuicStreamId stream_id, - int error) { - RTC_DCHECK(network_thread_->IsCurrent()); - LOG(LS_VERBOSE) << "Incoming queued stream " << stream_id << " is closed."; - incoming_quic_messages_.erase(stream_id); -} - -void QuicDataChannel::OnConnectionClosed() { - RTC_DCHECK(worker_thread_->IsCurrent()); - invoker_.AsyncInvoke(RTC_FROM_HERE, signaling_thread_, - rtc::Bind(&QuicDataChannel::Close, this)); -} - -void QuicDataChannel::OnMessage_s(const DataBuffer& received_data) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - if (observer_) { - observer_->OnMessage(received_data); - } -} - -void QuicDataChannel::SetState_s(DataState state) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - if (state_ == state || state_ == kClosed) { - return; - } - if (state_ == kClosing && state != kClosed) { - return; - } - LOG(LS_INFO) << "Setting state to " << state << " for QUIC data channel " - << id_; - state_ = state; - if (observer_) { - observer_->OnStateChange(); - } -} - -void QuicDataChannel::OnBufferedAmountChange_s(uint64_t buffered_amount) { - RTC_DCHECK(signaling_thread_->IsCurrent()); - if (observer_) { - observer_->OnBufferedAmountChange(buffered_amount); - } -} - -size_t QuicDataChannel::GetNumWriteBlockedStreams() const { - return write_blocked_quic_streams_.size(); -} - -size_t QuicDataChannel::GetNumIncomingStreams() const { - return incoming_quic_messages_.size(); -} - -} // namespace webrtc diff --git a/pc/quicdatachannel.h b/pc/quicdatachannel.h deleted file mode 100644 index 347d227fe1..0000000000 --- a/pc/quicdatachannel.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef PC_QUICDATACHANNEL_H_ -#define PC_QUICDATACHANNEL_H_ - -#include -#include -#include - -#include "api/datachannelinterface.h" -#include "rtc_base/asyncinvoker.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/thread.h" - -namespace cricket { -class QuicTransportChannel; -class ReliableQuicStream; -class TransportChannel; -} // namepsace cricket - -namespace net { -// TODO(mikescarlett): Make this uint64_t once QUIC uses 64-bit ids. -typedef uint32_t QuicStreamId; -} // namespace net - -namespace rtc { -class CopyOnWriteBuffer; -} // namespace rtc - -namespace webrtc { - -// Encodes a QUIC message header with the data channel ID and message ID, then -// stores the result in |header|. -void WriteQuicDataChannelMessageHeader(int data_channel_id, - uint64_t message_id, - rtc::CopyOnWriteBuffer* header); - -// Decodes the data channel ID and message ID from the initial data received by -// an incoming QUIC stream. The data channel ID is output to |data_channel_id|, -// the message ID is output to |message_id|, and the number of bytes read is -// output to |bytes_read|. Returns false if either ID cannot be read. -bool ParseQuicDataMessageHeader(const char* data, - size_t len, - int* data_channel_id, - uint64_t* message_id, - size_t* bytes_read); - -// QuicDataChannel is an implementation of DataChannelInterface based on the -// QUIC protocol. It uses a QuicTransportChannel to establish encryption and -// transfer data, and a QuicDataTransport to receive incoming messages at -// the correct data channel. Currently this class implements unordered, reliable -// delivery and does not send an "OPEN" message. -// -// Each time a message is sent: -// -// - The QuicDataChannel prepends it with the data channel id and message id. -// The QuicTransportChannel creates a ReliableQuicStream, then the -// ReliableQuicStream sends the message with a FIN. -// -// - The remote QuicSession creates a ReliableQuicStream to receive the data. -// The remote QuicDataTransport dispatches the ReliableQuicStream to the -// QuicDataChannel with the same id as this data channel. -// -// - The remote QuicDataChannel queues data from the ReliableQuicStream. Once -// it receives a QUIC stream frame with a FIN, it provides the message to the -// DataChannelObserver. -// -// TODO(mikescarlett): Implement ordered delivery, unreliable delivery, and -// an OPEN message similar to the one for SCTP. -class QuicDataChannel : public rtc::RefCountedObject, - public sigslot::has_slots<> { - public: - // Message stores buffered data from the incoming QUIC stream. The QUIC stream - // is provided so that remaining data can be received from the remote peer. - struct Message { - uint64_t id; - rtc::CopyOnWriteBuffer buffer; - cricket::ReliableQuicStream* stream; - }; - - QuicDataChannel(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - rtc::Thread* network_thread, - const std::string& label, - const DataChannelInit& config); - ~QuicDataChannel() override; - - // DataChannelInterface overrides. - std::string label() const override { return label_; } - bool reliable() const override { return true; } - bool ordered() const override { return false; } - uint16_t maxRetransmitTime() const override { return -1; } - uint16_t maxRetransmits() const override { return -1; } - bool negotiated() const override { return false; } - int id() const override { return id_; } - DataState state() const override { return state_; } - uint64_t buffered_amount() const override { return buffered_amount_; } - std::string protocol() const override { return protocol_; } - void RegisterObserver(DataChannelObserver* observer) override; - void UnregisterObserver() override; - void Close() override; - bool Send(const DataBuffer& buffer) override; - - // Called from QuicDataTransport to set the QUIC transport channel that the - // QuicDataChannel sends messages with. Returns false if a different QUIC - // transport channel is already set or |channel| is NULL. - // - // The QUIC transport channel is not set in the constructor to allow creating - // the QuicDataChannel before the PeerConnection has a QUIC transport channel, - // such as before the session description is not set. - bool SetTransportChannel(cricket::QuicTransportChannel* channel); - - // Called from QuicDataTransport when an incoming ReliableQuicStream is - // receiving a message received for this data channel. Once this function is - // called, |message| is owned by the QuicDataChannel and should not be - // accessed by the QuicDataTransport. - void OnIncomingMessage(Message&& message); - - // Methods for testing. - // Gets the number of outgoing QUIC streams with write blocked data that are - // currently open for this data channel and are not finished writing a - // message. This is equivalent to the size of |write_blocked_quic_streams_|. - size_t GetNumWriteBlockedStreams() const; - // Gets the number of incoming QUIC streams with buffered data that are - // currently open for this data channel and are not finished receiving a - // message. This is equivalent to the size of |incoming_quic_messages_|. - size_t GetNumIncomingStreams() const; - - private: - // Callbacks from ReliableQuicStream. - // Called when an incoming QUIC stream in |incoming_quic_messages_| has - // received a QUIC stream frame. - void OnDataReceived(net::QuicStreamId stream_id, - const char* data, - size_t len); - // Called when a write blocked QUIC stream that has been added to - // |write_blocked_quic_streams_| is closed. - void OnWriteBlockedStreamClosed(net::QuicStreamId stream_id, int error); - // Called when an incoming QUIC stream that has been added to - // |incoming_quic_messages_| is closed. - void OnIncomingQueuedStreamClosed(net::QuicStreamId stream_id, int error); - // Called when a write blocked QUIC stream in |write_blocked_quic_streams_| - // has written previously queued data. - void OnQueuedBytesWritten(net::QuicStreamId stream_id, - uint64_t queued_bytes_written); - - // Callbacks from |quic_transport_channel_|. - void OnReadyToSend(cricket::TransportChannel* channel); - void OnConnectionClosed(); - - // Network thread methods. - // Sends the data buffer to the remote peer using an outgoing QUIC stream. - // Returns true if the data buffer can be successfully sent, or if it is - // queued to be sent later. - bool Send_n(const DataBuffer& buffer); - - // Worker thread methods. - // Connects the |quic_transport_channel_| signals to this QuicDataChannel, - // then returns the new QuicDataChannel state. - DataState SetTransportChannel_w(); - // Closes the QUIC streams associated with this QuicDataChannel. - void Close_w(); - // Sets |buffered_amount_|. - void SetBufferedAmount_w(uint64_t buffered_amount); - - // Signaling thread methods. - // Triggers QuicDataChannelObserver::OnMessage when a message from the remote - // peer is ready to be read. - void OnMessage_s(const DataBuffer& received_data); - // Triggers QuicDataChannel::OnStateChange if the state change is valid. - // Otherwise does nothing if |state| == |state_| or |state| != kClosed when - // the data channel is closing. - void SetState_s(DataState state); - // Triggers QuicDataChannelObserver::OnBufferedAmountChange when the total - // buffered data changes for a QUIC stream. - void OnBufferedAmountChange_s(uint64_t buffered_amount); - - // QUIC transport channel which owns the QUIC session. It is used to create - // a QUIC stream for sending outgoing messages. - cricket::QuicTransportChannel* quic_transport_channel_ = nullptr; - // Signaling thread for DataChannelInterface methods. - rtc::Thread* const signaling_thread_; - // Worker thread for |quic_transport_channel_| callbacks. - rtc::Thread* const worker_thread_; - // Network thread for sending data and |quic_transport_channel_| callbacks. - rtc::Thread* const network_thread_; - rtc::AsyncInvoker invoker_; - // Map of QUIC stream ID => ReliableQuicStream* for write blocked QUIC - // streams. - std::unordered_map - write_blocked_quic_streams_; - // Map of QUIC stream ID => Message for each incoming QUIC stream. - std::unordered_map incoming_quic_messages_; - // Handles received data from the remote peer and data channel state changes. - DataChannelObserver* observer_ = nullptr; - // QuicDataChannel ID. - int id_; - // Connectivity state of the QuicDataChannel. - DataState state_; - // Total bytes that are buffered among the QUIC streams. - uint64_t buffered_amount_; - // Counter for number of sent messages that is used for message IDs. - uint64_t next_message_id_; - - // Variables for application use. - const std::string& label_; - const std::string& protocol_; -}; - -} // namespace webrtc - -#endif // PC_QUICDATACHANNEL_H_ diff --git a/pc/quicdatachannel_unittest.cc b/pc/quicdatachannel_unittest.cc deleted file mode 100644 index d1e34f58ea..0000000000 --- a/pc/quicdatachannel_unittest.cc +++ /dev/null @@ -1,658 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/quicdatachannel.h" - -#include -#include -#include -#include -#include - -#include "p2p/base/faketransportcontroller.h" -#include "p2p/quic/quictransportchannel.h" -#include "p2p/quic/reliablequicstream.h" -#include "rtc_base/bind.h" -#include "rtc_base/gunit.h" -#include "rtc_base/scoped_ref_ptr.h" - -using cricket::FakeTransportChannel; -using cricket::QuicTransportChannel; -using cricket::ReliableQuicStream; - -using webrtc::DataBuffer; -using webrtc::DataChannelObserver; -using webrtc::DataChannelInit; -using webrtc::QuicDataChannel; - -namespace { - -// Timeout for asynchronous operations. -static const int kTimeoutMs = 1000; // milliseconds - -// Small messages that can be sent within a single QUIC packet. -static const std::string kSmallMessage1 = "Hello, world!"; -static const std::string kSmallMessage2 = "WebRTC"; -static const std::string kSmallMessage3 = "1"; -static const std::string kSmallMessage4 = "abcdefghijklmnopqrstuvwxyz"; -static const DataBuffer kSmallBuffer1(kSmallMessage1); -static const DataBuffer kSmallBuffer2(kSmallMessage2); -static const DataBuffer kSmallBuffer3(kSmallMessage3); -static const DataBuffer kSmallBuffer4(kSmallMessage4); - -// Large messages (> 1350 bytes) that exceed the max size of a QUIC packet. -// These are < 16 KB so they don't exceed the QUIC stream flow control limit. -static const std::string kLargeMessage1 = std::string("a", 2000); -static const std::string kLargeMessage2 = std::string("a", 4000); -static const std::string kLargeMessage3 = std::string("a", 8000); -static const std::string kLargeMessage4 = std::string("a", 12000); -static const DataBuffer kLargeBuffer1(kLargeMessage1); -static const DataBuffer kLargeBuffer2(kLargeMessage2); -static const DataBuffer kLargeBuffer3(kLargeMessage3); -static const DataBuffer kLargeBuffer4(kLargeMessage4); - -// Oversized message (> 16 KB) that violates the QUIC stream flow control limit. -static const std::string kOversizedMessage = std::string("a", 20000); -static const DataBuffer kOversizedBuffer(kOversizedMessage); - -// Creates a fingerprint from a certificate. -static rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { - std::string digest_algorithm; - cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); - std::unique_ptr fingerprint( - rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); - return fingerprint.release(); -} - -// FakeObserver receives messages from the QuicDataChannel. -class FakeObserver : public DataChannelObserver { - public: - FakeObserver() - : on_state_change_count_(0), on_buffered_amount_change_count_(0) {} - - // DataChannelObserver overrides. - void OnStateChange() override { ++on_state_change_count_; } - void OnBufferedAmountChange(uint64_t previous_amount) override { - ++on_buffered_amount_change_count_; - } - void OnMessage(const webrtc::DataBuffer& buffer) override { - messages_.push_back(std::string(buffer.data.data(), buffer.size())); - } - - const std::vector& messages() const { return messages_; } - - size_t messages_received() const { return messages_.size(); } - - size_t on_state_change_count() const { return on_state_change_count_; } - - size_t on_buffered_amount_change_count() const { - return on_buffered_amount_change_count_; - } - - private: - std::vector messages_; - size_t on_state_change_count_; - size_t on_buffered_amount_change_count_; -}; - -// FakeQuicDataTransport simulates QuicDataTransport by dispatching QUIC -// stream messages to data channels and encoding/decoding messages. -class FakeQuicDataTransport : public sigslot::has_slots<> { - public: - FakeQuicDataTransport() {} - - void ConnectToTransportChannel(QuicTransportChannel* quic_transport_channel) { - quic_transport_channel->SignalIncomingStream.connect( - this, &FakeQuicDataTransport::OnIncomingStream); - } - - rtc::scoped_refptr CreateDataChannel( - int id, - const std::string& label, - const std::string& protocol) { - DataChannelInit config; - config.id = id; - config.protocol = protocol; - rtc::scoped_refptr data_channel( - new QuicDataChannel(rtc::Thread::Current(), rtc::Thread::Current(), - rtc::Thread::Current(), label, config)); - data_channel_by_id_[id] = data_channel; - return data_channel; - } - - private: - void OnIncomingStream(cricket::ReliableQuicStream* stream) { - incoming_stream_ = stream; - incoming_stream_->SignalDataReceived.connect( - this, &FakeQuicDataTransport::OnDataReceived); - } - - void OnDataReceived(net::QuicStreamId id, const char* data, size_t len) { - ASSERT_EQ(incoming_stream_->id(), id); - incoming_stream_->SignalDataReceived.disconnect(this); - // Retrieve the data channel ID and message ID. - int data_channel_id; - uint64_t message_id; - size_t bytes_read; - ASSERT_TRUE(webrtc::ParseQuicDataMessageHeader(data, len, &data_channel_id, - &message_id, &bytes_read)); - data += bytes_read; - len -= bytes_read; - // Dispatch the message to the matching QuicDataChannel. - const auto& kv = data_channel_by_id_.find(data_channel_id); - ASSERT_NE(kv, data_channel_by_id_.end()); - QuicDataChannel* data_channel = kv->second; - QuicDataChannel::Message message; - message.id = message_id; - message.buffer = rtc::CopyOnWriteBuffer(data, len); - message.stream = incoming_stream_; - data_channel->OnIncomingMessage(std::move(message)); - incoming_stream_ = nullptr; - } - - // Map of data channel ID => QuicDataChannel. - std::map> data_channel_by_id_; - // Last incoming QUIC stream which has arrived. - cricket::ReliableQuicStream* incoming_stream_ = nullptr; -}; - -// A peer who creates a QuicDataChannel to transfer data, and simulates network -// connectivity with a fake ICE channel wrapped by the QUIC transport channel. -class QuicDataChannelPeer { - public: - QuicDataChannelPeer() - : ice_transport_channel_(new FakeTransportChannel("data", 0)), - quic_transport_channel_(ice_transport_channel_) { - ice_transport_channel_->SetAsync(true); - fake_quic_data_transport_.ConnectToTransportChannel( - &quic_transport_channel_); - } - - void GenerateCertificateAndFingerprint() { - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("cert_name", rtc::KT_DEFAULT))); - quic_transport_channel_.SetLocalCertificate(local_cert); - local_fingerprint_.reset(CreateFingerprint(local_cert.get())); - } - - rtc::scoped_refptr CreateDataChannelWithTransportChannel( - int id, - const std::string& label, - const std::string& protocol) { - rtc::scoped_refptr data_channel = - fake_quic_data_transport_.CreateDataChannel(id, label, protocol); - data_channel->SetTransportChannel(&quic_transport_channel_); - return data_channel; - } - - rtc::scoped_refptr CreateDataChannelWithoutTransportChannel( - int id, - const std::string& label, - const std::string& protocol) { - return fake_quic_data_transport_.CreateDataChannel(id, label, protocol); - } - - // Connects |ice_transport_channel_| to that of the other peer. - void Connect(QuicDataChannelPeer* other_peer) { - ice_transport_channel_->SetDestination(other_peer->ice_transport_channel_); - } - - std::unique_ptr& local_fingerprint() { - return local_fingerprint_; - } - - QuicTransportChannel* quic_transport_channel() { - return &quic_transport_channel_; - } - - FakeTransportChannel* ice_transport_channel() { - return ice_transport_channel_; - } - - private: - FakeTransportChannel* ice_transport_channel_; - QuicTransportChannel quic_transport_channel_; - - std::unique_ptr local_fingerprint_; - - FakeQuicDataTransport fake_quic_data_transport_; -}; - -class QuicDataChannelTest : public testing::Test { - public: - QuicDataChannelTest() {} - - // Connect the QuicTransportChannels and complete the crypto handshake. - void ConnectTransportChannels() { - SetCryptoParameters(); - peer1_.Connect(&peer2_); - ASSERT_TRUE_WAIT(peer1_.quic_transport_channel()->writable() && - peer2_.quic_transport_channel()->writable(), - kTimeoutMs); - } - - // Sets crypto parameters required for the QUIC handshake. - void SetCryptoParameters() { - peer1_.GenerateCertificateAndFingerprint(); - peer2_.GenerateCertificateAndFingerprint(); - - peer1_.quic_transport_channel()->SetSslRole(rtc::SSL_CLIENT); - peer2_.quic_transport_channel()->SetSslRole(rtc::SSL_SERVER); - - std::unique_ptr& peer1_fingerprint = - peer1_.local_fingerprint(); - std::unique_ptr& peer2_fingerprint = - peer2_.local_fingerprint(); - - peer1_.quic_transport_channel()->SetRemoteFingerprint( - peer2_fingerprint->algorithm, - reinterpret_cast(peer2_fingerprint->digest.data()), - peer2_fingerprint->digest.size()); - peer2_.quic_transport_channel()->SetRemoteFingerprint( - peer1_fingerprint->algorithm, - reinterpret_cast(peer1_fingerprint->digest.data()), - peer1_fingerprint->digest.size()); - } - - protected: - QuicDataChannelPeer peer1_; - QuicDataChannelPeer peer2_; -}; - -// Tests that a QuicDataChannel transitions from connecting to open when -// the QuicTransportChannel becomes writable for the first time. -TEST_F(QuicDataChannelTest, DataChannelOpensWhenTransportChannelConnects) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(4, "label", "protocol"); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel->state()); - ConnectTransportChannels(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel->state(), - kTimeoutMs); -} - -// Tests that a QuicDataChannel transitions from connecting to open when -// SetTransportChannel is called with a QuicTransportChannel that is already -// writable. -TEST_F(QuicDataChannelTest, DataChannelOpensWhenTransportChannelWritable) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithoutTransportChannel(4, "label", "protocol"); - ConnectTransportChannels(); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel->state()); - data_channel->SetTransportChannel(peer1_.quic_transport_channel()); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel->state()); -} - -// Tests that the QuicDataChannel transfers messages small enough to fit into a -// single QUIC stream frame. -TEST_F(QuicDataChannelTest, TransferSmallMessage) { - ConnectTransportChannels(); - int data_channel_id = 2; - std::string label = "label"; - std::string protocol = "protocol"; - rtc::scoped_refptr peer1_data_channel = - peer1_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer1_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer2_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - - FakeObserver peer1_observer; - peer1_data_channel->RegisterObserver(&peer1_observer); - FakeObserver peer2_observer; - peer2_data_channel->RegisterObserver(&peer2_observer); - - // peer1 -> peer2 - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer1)); - ASSERT_EQ_WAIT(1, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kSmallMessage1, peer2_observer.messages()[0]); - // peer2 -> peer1 - EXPECT_TRUE(peer2_data_channel->Send(kSmallBuffer2)); - ASSERT_EQ_WAIT(1, peer1_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kSmallMessage2, peer1_observer.messages()[0]); - // peer2 -> peer1 - EXPECT_TRUE(peer2_data_channel->Send(kSmallBuffer3)); - ASSERT_EQ_WAIT(2, peer1_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kSmallMessage3, peer1_observer.messages()[1]); - // peer1 -> peer2 - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer4)); - ASSERT_EQ_WAIT(2, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kSmallMessage4, peer2_observer.messages()[1]); -} - -// Tests that QuicDataChannel transfers messages large enough to fit into -// multiple QUIC stream frames, which don't violate the QUIC flow control limit. -// These require buffering by the QuicDataChannel. -TEST_F(QuicDataChannelTest, TransferLargeMessage) { - ConnectTransportChannels(); - int data_channel_id = 347; - std::string label = "label"; - std::string protocol = "protocol"; - rtc::scoped_refptr peer1_data_channel = - peer1_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer1_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer2_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - - FakeObserver peer1_observer; - peer1_data_channel->RegisterObserver(&peer1_observer); - FakeObserver peer2_observer; - peer2_data_channel->RegisterObserver(&peer2_observer); - - // peer1 -> peer2 - EXPECT_TRUE(peer1_data_channel->Send(kLargeBuffer1)); - ASSERT_TRUE_WAIT(peer2_observer.messages_received() == 1, kTimeoutMs); - EXPECT_EQ(kLargeMessage1, peer2_observer.messages()[0]); - // peer2 -> peer1 - EXPECT_TRUE(peer2_data_channel->Send(kLargeBuffer2)); - ASSERT_EQ_WAIT(1, peer1_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kLargeMessage2, peer1_observer.messages()[0]); - // peer2 -> peer1 - EXPECT_TRUE(peer2_data_channel->Send(kLargeBuffer3)); - ASSERT_EQ_WAIT(2, peer1_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kLargeMessage3, peer1_observer.messages()[1]); - // peer1 -> peer2 - EXPECT_TRUE(peer1_data_channel->Send(kLargeBuffer4)); - ASSERT_EQ_WAIT(2, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kLargeMessage4, peer2_observer.messages()[1]); -} - -// Tests that when a message size exceeds the flow control limit (> 16KB), the -// QuicDataChannel can queue the data and send it after receiving window update -// frames from the remote peer. -TEST_F(QuicDataChannelTest, TransferOversizedMessage) { - ConnectTransportChannels(); - int data_channel_id = 189; - std::string label = "label"; - std::string protocol = "protocol"; - rtc::scoped_refptr peer1_data_channel = - peer1_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer2_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - - FakeObserver peer1_observer; - peer1_data_channel->RegisterObserver(&peer1_observer); - FakeObserver peer2_observer; - peer2_data_channel->RegisterObserver(&peer2_observer); - - EXPECT_TRUE(peer1_data_channel->Send(kOversizedBuffer)); - EXPECT_EQ(1, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_EQ_WAIT(1, peer2_data_channel->GetNumIncomingStreams(), kTimeoutMs); - ASSERT_EQ_WAIT(1, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(kOversizedMessage, peer2_observer.messages()[0]); - EXPECT_EQ(0, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_EQ(0, peer2_data_channel->GetNumIncomingStreams()); -} - -// Tests that empty messages can be sent. -TEST_F(QuicDataChannelTest, TransferEmptyMessage) { - ConnectTransportChannels(); - int data_channel_id = 69; - std::string label = "label"; - std::string protocol = "protocol"; - rtc::scoped_refptr peer1_data_channel = - peer1_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer2_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - - FakeObserver peer1_observer; - peer1_data_channel->RegisterObserver(&peer1_observer); - FakeObserver peer2_observer; - peer2_data_channel->RegisterObserver(&peer2_observer); - - EXPECT_TRUE(peer1_data_channel->Send(DataBuffer(""))); - ASSERT_EQ_WAIT(1, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ("", peer2_observer.messages()[0]); -} - -// Tests that when the QuicDataChannel is open and sends a message while the -// QuicTransportChannel is unwritable, it gets buffered then received once the -// QuicTransportChannel becomes writable again. -TEST_F(QuicDataChannelTest, MessagesReceivedWhenTransportChannelReconnects) { - ConnectTransportChannels(); - int data_channel_id = 401; - std::string label = "label"; - std::string protocol = "protocol"; - rtc::scoped_refptr peer1_data_channel = - peer1_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer1_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannelWithTransportChannel(data_channel_id, label, - protocol); - ASSERT_TRUE(peer2_data_channel->state() == - webrtc::DataChannelInterface::kOpen); - - FakeObserver peer1_observer; - peer1_data_channel->RegisterObserver(&peer1_observer); - FakeObserver peer2_observer; - peer2_data_channel->RegisterObserver(&peer2_observer); - // writable => unwritable - peer1_.ice_transport_channel()->SetWritable(false); - ASSERT_FALSE(peer1_.quic_transport_channel()->writable()); - // Verify that sent data is buffered. - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer1)); - EXPECT_EQ(1, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer2)); - EXPECT_EQ(2, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer3)); - EXPECT_EQ(3, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_TRUE(peer1_data_channel->Send(kSmallBuffer4)); - EXPECT_EQ(4, peer1_data_channel->GetNumWriteBlockedStreams()); - // unwritable => writable - peer1_.ice_transport_channel()->SetWritable(true); - ASSERT_TRUE(peer1_.quic_transport_channel()->writable()); - ASSERT_EQ_WAIT(4, peer2_observer.messages_received(), kTimeoutMs); - EXPECT_EQ(0, peer1_data_channel->GetNumWriteBlockedStreams()); - EXPECT_EQ(0, peer2_data_channel->GetNumIncomingStreams()); -} - -// Tests that the QuicDataChannel does not send before it is open. -TEST_F(QuicDataChannelTest, TransferMessageBeforeChannelOpens) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(6, "label", "protocol"); - ASSERT_TRUE(data_channel->state() == - webrtc::DataChannelInterface::kConnecting); - EXPECT_FALSE(data_channel->Send(kSmallBuffer1)); -} - -// Tests that the QuicDataChannel does not send after it is closed. -TEST_F(QuicDataChannelTest, TransferDataAfterChannelClosed) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(42, "label", "protocol"); - data_channel->Close(); - ASSERT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); - EXPECT_FALSE(data_channel->Send(kSmallBuffer1)); -} - -// Tests that QuicDataChannel state changes fire OnStateChanged() for the -// observer, with the correct data channel states, when the data channel -// transitions from kConnecting => kOpen => kClosing => kClosed. -TEST_F(QuicDataChannelTest, OnStateChangedFired) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(7, "label", "protocol"); - FakeObserver observer; - data_channel->RegisterObserver(&observer); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel->state()); - EXPECT_EQ(0, observer.on_state_change_count()); - ConnectTransportChannels(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel->state(), - kTimeoutMs); - EXPECT_EQ(1, observer.on_state_change_count()); - data_channel->Close(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); - // 2 state changes due to kClosing and kClosed. - EXPECT_EQ(3, observer.on_state_change_count()); -} - -// Tests that a QuicTransportChannel can be closed without being opened when it -// is connected to a transprot chanenl. -TEST_F(QuicDataChannelTest, NeverOpenedWithTransportChannel) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(7, "label", "protocol"); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel->state()); - data_channel->Close(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); -} - -// Tests that a QuicTransportChannel can be closed without being opened or -// connected to a transport channel. -TEST_F(QuicDataChannelTest, NeverOpenedWithoutTransportChannel) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithoutTransportChannel(7, "label", "protocol"); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel->state()); - data_channel->Close(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); -} - -// Tests that the QuicDataChannel is closed when the QUIC connection closes. -TEST_F(QuicDataChannelTest, ClosedOnTransportError) { - ConnectTransportChannels(); - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(1, "label", "protocol"); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel->state()); - ReliableQuicStream* stream = - peer1_.quic_transport_channel()->CreateQuicStream(); - ASSERT_NE(nullptr, stream); - stream->CloseConnectionWithDetails(net::QuicErrorCode::QUIC_NO_ERROR, - "Closing QUIC for testing"); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); -} - -// Tests that an already closed QuicDataChannel does not fire onStateChange and -// remains closed. -TEST_F(QuicDataChannelTest, DoesNotChangeStateWhenClosed) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(4, "label", "protocol"); - FakeObserver observer; - data_channel->RegisterObserver(&observer); - data_channel->Close(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kClosed, data_channel->state(), - kTimeoutMs); - // OnStateChange called for kClosing and kClosed. - EXPECT_EQ(2, observer.on_state_change_count()); - // Call Close() again to verify that the state cannot be kClosing. - data_channel->Close(); - EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state()); - EXPECT_EQ(2, observer.on_state_change_count()); - ConnectTransportChannels(); - EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state()); - EXPECT_EQ(2, observer.on_state_change_count()); - // writable => unwritable - peer1_.ice_transport_channel()->SetWritable(false); - ASSERT_FALSE(peer1_.quic_transport_channel()->writable()); - EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state()); - EXPECT_EQ(2, observer.on_state_change_count()); - // unwritable => writable - peer1_.ice_transport_channel()->SetWritable(true); - ASSERT_TRUE(peer1_.quic_transport_channel()->writable()); - EXPECT_EQ(webrtc::DataChannelInterface::kClosed, data_channel->state()); - EXPECT_EQ(2, observer.on_state_change_count()); -} - -// Tests that when the QuicDataChannel is open and the QuicTransportChannel -// transitions between writable and unwritable, it does not fire onStateChange -// and remains open. -TEST_F(QuicDataChannelTest, DoesNotChangeStateWhenTransportChannelReconnects) { - ConnectTransportChannels(); - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(4, "label", "protocol"); - FakeObserver observer; - data_channel->RegisterObserver(&observer); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel->state()); - EXPECT_EQ(0, observer.on_state_change_count()); - // writable => unwritable - peer1_.ice_transport_channel()->SetWritable(false); - ASSERT_FALSE(peer1_.quic_transport_channel()->writable()); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel->state()); - EXPECT_EQ(0, observer.on_state_change_count()); - // unwritable => writable - peer1_.ice_transport_channel()->SetWritable(true); - ASSERT_TRUE(peer1_.quic_transport_channel()->writable()); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel->state()); - EXPECT_EQ(0, observer.on_state_change_count()); -} - -// Tests that SetTransportChannel returns false when setting a NULL transport -// channel or a transport channel that is not equivalent to the one already set. -TEST_F(QuicDataChannelTest, SetTransportChannelReturnValue) { - rtc::scoped_refptr data_channel = - peer1_.CreateDataChannelWithTransportChannel(4, "label", "protocol"); - EXPECT_FALSE(data_channel->SetTransportChannel(nullptr)); - QuicTransportChannel* transport_channel = peer1_.quic_transport_channel(); - EXPECT_TRUE(data_channel->SetTransportChannel(transport_channel)); - EXPECT_TRUE(data_channel->SetTransportChannel(transport_channel)); - QuicTransportChannel* other_transport_channel = - peer2_.quic_transport_channel(); - EXPECT_FALSE(data_channel->SetTransportChannel(other_transport_channel)); -} - -// Tests that the QUIC message header is encoded with the correct number of -// bytes and is properly decoded. -TEST_F(QuicDataChannelTest, EncodeParseQuicDataMessageHeader) { - int data_channel_id1 = 127; // 1 byte - uint64_t message_id1 = 0; // 1 byte - rtc::CopyOnWriteBuffer header1; - webrtc::WriteQuicDataChannelMessageHeader(data_channel_id1, message_id1, - &header1); - EXPECT_EQ(2u, header1.size()); - - int decoded_data_channel_id1; - uint64_t decoded_message_id1; - size_t bytes_read1; - ASSERT_TRUE(webrtc::ParseQuicDataMessageHeader( - header1.data(), header1.size(), &decoded_data_channel_id1, - &decoded_message_id1, &bytes_read1)); - EXPECT_EQ(data_channel_id1, decoded_data_channel_id1); - EXPECT_EQ(message_id1, decoded_message_id1); - EXPECT_EQ(2u, bytes_read1); - - int data_channel_id2 = 4178; // 2 bytes - uint64_t message_id2 = 1324921792003; // 6 bytes - rtc::CopyOnWriteBuffer header2; - webrtc::WriteQuicDataChannelMessageHeader(data_channel_id2, message_id2, - &header2); - EXPECT_EQ(8u, header2.size()); - - int decoded_data_channel_id2; - uint64_t decoded_message_id2; - size_t bytes_read2; - ASSERT_TRUE(webrtc::ParseQuicDataMessageHeader( - header2.data(), header2.size(), &decoded_data_channel_id2, - &decoded_message_id2, &bytes_read2)); - EXPECT_EQ(data_channel_id2, decoded_data_channel_id2); - EXPECT_EQ(message_id2, decoded_message_id2); - EXPECT_EQ(8u, bytes_read2); -} - -} // namespace diff --git a/pc/quicdatatransport.cc b/pc/quicdatatransport.cc deleted file mode 100644 index 5c46af7720..0000000000 --- a/pc/quicdatatransport.cc +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/quicdatatransport.h" - -#include "p2p/quic/quictransportchannel.h" -#include "p2p/quic/reliablequicstream.h" -#include "rtc_base/bind.h" -#include "rtc_base/logging.h" - -namespace webrtc { - -QuicDataTransport::QuicDataTransport( - rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - rtc::Thread* network_thread, - cricket::TransportController* transport_controller) - : signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - network_thread_(network_thread), - transport_controller_(transport_controller) { - RTC_DCHECK(signaling_thread_); - RTC_DCHECK(worker_thread_); - RTC_DCHECK(network_thread_); -} - -QuicDataTransport::~QuicDataTransport() { - DestroyTransportChannel(quic_transport_channel_); - LOG(LS_INFO) << "Destroyed the QUIC data transport."; -} - -bool QuicDataTransport::SetTransport(const std::string& transport_name) { - if (transport_name_ == transport_name) { - // Nothing to do if transport name isn't changing - return true; - } - - cricket::QuicTransportChannel* transport_channel = - CreateTransportChannel(transport_name); - if (!SetTransportChannel(transport_channel)) { - DestroyTransportChannel(transport_channel); - return false; - } - - transport_name_ = transport_name; - return true; -} - -bool QuicDataTransport::SetTransportChannel( - cricket::QuicTransportChannel* channel) { - if (!channel) { - LOG(LS_ERROR) << "|channel| is NULL. Cannot set transport channel."; - return false; - } - if (quic_transport_channel_) { - if (channel == quic_transport_channel_) { - LOG(LS_WARNING) << "Ignoring duplicate transport channel."; - return true; - } - LOG(LS_ERROR) << "|channel| does not match existing transport channel."; - return false; - } - - LOG(LS_INFO) << "Setting QuicTransportChannel for QuicDataTransport"; - quic_transport_channel_ = channel; - quic_transport_channel_->SignalIncomingStream.connect( - this, &QuicDataTransport::OnIncomingStream); - bool success = true; - for (const auto& kv : data_channel_by_id_) { - rtc::scoped_refptr data_channel = kv.second; - if (!data_channel->SetTransportChannel(quic_transport_channel_)) { - LOG(LS_ERROR) - << "Cannot set QUIC transport channel for QUIC data channel " - << kv.first; - success = false; - } - } - return success; -} - -rtc::scoped_refptr QuicDataTransport::CreateDataChannel( - const std::string& label, - const DataChannelInit* config) { - if (config == nullptr) { - return nullptr; - } - if (data_channel_by_id_.find(config->id) != data_channel_by_id_.end()) { - LOG(LS_ERROR) << "QUIC data channel already exists with id " << config->id; - return nullptr; - } - rtc::scoped_refptr data_channel(new QuicDataChannel( - signaling_thread_, worker_thread_, network_thread_, label, *config)); - if (quic_transport_channel_) { - if (!data_channel->SetTransportChannel(quic_transport_channel_)) { - LOG(LS_ERROR) - << "Cannot set QUIC transport channel for QUIC data channel " - << config->id; - } - } - - data_channel_by_id_[data_channel->id()] = data_channel; - return data_channel; -} - -void QuicDataTransport::DestroyDataChannel(int id) { - data_channel_by_id_.erase(id); -} - -bool QuicDataTransport::HasDataChannel(int id) const { - return data_channel_by_id_.find(id) != data_channel_by_id_.end(); -} - -bool QuicDataTransport::HasDataChannels() const { - return !data_channel_by_id_.empty(); -} - -// Called when a QUIC stream is created for incoming data. -void QuicDataTransport::OnIncomingStream(cricket::ReliableQuicStream* stream) { - RTC_DCHECK(stream != nullptr); - quic_stream_by_id_[stream->id()] = stream; - stream->SignalDataReceived.connect(this, &QuicDataTransport::OnDataReceived); -} - -// Called when the first QUIC stream frame is received for incoming data. -void QuicDataTransport::OnDataReceived(net::QuicStreamId id, - const char* data, - size_t len) { - const auto& quic_stream_kv = quic_stream_by_id_.find(id); - if (quic_stream_kv == quic_stream_by_id_.end()) { - RTC_NOTREACHED(); - return; - } - cricket::ReliableQuicStream* stream = quic_stream_kv->second; - stream->SignalDataReceived.disconnect(this); - quic_stream_by_id_.erase(id); - // Read the data channel ID and message ID. - int data_channel_id; - uint64_t message_id; - size_t bytes_read; - if (!ParseQuicDataMessageHeader(data, len, &data_channel_id, &message_id, - &bytes_read)) { - LOG(LS_ERROR) << "Could not read QUIC message header from QUIC stream " - << id; - return; - } - data += bytes_read; - len -= bytes_read; - // Retrieve the data channel which will handle the message. - const auto& data_channel_kv = data_channel_by_id_.find(data_channel_id); - if (data_channel_kv == data_channel_by_id_.end()) { - // TODO(mikescarlett): Implement OPEN message to create a new - // QuicDataChannel when messages are received for a nonexistent ID. - LOG(LS_ERROR) << "Data was received for QUIC data channel " - << data_channel_id - << " but it is not registered to the QuicDataTransport."; - return; - } - QuicDataChannel* data_channel = data_channel_kv->second; - QuicDataChannel::Message message; - message.id = message_id; - message.buffer = rtc::CopyOnWriteBuffer(data, len); - message.stream = stream; - data_channel->OnIncomingMessage(std::move(message)); -} - -cricket::QuicTransportChannel* QuicDataTransport::CreateTransportChannel( - const std::string& transport_name) { - DCHECK(transport_controller_->quic()); - - cricket::TransportChannel* transport_channel = - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&cricket::TransportController::CreateTransportChannel_n, - transport_controller_, transport_name, - cricket::ICE_CANDIDATE_COMPONENT_DEFAULT)); - return static_cast(transport_channel); -} - -void QuicDataTransport::DestroyTransportChannel( - cricket::TransportChannel* transport_channel) { - if (transport_channel) { - network_thread_->Invoke( - RTC_FROM_HERE, - rtc::Bind(&cricket::TransportController::DestroyTransportChannel_n, - transport_controller_, transport_channel->transport_name(), - cricket::ICE_CANDIDATE_COMPONENT_DEFAULT)); - } -} - -} // namespace webrtc diff --git a/pc/quicdatatransport.h b/pc/quicdatatransport.h deleted file mode 100644 index b534b27222..0000000000 --- a/pc/quicdatatransport.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef PC_QUICDATATRANSPORT_H_ -#define PC_QUICDATATRANSPORT_H_ - -#include -#include - -#include "api/datachannelinterface.h" -#include "p2p/base/transportcontroller.h" -#include "pc/quicdatachannel.h" -#include "rtc_base/scoped_ref_ptr.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/thread.h" - -namespace cricket { -class QuicTransportChannel; -class ReliableQuicStream; -} // namepsace cricket - -namespace webrtc { - -// QuicDataTransport creates QuicDataChannels for the PeerConnection. It also -// handles QUIC stream demuxing by distributing incoming QUIC streams from the -// QuicTransportChannel among the QuicDataChannels that it has created. -// -// QuicDataTransport reads the data channel ID from the incoming QUIC stream, -// then looks it up in a map of ID => QuicDataChannel. If the data channel -// exists, it sends the QUIC stream to the QuicDataChannel. -class QuicDataTransport : public sigslot::has_slots<> { - public: - QuicDataTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - rtc::Thread* network_thread, - cricket::TransportController* transport_controller); - ~QuicDataTransport() override; - - // The QuicDataTransport acts like a BaseChannel with these functions. - bool SetTransport(const std::string& transport_name); - const std::string& transport_name() const { return transport_name_; } - const std::string& content_name() const { return content_name_; } - void set_content_name(const std::string& content_name) { - content_name_ = content_name; - } - - // Creates a QuicDataChannel that uses this QuicDataTransport. - rtc::scoped_refptr CreateDataChannel( - const std::string& label, - const DataChannelInit* config); - - // Removes a QuicDataChannel with the given ID from the QuicDataTransport's - // data channel map. - void DestroyDataChannel(int id); - - // True if the QuicDataTransport has a data channel with the given ID. - bool HasDataChannel(int id) const; - - // True if the QuicDataTransport has data channels. - bool HasDataChannels() const; - - cricket::QuicTransportChannel* quic_transport_channel() { - return quic_transport_channel_; - } - - private: - // Sets the QUIC transport channel for the QuicDataChannels and the - // QuicDataTransport. Returns false if a different QUIC transport channel is - // already set, the QUIC transport channel cannot be set for any of the - // QuicDataChannels, or |channel| is NULL. - bool SetTransportChannel(cricket::QuicTransportChannel* channel); - - // Called from the QuicTransportChannel when a ReliableQuicStream is created - // to receive incoming data. - void OnIncomingStream(cricket::ReliableQuicStream* stream); - // Called from the ReliableQuicStream when the first QUIC stream frame is - // received for incoming data. The QuicDataTransport reads the data channel ID - // and message ID from the incoming data, then dispatches the - // ReliableQuicStream to the QuicDataChannel with the same data channel ID. - void OnDataReceived(net::QuicStreamId stream_id, - const char* data, - size_t len); - - cricket::QuicTransportChannel* CreateTransportChannel( - const std::string& transport_name); - void DestroyTransportChannel(cricket::TransportChannel* transport_channel); - - // Map of data channel ID => QUIC data channel values. - std::unordered_map> - data_channel_by_id_; - // Map of QUIC stream ID => ReliableQuicStream* values. - std::unordered_map - quic_stream_by_id_; - // QuicTransportChannel for sending/receiving data. - cricket::QuicTransportChannel* quic_transport_channel_ = nullptr; - // Threads for the QUIC data channel. - rtc::Thread* const signaling_thread_; - rtc::Thread* const worker_thread_; - rtc::Thread* const network_thread_; - - cricket::TransportController* transport_controller_; - std::string content_name_; - std::string transport_name_; -}; - -} // namespace webrtc - -#endif // PC_QUICDATATRANSPORT_H_ diff --git a/pc/quicdatatransport_unittest.cc b/pc/quicdatatransport_unittest.cc deleted file mode 100644 index 2f6d13f92e..0000000000 --- a/pc/quicdatatransport_unittest.cc +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "pc/quicdatatransport.h" - -#include -#include -#include -#include -#include - -#include "p2p/base/faketransportcontroller.h" -#include "p2p/quic/quictransportchannel.h" -#include "p2p/quic/reliablequicstream.h" -#include "pc/quicdatachannel.h" -#include "rtc_base/bytebuffer.h" -#include "rtc_base/gunit.h" - -using webrtc::DataBuffer; -using webrtc::DataChannelInit; -using webrtc::DataChannelInterface; -using webrtc::DataChannelObserver; -using webrtc::QuicDataChannel; -using webrtc::QuicDataTransport; -using cricket::FakeTransportChannel; -using cricket::FakeTransportController; -using cricket::QuicTransportChannel; -using cricket::ReliableQuicStream; - -namespace { - -// Timeout for asynchronous operations. -static const int kTimeoutMs = 1000; // milliseconds -static const char kTransportName[] = "data"; - -// FakeObserver receives messages from the data channel. -class FakeObserver : public DataChannelObserver { - public: - FakeObserver() {} - - void OnStateChange() override {} - - void OnBufferedAmountChange(uint64_t previous_amount) override {} - - void OnMessage(const webrtc::DataBuffer& buffer) override { - messages_.push_back(std::string(buffer.data.data(), buffer.size())); - } - - const std::vector& messages() const { return messages_; } - - size_t messages_received() const { return messages_.size(); } - - private: - std::vector messages_; -}; - -// A peer who uses a QUIC transport channel and fake ICE transport channel to -// send or receive data. -class QuicDataTransportPeer { - public: - QuicDataTransportPeer() - : fake_transport_controller_(new FakeTransportController()), - quic_data_transport_(rtc::Thread::Current(), - rtc::Thread::Current(), - rtc::Thread::Current(), - fake_transport_controller_.get()) { - fake_transport_controller_->use_quic(); - quic_data_transport_.set_content_name("data"); - quic_data_transport_.SetTransport(kTransportName); - ice_transport_channel_ = static_cast( - quic_data_transport_.quic_transport_channel()->ice_transport_channel()); - ice_transport_channel_->SetAsync(true); - } - - void GenerateCertificateAndFingerprint() { - rtc::scoped_refptr local_cert = - rtc::RTCCertificate::Create(std::unique_ptr( - rtc::SSLIdentity::Generate("cert_name", rtc::KT_DEFAULT))); - quic_data_transport_.quic_transport_channel()->SetLocalCertificate( - local_cert); - local_fingerprint_.reset(CreateFingerprint(local_cert.get())); - } - - // Connects |ice_transport_channel_| to that of the other peer. - void Connect(QuicDataTransportPeer* other_peer) { - ice_transport_channel_->SetDestination(other_peer->ice_transport_channel_); - } - - std::unique_ptr& local_fingerprint() { - return local_fingerprint_; - } - - QuicTransportChannel* quic_transport_channel() { - return quic_data_transport_.quic_transport_channel(); - } - - // Write a messge directly to the ReliableQuicStream. - void WriteMessage(int data_channel_id, - uint64_t message_id, - const std::string& message) { - ReliableQuicStream* stream = - quic_data_transport_.quic_transport_channel()->CreateQuicStream(); - rtc::CopyOnWriteBuffer payload; - webrtc::WriteQuicDataChannelMessageHeader(data_channel_id, message_id, - &payload); - stream->Write(payload.data(), payload.size(), false); - stream->Write(message.data(), message.size(), true); - } - - rtc::scoped_refptr CreateDataChannel( - const DataChannelInit* config) { - return quic_data_transport_.CreateDataChannel("testing", config); - } - - QuicDataTransport* quic_data_transport() { return &quic_data_transport_; } - - private: - // Creates a fingerprint from a certificate. - rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { - std::string digest_algorithm; - cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); - std::unique_ptr fingerprint( - rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); - return fingerprint.release(); - } - - std::unique_ptr fake_transport_controller_; - QuicDataTransport quic_data_transport_; - FakeTransportChannel* ice_transport_channel_; - std::unique_ptr local_fingerprint_; -}; - -class QuicDataTransportTest : public testing::Test { - public: - QuicDataTransportTest() {} - - void ConnectTransportChannels() { - SetCryptoParameters(); - peer1_.Connect(&peer2_); - ASSERT_TRUE_WAIT(peer1_.quic_transport_channel()->writable() && - peer2_.quic_transport_channel()->writable(), - kTimeoutMs); - } - - // Sets crypto parameters required for the QUIC handshake. - void SetCryptoParameters() { - peer1_.GenerateCertificateAndFingerprint(); - peer2_.GenerateCertificateAndFingerprint(); - - peer1_.quic_transport_channel()->SetSslRole(rtc::SSL_CLIENT); - peer2_.quic_transport_channel()->SetSslRole(rtc::SSL_SERVER); - - std::unique_ptr& peer1_fingerprint = - peer1_.local_fingerprint(); - std::unique_ptr& peer2_fingerprint = - peer2_.local_fingerprint(); - - peer1_.quic_transport_channel()->SetRemoteFingerprint( - peer2_fingerprint->algorithm, - reinterpret_cast(peer2_fingerprint->digest.data()), - peer2_fingerprint->digest.size()); - peer2_.quic_transport_channel()->SetRemoteFingerprint( - peer1_fingerprint->algorithm, - reinterpret_cast(peer1_fingerprint->digest.data()), - peer1_fingerprint->digest.size()); - } - - protected: - QuicDataTransportPeer peer1_; - QuicDataTransportPeer peer2_; -}; - -// Tests creation and destruction of data channels. -TEST_F(QuicDataTransportTest, CreateAndDestroyDataChannels) { - QuicDataTransport* quic_data_transport = peer2_.quic_data_transport(); - EXPECT_FALSE(quic_data_transport->HasDataChannels()); - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - EXPECT_FALSE(quic_data_transport->HasDataChannel(data_channel_id)); - webrtc::DataChannelInit config; - config.id = data_channel_id; - rtc::scoped_refptr data_channel = - peer2_.CreateDataChannel(&config); - EXPECT_NE(nullptr, data_channel); - EXPECT_EQ(data_channel_id, data_channel->id()); - EXPECT_TRUE(quic_data_transport->HasDataChannel(data_channel_id)); - } - EXPECT_TRUE(quic_data_transport->HasDataChannels()); - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - quic_data_transport->DestroyDataChannel(data_channel_id); - EXPECT_FALSE(quic_data_transport->HasDataChannel(data_channel_id)); - } - EXPECT_FALSE(quic_data_transport->HasDataChannels()); -} - -// Tests that the QuicDataTransport does not allow creating multiple -// QuicDataChannels with the same id. -TEST_F(QuicDataTransportTest, CannotCreateDataChannelsWithSameId) { - webrtc::DataChannelInit config; - config.id = 2; - EXPECT_NE(nullptr, peer2_.CreateDataChannel(&config)); - EXPECT_EQ(nullptr, peer2_.CreateDataChannel(&config)); -} - -// Tests that any data channels created by the QuicDataTransport are in state -// kConnecting before the QuicTransportChannel is set, then transition to state -// kOpen when the transport channel becomes writable. -TEST_F(QuicDataTransportTest, DataChannelsOpenWhenTransportChannelWritable) { - webrtc::DataChannelInit config1; - config1.id = 7; - rtc::scoped_refptr data_channel1 = - peer2_.CreateDataChannel(&config1); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state()); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state()); - webrtc::DataChannelInit config2; - config2.id = 14; - rtc::scoped_refptr data_channel2 = - peer2_.CreateDataChannel(&config2); - EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel2->state()); - // Existing data channels should open once the transport channel is writable. - ConnectTransportChannels(); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel1->state(), - kTimeoutMs); - EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel2->state(), - kTimeoutMs); - // Any data channels created afterwards should start in state kOpen. - webrtc::DataChannelInit config3; - config3.id = 21; - rtc::scoped_refptr data_channel3 = - peer2_.CreateDataChannel(&config3); - EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel3->state()); -} - -// Tests that the QuicTransport dispatches messages for one QuicDataChannel. -TEST_F(QuicDataTransportTest, ReceiveMessagesForSingleDataChannel) { - ConnectTransportChannels(); - - int data_channel_id = 1337; - webrtc::DataChannelInit config; - config.id = data_channel_id; - rtc::scoped_refptr peer2_data_channel = - peer2_.CreateDataChannel(&config); - FakeObserver observer; - peer2_data_channel->RegisterObserver(&observer); - - uint64_t message1_id = 26u; - peer1_.WriteMessage(data_channel_id, message1_id, "Testing"); - ASSERT_EQ_WAIT(1, observer.messages_received(), kTimeoutMs); - EXPECT_EQ("Testing", observer.messages()[0]); - - uint64_t message2_id = 402u; - peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!"); - ASSERT_EQ_WAIT(2, observer.messages_received(), kTimeoutMs); - EXPECT_EQ("Hello, World!", observer.messages()[1]); - - uint64_t message3_id = 100260415u; - peer1_.WriteMessage(data_channel_id, message3_id, "Third message"); - ASSERT_EQ_WAIT(3, observer.messages_received(), kTimeoutMs); - EXPECT_EQ("Third message", observer.messages()[2]); -} - -// Tests that the QuicTransport dispatches messages to the correct data channel -// when multiple are in use. -TEST_F(QuicDataTransportTest, ReceiveMessagesForMultipleDataChannels) { - ConnectTransportChannels(); - - std::vector> data_channels; - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - webrtc::DataChannelInit config; - config.id = data_channel_id; - data_channels.push_back(peer2_.CreateDataChannel(&config)); - } - - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - uint64_t message1_id = 48023u; - FakeObserver observer; - DataChannelInterface* peer2_data_channel = - data_channels[data_channel_id].get(); - peer2_data_channel->RegisterObserver(&observer); - peer1_.WriteMessage(data_channel_id, message1_id, "Testing"); - ASSERT_EQ_WAIT(1, observer.messages_received(), kTimeoutMs); - EXPECT_EQ("Testing", observer.messages()[0]); - - uint64_t message2_id = 1372643095u; - peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!"); - ASSERT_EQ_WAIT(2, observer.messages_received(), kTimeoutMs); - EXPECT_EQ("Hello, World!", observer.messages()[1]); - } -} - -// Tests end-to-end that both peers can use multiple QuicDataChannels to -// send/receive messages using a QuicDataTransport. -TEST_F(QuicDataTransportTest, EndToEndSendReceiveMessages) { - ConnectTransportChannels(); - - std::vector> peer1_data_channels; - std::vector> peer2_data_channels; - - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - webrtc::DataChannelInit config; - config.id = data_channel_id; - peer1_data_channels.push_back(peer1_.CreateDataChannel(&config)); - peer2_data_channels.push_back(peer2_.CreateDataChannel(&config)); - } - - for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { - DataChannelInterface* peer1_data_channel = - peer1_data_channels[data_channel_id].get(); - FakeObserver observer1; - peer1_data_channel->RegisterObserver(&observer1); - DataChannelInterface* peer2_data_channel = - peer2_data_channels[data_channel_id].get(); - FakeObserver observer2; - peer2_data_channel->RegisterObserver(&observer2); - - peer1_data_channel->Send(webrtc::DataBuffer("Peer 1 message 1")); - ASSERT_EQ_WAIT(1, observer2.messages_received(), kTimeoutMs); - EXPECT_EQ("Peer 1 message 1", observer2.messages()[0]); - - peer1_data_channel->Send(webrtc::DataBuffer("Peer 1 message 2")); - ASSERT_EQ_WAIT(2, observer2.messages_received(), kTimeoutMs); - EXPECT_EQ("Peer 1 message 2", observer2.messages()[1]); - - peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 1")); - ASSERT_EQ_WAIT(1, observer1.messages_received(), kTimeoutMs); - EXPECT_EQ("Peer 2 message 1", observer1.messages()[0]); - - peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 2")); - ASSERT_EQ_WAIT(2, observer1.messages_received(), kTimeoutMs); - EXPECT_EQ("Peer 2 message 2", observer1.messages()[1]); - } -} - -// Tests that SetTransport returns false when setting a transport that is not -// equivalent to the one already set. -TEST_F(QuicDataTransportTest, SetTransportReturnValue) { - QuicDataTransport* quic_data_transport = peer1_.quic_data_transport(); - // Ignore the same transport name. - EXPECT_TRUE(quic_data_transport->SetTransport(kTransportName)); - // Return false when setting a different transport name. - EXPECT_FALSE(quic_data_transport->SetTransport("another transport name")); -} - -} // namespace diff --git a/pc/transportcontroller.cc b/pc/transportcontroller.cc index e2fdc62e43..aa6ddec729 100644 --- a/pc/transportcontroller.cc +++ b/pc/transportcontroller.cc @@ -248,9 +248,6 @@ DtlsTransportInternal* TransportController::CreateDtlsTransport_n( // Create DTLS channel wrapping ICE channel, and configure it. IceTransportInternal* ice = CreateIceTransportChannel_n(transport_name, component); - // TODO(deadbeef): To support QUIC, would need to create a - // QuicTransportChannel here. What is "dtls" in this file would then become - // "dtls or quic". DtlsTransportInternal* dtls = CreateDtlsTransportChannel_n(transport_name, component, ice); dtls->ice_transport()->SetMetricsObserver(metrics_observer_); diff --git a/pc/transportcontroller.h b/pc/transportcontroller.h index be8dd8af70..534f117186 100644 --- a/pc/transportcontroller.h +++ b/pc/transportcontroller.h @@ -127,9 +127,6 @@ class TransportController : public sigslot::has_slots<>, virtual void DestroyDtlsTransport_n(const std::string& transport_name, int component); - void use_quic() { quic_ = true; } - bool quic() const { return quic_; } - // TODO(deadbeef): Remove all for_testing methods! const rtc::scoped_refptr& certificate_for_testing() const { @@ -267,8 +264,6 @@ class TransportController : public sigslot::has_slots<>, rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; rtc::scoped_refptr certificate_; rtc::AsyncInvoker invoker_; - // True if QUIC is used instead of DTLS. - bool quic_ = false; webrtc::MetricsObserverInterface* metrics_observer_ = nullptr; diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc index abff2778cc..bbe9964e4d 100644 --- a/pc/webrtcsession.cc +++ b/pc/webrtcsession.cc @@ -38,10 +38,6 @@ #include "rtc_base/stringencode.h" #include "rtc_base/stringutils.h" -#ifdef HAVE_QUIC -#include "p2p/quic/quictransportchannel.h" -#endif // HAVE_QUIC - using cricket::ContentInfo; using cricket::ContentInfos; using cricket::MediaContentDescription; @@ -536,11 +532,6 @@ WebRtcSession::~WebRtcSession() { network_thread_->Invoke( RTC_FROM_HERE, rtc::Bind(&WebRtcSession::DestroySctpTransport_n, this)); } -#ifdef HAVE_QUIC - if (quic_data_transport_) { - quic_data_transport_.reset(); - } -#endif LOG(LS_INFO) << "Session: " << id() << " is destroyed."; } @@ -580,21 +571,7 @@ bool WebRtcSession::Initialize( // PeerConnectionFactoryInterface::Options. if (rtc_configuration.enable_rtp_data_channel) { data_channel_type_ = cricket::DCT_RTP; - } -#ifdef HAVE_QUIC - else if (rtc_configuration.enable_quic) { - // Use QUIC instead of DTLS when |enable_quic| is true. - data_channel_type_ = cricket::DCT_QUIC; - transport_controller_->use_quic(); - if (dtls_enabled_) { - LOG(LS_INFO) << "Using QUIC instead of DTLS"; - } - quic_data_transport_.reset( - new QuicDataTransport(signaling_thread(), worker_thread(), - network_thread(), transport_controller_.get())); - } -#endif // HAVE_QUIC - else { + } else { // DTLS has to be enabled to use SCTP. if (!options.disable_sctp_data_channels && dtls_enabled_) { data_channel_type_ = cricket::DCT_SCTP; @@ -1107,14 +1084,6 @@ bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) { } const std::string& transport_name = *first_content_name; -#ifdef HAVE_QUIC - if (quic_data_transport_ && - bundle.HasContentName(quic_data_transport_->content_name()) && - quic_data_transport_->transport_name() != transport_name) { - LOG(LS_ERROR) << "Unable to BUNDLE " << quic_data_transport_->content_name() - << " on " << transport_name << "with QUIC."; - } -#endif auto maybe_set_transport = [this, bundle, transport_name](cricket::BaseChannel* ch) { if (!ch || !bundle.HasContentName(ch->content_name())) { @@ -1723,12 +1692,6 @@ void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) { RTC_FROM_HERE, rtc::Bind(&WebRtcSession::DestroySctpTransport_n, this)); } -#ifdef HAVE_QUIC - // Clean up the existing QuicDataTransport and its QuicTransportChannels. - if (quic_data_transport_) { - quic_data_transport_.reset(); - } -#endif } } @@ -1897,13 +1860,6 @@ bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content, const std::string* bundle_transport) { const std::string transport_name = bundle_transport ? *bundle_transport : content->name; -#ifdef HAVE_QUIC - if (data_channel_type_ == cricket::DCT_QUIC) { - RTC_DCHECK(transport_controller_->quic()); - quic_data_transport_->SetTransports(transport_name); - return true; - } -#endif // HAVE_QUIC bool sctp = (data_channel_type_ == cricket::DCT_SCTP); if (sctp) { if (!sctp_factory_) { @@ -2409,12 +2365,6 @@ const std::string WebRtcSession::GetTransportName( const std::string& content_name) { cricket::BaseChannel* channel = GetChannel(content_name); if (!channel) { -#ifdef HAVE_QUIC - if (data_channel_type_ == cricket::DCT_QUIC && quic_data_transport_ && - content_name == quic_data_transport_->transport_name()) { - return quic_data_transport_->transport_name(); - } -#endif if (sctp_transport_) { RTC_DCHECK(sctp_content_name_); RTC_DCHECK(sctp_transport_name_); diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h index 185fa05ed4..37d553a89c 100644 --- a/pc/webrtcsession.h +++ b/pc/webrtcsession.h @@ -29,10 +29,6 @@ #include "rtc_base/sslidentity.h" #include "rtc_base/thread.h" -#ifdef HAVE_QUIC -#include "pc/quicdatatransport.h" -#endif // HAVE_QUIC - namespace cricket { class ChannelManager; @@ -43,10 +39,6 @@ class StatsReport; class VideoChannel; class VoiceChannel; -#ifdef HAVE_QUIC -class QuicTransportChannel; -#endif // HAVE_QUIC - } // namespace cricket namespace webrtc { @@ -375,11 +367,6 @@ class WebRtcSession : // std::string represents the data channel label. sigslot::signal2 SignalDataChannelOpenMessage; -#ifdef HAVE_QUIC - QuicDataTransport* quic_data_transport() { - return quic_data_transport_.get(); - } -#endif // HAVE_QUIC private: // Indicates the type of SessionDescription in a call to SetLocalDescription @@ -643,8 +630,6 @@ class WebRtcSession : // not set or false, SCTP is allowed (DCT_SCTP); // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP); // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE). - // The data channel type could be DCT_QUIC if the QUIC data channel is - // enabled. cricket::DataChannelType data_channel_type_; // List of content names for which the remote side triggered an ICE restart. std::set pending_ice_restarts_; @@ -665,10 +650,6 @@ class WebRtcSession : bool received_first_video_packet_ = false; bool received_first_audio_packet_ = false; -#ifdef HAVE_QUIC - std::unique_ptr quic_data_transport_; -#endif // HAVE_QUIC - RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcSession); }; } // namespace webrtc diff --git a/webrtc.gni b/webrtc.gni index de1c5e97b7..7154b87605 100644 --- a/webrtc.gni +++ b/webrtc.gni @@ -143,9 +143,6 @@ declare_args() { # http://www.openh264.org, https://www.ffmpeg.org/ rtc_use_h264 = proprietary_codecs && !is_android && !is_ios - # Determines whether QUIC code will be built. - rtc_use_quic = false - # By default, use normal platform audio support or dummy audio, but don't # use file-based audio playout and record. rtc_use_dummy_audio_file_devices = false