Log QUIC_BUG if connection sends multiple connection closes. PiperOrigin-RevId: 437010467
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 6234489..17f4b7d 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -4537,6 +4537,16 @@ auto* frame = new QuicConnectionCloseFrame( transport_version(), error, ietf_error, details, framer_.current_received_frame_type()); + if (level == ENCRYPTION_FORWARD_SECURE) { + if (connection_close_frame_sent_.has_value()) { + QUIC_BUG(quic_send_multiple_connection_closes) + << ENDPOINT << "Already sent connection close: " + << connection_close_frame_sent_.value() + << ", going to send connection close: " << *frame; + } else { + connection_close_frame_sent_ = *frame; + } + } packet_creator_.ConsumeRetransmittableControlFrame(QuicFrame(frame)); packet_creator_.FlushCurrentPacket(); }
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index ec39ff1..a0738e5 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -2255,6 +2255,10 @@ const bool flush_after_coalesce_higher_space_packets_ = GetQuicReloadableFlag(quic_flush_after_coalesce_higher_space_packets); + // Records the 1-RTT connection close frame sent. + // TODO(b/180103273): remove this after the bug gets fixed. + absl::optional<QuicConnectionCloseFrame> connection_close_frame_sent_; + // TODO(b/205023946) Debug-only fields, to be deprecated after the bug is // fixed. absl::optional<QuicWallTime> quic_bug_10511_43_timestamp_;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 9fe34d3..6a943c5 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -15699,6 +15699,38 @@ EXPECT_EQ(1u, writer_->stream_frames().size()); } +// Regression test for b/180103273 +TEST_P(QuicConnectionTest, SendMultipleConnectionCloses) { + if (!version().HasIetfQuicFrames() || + !GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { + return; + } + set_perspective(Perspective::IS_SERVER); + // Finish handshake. + QuicConnectionPeer::SetAddressValidated(&connection_); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + notifier_.NeuterUnencryptedData(); + connection_.NeuterUnencryptedPackets(); + connection_.OnHandshakeComplete(); + connection_.RemoveEncrypter(ENCRYPTION_INITIAL); + connection_.RemoveEncrypter(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + + SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); + ASSERT_TRUE(connection_.BlackholeDetectionInProgress()); + // Verify BeforeConnectionCloseSent gets called twice while OnConnectionClosed + // is called once. + EXPECT_CALL(visitor_, BeforeConnectionCloseSent()).Times(2); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); + // Send connection close w/o closing connection. + QuicConnectionPeer::SendConnectionClosePacket( + &connection_, INTERNAL_ERROR, QUIC_INTERNAL_ERROR, "internal error"); + // Fire blackhole detection alarm. + EXPECT_QUIC_BUG(connection_.GetBlackholeDetectorAlarm()->Fire(), + "Already sent connection close"); +} + } // namespace } // namespace test } // namespace quic