Add GetLargestGuaranteedMessagePayload to QuicSession/Connection/Generator/Creator to expose the largest message payload that's guaranteed to fit in any packet containing application data.
gfe-relnote: n/a (Only used in Quartc)
PiperOrigin-RevId: 242135946
Change-Id: I52cc763af88d22fc240210e00cf4d4062d0b9c59
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index c3f50ef..6935dee 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -3552,8 +3552,8 @@
}
SetPacketLossPercentage(30);
- ASSERT_GT(kMaxPacketSize, client_session->GetLargestMessagePayload());
- ASSERT_LT(0, client_session->GetLargestMessagePayload());
+ ASSERT_GT(kMaxPacketSize, client_session->GetCurrentLargestMessagePayload());
+ ASSERT_LT(0, client_session->GetCurrentLargestMessagePayload());
std::string message_string(kMaxPacketSize, 'a');
QuicStringPiece message_buffer(message_string);
@@ -3564,20 +3564,23 @@
QuicConnection::ScopedPacketFlusher flusher(
client_session->connection(), QuicConnection::SEND_ACK_IF_PENDING);
// Verify the largest message gets successfully sent.
- EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1),
- client_session->SendMessage(MakeSpan(
- client_session->connection()
- ->helper()
- ->GetStreamSendBufferAllocator(),
- QuicStringPiece(message_buffer.data(),
- client_session->GetLargestMessagePayload()),
- &storage)));
+ EXPECT_EQ(
+ MessageResult(MESSAGE_STATUS_SUCCESS, 1),
+ client_session->SendMessage(MakeSpan(
+ client_session->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator(),
+ QuicStringPiece(message_buffer.data(),
+ client_session->GetCurrentLargestMessagePayload()),
+ &storage)));
// Send more messages with size (0, largest_payload] until connection is
// write blocked.
const int kTestMaxNumberOfMessages = 100;
for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) {
size_t message_length =
- random->RandUint64() % client_session->GetLargestMessagePayload() + 1;
+ random->RandUint64() %
+ client_session->GetCurrentLargestMessagePayload() +
+ 1;
MessageResult result = client_session->SendMessage(MakeSpan(
client_session->connection()
->helper()
@@ -3592,17 +3595,17 @@
}
client_->WaitForDelayedAcks();
- EXPECT_EQ(
- MESSAGE_STATUS_TOO_LARGE,
- client_session
- ->SendMessage(MakeSpan(
- client_session->connection()
- ->helper()
- ->GetStreamSendBufferAllocator(),
- QuicStringPiece(message_buffer.data(),
- client_session->GetLargestMessagePayload() + 1),
- &storage))
- .status);
+ EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE,
+ client_session
+ ->SendMessage(MakeSpan(
+ client_session->connection()
+ ->helper()
+ ->GetStreamSendBufferAllocator(),
+ QuicStringPiece(
+ message_buffer.data(),
+ client_session->GetCurrentLargestMessagePayload() + 1),
+ &storage))
+ .status);
EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
}
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 68567b7..c6f939e 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -3875,7 +3875,7 @@
<< transport_version();
return MESSAGE_STATUS_UNSUPPORTED;
}
- if (message.total_length() > GetLargestMessagePayload()) {
+ if (message.total_length() > GetCurrentLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
@@ -3885,8 +3885,12 @@
return packet_generator_.AddMessageFrame(message_id, message);
}
-QuicPacketLength QuicConnection::GetLargestMessagePayload() const {
- return packet_generator_.GetLargestMessagePayload();
+QuicPacketLength QuicConnection::GetCurrentLargestMessagePayload() const {
+ return packet_generator_.GetCurrentLargestMessagePayload();
+}
+
+QuicPacketLength QuicConnection::GetGuaranteedLargestMessagePayload() const {
+ return packet_generator_.GetGuaranteedLargestMessagePayload();
}
bool QuicConnection::ShouldSetAckAlarm() const {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index edd132b..8176934 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -757,7 +757,13 @@
QuicMemSliceSpan message);
// Returns the largest payload that will fit into a single MESSAGE frame.
- QuicPacketLength GetLargestMessagePayload() const;
+ // Because overhead can vary during a connection, this method should be
+ // checked for every message.
+ QuicPacketLength GetCurrentLargestMessagePayload() const;
+ // Returns the largest payload that will fit into a single MESSAGE frame at
+ // any point during the connection. This assumes the version and
+ // connection ID lengths do not change.
+ QuicPacketLength GetGuaranteedLargestMessagePayload() const;
// Return the id of the cipher of the primary decrypter of the framer.
uint32_t cipher_id() const { return framer_.decrypter()->cipher_id(); }
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 3d1e483..f5a840a 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -8257,7 +8257,7 @@
connection_.SupportsMultiplePacketNumberSpaces()) {
return;
}
- std::string message(connection_.GetLargestMessagePayload() * 2, 'a');
+ std::string message(connection_.GetCurrentLargestMessagePayload() * 2, 'a');
QuicStringPiece message_data(message);
QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
{
@@ -8272,8 +8272,9 @@
MESSAGE_STATUS_SUCCESS,
connection_.SendMessage(
1, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
- QuicStringPiece(message_data.data(),
- connection_.GetLargestMessagePayload()),
+ QuicStringPiece(
+ message_data.data(),
+ connection_.GetCurrentLargestMessagePayload()),
&storage)));
}
// Fail to send a message if connection is congestion control blocked.
@@ -8289,11 +8290,11 @@
EXPECT_EQ(
MESSAGE_STATUS_TOO_LARGE,
connection_.SendMessage(
- 3,
- MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
- QuicStringPiece(message_data.data(),
- connection_.GetLargestMessagePayload() + 1),
- &storage)));
+ 3, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(),
+ QuicStringPiece(
+ message_data.data(),
+ connection_.GetCurrentLargestMessagePayload() + 1),
+ &storage)));
}
// Test to check that the path challenge/path response logic works
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 224aadf..4d5bd14 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -10,9 +10,11 @@
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_constants.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
@@ -984,7 +986,7 @@
}
}
-QuicPacketLength QuicPacketCreator::GetLargestMessagePayload() const {
+QuicPacketLength QuicPacketCreator::GetCurrentLargestMessagePayload() const {
if (framer_->transport_version() <= QUIC_VERSION_44) {
return 0;
}
@@ -992,13 +994,44 @@
framer_->transport_version(), GetDestinationConnectionIdLength(),
GetSourceConnectionIdLength(), IncludeVersionInHeader(),
IncludeNonceInPublicHeader(), GetPacketNumberLength(),
- GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength());
+ // No Retry token on packets containing application data.
+ 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);
}
+QuicPacketLength QuicPacketCreator::GetGuaranteedLargestMessagePayload() const {
+ if (framer_->transport_version() <= QUIC_VERSION_44) {
+ return 0;
+ }
+ // QUIC Crypto server packets may include a diversification nonce.
+ const bool may_include_nonce =
+ framer_->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO &&
+ framer_->perspective() == Perspective::IS_SERVER;
+ // IETF QUIC long headers include a length on client 0RTT packets.
+ QuicVariableLengthIntegerLength length_length =
+ framer_->perspective() == Perspective::IS_CLIENT
+ ? VARIABLE_LENGTH_INTEGER_LENGTH_2
+ : VARIABLE_LENGTH_INTEGER_LENGTH_0;
+ const size_t packet_header_size = GetPacketHeaderSize(
+ framer_->transport_version(), GetDestinationConnectionIdLength(),
+ // Assume CID lengths don't change, but version may be present.
+ GetSourceConnectionIdLength(), kIncludeVersion, may_include_nonce,
+ PACKET_4BYTE_PACKET_NUMBER,
+ // No Retry token on packets containing application data.
+ VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, length_length);
+ // This is the largest possible message payload when the length field is
+ // omitted.
+ const QuicPacketLength largest_payload =
+ 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;
+}
+
bool QuicPacketCreator::HasIetfLongHeader() const {
return framer_->transport_version() > QUIC_VERSION_43 &&
packet_.encryption_level < ENCRYPTION_FORWARD_SECURE;
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h
index 7c8f496..ea93552 100644
--- a/quic/core/quic_packet_creator.h
+++ b/quic/core/quic_packet_creator.h
@@ -255,7 +255,11 @@
void SetRetryToken(QuicStringPiece retry_token);
// Returns the largest payload that will fit into a single MESSAGE frame.
- QuicPacketLength GetLargestMessagePayload() const;
+ QuicPacketLength GetCurrentLargestMessagePayload() const;
+ // Returns the largest payload that will fit into a single MESSAGE frame at
+ // any point during the connection. This assumes the version and
+ // connection ID lengths do not change.
+ QuicPacketLength GetGuaranteedLargestMessagePayload() const;
void set_debug_delegate(DebugDelegate* debug_delegate) {
debug_delegate_ = debug_delegate;
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index aea0540..aa2f6f7 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -1606,9 +1606,9 @@
Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacketForTests));
QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
// Verify that there is enough room for the largest message payload.
- EXPECT_TRUE(
- creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
- std::string message(creator_.GetLargestMessagePayload(), 'a');
+ EXPECT_TRUE(creator_.HasRoomForMessageFrame(
+ creator_.GetCurrentLargestMessagePayload()));
+ std::string message(creator_.GetCurrentLargestMessagePayload(), 'a');
QuicMessageFrame* message_frame =
new QuicMessageFrame(1, MakeSpan(&allocator_, message, &storage));
EXPECT_TRUE(
@@ -1639,8 +1639,8 @@
EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame4), NOT_RETRANSMISSION));
EXPECT_TRUE(creator_.HasPendingFrames());
// Verify there is not enough room for largest payload.
- EXPECT_FALSE(
- creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload()));
+ EXPECT_FALSE(creator_.HasRoomForMessageFrame(
+ creator_.GetCurrentLargestMessagePayload()));
// Add largest message will causes the flush of the stream frame.
QuicMessageFrame frame5(5, MakeSpan(&allocator_, message, &storage));
EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&frame5), NOT_RETRANSMISSION));
@@ -1654,31 +1654,40 @@
std::string message_data(kDefaultMaxPacketSize, 'a');
QuicStringPiece message_buffer(message_data);
QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
- // Test all possible size of message frames.
- for (size_t message_size = 0;
- message_size <= creator_.GetLargestMessagePayload(); ++message_size) {
- QuicMessageFrame* frame = new QuicMessageFrame(
- 0, MakeSpan(&allocator_,
- QuicStringPiece(message_buffer.data(), message_size),
- &storage));
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION));
- EXPECT_TRUE(creator_.HasPendingFrames());
+ // Test all possible encryption levels of message frames.
+ for (EncryptionLevel level :
+ {ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
+ creator_.set_encryption_level(level);
+ // Test all possible sizes of message frames.
+ for (size_t message_size = 0;
+ message_size <= creator_.GetCurrentLargestMessagePayload();
+ ++message_size) {
+ QuicMessageFrame* frame = new QuicMessageFrame(
+ 0, MakeSpan(&allocator_,
+ QuicStringPiece(message_buffer.data(), message_size),
+ &storage));
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION));
+ EXPECT_TRUE(creator_.HasPendingFrames());
- size_t expansion_bytes = message_size >= 64 ? 2 : 1;
- EXPECT_EQ(expansion_bytes, creator_.ExpansionOnNewFrame());
- // Verify BytesFree returns bytes available for the next frame, which should
- // subtract the message length.
- size_t expected_bytes_free =
- creator_.GetLargestMessagePayload() - message_size < expansion_bytes
- ? 0
- : creator_.GetLargestMessagePayload() - expansion_bytes -
- message_size;
- EXPECT_EQ(expected_bytes_free, creator_.BytesFree());
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- DeleteSerializedPacket();
+ size_t expansion_bytes = message_size >= 64 ? 2 : 1;
+ EXPECT_EQ(expansion_bytes, creator_.ExpansionOnNewFrame());
+ // Verify BytesFree returns bytes available for the next frame, which
+ // should subtract the message length.
+ size_t expected_bytes_free =
+ creator_.GetCurrentLargestMessagePayload() - message_size <
+ expansion_bytes
+ ? 0
+ : creator_.GetCurrentLargestMessagePayload() - expansion_bytes -
+ message_size;
+ EXPECT_EQ(expected_bytes_free, creator_.BytesFree());
+ EXPECT_LE(creator_.GetGuaranteedLargestMessagePayload(),
+ creator_.GetCurrentLargestMessagePayload());
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ DeleteSerializedPacket();
+ }
}
}
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc
index 8267ade..831689b 100644
--- a/quic/core/quic_packet_generator.cc
+++ b/quic/core/quic_packet_generator.cc
@@ -472,7 +472,7 @@
MaybeBundleAckOpportunistically();
}
const QuicByteCount message_length = message.total_length();
- if (message_length > GetLargestMessagePayload()) {
+ if (message_length > GetCurrentLargestMessagePayload()) {
return MESSAGE_STATUS_TOO_LARGE;
}
SendQueuedFrames(/*flush=*/false);
@@ -530,8 +530,13 @@
return true;
}
-QuicPacketLength QuicPacketGenerator::GetLargestMessagePayload() const {
- return packet_creator_.GetLargestMessagePayload();
+QuicPacketLength QuicPacketGenerator::GetCurrentLargestMessagePayload() const {
+ return packet_creator_.GetCurrentLargestMessagePayload();
+}
+
+QuicPacketLength QuicPacketGenerator::GetGuaranteedLargestMessagePayload()
+ const {
+ return packet_creator_.GetGuaranteedLargestMessagePayload();
}
void QuicPacketGenerator::SetConnectionId(QuicConnectionId connection_id) {
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h
index 4c780f5..dc191a0 100644
--- a/quic/core/quic_packet_generator.h
+++ b/quic/core/quic_packet_generator.h
@@ -227,7 +227,8 @@
bool FlushAckFrame(const QuicFrames& frames);
// Returns the largest payload that will fit into a single MESSAGE frame.
- QuicPacketLength GetLargestMessagePayload() const;
+ QuicPacketLength GetCurrentLargestMessagePayload() const;
+ QuicPacketLength GetGuaranteedLargestMessagePayload() const;
// Update the connection ID used in outgoing packets.
void SetConnectionId(QuicConnectionId connection_id);
diff --git a/quic/core/quic_packet_generator_test.cc b/quic/core/quic_packet_generator_test.cc
index bc20bfe..09abb31 100644
--- a/quic/core/quic_packet_generator_test.cc
+++ b/quic/core/quic_packet_generator_test.cc
@@ -1531,9 +1531,10 @@
EXPECT_EQ(
MESSAGE_STATUS_SUCCESS,
generator_.AddMessageFrame(
- 2, MakeSpan(&allocator_,
- std::string(generator_.GetLargestMessagePayload(), 'a'),
- &storage)));
+ 2, MakeSpan(
+ &allocator_,
+ std::string(generator_.GetCurrentLargestMessagePayload(), 'a'),
+ &storage)));
EXPECT_TRUE(generator_.HasRetransmittableFrames());
// Failed to send messages which cannot fit into one packet.
@@ -1542,7 +1543,8 @@
generator_.AddMessageFrame(
3,
MakeSpan(&allocator_,
- std::string(generator_.GetLargestMessagePayload() + 10, 'a'),
+ std::string(
+ generator_.GetCurrentLargestMessagePayload() + 10, 'a'),
&storage)));
}
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 763d208..01d6feb 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1623,8 +1623,12 @@
return connection_->session_decides_what_to_write();
}
-QuicPacketLength QuicSession::GetLargestMessagePayload() const {
- return connection_->GetLargestMessagePayload();
+QuicPacketLength QuicSession::GetCurrentLargestMessagePayload() const {
+ return connection_->GetCurrentLargestMessagePayload();
+}
+
+QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const {
+ return connection_->GetGuaranteedLargestMessagePayload();
}
void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 776da8e..b13f627 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -320,7 +320,12 @@
// Returns the largest payload that will fit into a single MESSAGE frame.
// Because overhead can vary during a connection, this method should be
// checked for every message.
- QuicPacketLength GetLargestMessagePayload() const;
+ QuicPacketLength GetCurrentLargestMessagePayload() const;
+
+ // Returns the largest payload that will fit into a single MESSAGE frame at
+ // any point during the connection. This assumes the version and
+ // connection ID lengths do not change.
+ QuicPacketLength GetGuaranteedLargestMessagePayload() const;
bool goaway_sent() const { return goaway_sent_; }