| // Copyright (c) 2019 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 "quiche/quic/core/quic_coalesced_packet.h" | 
 |  | 
 | #include "quiche/quic/platform/api/quic_expect_bug.h" | 
 | #include "quiche/quic/platform/api/quic_test.h" | 
 | #include "quiche/quic/test_tools/quic_test_utils.h" | 
 | #include "quiche/common/test_tools/quiche_test_utils.h" | 
 |  | 
 | namespace quic { | 
 | namespace test { | 
 | namespace { | 
 |  | 
 | TEST(QuicCoalescedPacketTest, MaybeCoalescePacket) { | 
 |   QuicCoalescedPacket coalesced; | 
 |   EXPECT_EQ("total_length: 0 padding_size: 0 packets: {}", | 
 |             coalesced.ToString(0)); | 
 |   quiche::SimpleBufferAllocator allocator; | 
 |   EXPECT_EQ(0u, coalesced.length()); | 
 |   EXPECT_EQ(0u, coalesced.NumberOfPackets()); | 
 |   char buffer[1000]; | 
 |   QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); | 
 |   QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); | 
 |   SerializedPacket packet1(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   packet1.transmission_type = PTO_RETRANSMISSION; | 
 |   QuicAckFrame ack_frame(InitAckFrame(1)); | 
 |   packet1.nonretransmittable_frames.push_back(QuicFrame(&ack_frame)); | 
 |   packet1.retransmittable_frames.push_back( | 
 |       QuicFrame(QuicStreamFrame(1, true, 0, 100))); | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(PTO_RETRANSMISSION, | 
 |             coalesced.TransmissionTypeOfPacket(ENCRYPTION_INITIAL)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(500u, coalesced.length()); | 
 |   EXPECT_EQ(1u, coalesced.NumberOfPackets()); | 
 |   EXPECT_EQ( | 
 |       "total_length: 1500 padding_size: 1000 packets: {ENCRYPTION_INITIAL}", | 
 |       coalesced.ToString(1500)); | 
 |  | 
 |   // Cannot coalesce packet of the same encryption level. | 
 |   SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   EXPECT_FALSE(coalesced.MaybeCoalescePacket(packet2, self_address, | 
 |                                              peer_address, &allocator, 1500)); | 
 |  | 
 |   SerializedPacket packet3(QuicPacketNumber(3), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   packet3.nonretransmittable_frames.push_back(QuicFrame(QuicPaddingFrame(100))); | 
 |   packet3.encryption_level = ENCRYPTION_ZERO_RTT; | 
 |   packet3.transmission_type = LOSS_RETRANSMISSION; | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1000u, coalesced.length()); | 
 |   EXPECT_EQ(2u, coalesced.NumberOfPackets()); | 
 |   EXPECT_EQ(LOSS_RETRANSMISSION, | 
 |             coalesced.TransmissionTypeOfPacket(ENCRYPTION_ZERO_RTT)); | 
 |   EXPECT_EQ( | 
 |       "total_length: 1500 padding_size: 500 packets: {ENCRYPTION_INITIAL, " | 
 |       "ENCRYPTION_ZERO_RTT}", | 
 |       coalesced.ToString(1500)); | 
 |  | 
 |   SerializedPacket packet4(QuicPacketNumber(4), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   packet4.encryption_level = ENCRYPTION_FORWARD_SECURE; | 
 |   // Cannot coalesce packet of changed self/peer address. | 
 |   EXPECT_FALSE(coalesced.MaybeCoalescePacket( | 
 |       packet4, QuicSocketAddress(QuicIpAddress::Loopback4(), 3), peer_address, | 
 |       &allocator, 1500)); | 
 |  | 
 |   // Packet does not fit. | 
 |   SerializedPacket packet5(QuicPacketNumber(5), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 501, false, false); | 
 |   packet5.encryption_level = ENCRYPTION_FORWARD_SECURE; | 
 |   EXPECT_FALSE(coalesced.MaybeCoalescePacket(packet5, self_address, | 
 |                                              peer_address, &allocator, 1500)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1000u, coalesced.length()); | 
 |   EXPECT_EQ(2u, coalesced.NumberOfPackets()); | 
 |  | 
 |   // Max packet number length changed. | 
 |   SerializedPacket packet6(QuicPacketNumber(6), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 100, false, false); | 
 |   packet6.encryption_level = ENCRYPTION_FORWARD_SECURE; | 
 |   EXPECT_QUIC_BUG(coalesced.MaybeCoalescePacket(packet6, self_address, | 
 |                                                 peer_address, &allocator, 1000), | 
 |                   "Max packet length changes in the middle of the write path"); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1000u, coalesced.length()); | 
 |   EXPECT_EQ(2u, coalesced.NumberOfPackets()); | 
 | } | 
 |  | 
 | TEST(QuicCoalescedPacketTest, CopyEncryptedBuffers) { | 
 |   QuicCoalescedPacket coalesced; | 
 |   quiche::SimpleBufferAllocator allocator; | 
 |   QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); | 
 |   QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); | 
 |   std::string buffer(500, 'a'); | 
 |   std::string buffer2(500, 'b'); | 
 |   SerializedPacket packet1(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer.data(), 500, | 
 |                            /*has_ack=*/false, /*has_stop_waiting=*/false); | 
 |   packet1.encryption_level = ENCRYPTION_ZERO_RTT; | 
 |   SerializedPacket packet2(QuicPacketNumber(2), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer2.data(), 500, | 
 |                            /*has_ack=*/false, /*has_stop_waiting=*/false); | 
 |   packet2.encryption_level = ENCRYPTION_FORWARD_SECURE; | 
 |  | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet2, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(1000u, coalesced.length()); | 
 |  | 
 |   char copy_buffer[1000]; | 
 |   size_t length_copied = 0; | 
 |   EXPECT_FALSE( | 
 |       coalesced.CopyEncryptedBuffers(copy_buffer, 900, &length_copied)); | 
 |   ASSERT_TRUE( | 
 |       coalesced.CopyEncryptedBuffers(copy_buffer, 1000, &length_copied)); | 
 |   EXPECT_EQ(1000u, length_copied); | 
 |   char expected[1000]; | 
 |   memset(expected, 'a', 500); | 
 |   memset(expected + 500, 'b', 500); | 
 |   quiche::test::CompareCharArraysWithHexError("copied buffers", copy_buffer, | 
 |                                               length_copied, expected, 1000); | 
 | } | 
 |  | 
 | TEST(QuicCoalescedPacketTest, NeuterInitialPacket) { | 
 |   QuicCoalescedPacket coalesced; | 
 |   EXPECT_EQ("total_length: 0 padding_size: 0 packets: {}", | 
 |             coalesced.ToString(0)); | 
 |   // Noop when neutering initial packet on a empty coalescer. | 
 |   coalesced.NeuterInitialPacket(); | 
 |   EXPECT_EQ("total_length: 0 padding_size: 0 packets: {}", | 
 |             coalesced.ToString(0)); | 
 |  | 
 |   quiche::SimpleBufferAllocator allocator; | 
 |   EXPECT_EQ(0u, coalesced.length()); | 
 |   char buffer[1000]; | 
 |   QuicSocketAddress self_address(QuicIpAddress::Loopback4(), 1); | 
 |   QuicSocketAddress peer_address(QuicIpAddress::Loopback4(), 2); | 
 |   SerializedPacket packet1(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   packet1.transmission_type = PTO_RETRANSMISSION; | 
 |   QuicAckFrame ack_frame(InitAckFrame(1)); | 
 |   packet1.nonretransmittable_frames.push_back(QuicFrame(&ack_frame)); | 
 |   packet1.retransmittable_frames.push_back( | 
 |       QuicFrame(QuicStreamFrame(1, true, 0, 100))); | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(PTO_RETRANSMISSION, | 
 |             coalesced.TransmissionTypeOfPacket(ENCRYPTION_INITIAL)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(500u, coalesced.length()); | 
 |   EXPECT_EQ( | 
 |       "total_length: 1500 padding_size: 1000 packets: {ENCRYPTION_INITIAL}", | 
 |       coalesced.ToString(1500)); | 
 |   // Neuter initial packet. | 
 |   coalesced.NeuterInitialPacket(); | 
 |   EXPECT_EQ(0u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(0u, coalesced.length()); | 
 |   EXPECT_EQ("total_length: 0 padding_size: 0 packets: {}", | 
 |             coalesced.ToString(0)); | 
 |  | 
 |   // Coalesce initial packet again. | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet1, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |  | 
 |   SerializedPacket packet2(QuicPacketNumber(3), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 500, false, false); | 
 |   packet2.nonretransmittable_frames.push_back(QuicFrame(QuicPaddingFrame(100))); | 
 |   packet2.encryption_level = ENCRYPTION_ZERO_RTT; | 
 |   packet2.transmission_type = LOSS_RETRANSMISSION; | 
 |   ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet2, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1000u, coalesced.length()); | 
 |   EXPECT_EQ(LOSS_RETRANSMISSION, | 
 |             coalesced.TransmissionTypeOfPacket(ENCRYPTION_ZERO_RTT)); | 
 |   EXPECT_EQ( | 
 |       "total_length: 1500 padding_size: 500 packets: {ENCRYPTION_INITIAL, " | 
 |       "ENCRYPTION_ZERO_RTT}", | 
 |       coalesced.ToString(1500)); | 
 |  | 
 |   // Neuter initial packet. | 
 |   coalesced.NeuterInitialPacket(); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(500u, coalesced.length()); | 
 |   EXPECT_EQ( | 
 |       "total_length: 1500 padding_size: 1000 packets: {ENCRYPTION_ZERO_RTT}", | 
 |       coalesced.ToString(1500)); | 
 |  | 
 |   SerializedPacket packet3(QuicPacketNumber(5), PACKET_4BYTE_PACKET_NUMBER, | 
 |                            buffer, 501, false, false); | 
 |   packet3.encryption_level = ENCRYPTION_FORWARD_SECURE; | 
 |   EXPECT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, | 
 |                                             &allocator, 1500)); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1001u, coalesced.length()); | 
 |   // Neuter initial packet. | 
 |   coalesced.NeuterInitialPacket(); | 
 |   EXPECT_EQ(1500u, coalesced.max_packet_length()); | 
 |   EXPECT_EQ(1001u, coalesced.length()); | 
 | } | 
 |  | 
 | }  // namespace | 
 | }  // namespace test | 
 | }  // namespace quic |