gfe-relnote: In QUIC, add connected_ check in OnCanWrite and flusher's destructor. Protected by gfe2_reloadable_flag_quic_check_connected_before_flush.
PiperOrigin-RevId: 251653969
Change-Id: I93d9204391c7b900d0abb73aab9cab70f7ffabe9
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 9cca434..ba40e7a 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1943,7 +1943,11 @@
EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
connection_.OnCanWrite();
- EXPECT_EQ(1u, connection_.GetStats().packets_discarded);
+ if (GetQuicReloadableFlag(quic_check_connected_before_flush)) {
+ EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
+ } else {
+ EXPECT_EQ(1u, connection_.GetStats().packets_discarded);
+ }
}
TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) {
@@ -8505,6 +8509,44 @@
EXPECT_EQ(TestConnectionId(0x33), connection_.client_connection_id());
}
+// Regression test for b/134416344.
+TEST_P(QuicConnectionTest, CheckConnectedBeforeFlush) {
+ // This test mimics a scenario where a connection processes 2 packets and the
+ // 2nd packet contains connection close frame. When the 2nd flusher goes out
+ // of scope, a delayed ACK is pending, and ACK alarm should not be scheduled
+ // because connection is disconnected.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _));
+ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ std::unique_ptr<QuicConnectionCloseFrame> connection_close_frame(
+ new QuicConnectionCloseFrame(QUIC_INTERNAL_ERROR));
+ if (connection_.transport_version() == QUIC_VERSION_99) {
+ connection_close_frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+ }
+ // Received 2 packets.
+ QuicFrame frame;
+ if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+ frame = QuicFrame(&crypto_frame_);
+ EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+ } else {
+ frame = QuicFrame(QuicStreamFrame(
+ QuicUtils::GetCryptoStreamId(connection_.transport_version()), false,
+ 0u, QuicStringPiece()));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ }
+ ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+ ProcessFramePacketWithAddresses(QuicFrame(connection_close_frame.get()),
+ kSelfAddress, kPeerAddress);
+ if (GetQuicReloadableFlag(quic_check_connected_before_flush)) {
+ // Verify ack alarm is not set.
+ EXPECT_FALSE(ack_alarm->IsSet());
+ } else {
+ EXPECT_TRUE(ack_alarm->IsSet());
+ }
+}
+
} // namespace
} // namespace test
} // namespace quic