blob: 7a7701ef86c33fe9ca4a0efded8b13ceec25fa84 [file] [log] [blame]
// 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 <utility>
#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 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;
};
} // namespace
class TestPacketGenerator : public QuicPacketGenerator {
public:
TestPacketGenerator(QuicConnectionId connection_id,
QuicFramer* framer,
QuicRandom* random_generator,
QuicPacketCreator::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,
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));
}
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::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(generator_.HasPendingFrames());
EXPECT_FALSE(generator_.HasRetransmittableFrames());
}
TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
MakeIOVector("foo", &iov_);
QuicConsumedData consumed = generator_.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(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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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_handshake_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::QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&iov_, 1u, iov_.iov_len, 0, NO_FIN);
MakeIOVector("quux", &iov_);
QuicConsumedData consumed = generator_.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(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 =
GetQuicReloadableFlag(quic_coalesce_stream_frames) ? 1 : 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::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(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::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(generator_.HasPendingFrames());
EXPECT_TRUE(generator_.HasRetransmittableFrames());
creator_->FlushCurrentPacket();
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_.SetTransmissionType(LOSS_RETRANSMISSION);
// Create a 10000 byte IOVector.
CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
QuicConsumedData consumed = generator_.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(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::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(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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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();
// 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::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT);
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::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(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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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::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(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::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(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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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);
const QuicErrorCode kQuicErrorCode = QUIC_PACKET_WRITE_ERROR;
QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(
framer_.transport_version(), kQuicErrorCode, std::string(error_details),
/*transport_close_frame_type=*/0);
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::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
&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) {
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