Change `QuicConnection.termination_packets_` to `QuicConnection.termination_info_`, which bundles the termination packets with the connection close error code.
PiperOrigin-RevId: 683627540
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 9c59090..67f337d 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -3306,14 +3306,19 @@
// Termination packets are eventually owned by TimeWaitListManager.
// Others are deleted at the end of this call.
if (is_termination_packet) {
- if (termination_packets_ == nullptr) {
- termination_packets_.reset(
- new std::vector<std::unique_ptr<QuicEncryptedPacket>>);
+ if (termination_info_ == nullptr) {
+ termination_info_ = std::make_unique<TerminationInfo>(error_code);
+ } else {
+ QUIC_BUG_IF(quic_multiple_termination_packets_with_different_error_code,
+ error_code != termination_info_->error_code)
+ << "Initial error code: " << termination_info_->error_code
+ << ", new error code: " << error_code;
}
// Copy the buffer so it's owned in the future.
char* buffer_copy = CopyBuffer(*packet);
- termination_packets_->emplace_back(
- new QuicEncryptedPacket(buffer_copy, encrypted_length, true));
+ termination_info_->termination_packets.push_back(
+ std::make_unique<QuicEncryptedPacket>(buffer_copy, encrypted_length,
+ true));
if (error_code == QUIC_SILENT_IDLE_TIMEOUT) {
QUICHE_DCHECK_EQ(Perspective::IS_SERVER, perspective_);
// TODO(fayang): populate histogram indicating the time elapsed from this
@@ -3321,7 +3326,7 @@
QUIC_DVLOG(1) << ENDPOINT
<< "Added silent connection close to termination packets, "
"num of termination packets: "
- << termination_packets_->size();
+ << termination_info_->termination_packets.size();
return true;
}
}
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 0893193..93b9689 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -45,6 +45,7 @@
#include "quiche/quic/core/quic_connection_id_manager.h"
#include "quiche/quic/core/quic_connection_stats.h"
#include "quiche/quic/core/quic_constants.h"
+#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_framer.h"
#include "quiche/quic/core/quic_idle_network_detector.h"
#include "quiche/quic/core/quic_lru_cache.h"
@@ -1090,8 +1091,35 @@
// Returns the id of the cipher last used for decrypting packets.
uint32_t cipher_id() const;
- std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets() {
- return termination_packets_.get();
+ // Information about the connection close sent by this connection.
+ struct TerminationInfo {
+ explicit TerminationInfo(QuicErrorCode error_code)
+ : error_code(error_code) {}
+
+ const QuicErrorCode error_code; // The connection close error code.
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
+ };
+
+ const TerminationInfo* termination_info() const {
+ return termination_info_.get();
+ }
+
+ // Whether the connection has termination packets _and_ they have not been
+ // consumed by ConsumeTerminationPackets.
+ bool HasTerminationPackets() const {
+ return termination_info_ != nullptr &&
+ !termination_info_->termination_packets.empty();
+ }
+
+ // Returns the termination packets and clears them from the connection.
+ // Postcondition: HasTerminationPackets() == false
+ std::vector<std::unique_ptr<QuicEncryptedPacket>>
+ ConsumeTerminationPackets() {
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> packets;
+ if (termination_info_ != nullptr) {
+ packets.swap(termination_info_->termination_packets);
+ }
+ return packets;
}
bool ack_frame_updated() const;
@@ -2236,8 +2264,7 @@
QuicPacketCount max_tracked_packets_;
// Contains the connection close packets if the connection has been closed.
- std::unique_ptr<std::vector<std::unique_ptr<QuicEncryptedPacket>>>
- termination_packets_;
+ std::unique_ptr<TerminationInfo> termination_info_;
// Determines whether or not a connection close packet is sent to the peer
// after idle timeout due to lack of network activity. During the handshake,
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 1c123ce..506acf5 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -16094,6 +16094,10 @@
// Regression test for b/180103273
TEST_P(QuicConnectionTest, SendMultipleConnectionCloses) {
+ // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
+ if (!IsDefaultTestConfiguration()) {
+ return;
+ }
if (!version().HasIetfQuicFrames() ||
!GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) {
return;
@@ -16121,7 +16125,9 @@
&connection_, INTERNAL_ERROR, QUIC_INTERNAL_ERROR, "internal error");
// Fire blackhole detection alarm. This will invoke
// SendConnectionClosePacket() a second time.
- connection_.GetBlackholeDetectorAlarm()->Fire();
+ EXPECT_QUIC_BUG(connection_.GetBlackholeDetectorAlarm()->Fire(),
+ // 1=QUIC_INTERNAL_ERROR, 85=QUIC_TOO_MANY_RTOS.
+ "Initial error code: 1, new error code: 85");
}
// Regression test for b/157895910.
diff --git a/quiche/quic/core/quic_dispatcher.cc b/quiche/quic/core/quic_dispatcher.cc
index b14d1e3..1ffb383 100644
--- a/quiche/quic/core/quic_dispatcher.cc
+++ b/quiche/quic/core/quic_dispatcher.cc
@@ -795,8 +795,9 @@
write_blocked_list_.Remove(*connection);
QuicTimeWaitListManager::TimeWaitAction action =
QuicTimeWaitListManager::SEND_STATELESS_RESET;
- if (connection->termination_packets() != nullptr &&
- !connection->termination_packets()->empty()) {
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
+ if (connection->HasTerminationPackets()) {
+ termination_packets = connection->ConsumeTerminationPackets();
action = QuicTimeWaitListManager::SEND_CONNECTION_CLOSE_PACKETS;
} else {
if (!connection->IsHandshakeComplete()) {
@@ -822,7 +823,8 @@
time_wait_list_manager_->AddConnectionIdToTimeWait(
action,
TimeWaitConnectionInfo(
- /*ietf_quic=*/true, connection->termination_packets(),
+ /*ietf_quic=*/true,
+ termination_packets.empty() ? nullptr : &termination_packets,
connection->GetActiveServerConnectionIds(),
connection->sent_packet_manager().GetRttStats()->smoothed_rtt()));
}
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc
index 18c3bf0..6a47bfa 100644
--- a/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -205,13 +205,12 @@
}
// static
-QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket(
- QuicConnection* connection) {
- if (connection->termination_packets_ == nullptr ||
- connection->termination_packets_->empty()) {
+const QuicEncryptedPacket* QuicConnectionPeer::GetConnectionClosePacket(
+ const QuicConnection* connection) {
+ if (!connection->HasTerminationPackets()) {
return nullptr;
}
- return (*connection->termination_packets_)[0].get();
+ return connection->termination_info()->termination_packets[0].get();
}
// static
diff --git a/quiche/quic/test_tools/quic_connection_peer.h b/quiche/quic/test_tools/quic_connection_peer.h
index 32db849..2eff481 100644
--- a/quiche/quic/test_tools/quic_connection_peer.h
+++ b/quiche/quic/test_tools/quic_connection_peer.h
@@ -99,8 +99,8 @@
static void SetWriter(QuicConnection* connection, QuicPacketWriter* writer,
bool owns_writer);
static void TearDownLocalConnectionState(QuicConnection* connection);
- static QuicEncryptedPacket* GetConnectionClosePacket(
- QuicConnection* connection);
+ static const QuicEncryptedPacket* GetConnectionClosePacket(
+ const QuicConnection* connection);
static QuicPacketHeader* GetLastHeader(QuicConnection* connection);