gfe-relnote: In QUIC, add SetSoftMaxPacketLength to set a soft max packet length in creator. If a single frame is failed to be serialized, restore the actual max packet length. Not used yet. Not protected.

PiperOrigin-RevId: 278424350
Change-Id: Ie89ba741b6798dee0683b4678edc9242f37f7672
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index fa45cf9..9f7f160 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -124,6 +124,7 @@
       next_transmission_type_(NOT_RETRANSMISSION),
       flusher_attached_(false),
       fully_pad_crypto_handshake_packets_(true),
+      latched_hard_max_packet_length_(0),
       combine_generator_and_creator_(
           GetQuicReloadableFlag(quic_combine_generator_and_creator)),
       populate_nonretransmittable_frames_(
@@ -168,6 +169,25 @@
       << "Attempted to set max packet length too small";
 }
 
+void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
+  DCHECK(CanSetMaxPacketLength());
+  if (length > max_packet_length_) {
+    QUIC_BUG << ENDPOINT
+             << "Try to increase max_packet_length_ in "
+                "SetSoftMaxPacketLength, use SetMaxPacketLength instead.";
+    return;
+  }
+  if (framer_->GetMaxPlaintextSize(length) <
+      PacketHeaderSize() + MinPlaintextPacketSize(framer_->version())) {
+    QUIC_DLOG(INFO) << length << " is too small to fit packet header";
+    return;
+  }
+  QUIC_DVLOG(1) << "Setting soft max packet length to: " << length;
+  latched_hard_max_packet_length_ = max_packet_length_;
+  max_packet_length_ = length;
+  max_plaintext_size_ = framer_->GetMaxPlaintextSize(length);
+}
+
 // Stops serializing version of the protocol in packets sent after this call.
 // A packet that is already open might send kQuicVersionSize bytes less than the
 // maximum packet size if we stop sending version before it is serialized.
@@ -295,14 +315,28 @@
 bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
                                               QuicStreamOffset offset,
                                               size_t data_size) {
-  return BytesFree() >
-         QuicFramer::GetMinStreamFrameSize(framer_->transport_version(), id,
-                                           offset, true, data_size);
+  const size_t min_stream_frame_size = QuicFramer::GetMinStreamFrameSize(
+      framer_->transport_version(), id, offset, /*last_frame_in_packet=*/true,
+      data_size);
+  if (BytesFree() > min_stream_frame_size) {
+    return true;
+  }
+  if (!RemoveSoftMaxPacketLength()) {
+    return false;
+  }
+  return BytesFree() > min_stream_frame_size;
 }
 
 bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) {
-  return BytesFree() >= QuicFramer::GetMessageFrameSize(
-                            framer_->transport_version(), true, length);
+  const size_t message_frame_size = QuicFramer::GetMessageFrameSize(
+      framer_->transport_version(), /*last_frame_in_packet=*/true, length);
+  if (BytesFree() >= message_frame_size) {
+    return true;
+  }
+  if (!RemoveSoftMaxPacketLength()) {
+    return false;
+  }
+  return BytesFree() >= message_frame_size;
 }
 
 // TODO(fkastenholz): this method should not use constant values for
@@ -388,7 +422,8 @@
                                           QuicFrame* frame) {
   size_t min_frame_size =
       QuicFramer::GetMinCryptoFrameSize(write_length, offset);
-  if (BytesFree() <= min_frame_size) {
+  if (BytesFree() <= min_frame_size &&
+      (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) {
     return false;
   }
   size_t max_write_length = BytesFree() - min_frame_size;
@@ -423,6 +458,7 @@
 
   SerializedPacket packet(std::move(packet_));
   ClearPacket();
+  RemoveSoftMaxPacketLength();
   delegate_->OnSerializedPacket(&packet);
 }
 
@@ -730,6 +766,7 @@
 QuicPacketCreator::SerializeConnectivityProbingPacket() {
   QUIC_BUG_IF(VersionHasIetfQuicFrames(framer_->transport_version()))
       << "Must not be version 99 to serialize padded ping connectivity probe";
+  RemoveSoftMaxPacketLength();
   QuicPacketHeader header;
   // FillPacketHeader increments packet_number_.
   FillPacketHeader(&header);
@@ -765,6 +802,7 @@
       << "Must be version 99 to serialize path challenge connectivity probe, "
          "is version "
       << framer_->transport_version();
+  RemoveSoftMaxPacketLength();
   QuicPacketHeader header;
   // FillPacketHeader increments packet_number_.
   FillPacketHeader(&header);
@@ -801,6 +839,7 @@
       << "Must be version 99 to serialize path response connectivity probe, is "
          "version "
       << framer_->transport_version();
+  RemoveSoftMaxPacketLength();
   QuicPacketHeader header;
   // FillPacketHeader increments packet_number_.
   FillPacketHeader(&header);
@@ -1115,7 +1154,8 @@
   // the slow path loop.
   bool run_fast_path =
       !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() &&
-      write_length - total_bytes_consumed > kMaxOutgoingPacketSize;
+      write_length - total_bytes_consumed > kMaxOutgoingPacketSize &&
+      latched_hard_max_packet_length_ == 0;
 
   while (!run_fast_path && delegate_->ShouldGeneratePacket(
                                HAS_RETRANSMITTABLE_DATA,
@@ -1154,7 +1194,8 @@
 
     run_fast_path =
         !has_handshake && state != FIN_AND_PADDING && !HasPendingFrames() &&
-        write_length - total_bytes_consumed > kMaxOutgoingPacketSize;
+        write_length - total_bytes_consumed > kMaxOutgoingPacketSize &&
+        latched_hard_max_packet_length_ == 0;
   }
 
   if (run_fast_path) {
@@ -1449,6 +1490,12 @@
   size_t frame_len = framer_->GetSerializedFrameLength(
       frame, BytesFree(), queued_frames_.empty(),
       /* last_frame_in_packet= */ true, GetPacketNumberLength());
+  if (frame_len == 0 && RemoveSoftMaxPacketLength()) {
+    // Remove soft max_packet_length and retry.
+    frame_len = framer_->GetSerializedFrameLength(
+        frame, BytesFree(), queued_frames_.empty(),
+        /* last_frame_in_packet= */ true, GetPacketNumberLength());
+  }
   if (frame_len == 0) {
     // Current open packet is full.
     FlushCurrentPacket();
@@ -1528,6 +1575,21 @@
   return true;
 }
 
+bool QuicPacketCreator::RemoveSoftMaxPacketLength() {
+  if (latched_hard_max_packet_length_ == 0) {
+    return false;
+  }
+  if (!CanSetMaxPacketLength()) {
+    return false;
+  }
+  QUIC_DVLOG(1) << "Restoring max packet length to: "
+                << latched_hard_max_packet_length_;
+  SetMaxPacketLength(latched_hard_max_packet_length_);
+  // Reset latched_max_packet_length_.
+  latched_hard_max_packet_length_ = 0;
+  return true;
+}
+
 void QuicPacketCreator::MaybeAddPadding() {
   // The current packet should have no padding bytes because padding is only
   // added when this method is called just before the packet is serialized.
@@ -1639,8 +1701,12 @@
       VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, GetLengthLength());
   // This is the largest possible message payload when the length field is
   // omitted.
-  return max_plaintext_size_ -
-         std::min(max_plaintext_size_, packet_header_size + kQuicFrameTypeSize);
+  size_t max_plaintext_size =
+      latched_hard_max_packet_length_ == 0
+          ? max_plaintext_size_
+          : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_);
+  return max_plaintext_size -
+         std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize);
 }
 
 QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
@@ -1669,9 +1735,13 @@
       VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, length_length);
   // This is the largest possible message payload when the length field is
   // omitted.
+  size_t max_plaintext_size =
+      latched_hard_max_packet_length_ == 0
+          ? max_plaintext_size_
+          : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_);
   const QuicPacketLength largest_payload =
-      max_plaintext_size_ -
-      std::min(max_plaintext_size_, packet_header_size + kQuicFrameTypeSize);
+      max_plaintext_size -
+      std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize);
   // This must always be less than or equal to GetCurrentLargestMessagePayload.
   DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload());
   return largest_payload;