Skip to content

Commit 93f3b29

Browse files
yangfanudcopybara-github
authored andcommitted
Deliver STOP_SENDING to zombie streams.
This is to fix a bug that a zombie stream is not closed when receiving STOP_SENDING. Credit to external report in #76 Protected by FLAGS_quic_reloadable_flag_quic_deliver_stop_sending_to_zombie_streams. PiperOrigin-RevId: 677548901
1 parent 9232c78 commit 93f3b29

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

quiche/common/quiche_feature_flags_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ QUICHE_FLAG(bool, quiche_reloadable_flag_quic_conservative_cwnd_and_pacing_gains
2424
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true, true, "If true, default-enable 5RTO blachole detection.")
2525
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_to_bbr, true, false, "When true, defaults to BBR congestion control instead of Cubic.")
2626
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_to_bbr_v2, false, false, "If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr.")
27+
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_deliver_stop_sending_to_zombie_streams, false, false, "If true, deliver STOP_SENDING to zombie streams.")
2728
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_disable_batch_write, false, false, "If true, round-robin stream writes instead of batching in QuicWriteBlockedList.")
2829
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_disable_server_blackhole_detection, false, false, "If true, disable blackhole detection on server side.")
2930
QUICHE_FLAG(bool, quiche_reloadable_flag_quic_disable_version_draft_29, false, false, "If true, disable QUIC version h3-29.")

quiche/quic/core/quic_session.cc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,22 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
371371
return;
372372
}
373373

374-
QuicStream* stream = GetOrCreateStream(stream_id);
374+
QuicStream* stream = nullptr;
375+
if (enable_stop_sending_for_zombie_streams_) {
376+
stream = GetStream(stream_id);
377+
if (stream != nullptr) {
378+
if (stream->IsZombie()) {
379+
QUIC_RELOADABLE_FLAG_COUNT_N(
380+
quic_deliver_stop_sending_to_zombie_streams, 1, 3);
381+
} else {
382+
QUIC_RELOADABLE_FLAG_COUNT_N(
383+
quic_deliver_stop_sending_to_zombie_streams, 2, 3);
384+
}
385+
stream->OnStopSending(frame.error());
386+
return;
387+
}
388+
}
389+
stream = GetOrCreateStream(stream_id);
375390
if (!stream) {
376391
// Errors are handled by GetOrCreateStream.
377392
return;

quiche/quic/core/quic_session.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,10 @@ class QUICHE_EXPORT QuicSession
690690
// Returns the priority type used by the streams in the session.
691691
QuicPriorityType priority_type() const { return priority_type_; }
692692

693+
bool enable_stop_sending_for_zombie_streams() const {
694+
return enable_stop_sending_for_zombie_streams_;
695+
}
696+
693697
protected:
694698
using StreamMap =
695699
absl::flat_hash_map<QuicStreamId, std::unique_ptr<QuicStream>>;
@@ -1094,6 +1098,9 @@ class QUICHE_EXPORT QuicSession
10941098
std::unique_ptr<QuicAlarm> stream_count_reset_alarm_;
10951099

10961100
QuicPriorityType priority_type_;
1101+
1102+
const bool enable_stop_sending_for_zombie_streams_ =
1103+
GetQuicReloadableFlag(quic_deliver_stop_sending_to_zombie_streams);
10971104
};
10981105

10991106
} // namespace quic

quiche/quic/core/quic_session_test.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3047,6 +3047,44 @@ TEST_P(QuicSessionTestServer, OnStopSendingForWriteClosedStream) {
30473047
session_.OnStopSendingFrame(frame);
30483048
}
30493049

3050+
// Regression test for b/368421586.
3051+
TEST_P(QuicSessionTestServer, OnStopSendingForZombieStreams) {
3052+
if (!VersionHasIetfQuicFrames(transport_version())) {
3053+
return;
3054+
}
3055+
CompleteHandshake();
3056+
session_.set_writev_consumes_all_data(true);
3057+
3058+
TestStream* stream = session_.CreateOutgoingBidirectionalStream();
3059+
std::string body(100, '.');
3060+
QuicStreamPeer::CloseReadSide(stream);
3061+
stream->WriteOrBufferData(body, true, nullptr);
3062+
EXPECT_TRUE(stream->IsWaitingForAcks());
3063+
// Verify that the stream is a zombie.
3064+
EXPECT_TRUE(stream->IsZombie());
3065+
ASSERT_EQ(0u, session_.closed_streams()->size());
3066+
3067+
QuicStopSendingFrame frame(1, stream->id(), QUIC_STREAM_CANCELLED);
3068+
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
3069+
if (GetQuicReloadableFlag(quic_deliver_stop_sending_to_zombie_streams)) {
3070+
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1);
3071+
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(1);
3072+
} else {
3073+
EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
3074+
EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(0);
3075+
}
3076+
session_.OnStopSendingFrame(frame);
3077+
if (GetQuicReloadableFlag(quic_deliver_stop_sending_to_zombie_streams)) {
3078+
// STOP_SENDING should cause the stream to be closed.
3079+
EXPECT_FALSE(stream->IsZombie());
3080+
EXPECT_EQ(1u, session_.closed_streams()->size());
3081+
} else {
3082+
// STOP_SENDING is not delivered to zombie streams.
3083+
EXPECT_TRUE(stream->IsZombie());
3084+
EXPECT_EQ(0u, session_.closed_streams()->size());
3085+
}
3086+
}
3087+
30503088
// If stream is closed, return true and do not close the connection.
30513089
TEST_P(QuicSessionTestServer, OnStopSendingClosedStream) {
30523090
if (!VersionHasIetfQuicFrames(transport_version())) {

quiche/quic/core/quic_stream.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,12 @@ bool QuicStream::OnStopSending(QuicResetStreamError error) {
532532

533533
stream_error_ = error;
534534
MaybeSendRstStream(error);
535+
if (session()->enable_stop_sending_for_zombie_streams() &&
536+
read_side_closed_ && write_side_closed_ && !IsWaitingForAcks()) {
537+
QUIC_RELOADABLE_FLAG_COUNT_N(quic_deliver_stop_sending_to_zombie_streams, 3,
538+
3);
539+
session()->MaybeCloseZombieStream(id_);
540+
}
535541
return true;
536542
}
537543

0 commit comments

Comments
 (0)