// Copyright (c) 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/quic/quartc/quartc_factory.h" #include "net/quic/core/crypto/quic_random.h" #include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/quartc/quartc_session.h" namespace net { namespace { // Implements the QuicAlarm with QuartcTaskRunnerInterface for the Quartc // users other than Chromium. For example, WebRTC will create QuartcAlarm with // a QuartcTaskRunner implemented by WebRTC. class QuartcAlarm : public QuicAlarm, public QuartcTaskRunnerInterface::Task { public: QuartcAlarm(const QuicClock* clock, QuartcTaskRunnerInterface* task_runner, QuicArenaScopedPtr delegate) : QuicAlarm(std::move(delegate)), clock_(clock), task_runner_(task_runner) {} ~QuartcAlarm() override { // Cancel the scheduled task before getting deleted. CancelImpl(); } // QuicAlarm overrides. void SetImpl() override { DCHECK(deadline().IsInitialized()); // Cancel it if already set. CancelImpl(); int64_t delay_ms = (deadline() - (clock_->Now())).ToMilliseconds(); if (delay_ms < 0) { delay_ms = 0; } DCHECK(task_runner_); DCHECK(!scheduled_task_); scheduled_task_ = task_runner_->Schedule(this, delay_ms); } void CancelImpl() override { if (scheduled_task_) { scheduled_task_->Cancel(); scheduled_task_.reset(); } } // QuartcTaskRunner::Task overrides. void Run() override { // 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(); } private: // Not owned by QuartcAlarm. Owned by the QuartcFactory. const QuicClock* clock_; // Not owned by QuartcAlarm. Owned by the QuartcFactory. QuartcTaskRunnerInterface* task_runner_; // Owned by QuartcAlarm. std::unique_ptr scheduled_task_; }; // Adapts QuartcClockInterface (provided by the user) to QuicClock // (expected by QUIC). class QuartcClock : public QuicClock { public: explicit QuartcClock(QuartcClockInterface* clock) : clock_(clock) {} QuicTime ApproximateNow() const override { return Now(); } QuicTime Now() const override { return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(clock_->NowMicroseconds()); } QuicWallTime WallNow() const override { return QuicWallTime::FromUNIXMicroseconds(clock_->NowMicroseconds()); } private: QuartcClockInterface* clock_; }; } // namespace QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config) : task_runner_(factory_config.task_runner), clock_(new QuartcClock(factory_config.clock)) {} QuartcFactory::~QuartcFactory() {} std::unique_ptr QuartcFactory::CreateQuartcSession( const QuartcSessionConfig& quartc_session_config) { DCHECK(quartc_session_config.packet_transport); Perspective perspective = quartc_session_config.is_server ? Perspective::IS_SERVER : Perspective::IS_CLIENT; std::unique_ptr quic_connection = CreateQuicConnection(quartc_session_config, perspective); QuicTagVector copt; if (quartc_session_config.congestion_control == QuartcCongestionControl::kBBR) { copt.push_back(kTBBR); FLAGS_quic_reloadable_flag_quic_bbr_slower_startup = true; FLAGS_quic_reloadable_flag_quic_bbr_fully_drain_queue = true; FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt = true; for (const auto option : quartc_session_config.bbr_options) { switch (option) { case (QuartcBbrOptions::kSlowerStartup): copt.push_back(kBBRS); break; case (QuartcBbrOptions::kFullyDrainQueue): copt.push_back(kBBR3); break; case (QuartcBbrOptions::kReduceProbeRtt): copt.push_back(kBBR6); break; case (QuartcBbrOptions::kSkipProbeRtt): copt.push_back(kBBR7); break; case (QuartcBbrOptions::kSkipProbeRttAggressively): copt.push_back(kBBR8); break; case (QuartcBbrOptions::kFillUpLinkDuringProbing): quic_connection->set_fill_up_link_during_probing(true); break; } } } QuicConfig quic_config; quic_config.SetConnectionOptionsToSend(copt); quic_config.SetClientConnectionOptions(copt); if (quartc_session_config.max_time_before_crypto_handshake_secs > 0) { quic_config.set_max_time_before_crypto_handshake( QuicTime::Delta::FromSeconds( quartc_session_config.max_time_before_crypto_handshake_secs)); } if (quartc_session_config.max_idle_time_before_crypto_handshake_secs > 0) { quic_config.set_max_idle_time_before_crypto_handshake( QuicTime::Delta::FromSeconds( quartc_session_config.max_idle_time_before_crypto_handshake_secs)); } return std::unique_ptr(new QuartcSession( std::move(quic_connection), quic_config, quartc_session_config.unique_remote_server_id, perspective, this /*QuicConnectionHelperInterface*/, clock_.get())); } std::unique_ptr QuartcFactory::CreateQuicConnection( const QuartcSessionConfig& quartc_session_config, Perspective perspective) { // The QuicConnection will take the ownership. std::unique_ptr writer( new QuartcPacketWriter(quartc_session_config.packet_transport, quartc_session_config.max_packet_size)); // dummy_id and dummy_address are used because Quartc network layer will not // use these two. QuicConnectionId dummy_id = 0; QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/); return std::unique_ptr(new QuicConnection( dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/ this /*QuicAlarmFactory*/, writer.release(), true /*own the writer*/, perspective, AllSupportedTransportVersions())); } QuicAlarm* QuartcFactory::CreateAlarm(QuicAlarm::Delegate* delegate) { return new QuartcAlarm(GetClock(), task_runner_, QuicArenaScopedPtr(delegate)); } QuicArenaScopedPtr QuartcFactory::CreateAlarm( QuicArenaScopedPtr delegate, QuicConnectionArena* arena) { if (arena != nullptr) { return arena->New(GetClock(), task_runner_, std::move(delegate)); } return QuicArenaScopedPtr( new QuartcAlarm(GetClock(), task_runner_, std::move(delegate))); } const QuicClock* QuartcFactory::GetClock() const { return clock_.get(); } QuicRandom* QuartcFactory::GetRandomGenerator() { return QuicRandom::GetInstance(); } QuicBufferAllocator* QuartcFactory::GetStreamSendBufferAllocator() { return &buffer_allocator_; } std::unique_ptr CreateQuartcFactory( const QuartcFactoryConfig& factory_config) { return std::unique_ptr( new QuartcFactory(factory_config)); } } // namespace net