blob: 413c4f83f745816826c8bfc19750cf797f4acdd8 [file] [log] [blame]
// 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 <utility>
#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_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