gfe-relnote: In QUIC, do not use framer object in QuicDispatcher. Protected by gfe2_restart_flag_quic_no_framer_object_in_dispatcher.
Also, dispatcher does not parse and validate packet number anymore.
PiperOrigin-RevId: 247959538
Change-Id: Ia0f7901428537f392b05ffd6beb2984bffd00232
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index a9c6c4a..fa6fda7 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -10,6 +10,7 @@
#include "net/third_party/quiche/src/quic/core/chlo_extractor.h"
#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -303,8 +304,14 @@
last_error_(QUIC_NO_ERROR),
new_sessions_allowed_per_event_loop_(0u),
accept_new_connections_(true),
- allow_short_initial_connection_ids_(false) {
- framer_.set_visitor(this);
+ allow_short_initial_connection_ids_(false),
+ last_version_label_(0),
+ expected_connection_id_length_(expected_connection_id_length),
+ should_update_expected_connection_id_length_(false),
+ no_framer_(GetQuicRestartFlag(quic_no_framer_object_in_dispatcher)) {
+ if (!no_framer_) {
+ framer_.set_visitor(this);
+ }
}
QuicDispatcher::~QuicDispatcher() {
@@ -326,21 +333,60 @@
// GetClientAddress must be called after current_peer_address_ is set.
current_client_address_ = GetClientAddress();
current_packet_ = &packet;
- // ProcessPacket will cause the packet to be dispatched in
- // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
- // in OnUnauthenticatedHeader.
- framer_.ProcessPacket(packet);
- // TODO(rjshade): Return a status describing if/why a packet was dropped,
- // and log somehow. Maybe expose as a varz.
- // TODO(wub): Consider invalidate the current_* variables so processing of the
- // next packet does not use them incorrectly.
+ if (!no_framer_) {
+ // ProcessPacket will cause the packet to be dispatched in
+ // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
+ // in OnUnauthenticatedHeader.
+ framer_.ProcessPacket(packet);
+ // TODO(rjshade): Return a status describing if/why a packet was dropped,
+ // and log somehow. Maybe expose as a varz.
+ return;
+ }
+ QUIC_RESTART_FLAG_COUNT(quic_no_framer_object_in_dispatcher);
+ QuicPacketHeader header;
+ uint8_t destination_connection_id_length;
+ string detailed_error;
+ const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher(
+ packet, expected_connection_id_length_, &header.form,
+ &header.version_flag, &last_version_label_,
+ &destination_connection_id_length, &header.destination_connection_id,
+ &detailed_error);
+ if (error != QUIC_NO_ERROR) {
+ // Packet has framing error.
+ SetLastError(error);
+ QUIC_DLOG(ERROR) << detailed_error;
+ return;
+ }
+ header.version = ParseQuicVersionLabel(last_version_label_);
+ if (destination_connection_id_length != expected_connection_id_length_ &&
+ !should_update_expected_connection_id_length_ &&
+ !QuicUtils::VariableLengthConnectionIdAllowedForVersion(
+ header.version.transport_version)) {
+ SetLastError(QUIC_INVALID_PACKET_HEADER);
+ QUIC_DLOG(ERROR) << "Invalid Connection Id Length";
+ return;
+ }
+ if (should_update_expected_connection_id_length_) {
+ expected_connection_id_length_ = destination_connection_id_length;
+ }
+ // TODO(fayang): Instead of passing in QuicPacketHeader, pass format,
+ // version_flag, version and destination_connection_id. Combine
+ // OnUnauthenticatedPublicHeader and OnUnauthenticatedHeader to a single
+ // function when deprecating quic_no_framer_object_in_dispatcher.
+ if (!OnUnauthenticatedPublicHeader(header)) {
+ return;
+ }
+ OnUnauthenticatedHeader(header);
+ // TODO(wub): Consider invalidate the current_* variables so processing of
+ // the next packet does not use them incorrectly.
}
QuicConnectionId QuicDispatcher::MaybeReplaceConnectionId(
QuicConnectionId connection_id,
ParsedQuicVersion version) {
const uint8_t expected_connection_id_length =
- framer_.GetExpectedConnectionIdLength();
+ no_framer_ ? expected_connection_id_length_
+ : framer_.GetExpectedConnectionIdLength();
if (connection_id.length() == expected_connection_id_length) {
return connection_id;
}
@@ -383,16 +429,18 @@
// connection ID, the dispatcher picks a new one of its expected length.
// Therefore we should never receive a connection ID that is smaller
// than 64 bits and smaller than what we expect.
+ const uint8_t expected_connection_id_length =
+ no_framer_ ? expected_connection_id_length_
+ : framer_.GetExpectedConnectionIdLength();
if (connection_id.length() < kQuicMinimumInitialConnectionIdLength &&
- connection_id.length() < framer_.GetExpectedConnectionIdLength() &&
+ connection_id.length() < expected_connection_id_length &&
!allow_short_initial_connection_ids_) {
DCHECK(header.version_flag);
DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
header.version.transport_version));
QUIC_DLOG(INFO) << "Packet with short destination connection ID "
<< connection_id << " expected "
- << static_cast<int>(
- framer_.GetExpectedConnectionIdLength());
+ << static_cast<int>(expected_connection_id_length);
ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, header.form,
header.version_flag, header.version);
return false;
@@ -449,12 +497,14 @@
ParsedQuicVersion version = GetSupportedVersions().front();
if (header.version_flag) {
ParsedQuicVersion packet_version = header.version;
- if (framer_.supported_versions() != GetSupportedVersions()) {
+ if (!no_framer_ && framer_.supported_versions() != GetSupportedVersions()) {
// Reset framer's version if version flags change in flight.
framer_.SetSupportedVersions(GetSupportedVersions());
}
- if (!framer_.IsSupportedVersion(packet_version)) {
- if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) {
+ if (!IsSupportedVersion(packet_version)) {
+ if (ShouldCreateSessionForUnknownVersion(
+ no_framer_ ? last_version_label_
+ : framer_.last_version_label())) {
return true;
}
if (!crypto_config()->validate_chlo_size() ||
@@ -470,8 +520,10 @@
}
version = packet_version;
}
- // Set the framer's version and continue processing.
- framer_.set_version(version);
+ if (!no_framer_) {
+ // Set the framer's version and continue processing.
+ framer_.set_version(version);
+ }
if (version.HasHeaderProtection()) {
ProcessHeader(header);
@@ -573,6 +625,11 @@
return kFateTimeWait;
}
+ if (no_framer_) {
+ // Let the connection parse and validate packet number.
+ return kFateProcess;
+ }
+
// initial packet number of 0 is always invalid.
if (!framer_.version().HasHeaderProtection()) {
if (!header.packet_number.IsInitialized()) {
@@ -797,7 +854,7 @@
}
// If the version is known and supported by framer, send a connection close.
- if (framer_.IsSupportedVersion(version)) {
+ if (IsSupportedVersion(version)) {
QUIC_DVLOG(1)
<< "Statelessly terminating " << connection_id
<< " based on an ietf-long packet, which has a supported version:"
@@ -852,6 +909,7 @@
bool QuicDispatcher::OnProtocolVersionMismatch(
ParsedQuicVersion /*received_version*/,
PacketHeaderFormat /*form*/) {
+ DCHECK(!no_framer_);
QUIC_BUG_IF(
!time_wait_list_manager_->IsConnectionIdInTimeWait(
current_connection_id_) &&
@@ -1146,7 +1204,7 @@
EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
current_connection_id_, form != GOOGLE_QUIC_PACKET, *current_packet_,
current_self_address_, current_peer_address_,
- /*is_chlo=*/true, current_alpn_, framer_.version());
+ /*is_chlo=*/true, current_alpn_, version);
if (rs != EnqueuePacketResult::SUCCESS) {
OnBufferPacketFailure(rs, current_connection_id_);
}
@@ -1155,11 +1213,10 @@
QuicConnectionId original_connection_id = current_connection_id_;
current_connection_id_ =
- MaybeReplaceConnectionId(current_connection_id_, framer_.version());
+ MaybeReplaceConnectionId(current_connection_id_, version);
// Creates a new session and process all buffered packets for this connection.
- QuicSession* session =
- CreateQuicSession(current_connection_id_, current_peer_address_,
- current_alpn_, framer_.version());
+ QuicSession* session = CreateQuicSession(
+ current_connection_id_, current_peer_address_, current_alpn_, version);
if (original_connection_id != current_connection_id_) {
session->connection()->AddIncomingConnectionId(original_connection_id);
}
@@ -1338,7 +1395,9 @@
current_self_address_ = current_self_address;
current_packet_ = current_packet.get();
current_connection_id_ = rejector->connection_id();
- framer_.set_version(first_version);
+ if (!no_framer_) {
+ framer_.set_version(first_version);
+ }
// Stop buffering packets on this connection
const auto num_erased =
@@ -1391,7 +1450,7 @@
break;
case StatelessRejector::REJECTED: {
- QUIC_BUG_IF(first_version != framer_.version())
+ QUIC_BUG_IF(!no_framer_ && first_version != framer_.version())
<< "SREJ: Client's version: "
<< QuicVersionToString(first_version.transport_version)
<< " is different from current dispatcher framer's version: "
@@ -1438,7 +1497,22 @@
}
void QuicDispatcher::DisableFlagValidation() {
- framer_.set_validate_flags(false);
+ if (!no_framer_) {
+ framer_.set_validate_flags(false);
+ }
+}
+
+bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) {
+ if (!no_framer_) {
+ return framer_.IsSupportedVersion(version);
+ }
+ for (const ParsedQuicVersion& supported_version :
+ version_manager_->GetSupportedVersions()) {
+ if (version == supported_version) {
+ return true;
+ }
+ }
+ return false;
}
} // namespace quic