|  | // 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 |