gfe-relnote: In QUIC, when RTO fires and there is no packet to be RTOed, let connection send data. Protected by gfe2_reloadable_flag_quic_fix_rto_retransmission2 which replaces gfe2_reloadable_flag_quic_fix_rto_retransmission.
This fix only applies for version > 39.
PiperOrigin-RevId: 262347120
Change-Id: Ic164c2f9e7117c3f9af43f1f1a3e8b369d8a3052
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 39d2760..26c70f1 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -4159,25 +4159,25 @@
// Simulate the retransmission alarm firing.
clock_.AdvanceTime(DefaultRetransmissionTime());
// RTO fires, but there is no packet to be RTOed.
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
} else {
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
}
connection_.GetRetransmissionAlarm()->Fire();
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
EXPECT_EQ(1u, writer_->rst_stream_frames().size());
}
EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(40);
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(20);
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
EXPECT_CALL(visitor_, WillingAndAbleToWrite())
.WillRepeatedly(Return(false));
} else {
EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
}
- if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1);
} else {
// Since there is a buffered RST_STREAM, no retransmittable frame is bundled
@@ -8685,6 +8685,62 @@
EXPECT_TRUE(connection_.connected());
}
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, RtoAndWriteBlocked) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ return;
+ }
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_data_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Writer gets blocked.
+ writer_->SetWriteBlocked();
+
+ // Cancel the stream.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+ // Retransmission timer fires in RTO mode.
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify no packets get flushed when writer is blocked.
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, TlpAndWriteBlocked) {
+ if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+ ->fix_rto_retransmission()) {
+ return;
+ }
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ connection_.SetMaxTailLossProbes(1);
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_data_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+ SendStreamDataToPeer(4, "foo", 0, NO_FIN, &last_data_packet);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Writer gets blocked.
+ writer_->SetWriteBlocked();
+
+ // Cancel stream 2.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+ // Retransmission timer fires in TLP mode.
+ connection_.GetRetransmissionAlarm()->Fire();
+ // Verify one packets is forced flushed when writer is blocked.
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+}
+
} // namespace
} // namespace test
} // namespace quic