Plumb max_datagram_frame_size

In QUIC_CRYPTO, the maximum allowed size of a DATAGRAM/MESSAGE frame is unlimited. However, in QUIC+TLS, it's negotiated during the handshake using the max_datagram_frame_size IETF QUIC transport parameter. This CL adds this limit to QuicPacketCreator and plumbs it through during the handshake. Since all of our uses of the DATAGRAM/MESSAGE frame today only support QUIC_CRYPTO, this CL does not change any existing behavior.

Plumb max_datagram_frame_size, no behavior change, not flag protected

PiperOrigin-RevId: 310456458
Change-Id: Ib40d6e7e950865e496809ba5c880dc47cd243be9
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index cea1a1b..a9d7076 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <cstddef>
 #include <cstdint>
+#include <limits>
 #include <string>
 #include <utility>
 
@@ -130,8 +131,15 @@
       next_transmission_type_(NOT_RETRANSMISSION),
       flusher_attached_(false),
       fully_pad_crypto_handshake_packets_(true),
-      latched_hard_max_packet_length_(0) {
+      latched_hard_max_packet_length_(0),
+      max_datagram_frame_size_(0) {
   SetMaxPacketLength(kDefaultMaxPacketSize);
+  if (!framer_->version().UsesTls()) {
+    // QUIC+TLS negotiates the maximum datagram frame size via the
+    // IETF QUIC max_datagram_frame_size transport parameter.
+    // QUIC_CRYPTO however does not negotiate this so we set its value here.
+    SetMaxDatagramFrameSize(kMaxAcceptedDatagramFrameSize);
+  }
 }
 
 QuicPacketCreator::~QuicPacketCreator() {
@@ -165,6 +173,21 @@
       << "Attempted to set max packet length too small";
 }
 
+void QuicPacketCreator::SetMaxDatagramFrameSize(
+    QuicByteCount max_datagram_frame_size) {
+  constexpr QuicByteCount upper_bound =
+      std::min<QuicByteCount>(std::numeric_limits<QuicPacketLength>::max(),
+                              std::numeric_limits<size_t>::max());
+  if (max_datagram_frame_size > upper_bound) {
+    // A value of |max_datagram_frame_size| that is equal or greater than
+    // 2^16-1 is effectively infinite because QUIC packets cannot be that large.
+    // We therefore clamp the value here to allow us to safely cast
+    // |max_datagram_frame_size_| to QuicPacketLength or size_t.
+    max_datagram_frame_size = upper_bound;
+  }
+  max_datagram_frame_size_ = max_datagram_frame_size;
+}
+
 void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) {
   DCHECK(CanSetMaxPacketLength());
   if (length > max_packet_length_) {
@@ -326,6 +349,10 @@
 bool QuicPacketCreator::HasRoomForMessageFrame(QuicByteCount length) {
   const size_t message_frame_size = QuicFramer::GetMessageFrameSize(
       framer_->transport_version(), /*last_frame_in_packet=*/true, length);
+  if (static_cast<QuicByteCount>(message_frame_size) >
+      max_datagram_frame_size_) {
+    return false;
+  }
   if (BytesFree() >= message_frame_size) {
     return true;
   }
@@ -1705,8 +1732,12 @@
       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);
+  size_t largest_frame =
+      max_plaintext_size - std::min(max_plaintext_size, packet_header_size);
+  if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) {
+    largest_frame = static_cast<size_t>(max_datagram_frame_size_);
+  }
+  return largest_frame - std::min(largest_frame, kQuicFrameTypeSize);
 }
 
 QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
@@ -1739,9 +1770,13 @@
       latched_hard_max_packet_length_ == 0
           ? max_plaintext_size_
           : framer_->GetMaxPlaintextSize(latched_hard_max_packet_length_);
+  size_t largest_frame =
+      max_plaintext_size - std::min(max_plaintext_size, packet_header_size);
+  if (static_cast<QuicByteCount>(largest_frame) > max_datagram_frame_size_) {
+    largest_frame = static_cast<size_t>(max_datagram_frame_size_);
+  }
   const QuicPacketLength largest_payload =
-      max_plaintext_size -
-      std::min(max_plaintext_size, packet_header_size + kQuicFrameTypeSize);
+      largest_frame - std::min(largest_frame, kQuicFrameTypeSize);
   // This must always be less than or equal to GetCurrentLargestMessagePayload.
   DCHECK_LE(largest_payload, GetCurrentLargestMessagePayload());
   return largest_payload;