gfe-relnote: Remove QuicPacketGenerator.
Deprecate gfe2_reloadable_flag_quic_combine_generator_and_creator.
PiperOrigin-RevId: 278697040
Change-Id: I0358b83acdbb8c129b4decc40b237f3beb3b115a
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 4efcbfe..25161e1 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -30,6 +30,7 @@
#include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h"
+#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h"
using testing::_;
using testing::DoAll;
@@ -2239,6 +2240,1495 @@
EXPECT_TRUE(creator_.HasPendingFrames());
}
+class MockDelegate : public QuicPacketCreator::DelegateInterface {
+ public:
+ MockDelegate() {}
+ MockDelegate(const MockDelegate&) = delete;
+ MockDelegate& operator=(const MockDelegate&) = delete;
+ ~MockDelegate() override {}
+
+ MOCK_METHOD2(ShouldGeneratePacket,
+ bool(HasRetransmittableData retransmittable,
+ IsHandshake handshake));
+ MOCK_METHOD0(MaybeBundleAckOpportunistically, const QuicFrames());
+ MOCK_METHOD0(GetPacketBuffer, char*());
+ MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
+ MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, const std::string&));
+
+ void SetCanWriteAnything() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(true));
+ }
+
+ void SetCanNotWrite() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(false));
+ }
+
+ // Use this when only ack frames should be allowed to be written.
+ void SetCanWriteOnlyNonRetransmittable() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(true));
+ }
+};
+
+// Simple struct for describing the contents of a packet.
+// Useful in conjunction with a SimpleQuicFrame for validating that a packet
+// contains the expected frames.
+struct PacketContents {
+ PacketContents()
+ : num_ack_frames(0),
+ num_connection_close_frames(0),
+ num_goaway_frames(0),
+ num_rst_stream_frames(0),
+ num_stop_waiting_frames(0),
+ num_stream_frames(0),
+ num_crypto_frames(0),
+ num_ping_frames(0),
+ num_mtu_discovery_frames(0),
+ num_padding_frames(0) {}
+
+ size_t num_ack_frames;
+ size_t num_connection_close_frames;
+ size_t num_goaway_frames;
+ size_t num_rst_stream_frames;
+ size_t num_stop_waiting_frames;
+ size_t num_stream_frames;
+ size_t num_crypto_frames;
+ size_t num_ping_frames;
+ size_t num_mtu_discovery_frames;
+ size_t num_padding_frames;
+};
+
+class MultiplePacketsTestPacketCreator : public QuicPacketCreator {
+ public:
+ MultiplePacketsTestPacketCreator(
+ QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicPacketCreator::DelegateInterface* delegate,
+ SimpleDataProducer* producer)
+ : QuicPacketCreator(connection_id, framer, random_generator, delegate),
+ ack_frame_(InitAckFrame(1)),
+ delegate_(static_cast<MockDelegate*>(delegate)),
+ producer_(producer) {}
+
+ bool ConsumeRetransmittableControlFrame(const QuicFrame& frame,
+ bool bundle_ack) {
+ if (!has_ack()) {
+ QuicFrames frames;
+ if (bundle_ack) {
+ frames.push_back(QuicFrame(&ack_frame_));
+ }
+ if (delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically())
+ .WillOnce(Return(frames));
+ }
+ }
+ return QuicPacketCreator::ConsumeRetransmittableControlFrame(frame);
+ }
+
+ QuicConsumedData ConsumeDataFastPath(QuicStreamId id,
+ const struct iovec* iov,
+ int iov_count,
+ size_t total_length,
+ QuicStreamOffset offset,
+ bool fin) {
+ // Save data before data is consumed.
+ if (total_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
+ }
+ return QuicPacketCreator::ConsumeDataFastPath(id, total_length, offset, fin,
+ 0);
+ }
+
+ QuicConsumedData ConsumeData(QuicStreamId id,
+ const struct iovec* iov,
+ int iov_count,
+ size_t total_length,
+ QuicStreamOffset offset,
+ StreamSendingState state) {
+ // Save data before data is consumed.
+ if (total_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
+ }
+ if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1);
+ }
+ return QuicPacketCreator::ConsumeData(id, total_length, offset, state);
+ }
+
+ MessageStatus AddMessageFrame(QuicMessageId message_id,
+ QuicMemSliceSpan message) {
+ if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1);
+ }
+ return QuicPacketCreator::AddMessageFrame(message_id, message);
+ }
+
+ size_t ConsumeCryptoData(EncryptionLevel level,
+ QuicStringPiece data,
+ QuicStreamOffset offset) {
+ producer_->SaveCryptoData(level, offset, data);
+ if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1);
+ }
+ return QuicPacketCreator::ConsumeCryptoData(level, data.length(), offset);
+ }
+
+ QuicAckFrame ack_frame_;
+ MockDelegate* delegate_;
+ SimpleDataProducer* producer_;
+};
+
+class QuicPacketCreatorMultiplePacketsTest : public QuicTest {
+ public:
+ QuicPacketCreatorMultiplePacketsTest()
+ : framer_(AllSupportedVersions(),
+ QuicTime::Zero(),
+ Perspective::IS_CLIENT,
+ kQuicDefaultConnectionIdLength),
+ creator_(TestConnectionId(),
+ &framer_,
+ &random_creator_,
+ &delegate_,
+ &producer_),
+ ack_frame_(InitAckFrame(1)) {
+ EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
+ creator_.SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ framer_.set_data_producer(&producer_);
+ if (simple_framer_.framer()->version().KnowsWhichDecrypterToUse()) {
+ simple_framer_.framer()->InstallDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
+ }
+ creator_.AttachPacketFlusher();
+ }
+
+ ~QuicPacketCreatorMultiplePacketsTest() override {
+ for (SerializedPacket& packet : packets_) {
+ delete[] packet.encrypted_buffer;
+ ClearSerializedPacket(&packet);
+ }
+ }
+
+ void SavePacket(SerializedPacket* packet) {
+ packet->encrypted_buffer = CopyBuffer(*packet);
+ packets_.push_back(*packet);
+ packet->encrypted_buffer = nullptr;
+ packet->retransmittable_frames.clear();
+ }
+
+ protected:
+ QuicRstStreamFrame* CreateRstStreamFrame() {
+ return new QuicRstStreamFrame(1, 1, QUIC_STREAM_NO_ERROR, 0);
+ }
+
+ QuicGoAwayFrame* CreateGoAwayFrame() {
+ return new QuicGoAwayFrame(2, QUIC_NO_ERROR, 1, std::string());
+ }
+
+ void CheckPacketContains(const PacketContents& contents,
+ size_t packet_index) {
+ ASSERT_GT(packets_.size(), packet_index);
+ const SerializedPacket& packet = packets_[packet_index];
+ size_t num_retransmittable_frames =
+ contents.num_connection_close_frames + contents.num_goaway_frames +
+ contents.num_rst_stream_frames + contents.num_stream_frames +
+ contents.num_crypto_frames + contents.num_ping_frames;
+ size_t num_frames =
+ contents.num_ack_frames + contents.num_stop_waiting_frames +
+ contents.num_mtu_discovery_frames + contents.num_padding_frames +
+ num_retransmittable_frames;
+
+ if (num_retransmittable_frames == 0) {
+ ASSERT_TRUE(packet.retransmittable_frames.empty());
+ } else {
+ ASSERT_FALSE(packet.retransmittable_frames.empty());
+ EXPECT_EQ(num_retransmittable_frames,
+ packet.retransmittable_frames.size());
+ }
+
+ ASSERT_TRUE(packet.encrypted_buffer != nullptr);
+ ASSERT_TRUE(simple_framer_.ProcessPacket(
+ QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
+ size_t num_padding_frames = 0;
+ if (contents.num_padding_frames == 0) {
+ num_padding_frames = simple_framer_.padding_frames().size();
+ }
+ EXPECT_EQ(num_frames + num_padding_frames, simple_framer_.num_frames());
+ EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size());
+ EXPECT_EQ(contents.num_connection_close_frames,
+ simple_framer_.connection_close_frames().size());
+ EXPECT_EQ(contents.num_goaway_frames,
+ simple_framer_.goaway_frames().size());
+ EXPECT_EQ(contents.num_rst_stream_frames,
+ simple_framer_.rst_stream_frames().size());
+ EXPECT_EQ(contents.num_stream_frames,
+ simple_framer_.stream_frames().size());
+ EXPECT_EQ(contents.num_crypto_frames,
+ simple_framer_.crypto_frames().size());
+ EXPECT_EQ(contents.num_stop_waiting_frames,
+ simple_framer_.stop_waiting_frames().size());
+ if (contents.num_padding_frames != 0) {
+ EXPECT_EQ(contents.num_padding_frames,
+ simple_framer_.padding_frames().size());
+ }
+
+ // From the receiver's perspective, MTU discovery frames are ping frames.
+ EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames,
+ simple_framer_.ping_frames().size());
+ }
+
+ void CheckPacketHasSingleStreamFrame(size_t packet_index) {
+ ASSERT_GT(packets_.size(), packet_index);
+ const SerializedPacket& packet = packets_[packet_index];
+ ASSERT_FALSE(packet.retransmittable_frames.empty());
+ EXPECT_EQ(1u, packet.retransmittable_frames.size());
+ ASSERT_TRUE(packet.encrypted_buffer != nullptr);
+ ASSERT_TRUE(simple_framer_.ProcessPacket(
+ QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
+ EXPECT_EQ(1u, simple_framer_.num_frames());
+ EXPECT_EQ(1u, simple_framer_.stream_frames().size());
+ }
+
+ void CheckAllPacketsHaveSingleStreamFrame() {
+ for (size_t i = 0; i < packets_.size(); i++) {
+ CheckPacketHasSingleStreamFrame(i);
+ }
+ }
+
+ void CreateData(size_t len) {
+ data_array_.reset(new char[len]);
+ memset(data_array_.get(), '?', len);
+ iov_.iov_base = data_array_.get();
+ iov_.iov_len = len;
+ }
+
+ QuicFramer framer_;
+ MockRandom random_creator_;
+ StrictMock<MockDelegate> delegate_;
+ MultiplePacketsTestPacketCreator creator_;
+ SimpleQuicFramer simple_framer_;
+ std::vector<SerializedPacket> packets_;
+ QuicAckFrame ack_frame_;
+ struct iovec iov_;
+ SimpleBufferAllocator allocator_;
+
+ private:
+ std::unique_ptr<char[]> data_array_;
+ SimpleDataProducer producer_;
+};
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_NotWritable) {
+ delegate_.SetCanNotWrite();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool consumed =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false);
+ EXPECT_FALSE(consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ delete rst_frame;
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_OnlyAckWritable) {
+ delegate_.SetCanWriteOnlyNonRetransmittable();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool consumed =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false);
+ EXPECT_FALSE(consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ delete rst_frame;
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ AddControlFrame_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()),
+ /*bundle_ack=*/false);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ AddControlFrame_NotWritableBatchThenFlush) {
+ delegate_.SetCanNotWrite();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool consumed =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false);
+ EXPECT_FALSE(consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ delete rst_frame;
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ AddControlFrame_WritableAndShouldFlush) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()),
+ /*bundle_ack=*/false);
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_rst_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeCryptoData) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ std::string data = "crypto data";
+ size_t consumed_bytes =
+ creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
+ creator_.Flush();
+ EXPECT_EQ(data.length(), consumed_bytes);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_crypto_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) {
+ delegate_.SetCanNotWrite();
+
+ MakeIOVector("foo", &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(0u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeData_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+
+ MakeIOVector("foo", &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeData_WritableAndShouldFlush) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector("foo", &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ creator_.Flush();
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+// Test the behavior of ConsumeData when the data consumed is for the crypto
+// handshake stream. Ensure that the packet is always sent and padded even if
+// the creator operates in batch mode.
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_Handshake) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ std::string data = "foo bar";
+ MakeIOVector(data, &iov_);
+ size_t consumed_bytes = 0;
+ if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
+ consumed_bytes = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
+ } else {
+ consumed_bytes =
+ creator_
+ .ConsumeData(
+ QuicUtils::GetCryptoStreamId(framer_.transport_version()),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN)
+ .bytes_consumed;
+ }
+ EXPECT_EQ(7u, consumed_bytes);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
+ contents.num_crypto_frames = 1;
+ } else {
+ contents.num_stream_frames = 1;
+ }
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ ASSERT_EQ(1u, packets_.size());
+ ASSERT_EQ(kDefaultMaxPacketSize, creator_.max_packet_length());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+}
+
+// Test the behavior of ConsumeData when the data is for the crypto handshake
+// stream, but padding is disabled.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeData_Handshake_PaddingDisabled) {
+ creator_.set_fully_pad_crypto_handshake_packets(false);
+
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ std::string data = "foo";
+ MakeIOVector(data, &iov_);
+ size_t bytes_consumed = 0;
+ if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
+ bytes_consumed = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
+ } else {
+ bytes_consumed =
+ creator_
+ .ConsumeData(
+ QuicUtils::GetCryptoStreamId(framer_.transport_version()),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN)
+ .bytes_consumed;
+ }
+ EXPECT_EQ(3u, bytes_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
+ contents.num_crypto_frames = 1;
+ } else {
+ contents.num_stream_frames = 1;
+ }
+ contents.num_padding_frames = 0;
+ CheckPacketContains(contents, 0);
+
+ ASSERT_EQ(1u, packets_.size());
+
+ // Packet is not fully padded, but we want to future packets to be larger.
+ ASSERT_EQ(kDefaultMaxPacketSize, creator_.max_packet_length());
+ size_t expected_packet_length = 27;
+ if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
+ // The framing of CRYPTO frames is slightly different than that of stream
+ // frames, so the expected packet length differs slightly.
+ expected_packet_length = 28;
+ }
+ if (framer_.version().HasHeaderProtection()) {
+ expected_packet_length = 29;
+ }
+ EXPECT_EQ(expected_packet_length, packets_[0].encrypted_length);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_EmptyData) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_QUIC_BUG(creator_.ConsumeData(
+ QuicUtils::QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT),
+ nullptr, 0, 0, 0, NO_FIN),
+ "Attempt to consume empty data without FIN.");
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+
+ MakeIOVector("foo", &iov_);
+ creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ MakeIOVector("quux", &iov_);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN);
+ EXPECT_EQ(4u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_BatchOperations) {
+ delegate_.SetCanWriteAnything();
+
+ MakeIOVector("foo", &iov_);
+ creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ MakeIOVector("quux", &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 3, FIN);
+ EXPECT_EQ(4u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // Now both frames will be flushed out.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames =
+ GetQuicReloadableFlag(quic_coalesce_stream_frames) ? 1 : 2;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConsumeData_FramesPreviouslyQueued) {
+ // Set the packet size be enough for two stream frames with 0 stream offset,
+ // but not enough for a stream frame of 0 offset and one with non-zero offset.
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_.GetDestinationConnectionIdLength(),
+ creator_.GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(&creator_)) +
+ // Add an extra 3 bytes for the payload and 1 byte so
+ // BytesFree is larger than the GetMinStreamFrameSize.
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0,
+ false, 3) +
+ 3 +
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, true,
+ 1) +
+ 1;
+ creator_.SetMaxPacketLength(length);
+ delegate_.SetCanWriteAnything();
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ }
+ // Queue enough data to prevent a stream frame with a non-zero offset from
+ // fitting.
+ MakeIOVector("foo", &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // This frame will not fit with the existing frame, causing the queued frame
+ // to be serialized, and it will be added to a new open packet.
+ MakeIOVector("bar", &iov_);
+ consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 3, FIN);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ creator_.FlushCurrentPacket();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+ CheckPacketContains(contents, 1);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataFastPath) {
+ delegate_.SetCanWriteAnything();
+ creator_.SetTransmissionType(LOSS_RETRANSMISSION);
+
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ QuicConsumedData consumed = creator_.ConsumeDataFastPath(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, true);
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(LOSS_RETRANSMISSION, packet.transmission_type);
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ const QuicStreamFrame& stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) {
+ delegate_.SetCanWriteAnything();
+
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ const QuicStreamFrame& stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckFalse) {
+ delegate_.SetCanNotWrite();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool success =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/true);
+ EXPECT_FALSE(success);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ delegate_.SetCanWriteAnything();
+
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false);
+
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateRstStreamFrame()),
+ /*bundle_ack=*/true);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ creator_.Flush();
+
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ const QuicStreamFrame& stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLargeSendAckTrue) {
+ if (VersionHasIetfInvariantHeader(framer_.transport_version())) {
+ return;
+ }
+ delegate_.SetCanNotWrite();
+ delegate_.SetCanWriteAnything();
+
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ creator_.Flush();
+
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ EXPECT_FALSE(packets_.empty());
+ SerializedPacket packet = packets_.back();
+ EXPECT_TRUE(!packet.retransmittable_frames.empty());
+ EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type);
+ const QuicStreamFrame& stream_frame =
+ packet.retransmittable_frames.front().stream_frame;
+ EXPECT_EQ(10000u, stream_frame.data_length + stream_frame.offset);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, NotWritableThenBatchOperations) {
+ delegate_.SetCanNotWrite();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool consumed =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/true);
+ EXPECT_FALSE(consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(3));
+
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_TRUE(
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false));
+ // Send some data and a control frame
+ MakeIOVector("quux", &iov_);
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()),
+ /*bundle_ack=*/false);
+ }
+ EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(3));
+
+ // All five frames will be flushed out in a single packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(3));
+
+ PacketContents contents;
+ // ACK will be flushed by connection.
+ contents.num_ack_frames = 0;
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ contents.num_goaway_frames = 1;
+ } else {
+ contents.num_goaway_frames = 0;
+ }
+ contents.num_rst_stream_frames = 1;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, NotWritableThenBatchOperations2) {
+ delegate_.SetCanNotWrite();
+
+ QuicRstStreamFrame* rst_frame = CreateRstStreamFrame();
+ const bool success =
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/true);
+ EXPECT_FALSE(success);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ delegate_.SetCanWriteAnything();
+
+ {
+ InSequence dummy;
+ // All five frames will be flushed out in a single packet
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ }
+ EXPECT_TRUE(
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
+ /*bundle_ack=*/false));
+ // Send enough data to exceed one packet
+ size_t data_len = kDefaultMaxPacketSize + 100;
+ CreateData(data_len);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()),
+ /*bundle_ack=*/false);
+ }
+
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // The first packet should have the queued data and part of the stream data.
+ PacketContents contents;
+ // ACK will be sent by connection.
+ contents.num_ack_frames = 0;
+ contents.num_rst_stream_frames = 1;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ // The second should have the remainder of the stream data.
+ PacketContents contents2;
+ if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
+ contents2.num_goaway_frames = 1;
+ } else {
+ contents2.num_goaway_frames = 0;
+ }
+ contents2.num_stream_frames = 1;
+ CheckPacketContains(contents2, 1);
+}
+
+// Regression test of b/120493795.
+TEST_F(QuicPacketCreatorMultiplePacketsTest, PacketTransmissionType) {
+ delegate_.SetCanWriteAnything();
+
+ // The first ConsumeData will fill the packet without flush.
+ creator_.SetTransmissionType(LOSS_RETRANSMISSION);
+
+ size_t data_len = 1324;
+ CreateData(data_len);
+ QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ ASSERT_EQ(0u, creator_.BytesFree())
+ << "Test setup failed: Please increase data_len to "
+ << data_len + creator_.BytesFree() << " bytes.";
+
+ // The second ConsumeData can not be added to the packet and will flush.
+ creator_.SetTransmissionType(NOT_RETRANSMISSION);
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ QuicStreamId stream2_id = stream1_id + 4;
+
+ consumed =
+ creator_.ConsumeData(stream2_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+
+ // Ensure the packet is successfully created.
+ ASSERT_EQ(1u, packets_.size());
+ ASSERT_TRUE(packets_[0].encrypted_buffer);
+ ASSERT_EQ(1u, packets_[0].retransmittable_frames.size());
+ EXPECT_EQ(stream1_id,
+ packets_[0].retransmittable_frames[0].stream_frame.stream_id);
+
+ // Since the second frame was not added, the packet's transmission type
+ // should be the first frame's type.
+ EXPECT_EQ(packets_[0].transmission_type, LOSS_RETRANSMISSION);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, TestConnectionIdLength) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
+ creator_.SetServerConnectionIdLength(0);
+ EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID,
+ creator_.GetDestinationConnectionIdLength());
+
+ for (size_t i = 1; i < 10; i++) {
+ creator_.SetServerConnectionIdLength(i);
+ if (VersionHasIetfInvariantHeader(framer_.transport_version())) {
+ EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID,
+ creator_.GetDestinationConnectionIdLength());
+ } else {
+ EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID,
+ creator_.GetDestinationConnectionIdLength());
+ }
+ }
+}
+
+// Test whether SetMaxPacketLength() works in the situation when the queue is
+// empty, and we send three packets worth of data.
+TEST_F(QuicPacketCreatorMultiplePacketsTest, SetMaxPacketLength_Initial) {
+ delegate_.SetCanWriteAnything();
+
+ // Send enough data for three packets.
+ size_t data_len = 3 * kDefaultMaxPacketSize + 1;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxOutgoingPacketSize);
+ creator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, creator_.max_packet_length());
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ CreateData(data_len);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/0, FIN);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // We expect three packets, and first two of them have to be of packet_len
+ // size. We check multiple packets (instead of just one) because we want to
+ // ensure that |max_packet_length_| does not get changed incorrectly by the
+ // creator after first packet is serialized.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(packet_len, packets_[0].encrypted_length);
+ EXPECT_EQ(packet_len, packets_[1].encrypted_length);
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works in the situation when we first write
+// data, then change packet size, then write data again.
+TEST_F(QuicPacketCreatorMultiplePacketsTest, SetMaxPacketLength_Middle) {
+ delegate_.SetCanWriteAnything();
+
+ // We send enough data to overflow default packet length, but not the altered
+ // one.
+ size_t data_len = kDefaultMaxPacketSize;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxOutgoingPacketSize);
+
+ // We expect to see three packets in total.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ // Send two packets before packet size change.
+ CreateData(data_len);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/0, NO_FIN);
+ creator_.Flush();
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // Make sure we already have two packets.
+ ASSERT_EQ(2u, packets_.size());
+
+ // Increase packet size.
+ creator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, creator_.max_packet_length());
+
+ // Send a packet after packet size change.
+ CreateData(data_len);
+ creator_.AttachPacketFlusher();
+ consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, data_len, FIN);
+ creator_.Flush();
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // We expect first data chunk to get fragmented, but the second one to fit
+ // into a single packet.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_LE(kDefaultMaxPacketSize, packets_[2].encrypted_length);
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works correctly when we force the change of
+// the packet size in the middle of the batched packet.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ SetMaxPacketLength_MidpacketFlush) {
+ delegate_.SetCanWriteAnything();
+
+ size_t first_write_len = kDefaultMaxPacketSize / 2;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ size_t second_write_len = packet_len + 1;
+ ASSERT_LE(packet_len, kMaxOutgoingPacketSize);
+
+ // First send half of the packet worth of data. We are in the batch mode, so
+ // should not cause packet serialization.
+ CreateData(first_write_len);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/0, NO_FIN);
+ EXPECT_EQ(first_write_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // Make sure we have no packets so far.
+ ASSERT_EQ(0u, packets_.size());
+
+ // Expect a packet to be flushed.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ // Increase packet size after flushing all frames.
+ // Ensure it's immediately enacted.
+ creator_.FlushCurrentPacket();
+ creator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, creator_.max_packet_length());
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // We expect to see exactly one packet serialized after that, because we send
+ // a value somewhat exceeding new max packet size, and the tail data does not
+ // get serialized because we are still in the batch mode.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ // Send a more than a packet worth of data to the same stream. This should
+ // trigger serialization of one packet, and queue another one.
+ CreateData(second_write_len);
+ consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/first_write_len, FIN);
+ EXPECT_EQ(second_write_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // We expect the first packet to be underfilled, and the second packet be up
+ // to the new max packet size.
+ ASSERT_EQ(2u, packets_.size());
+ EXPECT_GT(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_EQ(packet_len, packets_[1].encrypted_length);
+
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test sending a connectivity probing packet.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ GenerateConnectivityProbingPacket) {
+ delegate_.SetCanWriteAnything();
+
+ OwningSerializedPacketPointer probing_packet;
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ QuicPathFrameBuffer payload = {
+ {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
+ probing_packet =
+ creator_.SerializePathChallengeConnectivityProbingPacket(&payload);
+ } else {
+ probing_packet = creator_.SerializeConnectivityProbingPacket();
+ }
+
+ ASSERT_TRUE(simple_framer_.ProcessPacket(QuicEncryptedPacket(
+ probing_packet->encrypted_buffer, probing_packet->encrypted_length)));
+
+ EXPECT_EQ(2u, simple_framer_.num_frames());
+ if (VersionHasIetfQuicFrames(framer_.transport_version())) {
+ EXPECT_EQ(1u, simple_framer_.path_challenge_frames().size());
+ } else {
+ EXPECT_EQ(1u, simple_framer_.ping_frames().size());
+ }
+ EXPECT_EQ(1u, simple_framer_.padding_frames().size());
+}
+
+// Test sending an MTU probe, without any surrounding data.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ GenerateMtuDiscoveryPacket_Simple) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxOutgoingPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ creator_.GenerateMtuDiscoveryPacket(target_mtu);
+
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+ ASSERT_EQ(1u, packets_.size());
+ EXPECT_EQ(target_mtu, packets_[0].encrypted_length);
+
+ PacketContents contents;
+ contents.num_mtu_discovery_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+// Test sending an MTU probe. Surround it with data, to ensure that it resets
+// the MTU to the value before the probe was sent.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ GenerateMtuDiscoveryPacket_SurroundedByData) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxOutgoingPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ // Send enough data so it would always cause two packets to be sent.
+ const size_t data_len = target_mtu + 1;
+
+ // Send a total of five packets: two packets before the probe, the probe
+ // itself, and two packets after the probe.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(5)
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ // Send data before the MTU probe.
+ CreateData(data_len);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/0, NO_FIN);
+ creator_.Flush();
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // Send the MTU probe.
+ creator_.GenerateMtuDiscoveryPacket(target_mtu);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ // Send data after the MTU probe.
+ CreateData(data_len);
+ creator_.AttachPacketFlusher();
+ consumed = creator_.ConsumeData(
+ QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
+ Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len,
+ /*offset=*/data_len, FIN);
+ creator_.Flush();
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ ASSERT_EQ(5u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_EQ(target_mtu, packets_[2].encrypted_length);
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].encrypted_length);
+
+ PacketContents probe_contents;
+ probe_contents.num_mtu_discovery_frames = 1;
+ probe_contents.num_padding_frames = 1;
+
+ CheckPacketHasSingleStreamFrame(0);
+ CheckPacketHasSingleStreamFrame(1);
+ CheckPacketContains(probe_contents, 2);
+ CheckPacketHasSingleStreamFrame(3);
+ CheckPacketHasSingleStreamFrame(4);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, DontCrashOnInvalidStopWaiting) {
+ if (VersionSupportsMessageFrames(framer_.transport_version())) {
+ return;
+ }
+ // Test added to ensure the creator does not crash when an invalid frame is
+ // added. Because this is an indication of internal programming errors,
+ // DFATALs are expected.
+ // A 1 byte packet number length can't encode a gap of 1000.
+ QuicPacketCreatorPeer::SetPacketNumber(&creator_, 1000);
+
+ delegate_.SetCanNotWrite();
+ delegate_.SetCanWriteAnything();
+
+ // This will not serialize any packets, because of the invalid frame.
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _));
+ EXPECT_QUIC_BUG(creator_.Flush(),
+ "packet_number_length 1 is too small "
+ "for least_unacked_delta: 1001");
+}
+
+// Regression test for b/31486443.
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ ConnectionCloseFrameLargerThanPacketSize) {
+ delegate_.SetCanWriteAnything();
+ char buf[2000] = {};
+ QuicStringPiece error_details(buf, 2000);
+ const QuicErrorCode kQuicErrorCode = QUIC_PACKET_WRITE_ERROR;
+
+ QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(
+ framer_.transport_version(), kQuicErrorCode, std::string(error_details),
+ /*transport_close_frame_type=*/0);
+ creator_.ConsumeRetransmittableControlFrame(QuicFrame(frame),
+ /*bundle_ack=*/false);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ RandomPaddingAfterFinSingleStreamSinglePacket) {
+ const QuicByteCount kStreamFramePayloadSize = 100u;
+ char buf[kStreamFramePayloadSize] = {};
+ const QuicStreamId kDataStreamId = 5;
+ // Set the packet size be enough for one stream frame with 0 stream offset and
+ // max size of random padding.
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_.GetDestinationConnectionIdLength(),
+ creator_.GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(&creator_)) +
+ QuicFramer::GetMinStreamFrameSize(
+ framer_.transport_version(), kDataStreamId, 0,
+ /*last_frame_in_packet=*/false,
+ kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) +
+ kStreamFramePayloadSize + kMaxNumRandomPaddingBytes;
+ creator_.SetMaxPacketLength(length);
+ delegate_.SetCanWriteAnything();
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+ creator_.Flush();
+ EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ EXPECT_EQ(1u, packets_.size());
+ PacketContents contents;
+ // The packet has both stream and padding frames.
+ contents.num_padding_frames = 1;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ RandomPaddingAfterFinSingleStreamMultiplePackets) {
+ const QuicByteCount kStreamFramePayloadSize = 100u;
+ char buf[kStreamFramePayloadSize] = {};
+ const QuicStreamId kDataStreamId = 5;
+ // Set the packet size be enough for one stream frame with 0 stream offset +
+ // 1. One or more packets will accommodate.
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_.GetDestinationConnectionIdLength(),
+ creator_.GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(&creator_)) +
+ QuicFramer::GetMinStreamFrameSize(
+ framer_.transport_version(), kDataStreamId, 0,
+ /*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) +
+ kStreamFramePayloadSize + 1;
+ creator_.SetMaxPacketLength(length);
+ delegate_.SetCanWriteAnything();
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+ creator_.Flush();
+ EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ EXPECT_LE(1u, packets_.size());
+ PacketContents contents;
+ // The first packet has both stream and padding frames.
+ contents.num_stream_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ for (size_t i = 1; i < packets_.size(); ++i) {
+ // Following packets only have paddings.
+ contents.num_stream_frames = 0;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, i);
+ }
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest,
+ RandomPaddingAfterFinMultipleStreamsMultiplePackets) {
+ const QuicByteCount kStreamFramePayloadSize = 100u;
+ char buf[kStreamFramePayloadSize] = {};
+ const QuicStreamId kDataStreamId1 = 5;
+ const QuicStreamId kDataStreamId2 = 6;
+ // Set the packet size be enough for first frame with 0 stream offset + second
+ // frame + 1 byte payload. two or more packets will accommodate.
+ size_t length =
+ NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.transport_version(),
+ creator_.GetDestinationConnectionIdLength(),
+ creator_.GetSourceConnectionIdLength(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_),
+ QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0,
+ QuicPacketCreatorPeer::GetLengthLength(&creator_)) +
+ QuicFramer::GetMinStreamFrameSize(
+ framer_.transport_version(), kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false, kStreamFramePayloadSize) +
+ kStreamFramePayloadSize +
+ QuicFramer::GetMinStreamFrameSize(framer_.transport_version(),
+ kDataStreamId1, 0,
+ /*last_frame_in_packet=*/false, 1) +
+ 1;
+ creator_.SetMaxPacketLength(length);
+ delegate_.SetCanWriteAnything();
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_);
+ QuicConsumedData consumed = creator_.ConsumeData(
+ kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+ EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
+ MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_);
+ consumed = creator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0,
+ FIN_AND_PADDING);
+ EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
+
+ EXPECT_LE(2u, packets_.size());
+ PacketContents contents;
+ // The first packet has two stream frames.
+ contents.num_stream_frames = 2;
+ CheckPacketContains(contents, 0);
+
+ // The second packet has one stream frame and padding frames.
+ contents.num_stream_frames = 1;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, 1);
+
+ for (size_t i = 2; i < packets_.size(); ++i) {
+ // Following packets only have paddings.
+ contents.num_stream_frames = 0;
+ contents.num_padding_frames = 1;
+ CheckPacketContains(contents, i);
+ }
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, AddMessageFrame) {
+ if (!VersionSupportsMessageFrames(framer_.transport_version())) {
+ return;
+ }
+ quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0);
+ delegate_.SetCanWriteAnything();
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(
+ Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+
+ MakeIOVector("foo", &iov_);
+ creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
+ framer_.transport_version(), Perspective::IS_CLIENT),
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ EXPECT_EQ(
+ MESSAGE_STATUS_SUCCESS,
+ creator_.AddMessageFrame(1, MakeSpan(&allocator_, "message", &storage)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // Add a message which causes the flush of current packet.
+ EXPECT_EQ(
+ MESSAGE_STATUS_SUCCESS,
+ creator_.AddMessageFrame(
+ 2,
+ MakeSpan(&allocator_,
+ std::string(creator_.GetCurrentLargestMessagePayload(), 'a'),
+ &storage)));
+ EXPECT_TRUE(creator_.HasPendingRetransmittableFrames());
+
+ // Failed to send messages which cannot fit into one packet.
+ EXPECT_EQ(
+ MESSAGE_STATUS_TOO_LARGE,
+ creator_.AddMessageFrame(
+ 3, MakeSpan(&allocator_,
+ std::string(
+ creator_.GetCurrentLargestMessagePayload() + 10, 'a'),
+ &storage)));
+}
+
+TEST_F(QuicPacketCreatorMultiplePacketsTest, ConnectionId) {
+ creator_.SetServerConnectionId(TestConnectionId(0x1337));
+ EXPECT_EQ(TestConnectionId(0x1337), creator_.GetDestinationConnectionId());
+ EXPECT_EQ(EmptyQuicConnectionId(), creator_.GetSourceConnectionId());
+ if (!framer_.version().SupportsClientConnectionIds()) {
+ return;
+ }
+ creator_.SetClientConnectionId(TestConnectionId(0x33));
+ EXPECT_EQ(TestConnectionId(0x1337), creator_.GetDestinationConnectionId());
+ EXPECT_EQ(TestConnectionId(0x33), creator_.GetSourceConnectionId());
+}
+
} // namespace
} // namespace test
} // namespace quic