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