| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h" |
| |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| |
| #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" |
| #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" |
| #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" |
| #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_packet_generator_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::InSequence; |
| using testing::Return; |
| using testing::StrictMock; |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| class MockDelegate : public QuicPacketGenerator::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; |
| }; |
| |
| } // namespace |
| |
| class TestPacketGenerator : public QuicPacketGenerator { |
| public: |
| TestPacketGenerator(QuicConnectionId connection_id, |
| QuicFramer* framer, |
| QuicRandom* random_generator, |
| DelegateInterface* delegate, |
| SimpleDataProducer* producer) |
| : QuicPacketGenerator(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 (!QuicPacketGeneratorPeer::GetPacketCreator(this)->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 QuicPacketGenerator::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 QuicPacketGenerator::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 (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && |
| delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, |
| NOT_HANDSHAKE)) { |
| EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); |
| } |
| return QuicPacketGenerator::ConsumeData(id, total_length, offset, state); |
| } |
| |
| MessageStatus AddMessageFrame(QuicMessageId message_id, |
| QuicMemSliceSpan message) { |
| if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && |
| delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, |
| NOT_HANDSHAKE)) { |
| EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); |
| } |
| return QuicPacketGenerator::AddMessageFrame(message_id, message); |
| } |
| |
| size_t ConsumeCryptoData(EncryptionLevel level, |
| QuicStringPiece data, |
| QuicStreamOffset offset) { |
| producer_->SaveCryptoData(level, offset, data); |
| if (!QuicPacketGeneratorPeer::GetPacketCreator(this)->has_ack() && |
| delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, |
| NOT_HANDSHAKE)) { |
| EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1); |
| } |
| return QuicPacketGenerator::ConsumeCryptoData(level, data.length(), offset); |
| } |
| |
| QuicAckFrame ack_frame_; |
| MockDelegate* delegate_; |
| SimpleDataProducer* producer_; |
| }; |
| |
| class QuicPacketGeneratorTest : public QuicTest { |
| public: |
| QuicPacketGeneratorTest() |
| : framer_(AllSupportedVersions(), |
| QuicTime::Zero(), |
| Perspective::IS_CLIENT, |
| kQuicDefaultConnectionIdLength), |
| generator_(TestConnectionId(), |
| &framer_, |
| &random_generator_, |
| &delegate_, |
| &producer_), |
| creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)), |
| ack_frame_(InitAckFrame(1)) { |
| EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); |
| creator_->SetEncrypter( |
| ENCRYPTION_FORWARD_SECURE, |
| QuicMakeUnique<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, |
| QuicMakeUnique<NullDecrypter>(Perspective::IS_SERVER)); |
| } |
| generator_.AttachPacketFlusher(); |
| } |
| |
| ~QuicPacketGeneratorTest() 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_generator_; |
| StrictMock<MockDelegate> delegate_; |
| TestPacketGenerator generator_; |
| QuicPacketCreator* 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_; |
| }; |
| |
| class MockDebugDelegate : public QuicPacketCreator::DebugDelegate { |
| public: |
| MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&)); |
| }; |
| |
| TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { |
| delegate_.SetCanNotWrite(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool consumed = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/false); |
| EXPECT_FALSE(consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| delete rst_frame; |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { |
| delegate_.SetCanWriteOnlyNonRetransmittable(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool consumed = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/false); |
| EXPECT_FALSE(consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| delete rst_frame; |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { |
| delegate_.SetCanWriteAnything(); |
| |
| generator_.ConsumeRetransmittableControlFrame( |
| QuicFrame(CreateRstStreamFrame()), |
| /*bundle_ack=*/false); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { |
| delegate_.SetCanNotWrite(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool consumed = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/false); |
| EXPECT_FALSE(consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| delete rst_frame; |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| |
| generator_.ConsumeRetransmittableControlFrame( |
| QuicFrame(CreateRstStreamFrame()), |
| /*bundle_ack=*/false); |
| generator_.Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| PacketContents contents; |
| contents.num_rst_stream_frames = 1; |
| CheckPacketContains(contents, 0); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeCryptoData) { |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| std::string data = "crypto data"; |
| size_t consumed_bytes = |
| generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); |
| generator_.Flush(); |
| EXPECT_EQ(data.length(), consumed_bytes); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| PacketContents contents; |
| contents.num_crypto_frames = 1; |
| contents.num_padding_frames = 1; |
| CheckPacketContains(contents, 0); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) { |
| delegate_.SetCanNotWrite(); |
| |
| MakeIOVector("foo", &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| EXPECT_EQ(0u, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { |
| delegate_.SetCanWriteAnything(); |
| |
| MakeIOVector("foo", &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| EXPECT_EQ(3u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| MakeIOVector("foo", &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| generator_.Flush(); |
| EXPECT_EQ(3u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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 generator operates in batch mode. |
| TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) { |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| std::string data = "foo bar"; |
| MakeIOVector(data, &iov_); |
| size_t consumed_bytes = 0; |
| if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { |
| consumed_bytes = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); |
| } else { |
| consumed_bytes = |
| generator_ |
| .ConsumeData( |
| QuicUtils::GetCryptoStreamId(framer_.transport_version()), |
| &iov_, 1u, iov_.iov_len, 0, NO_FIN) |
| .bytes_consumed; |
| } |
| EXPECT_EQ(7u, consumed_bytes); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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, generator_.GetCurrentMaxPacketLength()); |
| 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(QuicPacketGeneratorTest, ConsumeData_Handshake_PaddingDisabled) { |
| generator_.set_fully_pad_crypto_hadshake_packets(false); |
| |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| std::string data = "foo"; |
| MakeIOVector(data, &iov_); |
| size_t bytes_consumed = 0; |
| if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { |
| bytes_consumed = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); |
| } else { |
| bytes_consumed = |
| generator_ |
| .ConsumeData( |
| QuicUtils::GetCryptoStreamId(framer_.transport_version()), |
| &iov_, 1u, iov_.iov_len, 0, NO_FIN) |
| .bytes_consumed; |
| } |
| EXPECT_EQ(3u, bytes_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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, generator_.GetCurrentMaxPacketLength()); |
| 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(QuicPacketGeneratorTest, ConsumeData_EmptyData) { |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_QUIC_BUG(generator_.ConsumeData(QuicUtils::GetHeadersStreamId( |
| framer_.transport_version()), |
| nullptr, 0, 0, 0, NO_FIN), |
| "Attempt to consume empty data without FIN."); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, |
| ConsumeDataMultipleTimes_WritableAndShouldNotFlush) { |
| delegate_.SetCanWriteAnything(); |
| |
| MakeIOVector("foo", &iov_); |
| generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| MakeIOVector("quux", &iov_); |
| QuicConsumedData consumed = |
| generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN); |
| EXPECT_EQ(4u, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { |
| delegate_.SetCanWriteAnything(); |
| |
| MakeIOVector("foo", &iov_); |
| generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| MakeIOVector("quux", &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 3, NO_FIN); |
| EXPECT_EQ(4u, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // Now both frames will be flushed out. |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| generator_.Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| PacketContents contents; |
| contents.num_stream_frames = 2; |
| CheckPacketContains(contents, 0); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, 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; |
| generator_.SetMaxPacketLength(length); |
| delegate_.SetCanWriteAnything(); |
| { |
| InSequence dummy; |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| } |
| // Queue enough data to prevent a stream frame with a non-zero offset from |
| // fitting. |
| MakeIOVector("foo", &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, NO_FIN); |
| EXPECT_EQ(3u, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // 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 = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 3, FIN); |
| EXPECT_EQ(3u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| creator_->Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| PacketContents contents; |
| contents.num_stream_frames = 1; |
| CheckPacketContains(contents, 0); |
| CheckPacketContains(contents, 1); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) { |
| delegate_.SetCanWriteAnything(); |
| generator_.SetCanSetTransmissionType(true); |
| generator_.SetTransmissionType(LOSS_RETRANSMISSION); |
| |
| // Create a 10000 byte IOVector. |
| CreateData(10000); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| QuicConsumedData consumed = generator_.ConsumeDataFastPath( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, true); |
| EXPECT_EQ(10000u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, ConsumeDataLarge) { |
| delegate_.SetCanWriteAnything(); |
| |
| // Create a 10000 byte IOVector. |
| CreateData(10000); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| EXPECT_EQ(10000u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, ConsumeDataLargeSendAckFalse) { |
| delegate_.SetCanNotWrite(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool success = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/true); |
| EXPECT_FALSE(success); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| delegate_.SetCanWriteAnything(); |
| |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/false); |
| |
| // Create a 10000 byte IOVector. |
| CreateData(10000); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| generator_.ConsumeRetransmittableControlFrame( |
| QuicFrame(CreateRstStreamFrame()), |
| /*bundle_ack=*/true); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| generator_.Flush(); |
| |
| EXPECT_EQ(10000u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, 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, &QuicPacketGeneratorTest::SavePacket)); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| generator_.Flush(); |
| |
| EXPECT_EQ(10000u, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { |
| delegate_.SetCanNotWrite(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool consumed = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/true); |
| EXPECT_FALSE(consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| EXPECT_FALSE(generator_.HasPendingStreamFramesOfStream(3)); |
| |
| delegate_.SetCanWriteAnything(); |
| |
| EXPECT_TRUE( |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/false)); |
| // Send some data and a control frame |
| MakeIOVector("quux", &iov_); |
| generator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN); |
| if (!VersionHasIetfQuicFrames(framer_.transport_version())) { |
| generator_.ConsumeRetransmittableControlFrame( |
| QuicFrame(CreateGoAwayFrame()), |
| /*bundle_ack=*/false); |
| } |
| EXPECT_TRUE(generator_.HasPendingStreamFramesOfStream(3)); |
| |
| // All five frames will be flushed out in a single packet. |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| generator_.Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| EXPECT_FALSE(generator_.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(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { |
| delegate_.SetCanNotWrite(); |
| |
| QuicRstStreamFrame* rst_frame = CreateRstStreamFrame(); |
| const bool success = |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame), |
| /*bundle_ack=*/true); |
| EXPECT_FALSE(success); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| delegate_.SetCanWriteAnything(); |
| |
| { |
| InSequence dummy; |
| // All five frames will be flushed out in a single packet |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| } |
| EXPECT_TRUE( |
| generator_.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 = |
| generator_.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())) { |
| generator_.ConsumeRetransmittableControlFrame( |
| QuicFrame(CreateGoAwayFrame()), |
| /*bundle_ack=*/false); |
| } |
| |
| generator_.Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // 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(QuicPacketGeneratorTest, PacketTransmissionType) { |
| delegate_.SetCanWriteAnything(); |
| generator_.SetCanSetTransmissionType(true); |
| |
| // The first ConsumeData will fill the packet without flush. |
| generator_.SetTransmissionType(LOSS_RETRANSMISSION); |
| |
| size_t data_len = 1324; |
| CreateData(data_len); |
| QuicStreamId stream1_id = |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()); |
| QuicConsumedData consumed = |
| generator_.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. |
| generator_.SetTransmissionType(NOT_RETRANSMISSION); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| |
| QuicStreamId stream2_id = stream1_id + 4; |
| |
| consumed = |
| generator_.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(QuicPacketGeneratorTest, TestConnectionIdLength) { |
| QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); |
| generator_.SetServerConnectionIdLength(0); |
| EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, |
| creator_->GetDestinationConnectionIdLength()); |
| |
| for (size_t i = 1; i < 10; i++) { |
| generator_.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(QuicPacketGeneratorTest, 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); |
| generator_.SetMaxPacketLength(packet_len); |
| EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); |
| |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .Times(3) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| CreateData(data_len); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, |
| /*offset=*/0, FIN); |
| EXPECT_EQ(data_len, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // 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 |
| // generator 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(QuicPacketGeneratorTest, 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, &QuicPacketGeneratorTest::SavePacket)); |
| |
| // Send two packets before packet size change. |
| CreateData(data_len); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, |
| /*offset=*/0, NO_FIN); |
| generator_.Flush(); |
| EXPECT_EQ(data_len, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // Make sure we already have two packets. |
| ASSERT_EQ(2u, packets_.size()); |
| |
| // Increase packet size. |
| generator_.SetMaxPacketLength(packet_len); |
| EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); |
| |
| // Send a packet after packet size change. |
| CreateData(data_len); |
| generator_.AttachPacketFlusher(); |
| consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, data_len, FIN); |
| generator_.Flush(); |
| EXPECT_EQ(data_len, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // 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(QuicPacketGeneratorTest, 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 = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, |
| /*offset=*/0, NO_FIN); |
| EXPECT_EQ(first_write_len, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // 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, &QuicPacketGeneratorTest::SavePacket)); |
| |
| // Increase packet size after flushing all frames. |
| // Ensure it's immediately enacted. |
| generator_.FlushAllQueuedFrames(); |
| generator_.SetMaxPacketLength(packet_len); |
| EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // 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, &QuicPacketGeneratorTest::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 = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &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(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // 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(QuicPacketGeneratorTest, GenerateConnectivityProbingPacket) { |
| delegate_.SetCanWriteAnything(); |
| |
| OwningSerializedPacketPointer probing_packet; |
| if (VersionHasIetfQuicFrames(framer_.transport_version())) { |
| QuicPathFrameBuffer payload = { |
| {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}}; |
| probing_packet = |
| generator_.SerializePathChallengeConnectivityProbingPacket(&payload); |
| } else { |
| probing_packet = generator_.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(QuicPacketGeneratorTest, 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, &QuicPacketGeneratorTest::SavePacket)); |
| |
| generator_.GenerateMtuDiscoveryPacket(target_mtu); |
| |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| 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(QuicPacketGeneratorTest, 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, &QuicPacketGeneratorTest::SavePacket)); |
| |
| // Send data before the MTU probe. |
| CreateData(data_len); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, |
| /*offset=*/0, NO_FIN); |
| generator_.Flush(); |
| EXPECT_EQ(data_len, consumed.bytes_consumed); |
| EXPECT_FALSE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // Send the MTU probe. |
| generator_.GenerateMtuDiscoveryPacket(target_mtu); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| // Send data after the MTU probe. |
| CreateData(data_len); |
| generator_.AttachPacketFlusher(); |
| consumed = generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, |
| /*offset=*/data_len, FIN); |
| generator_.Flush(); |
| EXPECT_EQ(data_len, consumed.bytes_consumed); |
| EXPECT_TRUE(consumed.fin_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) { |
| if (VersionSupportsMessageFrames(framer_.transport_version())) { |
| return; |
| } |
| // Test added to ensure the generator 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(generator_.Flush(), |
| "packet_number_length 1 is too small " |
| "for least_unacked_delta: 1001"); |
| } |
| |
| // Regression test for b/31486443. |
| TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) { |
| delegate_.SetCanWriteAnything(); |
| char buf[2000] = {}; |
| QuicStringPiece error_details(buf, 2000); |
| QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame( |
| QUIC_PACKET_WRITE_ERROR, std::string(error_details)); |
| if (VersionHasIetfQuicFrames(framer_.transport_version())) { |
| frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; |
| } |
| generator_.ConsumeRetransmittableControlFrame(QuicFrame(frame), |
| /*bundle_ack=*/false); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, 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; |
| generator_.SetMaxPacketLength(length); |
| delegate_.SetCanWriteAnything(); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); |
| generator_.Flush(); |
| EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, |
| 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; |
| generator_.SetMaxPacketLength(length); |
| delegate_.SetCanWriteAnything(); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); |
| generator_.Flush(); |
| EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, |
| 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; |
| generator_.SetMaxPacketLength(length); |
| delegate_.SetCanWriteAnything(); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); |
| QuicConsumedData consumed = generator_.ConsumeData( |
| kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING); |
| EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); |
| MakeIOVector(QuicStringPiece(buf, kStreamFramePayloadSize), &iov_); |
| consumed = generator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0, |
| FIN_AND_PADDING); |
| EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed); |
| generator_.Flush(); |
| EXPECT_FALSE(generator_.HasPendingFrames()); |
| EXPECT_FALSE(generator_.HasRetransmittableFrames()); |
| |
| 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(QuicPacketGeneratorTest, AddMessageFrame) { |
| if (!VersionSupportsMessageFrames(framer_.transport_version())) { |
| return; |
| } |
| quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); |
| delegate_.SetCanWriteAnything(); |
| EXPECT_CALL(delegate_, OnSerializedPacket(_)) |
| .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); |
| |
| MakeIOVector("foo", &iov_); |
| generator_.ConsumeData( |
| QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, |
| iov_.iov_len, 0, FIN); |
| EXPECT_EQ(MESSAGE_STATUS_SUCCESS, |
| generator_.AddMessageFrame( |
| 1, MakeSpan(&allocator_, "message", &storage))); |
| EXPECT_TRUE(generator_.HasPendingFrames()); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // Add a message which causes the flush of current packet. |
| EXPECT_EQ( |
| MESSAGE_STATUS_SUCCESS, |
| generator_.AddMessageFrame( |
| 2, MakeSpan( |
| &allocator_, |
| std::string(generator_.GetCurrentLargestMessagePayload(), 'a'), |
| &storage))); |
| EXPECT_TRUE(generator_.HasRetransmittableFrames()); |
| |
| // Failed to send messages which cannot fit into one packet. |
| EXPECT_EQ( |
| MESSAGE_STATUS_TOO_LARGE, |
| generator_.AddMessageFrame( |
| 3, |
| MakeSpan(&allocator_, |
| std::string( |
| generator_.GetCurrentLargestMessagePayload() + 10, 'a'), |
| &storage))); |
| } |
| |
| TEST_F(QuicPacketGeneratorTest, ConnectionId) { |
| SetQuicRestartFlag(quic_do_not_override_connection_id, true); |
| generator_.SetServerConnectionId(TestConnectionId(0x1337)); |
| EXPECT_EQ(TestConnectionId(0x1337), creator_->GetDestinationConnectionId()); |
| EXPECT_EQ(EmptyQuicConnectionId(), creator_->GetSourceConnectionId()); |
| if (!framer_.version().SupportsClientConnectionIds()) { |
| return; |
| } |
| generator_.SetClientConnectionId(TestConnectionId(0x33)); |
| EXPECT_EQ(TestConnectionId(0x1337), creator_->GetDestinationConnectionId()); |
| EXPECT_EQ(TestConnectionId(0x33), creator_->GetSourceConnectionId()); |
| } |
| |
| } // namespace test |
| } // namespace quic |