Add CachedNetworkParameters to address token for IETF QUIC, and
- min_rtt received from a validated token will be used to set the initial rtt, if connection option 'TRTT' is set.
- Enable bandwidth resumption for IETF QUIC when connection options BWRE or BWMX exists.
Protected by FLAGS_quic_reloadable_flag_quic_add_cached_network_parameters_to_address_token.
PiperOrigin-RevId: 407578759
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index b2776be..c4ea956 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -381,6 +381,9 @@
const QuicTag kADE = TAG('A', 'D', 'E', 0); // Ack Delay Exponent (IETF
// QUIC ACK Frame Only).
const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us.
+const QuicTag kTRTT = TAG('T', 'R', 'T', 'T'); // If server receives an rtt
+ // from an address token, set
+ // it as the initial rtt.
const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name
// indication
const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 5f8675d..eae2996 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -1632,6 +1632,7 @@
}
TEST_P(EndToEndTest, AddressToken) {
+ client_extra_copts_.push_back(kTRTT);
ASSERT_TRUE(Initialize());
if (!version_.HasIetfQuicFrames()) {
return;
@@ -1659,13 +1660,41 @@
EXPECT_TRUE(client_->client()->EarlyDataAccepted());
server_thread_->Pause();
+ QuicSpdySession* server_session = GetServerSession();
QuicConnection* server_connection = GetServerConnection();
- if (server_connection != nullptr) {
+ if (server_session != nullptr && server_connection != nullptr) {
// Verify address is validated via validating token received in INITIAL
// packet.
EXPECT_FALSE(
server_connection->GetStats().address_validated_via_decrypting_packet);
EXPECT_TRUE(server_connection->GetStats().address_validated_via_token);
+
+ // Verify the server received a cached min_rtt from the token and used it as
+ // the initial rtt.
+ const CachedNetworkParameters* server_received_network_params =
+ static_cast<const QuicCryptoServerStreamBase*>(
+ server_session->GetCryptoStream())
+ ->PreviousCachedNetworkParams();
+ if (GetQuicReloadableFlag(
+ quic_add_cached_network_parameters_to_address_token)) {
+ ASSERT_NE(server_received_network_params, nullptr);
+ // QuicSentPacketManager::SetInitialRtt clamps the initial_rtt to between
+ // [min_initial_rtt, max_initial_rtt].
+ const QuicTime::Delta min_initial_rtt =
+ QuicTime::Delta::FromMicroseconds(kMinInitialRoundTripTimeUs);
+ const QuicTime::Delta max_initial_rtt =
+ QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs);
+ const QuicTime::Delta expected_initial_rtt =
+ std::max(min_initial_rtt,
+ std::min(max_initial_rtt,
+ QuicTime::Delta::FromMilliseconds(
+ server_received_network_params->min_rtt_ms())));
+ EXPECT_EQ(
+ server_connection->sent_packet_manager().GetRttStats()->initial_rtt(),
+ expected_initial_rtt);
+ } else {
+ EXPECT_EQ(server_received_network_params, nullptr);
+ }
} else {
ADD_FAILURE() << "Missing server connection";
}
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc
index 86ccafb..8edcb69 100644
--- a/quic/core/http/quic_server_session_base.cc
+++ b/quic/core/http/quic_server_session_base.cc
@@ -10,6 +10,7 @@
#include "quic/core/quic_connection.h"
#include "quic/core/quic_stream.h"
#include "quic/core/quic_tag.h"
+#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flag_utils.h"
@@ -50,6 +51,30 @@
return;
}
+ const CachedNetworkParameters* cached_network_params =
+ crypto_stream_->PreviousCachedNetworkParams();
+
+ // Set the initial rtt from cached_network_params.min_rtt_ms, which comes from
+ // a validated address token. This will override the initial rtt that may have
+ // been set by the transport parameters.
+ if (add_cached_network_parameters_to_address_token() && version().UsesTls() &&
+ cached_network_params != nullptr) {
+ if (cached_network_params->serving_region() == serving_region_) {
+ QUIC_CODE_COUNT(quic_server_received_network_params_at_same_region);
+ if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kTRTT)) {
+ QUIC_DLOG(INFO)
+ << "Server: Setting initial rtt to "
+ << cached_network_params->min_rtt_ms()
+ << "ms which is received from a validated address token";
+ connection()->sent_packet_manager().SetInitialRtt(
+ QuicTime::Delta::FromMilliseconds(
+ cached_network_params->min_rtt_ms()));
+ }
+ } else {
+ QUIC_CODE_COUNT(quic_server_received_network_params_at_different_region);
+ }
+ }
+
// Enable bandwidth resumption if peer sent correct connection options.
const bool last_bandwidth_resumption =
ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
@@ -61,13 +86,14 @@
// If the client has provided a bandwidth estimate from the same serving
// region as this server, then decide whether to use the data for bandwidth
// resumption.
- const CachedNetworkParameters* cached_network_params =
- crypto_stream_->PreviousCachedNetworkParams();
if (cached_network_params != nullptr &&
cached_network_params->serving_region() == serving_region_) {
- // Log the received connection parameters, regardless of how they
- // get used for bandwidth resumption.
- connection()->OnReceiveConnectionState(*cached_network_params);
+ if (!add_cached_network_parameters_to_address_token() ||
+ !version().UsesTls()) {
+ // Log the received connection parameters, regardless of how they
+ // get used for bandwidth resumption.
+ connection()->OnReceiveConnectionState(*cached_network_params);
+ }
if (bandwidth_resumption_enabled_) {
// Only do bandwidth resumption if estimate is recent enough.
@@ -150,49 +176,76 @@
return;
}
- bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
- QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
- << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
+ if (add_cached_network_parameters_to_address_token()) {
+ if (version().UsesTls()) {
+ if (version().HasIetfQuicFrames() && MaybeSendAddressToken()) {
+ bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
+ }
+ } else {
+ absl::optional<CachedNetworkParameters> cached_network_params =
+ GenerateCachedNetworkParameters();
- // Include max bandwidth in the update.
- QuicBandwidth max_bandwidth_estimate =
- bandwidth_recorder->MaxBandwidthEstimate();
- int32_t max_bandwidth_timestamp = bandwidth_recorder->MaxBandwidthTimestamp();
+ if (cached_network_params.has_value()) {
+ bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
+ QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
+ << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
- // Fill the proto before passing it to the crypto stream to send.
- const int32_t bw_estimate_bytes_per_second =
- BandwidthToCachedParameterBytesPerSecond(
- bandwidth_estimate_sent_to_client_);
- const int32_t max_bw_estimate_bytes_per_second =
- BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate);
- QUIC_BUG_IF(quic_bug_12513_1, max_bw_estimate_bytes_per_second < 0)
- << max_bw_estimate_bytes_per_second;
- QUIC_BUG_IF(quic_bug_10393_1, bw_estimate_bytes_per_second < 0)
- << bw_estimate_bytes_per_second;
+ QUICHE_DCHECK_EQ(
+ BandwidthToCachedParameterBytesPerSecond(
+ bandwidth_estimate_sent_to_client_),
+ cached_network_params->bandwidth_estimate_bytes_per_second());
- CachedNetworkParameters cached_network_params;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- bw_estimate_bytes_per_second);
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- max_bw_estimate_bytes_per_second);
- cached_network_params.set_max_bandwidth_timestamp_seconds(
- max_bandwidth_timestamp);
- cached_network_params.set_min_rtt_ms(
- sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
- cached_network_params.set_previous_connection_state(
- bandwidth_recorder->EstimateRecordedDuringSlowStart()
- ? CachedNetworkParameters::SLOW_START
- : CachedNetworkParameters::CONGESTION_AVOIDANCE);
- cached_network_params.set_timestamp(
- connection()->clock()->WallNow().ToUNIXSeconds());
- if (!serving_region_.empty()) {
- cached_network_params.set_serving_region(serving_region_);
+ crypto_stream_->SendServerConfigUpdate(&cached_network_params.value());
+
+ connection()->OnSendConnectionState(*cached_network_params);
+ }
+ }
+ } else {
+ bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
+ QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
+ << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
+
+ // Include max bandwidth in the update.
+ QuicBandwidth max_bandwidth_estimate =
+ bandwidth_recorder->MaxBandwidthEstimate();
+ int32_t max_bandwidth_timestamp =
+ bandwidth_recorder->MaxBandwidthTimestamp();
+
+ // Fill the proto before passing it to the crypto stream to send.
+ const int32_t bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(
+ bandwidth_estimate_sent_to_client_);
+ const int32_t max_bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate);
+ QUIC_BUG_IF(quic_bug_12513_1, max_bw_estimate_bytes_per_second < 0)
+ << max_bw_estimate_bytes_per_second;
+ QUIC_BUG_IF(quic_bug_10393_1, bw_estimate_bytes_per_second < 0)
+ << bw_estimate_bytes_per_second;
+
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ max_bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_timestamp_seconds(
+ max_bandwidth_timestamp);
+ cached_network_params.set_min_rtt_ms(
+ sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
+ cached_network_params.set_previous_connection_state(
+ bandwidth_recorder->EstimateRecordedDuringSlowStart()
+ ? CachedNetworkParameters::SLOW_START
+ : CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ cached_network_params.set_timestamp(
+ connection()->clock()->WallNow().ToUNIXSeconds());
+ if (!serving_region_.empty()) {
+ cached_network_params.set_serving_region(serving_region_);
+ }
+
+ crypto_stream_->SendServerConfigUpdate(&cached_network_params);
+
+ connection()->OnSendConnectionState(cached_network_params);
}
- crypto_stream_->SendServerConfigUpdate(&cached_network_params);
-
- connection()->OnSendConnectionState(cached_network_params);
-
last_scup_time_ = now;
last_scup_packet_number_ =
connection()->sent_packet_manager().GetLargestSentPacket();
@@ -262,7 +315,7 @@
}
int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
- const QuicBandwidth& bandwidth) {
+ const QuicBandwidth& bandwidth) const {
return static_cast<int32_t>(std::min<int64_t>(
bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max()));
}
@@ -303,4 +356,54 @@
return ssl_config;
}
+absl::optional<CachedNetworkParameters>
+QuicServerSessionBase::GenerateCachedNetworkParameters() const {
+ QUICHE_DCHECK(add_cached_network_parameters_to_address_token());
+ const QuicSentPacketManager& sent_packet_manager =
+ connection()->sent_packet_manager();
+ const QuicSustainedBandwidthRecorder* bandwidth_recorder =
+ sent_packet_manager.SustainedBandwidthRecorder();
+
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_timestamp(
+ connection()->clock()->WallNow().ToUNIXSeconds());
+
+ if (!sent_packet_manager.GetRttStats()->min_rtt().IsZero()) {
+ cached_network_params.set_min_rtt_ms(
+ sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
+ }
+
+ // Populate bandwidth estimates if any.
+ if (bandwidth_recorder != nullptr && bandwidth_recorder->HasEstimate()) {
+ const int32_t bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(
+ bandwidth_recorder->BandwidthEstimate());
+ const int32_t max_bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(
+ bandwidth_recorder->MaxBandwidthEstimate());
+ QUIC_BUG_IF(quic_bug_12513_1, max_bw_estimate_bytes_per_second < 0)
+ << max_bw_estimate_bytes_per_second;
+ QUIC_BUG_IF(quic_bug_10393_1, bw_estimate_bytes_per_second < 0)
+ << bw_estimate_bytes_per_second;
+
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ max_bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_timestamp_seconds(
+ bandwidth_recorder->MaxBandwidthTimestamp());
+
+ cached_network_params.set_previous_connection_state(
+ bandwidth_recorder->EstimateRecordedDuringSlowStart()
+ ? CachedNetworkParameters::SLOW_START
+ : CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ }
+
+ if (!serving_region_.empty()) {
+ cached_network_params.set_serving_region(serving_region_);
+ }
+
+ return cached_network_params;
+}
+
} // namespace quic
diff --git a/quic/core/http/quic_server_session_base.h b/quic/core/http/quic_server_session_base.h
index bd9f5e7..5903de6 100644
--- a/quic/core/http/quic_server_session_base.h
+++ b/quic/core/http/quic_server_session_base.h
@@ -76,6 +76,9 @@
const QuicCryptoServerStreamBase* GetCryptoStream() const override;
+ absl::optional<CachedNetworkParameters> GenerateCachedNetworkParameters()
+ const override;
+
// If an outgoing stream can be created, return true.
// Return false when connection is closed or forward secure encryption hasn't
// established yet or number of server initiated streams already reaches the
@@ -138,7 +141,7 @@
// stored in CachedNetworkParameters. TODO(jokulik): This function
// should go away once we fix http://b//27897982
int32_t BandwidthToCachedParameterBytesPerSecond(
- const QuicBandwidth& bandwidth);
+ const QuicBandwidth& bandwidth) const;
};
} // namespace quic
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index 279ff60..bde1384 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -503,13 +503,19 @@
MockTlsServerHandshaker& operator=(const MockTlsServerHandshaker&) = delete;
~MockTlsServerHandshaker() override {}
- MOCK_METHOD(void,
- SendServerConfigUpdate,
- (const CachedNetworkParameters*),
+ MOCK_METHOD(void, SendServerConfigUpdate, (const CachedNetworkParameters*),
(override));
+
+ MOCK_METHOD(std::string, GetAddressToken, (const CachedNetworkParameters*),
+ (const, override));
};
TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
+ if (version().UsesTls() && !version().HasIetfQuicFrames()) {
+ // Skip the Txxx versions.
+ return;
+ }
+
// Test that bandwidth estimate updates are sent to the client, only when
// bandwidth resumption is enabled, the bandwidth estimate has changed
// sufficiently, enough time has passed,
@@ -637,22 +643,30 @@
EXPECT_CALL(*quic_crypto_stream,
SendServerConfigUpdate(EqualsProto(expected_network_params)))
.Times(1);
- } else {
+ } else if (!GetQuicReloadableFlag(
+ quic_add_cached_network_parameters_to_address_token)) {
EXPECT_CALL(*tls_server_stream,
SendServerConfigUpdate(EqualsProto(expected_network_params)))
.Times(1);
+ } else {
+ EXPECT_CALL(*tls_server_stream,
+ GetAddressToken(EqualsProto(expected_network_params)))
+ .WillOnce(testing::Return("Test address token"));
}
EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1);
session_->OnCongestionWindowChange(now);
}
TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) {
- if (version().handshake_protocol == PROTOCOL_TLS1_3) {
- // This test relies on resumption, which is not currently supported by the
- // TLS handshake.
- // TODO(nharper): Add support for resumption to the TLS handshake.
- return;
+ if (version().UsesTls()) {
+ if (!version().HasIetfQuicFrames()) {
+ // Skip the Txxx versions.
+ return;
+ }
+ // Avoid a QUIC_BUG in QuicSession::OnConfigNegotiated.
+ connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
}
+
// Test that if a client provides a CachedNetworkParameters with the same
// serving region as the current server, and which was made within an hour of
// now, that this data is passed down to the send algorithm.
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index bf86955..964f6fb 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -173,7 +173,10 @@
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
void OnNewTokenReceived(absl::string_view /*token*/) override {}
- std::string GetAddressToken() const override { return ""; }
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_params*/) const override {
+ return "";
+ }
bool ValidateAddressToken(absl::string_view /*token*/) const override {
return true;
}
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc
index d75ea97..2732de2 100644
--- a/quic/core/http/quic_spdy_stream_test.cc
+++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -157,7 +157,11 @@
ConnectionCloseSource /*source*/) override {}
void OnHandshakeDoneReceived() override {}
void OnNewTokenReceived(absl::string_view /*token*/) override {}
- std::string GetAddressToken() const override { return ""; }
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_parameters*/)
+ const override {
+ return "";
+ }
bool ValidateAddressToken(absl::string_view /*token*/) const override {
return true;
}
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 1d9bf95..1ec7c7e 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -235,11 +235,11 @@
// Called by the server to validate |token| in received INITIAL packets.
// Consider the client address gets validated (and therefore remove
// amplification factor) once the |token| gets successfully validated.
- virtual bool ValidateToken(absl::string_view token) const = 0;
+ virtual bool ValidateToken(absl::string_view token) = 0;
// Called by the server to send another token.
// Return false if the crypto stream fail to generate one.
- virtual void MaybeSendAddressToken() = 0;
+ virtual bool MaybeSendAddressToken() = 0;
// Whether the server address is known to the connection.
virtual bool IsKnownServerAddress(const QuicSocketAddress& address) const = 0;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 1e3b70d..a6ed2a1 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2180,6 +2180,7 @@
EXPECT_CALL(visitor_, MaybeSendAddressToken()).WillOnce(Invoke([this]() {
connection_.SendControlFrame(
QuicFrame(new QuicNewTokenFrame(1, "new_token")));
+ return true;
}));
ProcessFramesPacketWithAddresses({QuicFrame(new QuicPathResponseFrame(
0, reverse_path_challenge_payload)),
diff --git a/quic/core/quic_crypto_client_stream.h b/quic/core/quic_crypto_client_stream.h
index 688d603..e37a570 100644
--- a/quic/core/quic_crypto_client_stream.h
+++ b/quic/core/quic_crypto_client_stream.h
@@ -75,7 +75,8 @@
return false;
}
- std::string GetAddressToken() const override {
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_params*/) const override {
QUICHE_DCHECK(false);
return "";
}
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc
index b598d3c..28bfe4a 100644
--- a/quic/core/quic_crypto_server_stream.cc
+++ b/quic/core/quic_crypto_server_stream.cc
@@ -353,7 +353,8 @@
QUICHE_DCHECK(false);
}
-std::string QuicCryptoServerStream::GetAddressToken() const {
+std::string QuicCryptoServerStream::GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_parameters*/) const {
QUICHE_DCHECK(false);
return "";
}
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 399eca3..cf4f6e0 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -48,7 +48,8 @@
ConnectionCloseSource /*source*/) override {}
void OnHandshakeDoneReceived() override;
void OnNewTokenReceived(absl::string_view token) override;
- std::string GetAddressToken() const override;
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_params*/) const override;
bool ValidateAddressToken(absl::string_view token) const override;
bool ShouldSendExpectCTHeader() const override;
bool DidCertMatchSni() const override;
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index 056186a..86b6913 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -13,6 +13,7 @@
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "quic/core/crypto/crypto_framer.h"
#include "quic/core/crypto/crypto_utils.h"
+#include "quic/core/proto/cached_network_parameters_proto.h"
#include "quic/core/quic_config.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream.h"
@@ -110,7 +111,8 @@
virtual void OnNewTokenReceived(absl::string_view token) = 0;
// Called to get an address token.
- virtual std::string GetAddressToken() const = 0;
+ virtual std::string GetAddressToken(
+ const CachedNetworkParameters* cached_network_params) const = 0;
// Called to validate |token|.
virtual bool ValidateAddressToken(absl::string_view token) const = 0;
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc
index fb1374f..1c18c7b 100644
--- a/quic/core/quic_crypto_stream_test.cc
+++ b/quic/core/quic_crypto_stream_test.cc
@@ -64,7 +64,11 @@
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
void OnNewTokenReceived(absl::string_view /*token*/) override {}
- std::string GetAddressToken() const override { return ""; }
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_parameters*/)
+ const override {
+ return "";
+ }
bool ValidateAddressToken(absl::string_view /*token*/) const override {
return true;
}
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 4fbb0ec..fb6032b 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -19,6 +19,8 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_no_probe_up_exit_if_no_queue, true)
// If true and connection option B201 is used, check if cwnd limited before aggregation epoch, instead of ack event, in PROBE_UP phase.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_check_cwnd_limited_before_aggregation_epoch, true)
+// If true, 1) NEW_TOKENs sent from a IETF QUIC session will include the cached network parameters proto, 2) A min_rtt received from a validated token will be used to set the initial rtt, 3) Enable bandwidth resumption for IETF QUIC when connection options BWRE or BWMX exists.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_add_cached_network_parameters_to_address_token, true)
// If true, QPACK decoder rejects CR, LF, and NULL in field (header) values, and causes the stream to be reset with H3_MESSAGE_ERROR.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reject_invalid_chars_in_field_value, true)
// If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index ccd1e56..e4a7036 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -471,6 +471,9 @@
num_ptos_for_path_degrading_ = num_ptos_for_path_degrading;
}
+ // Sets the initial RTT of the connection.
+ void SetInitialRtt(QuicTime::Delta rtt);
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
@@ -554,9 +557,6 @@
// this function.
void RecordOneSpuriousRetransmission(const QuicTransmissionInfo& info);
- // Sets the initial RTT of the connection.
- void SetInitialRtt(QuicTime::Delta rtt);
-
// Called when handshake is confirmed to remove the retransmittable frames
// from all packets of HANDSHAKE_DATA packet number space to ensure they don't
// get retransmitted and will eventually be removed from unacked packets map.
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index dc0e8f5..4664a44 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1677,12 +1677,18 @@
}
}
-void QuicSession::MaybeSendAddressToken() {
+bool QuicSession::MaybeSendAddressToken() {
QUICHE_DCHECK(perspective_ == Perspective::IS_SERVER &&
connection()->version().HasIetfQuicFrames());
- std::string address_token = GetCryptoStream()->GetAddressToken();
+ absl::optional<CachedNetworkParameters> cached_network_params;
+ if (add_cached_network_parameters_to_address_token()) {
+ cached_network_params = GenerateCachedNetworkParameters();
+ }
+ std::string address_token = GetCryptoStream()->GetAddressToken(
+ cached_network_params.has_value() ? &cached_network_params.value()
+ : nullptr);
if (address_token.empty()) {
- return;
+ return false;
}
const size_t buf_len = address_token.length() + 1;
auto buffer = std::make_unique<char[]>(buf_len);
@@ -1692,6 +1698,13 @@
writer.WriteBytes(address_token.data(), address_token.length());
control_frame_manager_.WriteOrBufferNewToken(
absl::string_view(buffer.get(), buf_len));
+ if (add_cached_network_parameters_to_address_token() &&
+ cached_network_params.has_value()) {
+ connection()->OnSendConnectionState(*cached_network_params);
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_add_cached_network_parameters_to_address_token, 1, 2);
+ }
+ return true;
}
void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) {
@@ -2638,7 +2651,7 @@
owns_writer);
}
-bool QuicSession::ValidateToken(absl::string_view token) const {
+bool QuicSession::ValidateToken(absl::string_view token) {
QUICHE_DCHECK_EQ(perspective_, Perspective::IS_SERVER);
if (GetQuicFlag(FLAGS_quic_reject_retry_token_in_initial_packet)) {
return false;
@@ -2647,8 +2660,19 @@
// Validate the prefix for token received in NEW_TOKEN frame.
return false;
}
- return GetCryptoStream()->ValidateAddressToken(
+ const bool valid = GetCryptoStream()->ValidateAddressToken(
absl::string_view(token.data() + 1, token.length() - 1));
+ if (add_cached_network_parameters_to_address_token() && valid) {
+ const CachedNetworkParameters* cached_network_params =
+ GetCryptoStream()->PreviousCachedNetworkParams();
+ if (cached_network_params != nullptr &&
+ cached_network_params->timestamp() > 0) {
+ connection()->OnReceiveConnectionState(*cached_network_params);
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_add_cached_network_parameters_to_address_token, 2, 2);
+ }
+ }
+ return valid;
}
#undef ENDPOINT // undef for jumbo builds
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 56ec3b2..cb06d87 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -24,6 +24,7 @@
#include "quic/core/frames/quic_window_update_frame.h"
#include "quic/core/handshaker_delegate_interface.h"
#include "quic/core/legacy_quic_stream_id_manager.h"
+#include "quic/core/proto/cached_network_parameters_proto.h"
#include "quic/core/quic_connection.h"
#include "quic/core/quic_control_frame_manager.h"
#include "quic/core/quic_crypto_stream.h"
@@ -171,8 +172,8 @@
override;
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override;
void BeforeConnectionCloseSent() override {}
- bool ValidateToken(absl::string_view token) const override;
- void MaybeSendAddressToken() override;
+ bool ValidateToken(absl::string_view token) override;
+ bool MaybeSendAddressToken() override;
bool IsKnownServerAddress(
const QuicSocketAddress& /*address*/) const override {
return false;
@@ -621,6 +622,11 @@
// Latched value of flag --quic_tls_server_support_client_cert.
bool support_client_cert() const { return support_client_cert_; }
+ // Get latched flag value.
+ bool add_cached_network_parameters_to_address_token() const {
+ return add_cached_network_parameters_to_address_token_;
+ }
+
// Try converting all pending streams to normal streams.
void ProcessAllPendingStreams();
@@ -793,6 +799,15 @@
return ietf_streamid_manager_;
}
+ // Only called at a server session. Generate a CachedNetworkParameters that
+ // can be sent to the client as part of the address token, based on the latest
+ // bandwidth/rtt information. If return absl::nullopt, address token will not
+ // contain the CachedNetworkParameters.
+ virtual absl::optional<CachedNetworkParameters>
+ GenerateCachedNetworkParameters() const {
+ return absl::nullopt;
+ }
+
private:
friend class test::QuicSessionPeer;
@@ -981,6 +996,10 @@
// creation of new outgoing bidirectional streams.
bool liveness_testing_in_progress_;
+ const bool add_cached_network_parameters_to_address_token_ =
+ GetQuicReloadableFlag(
+ quic_add_cached_network_parameters_to_address_token);
+
// Whether BoringSSL randomizes the order of TLS extensions.
bool permutes_tls_extensions_ = true;
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 81decdc..8d5e477 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -141,7 +141,11 @@
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
void OnNewTokenReceived(absl::string_view /*token*/) override {}
- std::string GetAddressToken() const override { return ""; }
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_parameters*/)
+ const override {
+ return "";
+ }
bool ValidateAddressToken(absl::string_view /*token*/) const override {
return true;
}
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index 637435c..49bd5a0 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -296,11 +296,14 @@
const CachedNetworkParameters*
TlsServerHandshaker::PreviousCachedNetworkParams() const {
- return nullptr;
+ return last_received_cached_network_params_.get();
}
void TlsServerHandshaker::SetPreviousCachedNetworkParams(
- CachedNetworkParameters /*cached_network_params*/) {}
+ CachedNetworkParameters cached_network_params) {
+ last_received_cached_network_params_ =
+ std::make_unique<CachedNetworkParameters>(cached_network_params);
+}
void TlsServerHandshaker::OnPacketDecrypted(EncryptionLevel level) {
if (level == ENCRYPTION_HANDSHAKE && state_ < HANDSHAKE_PROCESSED) {
@@ -318,14 +321,17 @@
QUICHE_DCHECK(false);
}
-std::string TlsServerHandshaker::GetAddressToken() const {
+std::string TlsServerHandshaker::GetAddressToken(
+ const CachedNetworkParameters* cached_network_params) const {
SourceAddressTokens empty_previous_tokens;
const QuicConnection* connection = session()->connection();
return crypto_config_->NewSourceAddressToken(
crypto_config_->source_address_token_boxer(), empty_previous_tokens,
connection->effective_peer_address().host(),
connection->random_generator(), connection->clock()->WallNow(),
- /*cached_network_params=*/nullptr);
+ session()->add_cached_network_parameters_to_address_token()
+ ? cached_network_params
+ : nullptr);
}
bool TlsServerHandshaker::ValidateAddressToken(absl::string_view token) const {
@@ -337,15 +343,21 @@
<< CryptoUtils::HandshakeFailureReasonToString(reason);
return false;
}
+ auto cached_network_params = std::make_unique<CachedNetworkParameters>();
reason = crypto_config_->ValidateSourceAddressTokens(
tokens, session()->connection()->effective_peer_address().host(),
session()->connection()->clock()->WallNow(),
- /*cached_network_params=*/nullptr);
+ session()->add_cached_network_parameters_to_address_token()
+ ? cached_network_params.get()
+ : nullptr);
if (reason != HANDSHAKE_OK) {
QUIC_DLOG(WARNING) << "Failed to validate source address token: "
<< CryptoUtils::HandshakeFailureReasonToString(reason);
return false;
}
+ if (session()->add_cached_network_parameters_to_address_token()) {
+ last_received_cached_network_params_ = std::move(cached_network_params);
+ }
return true;
}
diff --git a/quic/core/tls_server_handshaker.h b/quic/core/tls_server_handshaker.h
index 6a7f358..9a492c5 100644
--- a/quic/core/tls_server_handshaker.h
+++ b/quic/core/tls_server_handshaker.h
@@ -58,7 +58,8 @@
void OnConnectionClosed(QuicErrorCode error,
ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
- std::string GetAddressToken() const override;
+ std::string GetAddressToken(
+ const CachedNetworkParameters* cached_network_params) const override;
bool ValidateAddressToken(absl::string_view token) const override;
void OnNewTokenReceived(absl::string_view token) override;
bool ShouldSendExpectCTHeader() const override;
@@ -372,6 +373,9 @@
crypto_negotiated_params_;
TlsServerConnection tls_connection_;
const QuicCryptoServerConfig* crypto_config_; // Unowned.
+ // The last received CachedNetworkParameters from a validated address token.
+ mutable std::unique_ptr<CachedNetworkParameters>
+ last_received_cached_network_params_;
const bool restore_connection_context_in_callbacks_ =
GetQuicReloadableFlag(quic_tls_restore_connection_context_in_callbacks);
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 77b7cbb..b064a4a 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -500,8 +500,8 @@
MOCK_METHOD(std::unique_ptr<QuicEncrypter>, CreateCurrentOneRttEncrypter, (),
(override));
MOCK_METHOD(void, BeforeConnectionCloseSent, (), (override));
- MOCK_METHOD(bool, ValidateToken, (absl::string_view), (const, override));
- MOCK_METHOD(void, MaybeSendAddressToken, (), (override));
+ MOCK_METHOD(bool, ValidateToken, (absl::string_view), (override));
+ MOCK_METHOD(bool, MaybeSendAddressToken, (), (override));
bool IsKnownServerAddress(
const QuicSocketAddress& /*address*/) const override {
@@ -827,7 +827,11 @@
void OnHandshakePacketSent() override {}
void OnHandshakeDoneReceived() override {}
void OnNewTokenReceived(absl::string_view /*token*/) override {}
- std::string GetAddressToken() const override { return ""; }
+ std::string GetAddressToken(
+ const CachedNetworkParameters* /*cached_network_parameters*/)
+ const override {
+ return "";
+ }
bool ValidateAddressToken(absl::string_view /*token*/) const override {
return true;
}
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index 01d35d3..3e445dc 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -110,10 +110,8 @@
return nullptr;
}
void BeforeConnectionCloseSent() override {}
- bool ValidateToken(absl::string_view /*token*/) const override {
- return true;
- }
- void MaybeSendAddressToken() override {}
+ bool ValidateToken(absl::string_view /*token*/) override { return true; }
+ bool MaybeSendAddressToken() override { return false; }
bool IsKnownServerAddress(
const QuicSocketAddress& /*address*/) const override {
return false;