Deliver INITIAL packets before other packets.
Protected by FLAGS_quic_reloadable_flag_quic_deliver_initial_packets_first.
PiperOrigin-RevId: 442825047
diff --git a/quiche/quic/core/quic_buffered_packet_store.cc b/quiche/quic/core/quic_buffered_packet_store.cc
index d5aa841..0269cdf 100644
--- a/quiche/quic/core/quic_buffered_packet_store.cc
+++ b/quiche/quic/core/quic_buffered_packet_store.cc
@@ -6,6 +6,10 @@
#include <string>
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_types.h"
+#include "quiche/quic/core/quic_versions.h"
#include "quiche/quic/platform/api/quic_bug_tracker.h"
#include "quiche/quic/platform/api/quic_flags.h"
@@ -176,6 +180,39 @@
if (it != undecryptable_packets_.end()) {
packets_to_deliver = std::move(it->second);
undecryptable_packets_.erase(connection_id);
+ if (GetQuicReloadableFlag(quic_deliver_initial_packets_first)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_deliver_initial_packets_first);
+ std::list<BufferedPacket> initial_packets;
+ std::list<BufferedPacket> other_packets;
+ for (auto& packet : packets_to_deliver.buffered_packets) {
+ QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+ PacketHeaderFormat unused_format;
+ bool unused_version_flag;
+ bool unused_use_length_prefix;
+ QuicVersionLabel unused_version_label;
+ ParsedQuicVersion unused_parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId unused_destination_connection_id;
+ QuicConnectionId unused_source_connection_id;
+ absl::optional<absl::string_view> unused_retry_token;
+ std::string unused_detailed_error;
+
+ QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ *packet.packet, kQuicDefaultConnectionIdLength, &unused_format,
+ &long_packet_type, &unused_version_flag, &unused_use_length_prefix,
+ &unused_version_label, &unused_parsed_version,
+ &unused_destination_connection_id, &unused_source_connection_id,
+ &unused_retry_token, &unused_detailed_error);
+
+ if (error_code == QUIC_NO_ERROR && long_packet_type == INITIAL) {
+ initial_packets.push_back(std::move(packet));
+ } else {
+ other_packets.push_back(std::move(packet));
+ }
+ }
+
+ initial_packets.splice(initial_packets.end(), other_packets);
+ packets_to_deliver.buffered_packets = std::move(initial_packets);
+ }
}
return packets_to_deliver;
}
diff --git a/quiche/quic/core/quic_buffered_packet_store_test.cc b/quiche/quic/core/quic_buffered_packet_store_test.cc
index b6d65e1..012ae6e 100644
--- a/quiche/quic/core/quic_buffered_packet_store_test.cc
+++ b/quiche/quic/core/quic_buffered_packet_store_test.cc
@@ -5,8 +5,13 @@
#include "quiche/quic/core/quic_buffered_packet_store.h"
#include <list>
+#include <memory>
#include <string>
+#include "quiche/quic/core/crypto/transport_parameters.h"
+#include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_versions.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/quic/platform/api/quic_test.h"
@@ -30,7 +35,14 @@
using BufferedPacket = QuicBufferedPacketStore::BufferedPacket;
using BufferedPacketList = QuicBufferedPacketStore::BufferedPacketList;
using EnqueuePacketResult = QuicBufferedPacketStore::EnqueuePacketResult;
+using ::testing::A;
+using ::testing::Conditional;
+using ::testing::Each;
using ::testing::ElementsAre;
+using ::testing::Ne;
+using ::testing::SizeIs;
+using ::testing::Truly;
+
class QuicBufferedPacketStoreVisitor
: public QuicBufferedPacketStore::VisitorInterface {
public:
@@ -497,6 +509,94 @@
EXPECT_FALSE(resumption_attempted);
EXPECT_FALSE(early_data_attempted);
}
+
+TEST_F(QuicBufferedPacketStoreTest, DeliverInitialPacketsFirst) {
+ QuicConfig config;
+ QuicConnectionId connection_id = TestConnectionId(1);
+
+ // Force the TLS CHLO to span multiple packets.
+ constexpr auto kCustomParameterId =
+ static_cast<TransportParameters::TransportParameterId>(0xff33);
+ std::string custom_parameter_value(2000, '-');
+ config.custom_transport_parameters_to_send()[kCustomParameterId] =
+ custom_parameter_value;
+ auto initial_packets = GetFirstFlightOfPackets(valid_version_, config);
+ ASSERT_THAT(initial_packets, SizeIs(2));
+
+ // Verify that the packets generated are INITIAL packets.
+ EXPECT_THAT(
+ initial_packets,
+ Each(Truly([](const std::unique_ptr<QuicReceivedPacket>& packet) {
+ QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+ PacketHeaderFormat unused_format;
+ bool unused_version_flag;
+ bool unused_use_length_prefix;
+ QuicVersionLabel unused_version_label;
+ ParsedQuicVersion unused_parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId unused_destination_connection_id;
+ QuicConnectionId unused_source_connection_id;
+ absl::optional<absl::string_view> unused_retry_token;
+ std::string unused_detailed_error;
+ QuicErrorCode error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ *packet, kQuicDefaultConnectionIdLength, &unused_format,
+ &long_packet_type, &unused_version_flag, &unused_use_length_prefix,
+ &unused_version_label, &unused_parsed_version,
+ &unused_destination_connection_id, &unused_source_connection_id,
+ &unused_retry_token, &unused_detailed_error);
+ return error_code == QUIC_NO_ERROR && long_packet_type == INITIAL;
+ })));
+
+ QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE;
+ PacketHeaderFormat unused_format;
+ bool unused_version_flag;
+ bool unused_use_length_prefix;
+ QuicVersionLabel unused_version_label;
+ ParsedQuicVersion unused_parsed_version = UnsupportedQuicVersion();
+ QuicConnectionId unused_destination_connection_id;
+ QuicConnectionId unused_source_connection_id;
+ absl::optional<absl::string_view> unused_retry_token;
+ std::string unused_detailed_error;
+ QuicErrorCode error_code = QUIC_NO_ERROR;
+
+ // Verify that packet_ is not an INITIAL packet.
+ error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ packet_, kQuicDefaultConnectionIdLength, &unused_format,
+ &long_packet_type, &unused_version_flag, &unused_use_length_prefix,
+ &unused_version_label, &unused_parsed_version,
+ &unused_destination_connection_id, &unused_source_connection_id,
+ &unused_retry_token, &unused_detailed_error);
+ EXPECT_THAT(error_code, IsQuicNoError());
+ EXPECT_NE(long_packet_type, INITIAL);
+
+ store_.EnqueuePacket(connection_id, false, packet_, self_address_,
+ peer_address_, valid_version_, kNoParsedChlo);
+ store_.EnqueuePacket(connection_id, false, *initial_packets[0], self_address_,
+ peer_address_, valid_version_, kNoParsedChlo);
+ store_.EnqueuePacket(connection_id, false, *initial_packets[1], self_address_,
+ peer_address_, valid_version_, kNoParsedChlo);
+
+ BufferedPacketList delivered_packets = store_.DeliverPackets(connection_id);
+ EXPECT_THAT(delivered_packets.buffered_packets, SizeIs(3));
+
+ QuicLongHeaderType previous_packet_type = INITIAL;
+ for (const auto& packet : delivered_packets.buffered_packets) {
+ error_code = QuicFramer::ParsePublicHeaderDispatcher(
+ *packet.packet, kQuicDefaultConnectionIdLength, &unused_format,
+ &long_packet_type, &unused_version_flag, &unused_use_length_prefix,
+ &unused_version_label, &unused_parsed_version,
+ &unused_destination_connection_id, &unused_source_connection_id,
+ &unused_retry_token, &unused_detailed_error);
+ EXPECT_THAT(error_code, IsQuicNoError());
+
+ if (GetQuicReloadableFlag(quic_deliver_initial_packets_first)) {
+ // INITIAL packets should not follow a non-INITIAL packet.
+ EXPECT_THAT(long_packet_type,
+ Conditional(previous_packet_type == INITIAL,
+ A<QuicLongHeaderType>(), Ne(INITIAL)));
+ previous_packet_type = long_packet_type;
+ }
+ }
+}
} // namespace
} // namespace test
} // namespace quic
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 092ce91..085f9d3 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -43,6 +43,8 @@
QUIC_FLAG(FLAGS_quic_restart_flag_quic_default_on_pto2, true)
// If true, default-enable 5RTO blachole detection.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true)
+// If true, deliver INITIAL packets before other types of packets in QuicBufferedPacketStore.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_deliver_initial_packets_first, true)
// If true, disable QUIC version Q043.
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_q043, false)
// If true, disable QUIC version Q046.