In GFE QUIC, add a TCS record for statelessly closed connections.

Protected by FLAGS_quic_restart_flag_quic_tcs_logging_for_statelessly_closed_connections.

PiperOrigin-RevId: 567703047
diff --git a/quiche/quic/core/quic_dispatcher.cc b/quiche/quic/core/quic_dispatcher.cc
index 5beeeff..bdc339a 100644
--- a/quiche/quic/core/quic_dispatcher.cc
+++ b/quiche/quic/core/quic_dispatcher.cc
@@ -547,6 +547,7 @@
     // By adding the connection to time wait list, following packets on this
     // connection will not reach ShouldAcceptNewConnections().
     StatelesslyTerminateConnection(
+        packet_info.self_address, packet_info.peer_address,
         packet_info.destination_connection_id, packet_info.form,
         packet_info.version_flag, packet_info.use_length_prefix,
         packet_info.version, QUIC_HANDSHAKE_FAILED,
@@ -650,6 +651,7 @@
           tls_alert_error_detail.empty() ? "Reject connection"
                                          : tls_alert_error_detail;
       StatelesslyTerminateConnection(
+          packet_info->self_address, packet_info->peer_address,
           server_connection_id, packet_info->form, packet_info->version_flag,
           packet_info->use_length_prefix, packet_info->version,
           connection_close_error_code, connection_close_error_detail,
@@ -1038,6 +1040,8 @@
 }
 
 void QuicDispatcher::StatelesslyTerminateConnection(
+    const QuicSocketAddress& self_address,
+    const QuicSocketAddress& peer_address,
     QuicConnectionId server_connection_id, PacketHeaderFormat format,
     bool version_flag, bool use_length_prefix, ParsedQuicVersion version,
     QuicErrorCode error_code, const std::string& error_details,
@@ -1071,6 +1075,9 @@
     QUIC_CODE_COUNT(quic_dispatcher_generated_connection_close);
     QuicSession::RecordConnectionCloseAtServer(
         error_code, ConnectionCloseSource::FROM_SELF);
+    OnStatelessConnectionCloseGenerated(self_address, peer_address,
+                                        server_connection_id, version,
+                                        error_code, error_details);
     return;
   }
 
@@ -1108,8 +1115,13 @@
         quic_new_error_code_when_packets_buffered_too_long);
     error_code = QUIC_HANDSHAKE_FAILED_PACKETS_BUFFERED_TOO_LONG;
   }
+  QuicSocketAddress self_address, peer_address;
+  if (!early_arrived_packets.buffered_packets.empty()) {
+    self_address = early_arrived_packets.buffered_packets.front().self_address;
+    peer_address = early_arrived_packets.buffered_packets.front().peer_address;
+  }
   StatelesslyTerminateConnection(
-      server_connection_id,
+      self_address, peer_address, server_connection_id,
       early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET
                                       : GOOGLE_QUIC_PACKET,
       /*version_flag=*/true,
@@ -1286,7 +1298,8 @@
       // The original connection ID does not correspond to an existing
       // session. It is safe to send CONNECTION_CLOSE and add to TIME_WAIT.
       StatelesslyTerminateConnection(
-          original_connection_id, IETF_QUIC_LONG_HEADER_PACKET,
+          self_address, peer_address, original_connection_id,
+          IETF_QUIC_LONG_HEADER_PACKET,
           /*version_flag=*/true, version.HasLengthPrefixedConnectionIds(),
           version, QUIC_HANDSHAKE_FAILED,
           "Connection ID collision, please retry",
diff --git a/quiche/quic/core/quic_dispatcher.h b/quiche/quic/core/quic_dispatcher.h
index 7f06b78..183b335 100644
--- a/quiche/quic/core/quic_dispatcher.h
+++ b/quiche/quic/core/quic_dispatcher.h
@@ -300,7 +300,11 @@
   // 1) send connection close with |error_code| and |error_details| and add
   // connection to time wait list or 2) directly add connection to time wait
   // list with |action|.
+  // |self_address| and |peer_address| are passed to
+  // |OnStatelessConnectionCloseSent| when a connection close is sent.
   void StatelesslyTerminateConnection(
+      const QuicSocketAddress& self_address,
+      const QuicSocketAddress& peer_address,
       QuicConnectionId server_connection_id, PacketHeaderFormat format,
       bool version_flag, bool use_length_prefix, ParsedQuicVersion version,
       QuicErrorCode error_code, const std::string& error_details,
@@ -330,6 +334,14 @@
   // Called if a packet from an unseen connection is reset or rejected.
   virtual void OnNewConnectionRejected() {}
 
+  // Called by |StatelesslyTerminateConnection| when a connection close packet
+  // is generated.
+  virtual void OnStatelessConnectionCloseGenerated(
+      const QuicSocketAddress& /*self_address*/,
+      const QuicSocketAddress& /*peer_address*/,
+      QuicConnectionId /*connection_id*/, ParsedQuicVersion /*version*/,
+      QuicErrorCode /*error_code*/, const std::string& /*error_details*/) {}
+
   // Selects the preferred ALPN from a vector of ALPNs.
   // This runs through the list of ALPNs provided by the client and picks the
   // first one it supports. If no supported versions are found, the first
diff --git a/quiche/quic/test_tools/packet_dropping_test_writer.cc b/quiche/quic/test_tools/packet_dropping_test_writer.cc
index ac9625f..5987338 100644
--- a/quiche/quic/test_tools/packet_dropping_test_writer.cc
+++ b/quiche/quic/test_tools/packet_dropping_test_writer.cc
@@ -52,6 +52,7 @@
     : clock_(nullptr),
       cur_buffer_size_(0),
       num_calls_to_write_(0),
+      passthrough_for_next_n_packets_(0),
       // Do not require any number of successful writes before the first dropped
       // packet.
       num_consecutive_succesful_writes_(kMinSuccesfulWritesAfterPacketLoss),
@@ -94,6 +95,12 @@
   ReleaseOldPackets();
 
   QuicWriterMutexLock lock(&config_mutex_);
+  if (passthrough_for_next_n_packets_ > 0) {
+    --passthrough_for_next_n_packets_;
+    return QuicPacketWriterWrapper::WritePacket(buffer, buf_len, self_address,
+                                                peer_address, options, params);
+  }
+
   if (fake_drop_first_n_packets_ > 0 &&
       num_calls_to_write_ <=
           static_cast<uint64_t>(fake_drop_first_n_packets_)) {
diff --git a/quiche/quic/test_tools/packet_dropping_test_writer.h b/quiche/quic/test_tools/packet_dropping_test_writer.h
index dd83cb3..2b05005 100644
--- a/quiche/quic/test_tools/packet_dropping_test_writer.h
+++ b/quiche/quic/test_tools/packet_dropping_test_writer.h
@@ -84,6 +84,15 @@
     fake_packet_loss_percentage_ = fake_packet_loss_percentage;
   }
 
+  // Once called, the next |passthrough_for_next_n_packets_| WritePacket() calls
+  // will always send the packets immediately, without being affected by the
+  // simulated error conditions.
+  void set_passthrough_for_next_n_packets(
+      uint32_t passthrough_for_next_n_packets) {
+    QuicWriterMutexLock lock(&config_mutex_);
+    passthrough_for_next_n_packets_ = passthrough_for_next_n_packets;
+  }
+
   // Simulate dropping the first n packets unconditionally.
   // Subsequent packets will be lost at fake_packet_loss_percentage_ if set.
   void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) {
@@ -170,6 +179,7 @@
   DelayedPacketList delayed_packets_;
   QuicByteCount cur_buffer_size_;
   uint64_t num_calls_to_write_;
+  uint32_t passthrough_for_next_n_packets_ QUIC_GUARDED_BY(config_mutex_);
   int32_t num_consecutive_succesful_writes_;
 
   QuicMutex config_mutex_;
diff --git a/quiche/quic/tools/quic_client_base.h b/quiche/quic/tools/quic_client_base.h
index d17503f..8e73acc 100644
--- a/quiche/quic/tools/quic_client_base.h
+++ b/quiche/quic/tools/quic_client_base.h
@@ -277,6 +277,8 @@
 
   QuicConnectionHelperInterface* helper() { return helper_.get(); }
 
+  QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
+
   NetworkHelper* network_helper();
   const NetworkHelper* network_helper() const;
 
@@ -365,8 +367,6 @@
   // Returns the client connection ID to use.
   virtual QuicConnectionId GetClientConnectionId();
 
-  QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
-
   // Subclasses may need to explicitly clear the session on destruction
   // if they create it with objects that will be destroyed before this is.
   // You probably want to call this if you override CreateQuicSpdyClientSession.