Add ability to set a non-zero send alarm delay for QUIC connection. Default remains set to a Zero delay. No functional change. PiperOrigin-RevId: 527641180
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index 274a52a..dd35b76 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -2451,7 +2451,9 @@ // Now that we have received an ack, we might be able to send packets which // are queued locally, or drain streams which are blocked. if (defer_send_in_response_to_packets_) { - send_alarm_->Update(clock_->ApproximateNow(), QuicTime::Delta::Zero()); + send_alarm_->Update(clock_->ApproximateNow() + + sent_packet_manager_.GetDeferredSendAlarmDelay(), + QuicTime::Delta::Zero()); } else { WriteIfNotBlocked(); }
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index e36c817..9858f0b 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc
@@ -4666,6 +4666,39 @@ EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); } +TEST_P(QuicConnectionTest, SendAlarmNonZeroDelay) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + // Set a 10 ms send alarm delay. The send alarm after processing the packet + // should fire after waiting 10ms, not immediately. + connection_.set_defer_send_in_response_to_packets(true); + connection_.sent_packet_manager().SetDeferredSendAlarmDelay( + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); + + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + // Process packet number 1. Can not call ProcessPacket or ProcessDataPacket + // here, because they will fire the alarm after QuicConnection::ProcessPacket + // is returned. + const uint64_t received_packet_num = 1; + const bool has_stop_waiting = false; + const EncryptionLevel level = ENCRYPTION_FORWARD_SECURE; + std::unique_ptr<QuicPacket> packet( + ConstructDataPacket(received_packet_num, has_stop_waiting, level)); + char buffer[kMaxOutgoingPacketSize]; + size_t encrypted_length = + peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num), + *packet, buffer, kMaxOutgoingPacketSize); + connection_.ProcessUdpPacket( + kSelfAddress, kPeerAddress, + QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false)); + + EXPECT_TRUE(connection_.GetSendAlarm()->IsSet()); + // It was set to be 10 ms in the future, so it should at the least be greater + // than now + 5 ms. + EXPECT_TRUE(connection_.GetSendAlarm()->deadline() > + clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5)); +} + TEST_P(QuicConnectionTest, AddToWriteBlockedListIfWriterBlockedWhenProcessing) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr);
diff --git a/quiche/quic/core/quic_sent_packet_manager.h b/quiche/quic/core/quic_sent_packet_manager.h index a0e5c6a..d90fda0 100644 --- a/quiche/quic/core/quic_sent_packet_manager.h +++ b/quiche/quic/core/quic_sent_packet_manager.h
@@ -152,6 +152,18 @@ pacing_sender_.set_max_pacing_rate(max_pacing_rate); } + // The delay to use for the send alarm. If zero, it essentially means + // to queue the send call immediately. + // WARNING: This is currently an experimental API. + // TODO(genioshelo): This should implement a dynamic delay based on the + // underlying connection properties and lumpy pacing. + QuicTime::Delta GetDeferredSendAlarmDelay() const { + return deferred_send_alarm_delay_.value_or(QuicTime::Delta::Zero()); + } + void SetDeferredSendAlarmDelay(QuicTime::Delta delay) { + deferred_send_alarm_delay_ = delay; + } + QuicBandwidth MaxPacingRate() const { return pacing_sender_.max_pacing_rate(); } @@ -703,6 +715,8 @@ // Most recent ECN codepoint counts received in an ACK frame sent by the peer. QuicEcnCounts peer_ack_ecn_counts_[NUM_PACKET_NUMBER_SPACES]; + + absl::optional<QuicTime::Delta> deferred_send_alarm_delay_; }; } // namespace quic