|  | // 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/core/quic_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" | 
|  | #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" | 
|  | #include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.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_connection_helper.h" | 
|  | #include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" | 
|  | #include "net/third_party/quiche/src/quic/quartc/quartc_session.h" | 
|  |  | 
|  | namespace quic { | 
|  |  | 
|  | std::unique_ptr<QuartcSession> CreateQuartcClientSession( | 
|  | const QuartcSessionConfig& quartc_session_config, | 
|  | const QuicClock* clock, | 
|  | QuicAlarmFactory* alarm_factory, | 
|  | QuicConnectionHelperInterface* connection_helper, | 
|  | const ParsedQuicVersionVector& supported_versions, | 
|  | QuicStringPiece server_crypto_config, | 
|  | QuartcPacketTransport* packet_transport) { | 
|  | DCHECK(packet_transport); | 
|  |  | 
|  | // QuartcSession will eventually own both |writer| and |quic_connection|. | 
|  | auto writer = std::make_unique<QuartcPacketWriter>( | 
|  | packet_transport, quartc_session_config.max_packet_size); | 
|  |  | 
|  | // While the QuicConfig is not directly used by the connection, creating it | 
|  | // also sets flag values which must be set before creating the connection. | 
|  | QuicConfig quic_config = CreateQuicConfig(quartc_session_config); | 
|  |  | 
|  | // |dummy_id| and |dummy_address| are used because Quartc network layer will | 
|  | // not use these two. | 
|  | QuicConnectionId dummy_id = QuicUtils::CreateZeroConnectionId( | 
|  | supported_versions[0].transport_version); | 
|  | QuicSocketAddress dummy_address(QuicIpAddress::Any4(), /*port=*/0); | 
|  | std::unique_ptr<QuicConnection> quic_connection = CreateQuicConnection( | 
|  | dummy_id, dummy_address, connection_helper, alarm_factory, writer.get(), | 
|  | Perspective::IS_CLIENT, supported_versions); | 
|  |  | 
|  | // Quartc sets its own ack delay; get that ack delay and copy it over | 
|  | // to the QuicConfig so that it can be properly advertised to the peer | 
|  | // via transport parameter negotiation. | 
|  | quic_config.SetMaxAckDelayToSendMs(quic_connection->received_packet_manager() | 
|  | .max_ack_delay() | 
|  | .ToMilliseconds()); | 
|  |  | 
|  | return std::make_unique<QuartcClientSession>( | 
|  | std::move(quic_connection), quic_config, supported_versions, clock, | 
|  | std::move(writer), | 
|  | CreateCryptoClientConfig(quartc_session_config.pre_shared_key), | 
|  | server_crypto_config); | 
|  | } | 
|  |  | 
|  | void ConfigureGlobalQuicSettings() { | 
|  | // Fixes behavior of StopReading() with level-triggered stream sequencers. | 
|  | SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); | 
|  |  | 
|  | // Enable version 47 to enable variable-length connection ids. | 
|  | SetQuicReloadableFlag(quic_enable_version_47, true); | 
|  |  | 
|  | // Enable version 48 to be compatible with the latest version of Chrome. | 
|  | SetQuicReloadableFlag(quic_enable_version_48_2, 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()); | 
|  |  | 
|  | // Enable and request QUIC to include receive timestamps in ACK frames. | 
|  | SetQuicReloadableFlag(quic_send_timestamps, true); | 
|  |  | 
|  | // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be | 
|  | // false. | 
|  | SetQuicReloadableFlag(quic_enable_ack_decimation, false); | 
|  |  | 
|  | // 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_flexible_app_limited, true);  // Enable BBR9. | 
|  | } | 
|  |  | 
|  | QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { | 
|  | // TODO(b/124398962): Figure out a better way to initialize QUIC flags. | 
|  | // Creating a config shouldn't have global side-effects on flags.  However, | 
|  | // this has the advantage of ensuring that flag values stay in sync with the | 
|  | // options requested by configs, so simply splitting the config and flag | 
|  | // settings doesn't seem preferable. | 
|  | ConfigureGlobalQuicSettings(); | 
|  |  | 
|  | // In exoblaze this may return false. DCHECK to avoid problems caused by | 
|  | // incorrect flags configuration. | 
|  | DCHECK(GetQuicReloadableFlag(quic_enable_version_47)) | 
|  | << "Your build does not support quic reloadable flags and shouldn't " | 
|  | "place Quartc calls"; | 
|  |  | 
|  | QuicTagVector copt; | 
|  | copt.push_back(kNSTP); | 
|  |  | 
|  | // Enable and request QUIC to include receive timestamps in ACK frames. | 
|  | copt.push_back(kSTMP); | 
|  |  | 
|  | // Enable ACK_DECIMATION_WITH_REORDERING. It requires ack_decimation to be | 
|  | // 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); | 
|  |  | 
|  | 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(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); | 
|  | } | 
|  |  | 
|  | // 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.SetMaxIncomingBidirectionalStreamsToSend(1000); | 
|  |  | 
|  | return quic_config; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicConnection> CreateQuicConnection( | 
|  | QuicConnectionId connection_id, | 
|  | const QuicSocketAddress& peer_address, | 
|  | QuicConnectionHelperInterface* connection_helper, | 
|  | QuicAlarmFactory* alarm_factory, | 
|  | QuicPacketWriter* packet_writer, | 
|  | Perspective perspective, | 
|  | ParsedQuicVersionVector supported_versions) { | 
|  | auto quic_connection = std::make_unique<QuicConnection>( | 
|  | connection_id, peer_address, connection_helper, alarm_factory, | 
|  | packet_writer, | 
|  | /*owns_writer=*/false, perspective, supported_versions); | 
|  | quic_connection->SetMaxPacketLength( | 
|  | packet_writer->GetMaxPacketSize(peer_address)); | 
|  |  | 
|  | QuicSentPacketManager& sent_packet_manager = | 
|  | quic_connection->sent_packet_manager(); | 
|  | UberReceivedPacketManager& received_packet_manager = | 
|  | quic_connection->received_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. | 
|  | received_packet_manager.set_max_ack_delay( | 
|  | QuicTime::Delta::FromMilliseconds(100)); | 
|  | sent_packet_manager.set_peer_max_ack_delay( | 
|  | QuicTime::Delta::FromMilliseconds(100)); | 
|  |  | 
|  | 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); | 
|  |  | 
|  | return quic_connection; | 
|  | } | 
|  |  | 
|  | }  // namespace quic |