| // 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/quiche/src/quic/quartc/quartc_factory.h" | |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" | |
| #include "net/third_party/quiche/src/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<QuartcSession> 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<QuartcPacketWriter>(quartc_session_config.packet_transport, | |
| quartc_session_config.max_packet_size); | |
| // Fixes behavior of StopReading() with level-triggered stream sequencers. | |
| SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); | |
| // Fix b/110259444. | |
| SetQuicReloadableFlag(quic_fix_spurious_ack_alarm, true); | |
| // Enable version 45+ to enable SendMessage API. | |
| // Enable version 47+ to enable 'quic bit' per draft 17. | |
| SetQuicReloadableFlag(quic_enable_version_45, true); | |
| SetQuicReloadableFlag(quic_enable_version_46, true); | |
| SetQuicReloadableFlag(quic_enable_version_47, true); | |
| // Fix for inconsistent reporting of crypto handshake. | |
| SetQuicReloadableFlag(quic_fix_has_pending_crypto_data, true); | |
| // Ensure that we don't drop data because QUIC streams refuse to buffer it. | |
| // TODO(b/120099046): Replace this with correct handling of WriteMemSlices(). | |
| SetQuicFlag(&FLAGS_quic_buffered_data_threshold, | |
| std::numeric_limits<int>::max()); | |
| // TODO(b/117157454): Perform version negotiation for Quartc outside of | |
| // QuicSession/QuicConnection. Currently default of | |
| // gfe2_restart_flag_quic_no_server_conn_ver_negotiation2 is false, | |
| // but we fail blueprint test that sets all QUIC flags to true. | |
| // | |
| // Forcing flag to false to pass blueprint tests, but eventually we'll have | |
| // to implement negotiation outside of QuicConnection. | |
| SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, false); | |
| std::unique_ptr<QuicConnection> quic_connection = | |
| CreateQuicConnection(perspective, writer.get()); | |
| QuicTagVector copt; | |
| copt.push_back(kNSTP); | |
| // Enable and request QUIC to include receive timestamps in ACK frames. | |
| SetQuicReloadableFlag(quic_send_timestamps, true); | |
| copt.push_back(kSTMP); | |
| // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be | |
| // false. | |
| SetQuicReloadableFlag(quic_enable_ack_decimation, false); | |
| copt.push_back(kAKD2); | |
| // Use unlimited decimation in order to reduce number of unbundled ACKs. | |
| copt.push_back(kAKDU); | |
| // Enable time-based loss detection. | |
| copt.push_back(kTIME); | |
| QuicSentPacketManager& sent_packet_manager = | |
| quic_connection->sent_packet_manager(); | |
| // Default delayed ack time is 25ms. | |
| // If data packets are sent less often (e.g. because p-time was modified), | |
| // we would force acks to be sent every 25ms regardless, increasing | |
| // overhead. Since generally we guarantee a packet every 20ms, changing | |
| // this value should have miniscule effect on quality on good connections, | |
| // but on poor connections, changing this number significantly reduced the | |
| // number of ack-only packets. | |
| // The p-time can go up to as high as 120ms, and when it does, it's | |
| // when the low overhead is the most important thing. Ideally it should be | |
| // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms. | |
| sent_packet_manager.set_delayed_ack_time( | |
| QuicTime::Delta::FromMilliseconds(100)); | |
| // 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. | |
| SetQuicReloadableFlag(quic_bbr_flexible_app_limited, true); // Enable BBR9. | |
| 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(kBBR9); // Ignore app-limited if enough data is in flight. | |
| 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. | |
| if (!quartc_session_config.enable_tail_loss_probe) { | |
| copt.push_back(kNTLP); | |
| } | |
| quic_connection->set_fill_up_link_during_probing(true); | |
| // We start ack decimation after 15 packets. Typically, we would see | |
| // 1-2 crypto handshake packets, one media packet, and 10 probing packets. | |
| // We want to get acks for the probing packets as soon as possible, | |
| // but we can start using ack decimation right after first probing completes. | |
| // The default was to not start ack decimation for the first 100 packets. | |
| quic_connection->set_min_received_before_ack_decimation(15); | |
| // 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); | |
| // Allow up to 1000 incoming streams at once. Quartc streams typically contain | |
| // one audio or video frame and close immediately. However, when a video frame | |
| // becomes larger than one packet, there is some delay between the start and | |
| // end of each stream. The default maximum of 100 only leaves about 1 second | |
| // of headroom (Quartc sends ~30 video frames per second) before QUIC starts | |
| // to refuse incoming streams. Back-pressure should clear backlogs of | |
| // incomplete streams, but targets 1 second for recovery. Increasing the | |
| // number of open streams gives sufficient headroom to recover before QUIC | |
| // refuses new streams. | |
| quic_config.SetMaxIncomingDynamicStreamsToSend(1000); | |
| return QuicMakeUnique<QuartcSession>( | |
| std::move(quic_connection), quic_config, CurrentSupportedVersions(), | |
| quartc_session_config.unique_remote_server_id, perspective, | |
| this /*QuicConnectionHelperInterface*/, clock_, std::move(writer)); | |
| } | |
| std::unique_ptr<QuicConnection> 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; | |
| if (!QuicConnectionIdSupportsVariableLength(perspective)) { | |
| dummy_id = QuicConnectionIdFromUInt64(0); | |
| } else { | |
| char connection_id_bytes[sizeof(uint64_t)] = {}; | |
| dummy_id = QuicConnectionId(static_cast<char*>(connection_id_bytes), | |
| sizeof(connection_id_bytes)); | |
| } | |
| QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/); | |
| return QuicMakeUnique<QuicConnection>( | |
| 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<QuartcFactory> CreateQuartcFactory( | |
| const QuartcFactoryConfig& factory_config) { | |
| return std::unique_ptr<QuartcFactory>(new QuartcFactory(factory_config)); | |
| } | |
| } // namespace quic |