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.