gfe-relnote: Add QuicCoalescedPacket class. Not used in prod, not protected. PiperOrigin-RevId: 276269515 Change-Id: I66c08eedac83bf190f871be093bfea9ec99967c9
diff --git a/quic/core/quic_coalesced_packet.cc b/quic/core/quic_coalesced_packet.cc new file mode 100644 index 0000000..62eee42 --- /dev/null +++ b/quic/core/quic_coalesced_packet.cc
@@ -0,0 +1,103 @@ +// 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 "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" + +namespace quic { + +QuicCoalescedPacket::QuicCoalescedPacket() + : length_(0), max_packet_length_(0) {} + +QuicCoalescedPacket::~QuicCoalescedPacket() { + Clear(); +} + +bool QuicCoalescedPacket::MaybeCoalescePacket( + const SerializedPacket& packet, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicBufferAllocator* allocator, + QuicPacketLength current_max_packet_length) { + if (packet.encrypted_length == 0) { + QUIC_BUG << "Trying to coalesce an empty packet"; + return true; + } + if (length_ == 0) { +#ifndef NDEBUG + for (const auto& buffer : encrypted_buffers_) { + DCHECK(buffer.empty()); + } +#endif + DCHECK(initial_packet_ == nullptr); + // This is the first packet, set max_packet_length and self/peer + // addresses. + max_packet_length_ = current_max_packet_length; + self_address_ = self_address; + peer_address_ = peer_address; + } else { + if (self_address_ != self_address || peer_address_ != peer_address) { + // Do not coalesce packet with different self/peer addresses. + QUIC_DLOG(INFO) + << "Cannot coalesce packet because self/peer address changed"; + return false; + } + if (max_packet_length_ != current_max_packet_length) { + QUIC_DLOG(INFO) + << "Do not try to coalesce packet when max packet length changed."; + return false; + } + if (!encrypted_buffers_[packet.encryption_level].empty() || + (packet.encryption_level == ENCRYPTION_INITIAL && + initial_packet_ != nullptr)) { + // Do not coalesce packets of the same encryption level. + return false; + } + } + + if (packet.encryption_level == ENCRYPTION_INITIAL) { + for (const auto& frame : packet.nonretransmittable_frames) { + if (frame.type == PADDING_FRAME) { + QUIC_BUG << "ENCRYPTION_INITIAL packet should not contain padding " + "frame if trying to send coalesced packet"; + return false; + } + } + } + if (length_ + packet.encrypted_length > max_packet_length_) { + // Packet does not fit. + return false; + } + + length_ += packet.encrypted_length; + if (packet.encryption_level == ENCRYPTION_INITIAL) { + // Save a copy of ENCRYPTION_INITIAL packet (excluding encrypted buffer, as + // the packet will be re-serialized later). + initial_packet_ = QuicWrapUnique<SerializedPacket>( + CopySerializedPacket(packet, allocator, /*copy_buffer=*/false)); + return true; + } + // Copy encrypted buffer of packets with other encryption levels. + encrypted_buffers_[packet.encryption_level] = + std::string(packet.encrypted_buffer, packet.encrypted_length); + return true; +} + +void QuicCoalescedPacket::Clear() { + self_address_ = QuicSocketAddress(); + peer_address_ = QuicSocketAddress(); + length_ = 0; + max_packet_length_ = 0; + for (auto& packet : encrypted_buffers_) { + packet.clear(); + } + if (initial_packet_ != nullptr) { + ClearSerializedPacket(initial_packet_.get()); + } + initial_packet_ = nullptr; +} + +} // namespace quic
diff --git a/quic/core/quic_coalesced_packet.h b/quic/core/quic_coalesced_packet.h new file mode 100644 index 0000000..9fbdff2 --- /dev/null +++ b/quic/core/quic_coalesced_packet.h
@@ -0,0 +1,59 @@ +// 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. + +#ifndef QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_ +#define QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_ + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" + +namespace quic { + +// QuicCoalescedPacket is used to buffer multiple packets which can be coalesced +// into the same UDP datagram. +class QUIC_EXPORT_PRIVATE QuicCoalescedPacket { + public: + QuicCoalescedPacket(); + ~QuicCoalescedPacket(); + + // Returns true if |packet| is successfully coalesced with existing packets. + // Returns false otherwise. + bool MaybeCoalescePacket(const SerializedPacket& packet, + const QuicSocketAddress& self_address, + const QuicSocketAddress& peer_address, + QuicBufferAllocator* allocator, + QuicPacketLength current_max_packet_length); + + // Clears this coalesced packet. + void Clear(); + + QuicPacketLength length() const { return length_; } + + QuicPacketLength max_packet_length() const { return max_packet_length_; } + + private: + // self/peer addresses are set when trying to coalesce the first packet. + // Packets with different self/peer addresses cannot be coalesced. + QuicSocketAddress self_address_; + QuicSocketAddress peer_address_; + // Length of this coalesced packet. + QuicPacketLength length_; + // Max packet length. Do not try to coalesce packet when max packet length + // changes (e.g., with MTU discovery). + QuicPacketLength max_packet_length_; + // Copies of packets' encrypted buffers according to different encryption + // levels. + // TODO(fayang): Test serialization when implementing + // QuicPacketCreator::SerializeCoalescedPacket. + std::string encrypted_buffers_[NUM_ENCRYPTION_LEVELS]; + + // A copy of ENCRYPTION_INITIAL packet if this coalesced packet contains one. + // Null otherwise. Please note, the encrypted_buffer field is not copied. The + // frames are copied to allow it be re-serialized when this coalesced packet + // gets sent. + std::unique_ptr<SerializedPacket> initial_packet_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_COALESCED_PACKET_H_
diff --git a/quic/core/quic_coalesced_packet_test.cc b/quic/core/quic_coalesced_packet_test.cc new file mode 100644 index 0000000..aa6b781 --- /dev/null +++ b/quic/core/quic_coalesced_packet_test.cc
@@ -0,0 +1,76 @@ +// 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 "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +TEST(QuicCoalescedPacketTest, MaybeCoalescePacket) { + QuicCoalescedPacket coalesced; + 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); + 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(1500u, coalesced.max_packet_length()); + EXPECT_EQ(500u, coalesced.length()); + + // 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; + ASSERT_TRUE(coalesced.MaybeCoalescePacket(packet3, self_address, peer_address, + &allocator, 1500)); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(1000u, coalesced.length()); + + 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()); + + // Max packet number length changed. + SerializedPacket packet6(QuicPacketNumber(6), PACKET_4BYTE_PACKET_NUMBER, + buffer, 100, false, false); + packet6.encryption_level = ENCRYPTION_FORWARD_SECURE; + EXPECT_FALSE(coalesced.MaybeCoalescePacket(packet6, self_address, + peer_address, &allocator, 1000)); + EXPECT_EQ(1500u, coalesced.max_packet_length()); + EXPECT_EQ(1000u, coalesced.length()); +} + +} // namespace +} // namespace test +} // namespace quic