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