Send bandwidth estimate when the server network idles for half of idle_network_timeout for IETF QUIC guarded by connection option BWID.
Guarded with the same flag and connection option:
1. No longer sending bandwidth estimates when only bandwidth resumption is enabled.
2. When sending the bandwidth after idle long enough, the bandwidth from SendAlgorithm is used.
3. When the NEW_TOKEN frame is sent after the handshake, bandwidth from the previous session is sent along if there is no better measurement.
Protected by FLAGS_quic_reloadable_flag_quic_enable_sending_bandwidth_estimate_when_network_idle.
PiperOrigin-RevId: 443223110
diff --git a/quiche/quic/core/crypto/crypto_protocol.h b/quiche/quic/core/crypto/crypto_protocol.h
index 907857b..aef3ff1 100644
--- a/quiche/quic/core/crypto/crypto_protocol.h
+++ b/quiche/quic/core/crypto/crypto_protocol.h
@@ -300,6 +300,7 @@
// Enable bandwidth resumption experiment.
const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption.
const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption.
+const QuicTag kBWID = TAG('B', 'W', 'I', 'D'); // Send bandwidth when idle.
const QuicTag kBWRS = TAG('B', 'W', 'R', 'S'); // Server bandwidth resumption.
const QuicTag kBWS2 = TAG('B', 'W', 'S', '2'); // Server bw resumption v2.
const QuicTag kBWS3 = TAG('B', 'W', 'S', '3'); // QUIC Initial CWND - Control.
diff --git a/quiche/quic/core/http/quic_server_session_base.cc b/quiche/quic/core/http/quic_server_session_base.cc
index fd38825..ade86ae 100644
--- a/quiche/quic/core/http/quic_server_session_base.cc
+++ b/quiche/quic/core/http/quic_server_session_base.cc
@@ -10,12 +10,14 @@
#include "quiche/quic/core/quic_connection.h"
#include "quiche/quic/core/quic_stream.h"
#include "quiche/quic/core/quic_tag.h"
+#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_utils.h"
#include "quiche/quic/platform/api/quic_bug_tracker.h"
#include "quiche/quic/platform/api/quic_flag_utils.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_logging.h"
+#include "quiche/common/platform/api/quiche_logging.h"
namespace quic {
@@ -96,6 +98,12 @@
<< "Failed to disable resumption";
}
+ enable_sending_bandwidth_estimate_when_network_idle_ =
+ GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle) &&
+ version().HasIetfQuicFrames() &&
+ ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWID);
+
// Enable bandwidth resumption if peer sent correct connection options.
const bool last_bandwidth_resumption =
ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
@@ -138,7 +146,31 @@
}
}
+void QuicServerSessionBase::OnBandwidthUpdateTimeout() {
+ if (!enable_sending_bandwidth_estimate_when_network_idle_) {
+ return;
+ }
+ QUIC_DVLOG(1) << "Bandwidth update timed out.";
+ const SendAlgorithmInterface* send_algorithm =
+ connection()->sent_packet_manager().GetSendAlgorithm();
+ if (send_algorithm != nullptr &&
+ send_algorithm->HasGoodBandwidthEstimateForResumption()) {
+ const bool success = MaybeSendAddressToken();
+ QUIC_BUG_IF(QUIC_BUG_25522, !success) << "Failed to send address token.";
+ QUIC_RESTART_FLAG_COUNT_N(
+ quic_enable_sending_bandwidth_estimate_when_network_idle, 2, 3);
+ }
+}
+
void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
+ // Sending bandwidth is no longer conditioned on if session does bandwidth
+ // resumption.
+ if (GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle)) {
+ QUIC_RESTART_FLAG_COUNT_N(
+ quic_enable_sending_bandwidth_estimate_when_network_idle, 3, 3);
+ return;
+ }
if (!bandwidth_resumption_enabled_) {
return;
}
@@ -345,30 +377,55 @@
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;
+ if (enable_sending_bandwidth_estimate_when_network_idle_) {
+ const SendAlgorithmInterface* send_algorithm =
+ sent_packet_manager.GetSendAlgorithm();
+ if (send_algorithm != nullptr &&
+ send_algorithm->HasGoodBandwidthEstimateForResumption()) {
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ BandwidthToCachedParameterBytesPerSecond(
+ send_algorithm->BandwidthEstimate()));
+ QUIC_CODE_COUNT(quic_send_measured_bandwidth_in_token);
+ } else {
+ const quic::CachedNetworkParameters* previous_cached_network_params =
+ crypto_stream()->PreviousCachedNetworkParams();
+ if (previous_cached_network_params != nullptr &&
+ previous_cached_network_params
+ ->bandwidth_estimate_bytes_per_second() > 0) {
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ previous_cached_network_params
+ ->bandwidth_estimate_bytes_per_second());
+ QUIC_CODE_COUNT(quic_send_previous_bandwidth_in_token);
+ } else {
+ QUIC_CODE_COUNT(quic_not_send_bandwidth_in_token);
+ }
+ }
+ } else {
+ // 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_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);
+ cached_network_params.set_previous_connection_state(
+ bandwidth_recorder->EstimateRecordedDuringSlowStart()
+ ? CachedNetworkParameters::SLOW_START
+ : CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ }
}
if (!serving_region_.empty()) {
diff --git a/quiche/quic/core/http/quic_server_session_base.h b/quiche/quic/core/http/quic_server_session_base.h
index d30b9dd..7fbbf8b 100644
--- a/quiche/quic/core/http/quic_server_session_base.h
+++ b/quiche/quic/core/http/quic_server_session_base.h
@@ -48,6 +48,9 @@
void OnConnectionClosed(const QuicConnectionCloseFrame& frame,
ConnectionCloseSource source) override;
+ // Override to send bandwidth estimate.
+ void OnBandwidthUpdateTimeout() override;
+
// Sends a server config update to the client, containing new bandwidth
// estimate.
void OnCongestionWindowChange(QuicTime now) override;
@@ -129,8 +132,9 @@
// The most recent bandwidth estimate sent to the client.
QuicBandwidth bandwidth_estimate_sent_to_client_;
- // Text describing server location. Sent to the client as part of the bandwith
- // estimate in the source-address token. Optional, can be left empty.
+ // Text describing server location. Sent to the client as part of the
+ // bandwidth estimate in the source-address token. Optional, can be left
+ // empty.
std::string serving_region_;
// Time at which we send the last SCUP to the client.
@@ -144,6 +148,8 @@
// should go away once we fix http://b//27897982
int32_t BandwidthToCachedParameterBytesPerSecond(
const QuicBandwidth& bandwidth) const;
+
+ bool enable_sending_bandwidth_estimate_when_network_idle_ = false;
};
} // namespace quic
diff --git a/quiche/quic/core/http/quic_server_session_base_test.cc b/quiche/quic/core/http/quic_server_session_base_test.cc
index 56aa06a..df099a6 100644
--- a/quiche/quic/core/http/quic_server_session_base_test.cc
+++ b/quiche/quic/core/http/quic_server_session_base_test.cc
@@ -510,6 +510,7 @@
// Client has sent kBWRE connection option to trigger bandwidth resumption.
QuicTagVector copt;
copt.push_back(kBWRE);
+ copt.push_back(kBWID);
QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
session_->OnConfigNegotiated();
@@ -606,35 +607,40 @@
sent_packet_manager->OnPacketSent(&packet, now, NOT_RETRANSMISSION,
HAS_RETRANSMITTABLE_DATA, true);
- // Verify that the proto has exactly the values we expect.
- CachedNetworkParameters expected_network_params;
- expected_network_params.set_bandwidth_estimate_bytes_per_second(
- bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond());
- expected_network_params.set_max_bandwidth_estimate_bytes_per_second(
- bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond());
- expected_network_params.set_max_bandwidth_timestamp_seconds(
- bandwidth_recorder.MaxBandwidthTimestamp());
- expected_network_params.set_min_rtt_ms(session_->connection()
- ->sent_packet_manager()
- .GetRttStats()
- ->min_rtt()
- .ToMilliseconds());
- expected_network_params.set_previous_connection_state(
- CachedNetworkParameters::CONGESTION_AVOIDANCE);
- expected_network_params.set_timestamp(
- session_->connection()->clock()->WallNow().ToUNIXSeconds());
- expected_network_params.set_serving_region(serving_region);
-
- if (quic_crypto_stream) {
- EXPECT_CALL(*quic_crypto_stream,
- SendServerConfigUpdate(EqualsProto(expected_network_params)))
- .Times(1);
+ if (GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle)) {
+ EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(0);
} else {
- EXPECT_CALL(*tls_server_stream,
- GetAddressToken(EqualsProto(expected_network_params)))
- .WillOnce(testing::Return("Test address token"));
+ // Verify that the proto has exactly the values we expect.
+ CachedNetworkParameters expected_network_params;
+ expected_network_params.set_bandwidth_estimate_bytes_per_second(
+ bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond());
+ expected_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond());
+ expected_network_params.set_max_bandwidth_timestamp_seconds(
+ bandwidth_recorder.MaxBandwidthTimestamp());
+ expected_network_params.set_min_rtt_ms(session_->connection()
+ ->sent_packet_manager()
+ .GetRttStats()
+ ->min_rtt()
+ .ToMilliseconds());
+ expected_network_params.set_previous_connection_state(
+ CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ expected_network_params.set_timestamp(
+ session_->connection()->clock()->WallNow().ToUNIXSeconds());
+ expected_network_params.set_serving_region(serving_region);
+
+ if (quic_crypto_stream) {
+ EXPECT_CALL(*quic_crypto_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);
}
- EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1);
session_->OnCongestionWindowChange(now);
}
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 51dfd24..db2597b 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -6259,6 +6259,10 @@
idle_timeout_connection_close_behavior_);
}
+void QuicConnection::OnBandwidthUpdateTimeout() {
+ visitor_->OnBandwidthUpdateTimeout();
+}
+
void QuicConnection::OnKeepAliveTimeout() {
QUICHE_DCHECK(use_ping_manager_);
if (retransmission_alarm_->IsSet() ||
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 5a4e655..b73f5c4 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -239,6 +239,9 @@
// Whether the server address is known to the connection.
virtual bool IsKnownServerAddress(const QuicSocketAddress& address) const = 0;
+
+ // When bandwidth update alarms.
+ virtual void OnBandwidthUpdateTimeout() = 0;
};
// Interface which gets callbacks from the QuicConnection at interesting
@@ -711,6 +714,7 @@
// QuicIdleNetworkDetector::Delegate
void OnHandshakeTimeout() override;
void OnIdleNetworkDetected() override;
+ void OnBandwidthUpdateTimeout() override;
// QuicPingManager::Delegate
void OnKeepAliveTimeout() override;
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 34c7ba0..932addc 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -5860,6 +5860,7 @@
&config, connection_.connection_id());
}
connection_.SetFromConfig(config);
+ QuicConnectionPeer::DisableBandwidthUpdate(&connection_);
const QuicTime::Delta default_idle_timeout =
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
@@ -5935,6 +5936,7 @@
EXPECT_THAT(error, IsQuicNoError());
connection_.SetFromConfig(config);
+ QuicConnectionPeer::DisableBandwidthUpdate(&connection_);
const QuicTime::Delta default_idle_timeout =
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
@@ -5997,6 +5999,7 @@
&config, connection_.connection_id());
}
connection_.SetFromConfig(config);
+ QuicConnectionPeer::DisableBandwidthUpdate(&connection_);
const QuicTime::Delta default_idle_timeout =
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs - 1);
@@ -6092,6 +6095,7 @@
connection_.SetNetworkTimeouts(
QuicTime::Delta::Infinite(),
initial_idle_timeout + QuicTime::Delta::FromSeconds(1));
+ QuicConnectionPeer::DisableBandwidthUpdate(&connection_);
const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
@@ -11680,14 +11684,14 @@
ASSERT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
EXPECT_FALSE(connection_.MaybeTestLiveness());
- QuicTime deadline = connection_.GetTimeoutAlarm()->deadline();
+ QuicTime deadline = QuicConnectionPeer::GetIdleNetworkDeadline(&connection_);
QuicTime::Delta timeout = deadline - clock_.ApproximateNow();
// Advance time to near the idle timeout.
clock_.AdvanceTime(timeout - QuicTime::Delta::FromMilliseconds(1));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_TRUE(connection_.MaybeTestLiveness());
// Verify idle deadline does not change.
- EXPECT_EQ(deadline, connection_.GetTimeoutAlarm()->deadline());
+ EXPECT_EQ(deadline, QuicConnectionPeer::GetIdleNetworkDeadline(&connection_));
}
TEST_P(QuicConnectionTest, SilentIdleTimeout) {
@@ -11717,6 +11721,11 @@
EXPECT_CALL(visitor_,
OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ if (!QuicConnectionPeer::GetBandwidthUpdateTimeout(&connection_)
+ .IsInfinite()) {
+ // Fires the bandwidth update.
+ connection_.GetTimeoutAlarm()->Fire();
+ }
connection_.GetTimeoutAlarm()->Fire();
// Verify the connection close packets get serialized and added to
// termination packets list.
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 179eda3..4408626 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -83,6 +83,8 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_require_handshake_confirmation, false)
// If true, server proactively retires client issued connection ID on reverse path validation failure.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_retire_cid_on_reverse_path_validation_failure, true)
+// If true, server sends bandwidth eastimate when network is idle for a while.
+QUIC_FLAG(FLAGS_quic_restart_flag_quic_enable_sending_bandwidth_estimate_when_network_idle, false)
// If true, servers drop received packets with changed server address.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_drop_packets_with_changed_server_address, true)
// If true, set burst token to 2 in cwnd bootstrapping experiment.
diff --git a/quiche/quic/core/quic_idle_network_detector.cc b/quiche/quic/core/quic_idle_network_detector.cc
index edb5483..6371596 100644
--- a/quiche/quic/core/quic_idle_network_detector.cc
+++ b/quiche/quic/core/quic_idle_network_detector.cc
@@ -5,7 +5,10 @@
#include "quiche/quic/core/quic_idle_network_detector.h"
#include "quiche/quic/core/quic_constants.h"
+#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/platform/api/quic_flag_utils.h"
+#include "quiche/quic/platform/api/quic_flags.h"
+#include "quiche/common/platform/api/quiche_logging.h"
namespace quic {
@@ -36,10 +39,18 @@
time_of_last_received_packet_(now),
time_of_first_packet_sent_after_receiving_(QuicTime::Zero()),
idle_network_timeout_(QuicTime::Delta::Infinite()),
+ bandwidth_update_timeout_(QuicTime::Delta::Infinite()),
alarm_(alarm_factory->CreateAlarm(
arena->New<AlarmDelegate>(this, context), arena)) {}
void QuicIdleNetworkDetector::OnAlarm() {
+ if (!bandwidth_update_timeout_.IsInfinite()) {
+ QUICHE_DCHECK(handshake_timeout_.IsInfinite());
+ bandwidth_update_timeout_ = QuicTime::Delta::Infinite();
+ SetAlarm();
+ delegate_->OnBandwidthUpdateTimeout();
+ return;
+ }
if (handshake_timeout_.IsInfinite()) {
delegate_->OnIdleNetworkDetected();
return;
@@ -61,6 +72,14 @@
handshake_timeout_ = handshake_timeout;
idle_network_timeout_ = idle_network_timeout;
+ if (GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle) &&
+ handshake_timeout_.IsInfinite()) {
+ QUIC_RESTART_FLAG_COUNT_N(
+ quic_enable_sending_bandwidth_estimate_when_network_idle, 1, 3);
+ bandwidth_update_timeout_ = idle_network_timeout_ * 0.5;
+ }
+
SetAlarm();
}
@@ -68,6 +87,7 @@
alarm_->PermanentCancel();
handshake_timeout_ = QuicTime::Delta::Infinite();
idle_network_timeout_ = QuicTime::Delta::Infinite();
+ handshake_timeout_ = QuicTime::Delta::Infinite();
stopped_ = true;
}
@@ -115,6 +135,9 @@
new_deadline = idle_network_deadline;
}
}
+ if (!bandwidth_update_timeout_.IsInfinite()) {
+ new_deadline = std::min(new_deadline, GetBandwidthUpdateDeadline());
+ }
alarm_->Update(new_deadline, kAlarmGranularity);
}
@@ -141,4 +164,9 @@
return last_network_activity_time() + idle_network_timeout_;
}
+QuicTime QuicIdleNetworkDetector::GetBandwidthUpdateDeadline() const {
+ QUICHE_DCHECK(!bandwidth_update_timeout_.IsInfinite());
+ return last_network_activity_time() + bandwidth_update_timeout_;
+}
+
} // namespace quic
diff --git a/quiche/quic/core/quic_idle_network_detector.h b/quiche/quic/core/quic_idle_network_detector.h
index 0b5a20e..ca43148 100644
--- a/quiche/quic/core/quic_idle_network_detector.h
+++ b/quiche/quic/core/quic_idle_network_detector.h
@@ -34,6 +34,9 @@
// Called when idle network has been detected.
virtual void OnIdleNetworkDetected() = 0;
+
+ // Called when bandwidth update alarms.
+ virtual void OnBandwidthUpdateTimeout() = 0;
};
QuicIdleNetworkDetector(Delegate* delegate, QuicTime now,
@@ -73,6 +76,10 @@
QuicTime::Delta idle_network_timeout() const { return idle_network_timeout_; }
+ QuicTime::Delta bandwidth_update_timeout() const {
+ return bandwidth_update_timeout_;
+ }
+
QuicTime GetIdleNetworkDeadline() const;
private:
@@ -83,13 +90,15 @@
void MaybeSetAlarmOnSentPacket(QuicTime::Delta pto_delay);
+ QuicTime GetBandwidthUpdateDeadline() const;
+
Delegate* delegate_; // Not owned.
// Start time of the detector, handshake deadline = start_time_ +
// handshake_timeout_.
const QuicTime start_time_;
- // Handshake timeout. Infinit means handshake has completed.
+ // Handshake timeout. Infinite means handshake has completed.
QuicTime::Delta handshake_timeout_;
// Time that last packet is received for this connection. Initialized to
@@ -102,9 +111,12 @@
// Initialized to 0.
QuicTime time_of_first_packet_sent_after_receiving_;
- // Idle network timeout. Infinit means no idle network timeout.
+ // Idle network timeout. Infinite means no idle network timeout.
QuicTime::Delta idle_network_timeout_;
+ // Bandwidth update timeout. Infinite means no bandwidth update timeout.
+ QuicTime::Delta bandwidth_update_timeout_;
+
QuicArenaScopedPtr<QuicAlarm> alarm_;
bool shorter_idle_timeout_on_sent_packet_ = false;
diff --git a/quiche/quic/core/quic_idle_network_detector_test.cc b/quiche/quic/core/quic_idle_network_detector_test.cc
index 31aa8b4..b838cbd 100644
--- a/quiche/quic/core/quic_idle_network_detector_test.cc
+++ b/quiche/quic/core/quic_idle_network_detector_test.cc
@@ -5,7 +5,9 @@
#include "quiche/quic/core/quic_idle_network_detector.h"
#include "quiche/quic/core/quic_one_block_arena.h"
+#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/platform/api/quic_expect_bug.h"
+#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/quic/test_tools/quic_test_utils.h"
@@ -25,6 +27,7 @@
public:
MOCK_METHOD(void, OnHandshakeTimeout, (), (override));
MOCK_METHOD(void, OnIdleNetworkDetected, (), (override));
+ MOCK_METHOD(void, OnBandwidthUpdateTimeout, (), (override));
};
class QuicIdleNetworkDetectorTest : public QuicTest {
@@ -90,6 +93,8 @@
/*handshake_timeout=*/QuicTime::Delta::FromSeconds(30),
/*idle_network_timeout=*/QuicTime::Delta::FromSeconds(20));
EXPECT_TRUE(alarm_->IsSet());
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(20),
+ alarm_->deadline());
// Handshake completes in 200ms.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(200));
@@ -97,11 +102,30 @@
detector_->SetTimeouts(
/*handshake_timeout=*/QuicTime::Delta::Infinite(),
/*idle_network_timeout=*/QuicTime::Delta::FromSeconds(600));
- EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(600),
+ if (!GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle)) {
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(600),
+ alarm_->deadline());
+
+ // No network activity for 600s.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(600));
+ EXPECT_CALL(delegate_, OnIdleNetworkDetected());
+ alarm_->Fire();
+ return;
+ }
+
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(300),
+ alarm_->deadline());
+
+ // No network activity for 300s.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(300));
+ EXPECT_CALL(delegate_, OnBandwidthUpdateTimeout());
+ alarm_->Fire();
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(300),
alarm_->deadline());
// No network activity for 600s.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(600));
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(300));
EXPECT_CALL(delegate_, OnIdleNetworkDetected());
alarm_->Fire();
}
@@ -115,11 +139,16 @@
EXPECT_TRUE(alarm_->IsSet());
// Handshake completes in 200ms.
+ const bool enable_sending_bandwidth_estimate_when_network_idle =
+ GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle);
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(200));
detector_->OnPacketReceived(clock_.Now());
detector_->SetTimeouts(
/*handshake_timeout=*/QuicTime::Delta::Infinite(),
- /*idle_network_timeout=*/QuicTime::Delta::FromSeconds(600));
+ enable_sending_bandwidth_estimate_when_network_idle
+ ? QuicTime::Delta::FromSeconds(1200)
+ : QuicTime::Delta::FromSeconds(600));
EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(600),
alarm_->deadline());
@@ -133,22 +162,46 @@
// Sent another packet after 200ms
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(200));
detector_->OnPacketSent(clock_.Now(), QuicTime::Delta::Zero());
- // Verify idle network deadline does not extend.
+ // Verify network deadline does not extend.
EXPECT_EQ(packet_sent_time + QuicTime::Delta::FromSeconds(600),
alarm_->deadline());
- // No network activity for 600s.
+ if (!enable_sending_bandwidth_estimate_when_network_idle) {
+ // No network activity for 600s.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(600) -
+ QuicTime::Delta::FromMilliseconds(200));
+ EXPECT_CALL(delegate_, OnIdleNetworkDetected());
+ alarm_->Fire();
+ return;
+ }
+
+ // Bandwidth update times out after no network activity for 600s.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(600) -
QuicTime::Delta::FromMilliseconds(200));
+ EXPECT_CALL(delegate_, OnBandwidthUpdateTimeout());
+ alarm_->Fire();
+ EXPECT_TRUE(alarm_->IsSet());
+ EXPECT_EQ(packet_sent_time + QuicTime::Delta::FromSeconds(1200),
+ alarm_->deadline());
+
+ // Network idle time out after no network activity for 1200s.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1200) -
+ QuicTime::Delta::FromMilliseconds(600));
EXPECT_CALL(delegate_, OnIdleNetworkDetected());
alarm_->Fire();
}
TEST_F(QuicIdleNetworkDetectorTest, ShorterIdleTimeoutOnSentPacket) {
detector_->enable_shorter_idle_timeout_on_sent_packet();
+ QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
+ if (GetQuicRestartFlag(
+ quic_enable_sending_bandwidth_estimate_when_network_idle)) {
+ idle_network_timeout = QuicTime::Delta::FromSeconds(60);
+ } else {
+ idle_network_timeout = QuicTime::Delta::FromSeconds(30);
+ }
detector_->SetTimeouts(
- /*handshake_timeout=*/QuicTime::Delta::Infinite(),
- /*idle_network_timeout=*/QuicTime::Delta::FromSeconds(30));
+ /*handshake_timeout=*/QuicTime::Delta::Infinite(), idle_network_timeout);
EXPECT_TRUE(alarm_->IsSet());
const QuicTime deadline = alarm_->deadline();
EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(30), deadline);
@@ -175,7 +228,7 @@
EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromSeconds(30),
alarm_->deadline());
- // Send a packet near timeout..
+ // Send a packet near timeout.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(29));
detector_->OnPacketSent(clock_.Now(), QuicTime::Delta::FromSeconds(2));
EXPECT_TRUE(alarm_->IsSet());
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index 3051cf6..f43ef95 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -173,6 +173,7 @@
const QuicSocketAddress& /*address*/) const override {
return false;
}
+ void OnBandwidthUpdateTimeout() override {}
// QuicStreamFrameDataProducer
WriteStreamDataResult WriteStreamData(QuicStreamId id,
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc
index 9eaa6fb..c00d12f 100644
--- a/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -60,6 +60,23 @@
}
// static
+QuicTime::Delta QuicConnectionPeer::GetBandwidthUpdateTimeout(
+ QuicConnection* connection) {
+ return connection->idle_network_detector_.bandwidth_update_timeout_;
+}
+
+// static
+void QuicConnectionPeer::DisableBandwidthUpdate(QuicConnection* connection) {
+ if (connection->idle_network_detector_.bandwidth_update_timeout_
+ .IsInfinite()) {
+ return;
+ }
+ connection->idle_network_detector_.bandwidth_update_timeout_ =
+ QuicTime::Delta::Infinite();
+ connection->idle_network_detector_.SetAlarm();
+}
+
+// static
void QuicConnectionPeer::SetPerspective(QuicConnection* connection,
Perspective perspective) {
connection->perspective_ = perspective;
diff --git a/quiche/quic/test_tools/quic_connection_peer.h b/quiche/quic/test_tools/quic_connection_peer.h
index ffe3b3c..1b85081 100644
--- a/quiche/quic/test_tools/quic_connection_peer.h
+++ b/quiche/quic/test_tools/quic_connection_peer.h
@@ -53,6 +53,10 @@
static QuicTime::Delta GetHandshakeTimeout(QuicConnection* connection);
+ static QuicTime::Delta GetBandwidthUpdateTimeout(QuicConnection* connection);
+
+ static void DisableBandwidthUpdate(QuicConnection* connection);
+
static void SetPerspective(QuicConnection* connection,
Perspective perspective);
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index 84aebc1..b7bda22 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -504,6 +504,8 @@
const QuicSocketAddress& /*address*/) const override {
return false;
}
+
+ void OnBandwidthUpdateTimeout() override {}
};
class MockQuicConnectionHelper : public QuicConnectionHelperInterface {
diff --git a/quiche/quic/test_tools/simulator/quic_endpoint.h b/quiche/quic/test_tools/simulator/quic_endpoint.h
index e1a8c3e..853944a 100644
--- a/quiche/quic/test_tools/simulator/quic_endpoint.h
+++ b/quiche/quic/test_tools/simulator/quic_endpoint.h
@@ -108,6 +108,7 @@
const QuicSocketAddress& /*address*/) const override {
return false;
}
+ void OnBandwidthUpdateTimeout() override {}
// End QuicConnectionVisitorInterface implementation.