// 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/third_party/quic/quartc/quartc_factory.h" #include "net/third_party/quic/core/crypto/quic_random.h" #include "net/third_party/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quic/platform/api/quic_socket_address.h" #include "net/third_party/quic/quartc/quartc_session.h" namespace quic { QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config) : alarm_factory_(factory_config.alarm_factory), clock_(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.perspective; // QuartcSession will eventually own both |writer| and |quic_connection|. auto writer = QuicMakeUnique(quartc_session_config.packet_transport, quartc_session_config.max_packet_size); // ACK less aggressively when reordered packets are present. // Must be set before the connection is created. SetQuicReloadableFlag(quic_ack_reordered_packets, true); std::unique_ptr quic_connection = CreateQuicConnection(perspective, writer.get()); QuicTagVector copt; copt.push_back(kNSTP); // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be // false. SetQuicReloadableFlag(quic_enable_ack_decimation, false); copt.push_back(kAKD2); // Enable time-based loss detection. copt.push_back(kTIME); // Use BBR for congestion control. copt.push_back(kTBBR); // Note: flag settings have no effect for Exoblaze builds since // SetQuicReloadableFlag() gets stubbed out. SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); // Enable BBR6,7,8. SetQuicReloadableFlag(quic_unified_iw_options, true); // Enable IWXX opts. SetQuicReloadableFlag(quic_bbr_slower_startup3, true); // Enable BBQX opts. copt.push_back(kBBR3); // Stay in low-gain until in-flight < BDP. copt.push_back(kBBR5); // 40 RTT ack aggregation. copt.push_back(kBBR6); // Use a 0.75 * BDP cwnd during PROBE_RTT. copt.push_back(kBBR8); // Skip PROBE_RTT if app-limited. copt.push_back(kBBQ1); // 2.773 pacing gain in STARTUP. copt.push_back(kBBQ2); // 2.0 CWND gain in STARTUP. copt.push_back(kBBQ4); // 0.75 pacing gain in DRAIN. copt.push_back(k1RTT); // Exit STARTUP after 1 RTT with no gains. copt.push_back(kIW10); // 10-packet (14600 byte) initial cwnd. // TODO(b/112192494): Enable pipe-filling once it no longer starves Quartc. // quic_connection->set_fill_up_link_during_probing(true); // TODO(b/112192153): Test and possible enable slower startup when pipe // filling is ready to use. Slower startup is kBBRS. QuicConfig quic_config; // Use the limits for the session & stream flow control. The default 16KB // limit leads to significantly undersending (not reaching BWE on the outgoing // bitrate) due to blocked frames, and it leads to high latency (and one-way // delay). Setting it to its limits is not going to cause issues (our streams // are small generally, and if we were to buffer 24MB it wouldn't be the end // of the world). We can consider setting different limits in future (e.g. 1MB // stream, 1.5MB session). It's worth noting that on 1mbps bitrate, limit of // 24MB can capture approx 4 minutes of the call, and the default increase in // size of the window (half of the window size) is approximately 2 minutes of // the call. quic_config.SetInitialSessionFlowControlWindowToSend( kSessionReceiveWindowLimit); quic_config.SetInitialStreamFlowControlWindowToSend( kStreamReceiveWindowLimit); quic_config.SetConnectionOptionsToSend(copt); quic_config.SetClientConnectionOptions(copt); if (quartc_session_config.max_time_before_crypto_handshake > QuicTime::Delta::Zero()) { quic_config.set_max_time_before_crypto_handshake( quartc_session_config.max_time_before_crypto_handshake); } if (quartc_session_config.max_idle_time_before_crypto_handshake > QuicTime::Delta::Zero()) { quic_config.set_max_idle_time_before_crypto_handshake( quartc_session_config.max_idle_time_before_crypto_handshake); } if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) { quic_config.SetIdleNetworkTimeout( quartc_session_config.idle_network_timeout, quartc_session_config.idle_network_timeout); } // The ICE transport provides a unique 5-tuple for each connection. Save // overhead by omitting the connection id. quic_config.SetBytesForConnectionIdToSend(0); return QuicMakeUnique( std::move(quic_connection), quic_config, quartc_session_config.unique_remote_server_id, perspective, this /*QuicConnectionHelperInterface*/, clock_, std::move(writer)); } std::unique_ptr QuartcFactory::CreateQuicConnection( Perspective perspective, QuartcPacketWriter* packet_writer) { // 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 QuicMakeUnique( dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/ alarm_factory_ /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false, perspective, CurrentSupportedVersions()); } const QuicClock* QuartcFactory::GetClock() const { return clock_; } 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 quic