Merge changes Ie1e628a3,Icb06e692
* changes:
IETF CONNECTION CLOSE code is varint encoded
gfe-relnote: Deprecate gfe2_reloadable_flag_quic_check_connected_before_flush.
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc
index 88343b4..11a625c 100644
--- a/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -20,7 +20,8 @@
last_acked_packet_sent_time_(QuicTime::Zero()),
last_acked_packet_ack_time_(QuicTime::Zero()),
is_app_limited_(false),
- connection_state_map_() {}
+ connection_state_map_(),
+ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)) {}
BandwidthSampler::~BandwidthSampler() {}
@@ -55,7 +56,7 @@
if (!connection_state_map_.IsEmpty() &&
packet_number >
- connection_state_map_.last_packet() + kMaxTrackedPackets) {
+ connection_state_map_.last_packet() + max_tracked_packets_) {
QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum "
"number "
"of tracked packets.";
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h
index 4de05b0..9a58cf6 100644
--- a/quic/core/congestion_control/bandwidth_sampler.h
+++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -324,6 +324,9 @@
// sent, indexed by the packet number.
PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_;
+ // Maximum number of tracked packets.
+ const QuicPacketCount max_tracked_packets_;
+
// Handles the actual bandwidth calculations, whereas the outer method handles
// retrieving and removing |sent_packet|.
BandwidthSample OnPacketAcknowledgedInner(
diff --git a/quic/core/frames/quic_rst_stream_frame.h b/quic/core/frames/quic_rst_stream_frame.h
index 0957614..9a9ed56 100644
--- a/quic/core/frames/quic_rst_stream_frame.h
+++ b/quic/core/frames/quic_rst_stream_frame.h
@@ -39,6 +39,7 @@
QuicRstStreamErrorCode error_code;
// In IETF QUIC the code is up to the app on top of quic, so is
// more general than QuicRstStreamErrorCode allows.
+ // TODO(fkastenholz): Upgrade to uint64_t
uint16_t ietf_error_code;
};
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc
index 1c4c083..3388b2c 100644
--- a/quic/core/http/http_decoder.cc
+++ b/quic/core/http/http_decoder.cc
@@ -449,27 +449,42 @@
bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
PriorityFrame* frame) {
uint8_t flags;
- bool success = reader->ReadUInt8(&flags);
- DCHECK(success);
+ if (!reader->ReadUInt8(&flags)) {
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Unable to read PRIORITY frame flags.");
+ return false;
+ }
frame->prioritized_type =
static_cast<PriorityElementType>(ExtractBits(flags, 2, 6));
frame->dependency_type =
static_cast<PriorityElementType>(ExtractBits(flags, 2, 4));
+ // TODO(b/137662729): Update bitmask for exclusive flag.
frame->exclusive = flags % 2 == 1;
- // TODO(bnc): Handle partial delivery.
+ // TODO(b/137359636): Handle partial delivery.
if (frame->prioritized_type != ROOT_OF_TREE &&
!reader->ReadVarInt62(&frame->prioritized_element_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read prioritized_element_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Unable to read prioritized_element_id.");
return false;
}
if (frame->dependency_type != ROOT_OF_TREE &&
!reader->ReadVarInt62(&frame->element_dependency_id)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read element_dependency_id");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Unable to read element_dependency_id.");
return false;
}
if (!reader->ReadUInt8(&frame->weight)) {
- RaiseError(QUIC_INTERNAL_ERROR, "Unable to read priority frame weight");
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA,
+ "Unable to read priority frame weight.");
+ return false;
+ }
+ if (!reader->IsDoneReading()) {
+ // TODO(b/124216424): Use HTTP_MALFORMED_FRAME.
+ RaiseError(QUIC_INVALID_FRAME_DATA, "Superfluous data in priority frame.");
return false;
}
return true;
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc
index 9229db0..735f322 100644
--- a/quic/core/http/http_decoder_test.cc
+++ b/quic/core/http/http_decoder_test.cc
@@ -411,6 +411,52 @@
EXPECT_EQ("", decoder_.error_detail());
}
+// Regression test for https://crbug.com/981291 and https://crbug.com/981646.
+TEST_F(HttpDecoderTest, CorruptPriorityFrame) {
+ const char* const payload1 =
+ "\x01" // request stream, request stream, exclusive
+ "\x03" // prioritized_element_id
+ "\x04" // element_dependency_id
+ "\xFF" // weight
+ "\xFF"; // superfluous data
+ const char* const payload2 =
+ "\xf1" // root of tree, root of tree, exclusive
+ "\xFF" // weight
+ "\xFF"; // superfluous data
+ struct {
+ const char* const payload;
+ size_t payload_length;
+ const char* const error_message;
+ } kTestData[] = {
+ {payload1, 0, "Unable to read PRIORITY frame flags."},
+ {payload1, 1, "Unable to read prioritized_element_id."},
+ {payload1, 2, "Unable to read element_dependency_id."},
+ {payload1, 3, "Unable to read priority frame weight."},
+ {payload1, 5, "Superfluous data in priority frame."},
+ {payload2, 0, "Unable to read PRIORITY frame flags."},
+ {payload2, 1, "Unable to read priority frame weight."},
+ {payload2, 3, "Superfluous data in priority frame."},
+ };
+
+ for (const auto& test_data : kTestData) {
+ std::string input;
+ input.push_back(2u); // type PRIORITY
+ input.push_back(test_data.payload_length);
+ size_t header_length = input.size();
+ input.append(test_data.payload, test_data.payload_length);
+
+ HttpDecoder decoder(&visitor_);
+ EXPECT_CALL(visitor_, OnPriorityFrameStart(Http3FrameLengths(
+ header_length, test_data.payload_length)));
+
+ QuicByteCount processed_bytes =
+ decoder.ProcessInput(input.data(), input.size());
+ EXPECT_EQ(input.size(), processed_bytes);
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, decoder.error());
+ EXPECT_EQ(test_data.error_message, decoder.error_detail());
+ }
+}
+
TEST_F(HttpDecoderTest, SettingsFrame) {
InSequence s;
std::string input(
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc
index b521046..0041c85 100644
--- a/quic/core/http/quic_server_session_base_test.cc
+++ b/quic/core/http/quic_server_session_base_test.cc
@@ -361,8 +361,8 @@
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
// Open the max configured number of streams, should be no problem.
for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(),
+ stream_id));
stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
}
@@ -370,8 +370,8 @@
// Open more streams: server should accept slightly more than the limit.
// Excess streams are for non-version-99 only.
for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) {
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(session_.get(),
+ stream_id));
stream_id += QuicUtils::StreamIdDelta(connection_->transport_version());
}
}
@@ -390,8 +390,8 @@
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
}
// Even if the connection remains open, the stream creation should fail.
- EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
+ EXPECT_FALSE(
+ QuicServerSessionBasePeer::GetOrCreateStream(session_.get(), stream_id));
}
TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) {
@@ -404,7 +404,7 @@
session_->MaxAvailableBidirectionalStreams();
EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(), GetNthClientInitiatedBidirectionalId(0)));
// Establish available streams up to the server's limit.
@@ -416,7 +416,7 @@
// This exceeds the stream limit. In versions other than 99
// this is allowed. Version 99 hews to the IETF spec and does
// not allow it.
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(), kLimitingStreamId));
// A further available stream will result in connection close.
EXPECT_CALL(*connection_,
@@ -428,14 +428,14 @@
// This forces stream kLimitingStreamId + 2 to become available, which
// violates the quota.
- EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(), kLimitingStreamId + 2 * next_id));
}
TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
// Incoming streams on the server session must be odd.
EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
- EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(),
session_->next_outgoing_unidirectional_stream_id()));
}
@@ -448,7 +448,7 @@
// Don't create new streams if the connection is disconnected.
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_QUIC_BUG(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ EXPECT_QUIC_BUG(QuicServerSessionBasePeer::GetOrCreateStream(
session_.get(), GetNthClientInitiatedBidirectionalId(0)),
"ShouldCreateIncomingStream called when disconnected");
}
diff --git a/quic/core/http/quic_spdy_client_session_base.cc b/quic/core/http/quic_spdy_client_session_base.cc
index ba5a9cc..f27411a 100644
--- a/quic/core/http/quic_spdy_client_session_base.cc
+++ b/quic/core/http/quic_spdy_client_session_base.cc
@@ -24,7 +24,8 @@
: QuicSpdySession(connection, nullptr, config, supported_versions),
push_promise_index_(push_promise_index),
largest_promised_stream_id_(
- QuicUtils::GetInvalidStreamId(connection->transport_version())) {}
+ QuicUtils::GetInvalidStreamId(connection->transport_version())),
+ max_allowed_push_id_(0) {}
QuicSpdyClientSessionBase::~QuicSpdyClientSessionBase() {
// all promised streams for this session
@@ -88,6 +89,14 @@
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
return;
}
+
+ if (VersionHasIetfQuicFrames(connection()->transport_version()) &&
+ promised_stream_id > max_allowed_push_id()) {
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID,
+ "Received push stream id higher than MAX_PUSH_ID.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
largest_promised_stream_id_ = promised_stream_id;
QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
@@ -209,4 +218,9 @@
return !HasActiveRequestStreams() && promised_by_id_.empty();
}
+void QuicSpdyClientSessionBase::set_max_allowed_push_id(
+ QuicStreamId max_allowed_push_id) {
+ max_allowed_push_id_ = max_allowed_push_id;
+}
+
} // namespace quic
diff --git a/quic/core/http/quic_spdy_client_session_base.h b/quic/core/http/quic_spdy_client_session_base.h
index aec5e75..98b8589 100644
--- a/quic/core/http/quic_spdy_client_session_base.h
+++ b/quic/core/http/quic_spdy_client_session_base.h
@@ -111,6 +111,10 @@
// Returns true if there are no active requests and no promised streams.
bool ShouldReleaseHeadersStreamSequencerBuffer() override;
+ void set_max_allowed_push_id(QuicStreamId max_allowed_push_id);
+
+ QuicStreamId max_allowed_push_id() { return max_allowed_push_id_; }
+
size_t get_max_promises() const {
return max_open_incoming_unidirectional_streams() *
kMaxPromisedStreamsMultiplier;
@@ -134,6 +138,7 @@
QuicClientPushPromiseIndex* push_promise_index_;
QuicPromisedByIdMap promised_by_id_;
QuicStreamId largest_promised_stream_id_;
+ QuicStreamId max_allowed_push_id_;
};
} // namespace quic
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index 716ae42..dfa3031 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -610,6 +610,38 @@
QuicHeaderList());
}
+TEST_P(QuicSpdyClientSessionTest, PushPromiseStreamIdTooHigh) {
+ // Initialize crypto before the client session will create a stream.
+ CompleteCryptoHandshake();
+ QuicStreamId stream_id =
+ QuicSessionPeer::GetNextOutgoingBidirectionalStreamId(session_.get());
+ QuicSessionPeer::ActivateStream(
+ session_.get(), QuicMakeUnique<QuicSpdyClientStream>(
+ stream_id, session_.get(), BIDIRECTIONAL));
+
+ session_->set_max_allowed_push_id(GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 10));
+ if (VersionHasIetfQuicFrames(connection_->transport_version())) {
+ // TODO(b/136295430) Use PushId to represent Push IDs instead of
+ // QuicStreamId.
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_STREAM_ID,
+ "Received push stream id higher than MAX_PUSH_ID.", _));
+ }
+ auto promise_id = GetNthServerInitiatedUnidirectionalStreamId(
+ connection_->transport_version(), 11);
+ auto headers = QuicHeaderList();
+ headers.OnHeaderBlockStart();
+ headers.OnHeader(":path", "/bar");
+ headers.OnHeader(":authority", "www.google.com");
+ headers.OnHeader(":version", "HTTP/1.1");
+ headers.OnHeader(":method", "GET");
+ headers.OnHeader(":scheme", "https");
+ headers.OnHeaderBlockEnd(0, 0);
+ session_->OnPromiseHeaderList(stream_id, promise_id, 0, headers);
+}
+
TEST_P(QuicSpdyClientSessionTest, PushPromiseOnPromiseHeadersAlreadyClosed) {
// Initialize crypto before the client session will create a stream.
CompleteCryptoHandshake();
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 3fe1f5c..4a8dad7 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -375,12 +375,12 @@
kDefaultQpackMaxDynamicTableCapacity);
}
- headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
+ auto headers_stream = QuicMakeUnique<QuicHeadersStream>((this));
DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
- headers_stream_->id());
+ headers_stream->id());
- unowned_headers_stream_ = headers_stream_.get();
- RegisterStaticStream(std::move(headers_stream_),
+ headers_stream_ = headers_stream.get();
+ RegisterStaticStream(std::move(headers_stream),
/*stream_already_counted = */ false);
if (VersionHasStreamType(connection()->transport_version())) {
@@ -559,7 +559,14 @@
QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
const QuicStreamId stream_id) {
- QuicStream* stream = GetOrCreateDynamicStream(stream_id);
+ QuicStream* stream = nullptr;
+ if (GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream) &&
+ GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_inline_getorcreatedynamicstream);
+ stream = GetOrCreateStream(stream_id);
+ } else {
+ stream = GetOrCreateDynamicStream(stream_id);
+ }
if (GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream) && stream &&
stream->is_static()) {
QUIC_RELOADABLE_FLAG_COUNT(quic_handle_staticness_for_spdy_stream);
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 0a009bf..1acdbd5 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -147,11 +147,9 @@
QpackEncoder* qpack_encoder();
QpackDecoder* qpack_decoder();
- QuicHeadersStream* headers_stream() { return unowned_headers_stream_; }
+ QuicHeadersStream* headers_stream() { return headers_stream_; }
- const QuicHeadersStream* headers_stream() const {
- return unowned_headers_stream_;
- }
+ const QuicHeadersStream* headers_stream() const { return headers_stream_; }
bool server_push_enabled() const { return server_push_enabled_; }
@@ -285,15 +283,8 @@
std::unique_ptr<QpackEncoder> qpack_encoder_;
std::unique_ptr<QpackDecoder> qpack_decoder_;
- // TODO(123528590): Remove this member.
- std::unique_ptr<QuicHeadersStream> headers_stream_;
-
- // Unowned headers stream pointer that points to the stream
- // in dynamic_stream_map.
- // TODO(renjietang): Merge this with headers_stream_ and clean up other
- // static_stream_map logic when flag eliminate_static_stream_map
- // is deprecated.
- QuicHeadersStream* unowned_headers_stream_;
+ // Pointer to the header stream in stream_map_.
+ QuicHeadersStream* headers_stream_;
// HTTP/3 control streams. They are owned by QuicSession inside dynamic
// stream map, and can be accessed by those unowned pointers below.
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 4b450e9..36fd20c 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -212,8 +212,8 @@
return QuicSession::IsClosedStream(id);
}
- QuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) {
- return QuicSpdySession::GetOrCreateDynamicStream(stream_id);
+ QuicStream* GetOrCreateStream(QuicStreamId stream_id) {
+ return QuicSpdySession::GetOrCreateStream(stream_id);
}
QuicConsumedData WritevData(QuicStream* stream,
@@ -426,16 +426,16 @@
}
TEST_P(QuicSpdySessionTestServer, AvailableStreams) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(2)) != nullptr);
// Both client initiated streams with smaller stream IDs are available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedBidirectionalId(0)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedBidirectionalId(1)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(1)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(0)) != nullptr);
}
@@ -455,15 +455,15 @@
TEST_P(QuicSpdySessionTestServer, IsClosedStreamPeerCreated) {
QuicStreamId stream_id1 = GetNthClientInitiatedBidirectionalId(0);
QuicStreamId stream_id2 = GetNthClientInitiatedBidirectionalId(1);
- session_.GetOrCreateDynamicStream(stream_id1);
- session_.GetOrCreateDynamicStream(stream_id2);
+ session_.GetOrCreateStream(stream_id1);
+ session_.GetOrCreateStream(stream_id2);
CheckClosedStreams();
CloseStream(stream_id1);
CheckClosedStreams();
CloseStream(stream_id2);
// Create a stream, and make another available.
- QuicStream* stream3 = session_.GetOrCreateDynamicStream(stream_id2 + 4);
+ QuicStream* stream3 = session_.GetOrCreateStream(stream_id2 + 4);
CheckClosedStreams();
// Close one, but make sure the other is still not closed
CloseStream(stream3->id());
@@ -484,13 +484,13 @@
headers_stream_offset,
Perspective::IS_CLIENT, // Client initates stream, allocs stream id.
/*bidirectional=*/true);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
stream_id = StreamCountToId(
QuicSessionPeer::v99_streamid_manager(&session_)
->actual_max_allowed_incoming_unidirectional_streams(),
Perspective::IS_CLIENT,
/*bidirectional=*/false);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(2);
// Get the (max allowed stream ID)++. These should all fail.
stream_id = StreamCountToId(
@@ -499,7 +499,7 @@
1 - headers_stream_offset,
Perspective::IS_CLIENT,
/*bidirectional=*/true);
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id));
stream_id = StreamCountToId(
QuicSessionPeer::v99_streamid_manager(&session_)
@@ -507,14 +507,14 @@
1,
Perspective::IS_CLIENT,
/*bidirectional=*/false);
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id));
} else {
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
- session_.GetOrCreateDynamicStream(stream_id);
+ session_.GetOrCreateStream(stream_id);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_NE(
nullptr,
- session_.GetOrCreateDynamicStream(
+ session_.GetOrCreateStream(
stream_id +
IdDelta() *
(session_.max_open_incoming_bidirectional_streams() - 1)));
@@ -524,7 +524,7 @@
TEST_P(QuicSpdySessionTestServer, TooManyAvailableStreams) {
QuicStreamId stream_id1 = GetNthClientInitiatedBidirectionalId(0);
QuicStreamId stream_id2;
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id1));
// A stream ID which is too large to create.
stream_id2 = GetNthClientInitiatedBidirectionalId(
2 * session_.MaxAvailableBidirectionalStreams() + 4);
@@ -534,7 +534,7 @@
EXPECT_CALL(*connection_,
CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
}
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2));
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id2));
}
TEST_P(QuicSpdySessionTestServer, ManyAvailableStreams) {
@@ -547,12 +547,12 @@
}
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
// Create one stream.
- session_.GetOrCreateDynamicStream(stream_id);
+ session_.GetOrCreateStream(stream_id);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
// Stream count is 200, GetNth... starts counting at 0, so the 200'th stream
// is 199. BUT actually we need to do 198 because the crypto stream (Stream
// ID 0) has not been registered, but GetNth... assumes that it has.
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(198)));
}
@@ -928,9 +928,9 @@
}
TestHeadersStream* headers_stream;
- QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, nullptr);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr);
headers_stream = new TestHeadersStream(&session_);
- QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, headers_stream);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
session_.MarkConnectionLevelWriteBlocked(
QuicUtils::GetHeadersStreamId(connection_->transport_version()));
EXPECT_CALL(*headers_stream, OnCanWrite());
@@ -964,7 +964,7 @@
EXPECT_CALL(*connection_,
OnStreamReset(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY))
.Times(0);
- EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId));
+ EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
}
TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) {
@@ -1662,16 +1662,16 @@
}
TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(2)) != nullptr);
// Both server initiated streams with smaller stream IDs should be available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedBidirectionalId(0)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedBidirectionalId(1)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(0)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(1)) != nullptr);
// And client initiated stream ID should be not available.
EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(
@@ -1741,9 +1741,9 @@
TEST_P(QuicSpdySessionTestClient, WritePriority) {
TestHeadersStream* headers_stream;
- QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, nullptr);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, nullptr);
headers_stream = new TestHeadersStream(&session_);
- QuicSpdySessionPeer::SetUnownedHeadersStream(&session_, headers_stream);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
// Make packet writer blocked so |headers_stream| will buffer its write data.
MockPacketWriter* writer = static_cast<MockPacketWriter*>(
@@ -1789,7 +1789,7 @@
QuicStreamFrame data1(stream_id1, false, 0, QuicStringPiece(data));
session_.OnStreamFrame(data1);
EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
- QuicStream* stream = session_.GetOrCreateDynamicStream(stream_id1);
+ QuicStream* stream = session_.GetOrCreateStream(stream_id1);
EXPECT_EQ(1u, stream->flow_controller()->bytes_consumed());
EXPECT_EQ(1u, session_.flow_controller()->bytes_consumed());
@@ -1800,7 +1800,7 @@
QuicStreamFrame data2(stream_id2, false, 0, QuicStringPiece(data));
session_.OnStreamFrame(data2);
EXPECT_EQ(2u, session_.GetNumOpenIncomingStreams());
- stream = session_.GetOrCreateDynamicStream(stream_id2);
+ stream = session_.GetOrCreateStream(stream_id2);
EXPECT_EQ(4u, stream->flow_controller()->bytes_consumed());
EXPECT_EQ(5u, session_.flow_controller()->bytes_consumed());
}
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 1ad2ddb..ecab751 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -244,7 +244,7 @@
last_decrypted_packet_level_(ENCRYPTION_INITIAL),
should_last_packet_instigate_acks_(false),
max_undecryptable_packets_(0),
- max_tracked_packets_(kMaxTrackedPackets),
+ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
pending_version_negotiation_packet_(false),
send_ietf_version_negotiation_packet_(false),
idle_timeout_connection_close_behavior_(
@@ -963,7 +963,8 @@
return true;
}
const AckResult ack_result = sent_packet_manager_.OnAckFrameEnd(
- time_of_last_received_packet_, last_decrypted_packet_level_);
+ time_of_last_received_packet_, last_header_.packet_number,
+ last_decrypted_packet_level_);
if (ack_result != PACKETS_NEWLY_ACKED &&
ack_result != NO_PACKETS_NEWLY_ACKED) {
// Error occurred (e.g., this ACK tries to ack packets in wrong packet
@@ -2422,6 +2423,13 @@
void QuicConnection::OnRetransmissionTimeout() {
DCHECK(!sent_packet_manager_.unacked_packets().empty());
+ const QuicPacketNumber previous_created_packet_number =
+ packet_generator_.packet_number();
+ const size_t previous_crypto_retransmit_count =
+ stats_.crypto_retransmit_count;
+ const size_t previous_loss_timeout_count = stats_.loss_timeout_count;
+ const size_t previous_tlp_count = stats_.tlp_count;
+ const size_t pervious_rto_count = stats_.rto_count;
if (close_connection_after_five_rtos_ &&
sent_packet_manager_.GetConsecutiveRtoCount() >= 4) {
// Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred.
@@ -2446,6 +2454,29 @@
WriteIfNotBlocked();
}
+ if (sent_packet_manager_.fix_rto_retransmission()) {
+ // Making sure at least one packet is created when retransmission timer
+ // fires in TLP, RTO or HANDSHAKE mode. It is possible that loss algorithm
+ // invokes timer based loss but the packet does not need to be
+ // retransmitted.
+ QUIC_BUG_IF(stats_.loss_timeout_count == previous_loss_timeout_count &&
+ packet_generator_.packet_number() ==
+ previous_created_packet_number)
+ << "previous_crypto_retransmit_count: "
+ << previous_crypto_retransmit_count
+ << ", crypto_retransmit_count: " << stats_.crypto_retransmit_count
+ << ", previous_loss_timeout_count: " << previous_loss_timeout_count
+ << ", loss_timeout_count: " << stats_.loss_timeout_count
+ << ", previous_tlp_count: " << previous_tlp_count
+ << ", tlp_count: " << stats_.tlp_count
+ << ", pervious_rto_count: " << pervious_rto_count
+ << ", rto_count: " << stats_.rto_count
+ << ", previous_created_packet_number: "
+ << previous_created_packet_number
+ << ", packet_number: " << packet_generator_.packet_number()
+ << ", session has data to write: " << visitor_->WillingAndAbleToWrite();
+ }
+
// Ensure the retransmission alarm is always set if there are unacked packets
// and nothing waiting to be sent.
// This happens if the loss algorithm invokes a timer based loss, but the
diff --git a/quic/core/quic_connection_id.cc b/quic/core/quic_connection_id.cc
index a74e3b1..7b4f41b 100644
--- a/quic/core/quic_connection_id.cc
+++ b/quic/core/quic_connection_id.cc
@@ -4,11 +4,14 @@
#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <string>
+#include "third_party/boringssl/src/include/openssl/siphash.h"
+#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
@@ -19,6 +22,34 @@
namespace quic {
+namespace {
+
+// QuicConnectionIdHasher can be used to generate a stable connection ID hash
+// function that will return the same value for two equal connection IDs for
+// the duration of process lifetime. It is meant to be used as input to data
+// structures that do not outlast process lifetime. A new key is generated once
+// per process to prevent attackers from crafting connection IDs in such a way
+// that they always land in the same hash bucket.
+class QuicConnectionIdHasher {
+ public:
+ inline QuicConnectionIdHasher()
+ : QuicConnectionIdHasher(QuicRandom::GetInstance()) {}
+
+ inline QuicConnectionIdHasher(QuicRandom* random) {
+ random->RandBytes(&sip_hash_key_, sizeof(sip_hash_key_));
+ }
+
+ inline size_t Hash(const char* input, size_t input_len) const {
+ return static_cast<size_t>(SIPHASH_24(
+ sip_hash_key_, reinterpret_cast<const uint8_t*>(input), input_len));
+ }
+
+ private:
+ uint64_t sip_hash_key_[2];
+};
+
+} // namespace
+
QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {}
QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
@@ -127,14 +158,20 @@
}
size_t QuicConnectionId::Hash() const {
- uint64_t data_bytes[3] = {0, 0, 0};
- static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
- "kQuicMaxConnectionIdLength changed");
- memcpy(data_bytes, data(), length_);
- // This Hash function is designed to return the same value as the host byte
- // order representation when the connection ID length is 64 bits.
- return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^
- data_bytes[0] ^ data_bytes[1] ^ data_bytes[2]);
+ if (!GetQuicRestartFlag(quic_connection_id_use_siphash)) {
+ uint64_t data_bytes[3] = {0, 0, 0};
+ static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength,
+ "kQuicMaxConnectionIdLength changed");
+ memcpy(data_bytes, data(), length_);
+ // This Hash function is designed to return the same value as the host byte
+ // order representation when the connection ID length is 64 bits.
+ return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^
+ data_bytes[0] ^ data_bytes[1] ^
+ data_bytes[2]);
+ }
+ QUIC_RESTART_FLAG_COUNT(quic_connection_id_use_siphash);
+ static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
+ return hasher.Hash(data(), length_);
}
std::string QuicConnectionId::ToString() const {
diff --git a/quic/core/quic_connection_id.h b/quic/core/quic_connection_id.h
index 4b76f31..6b1b0bc 100644
--- a/quic/core/quic_connection_id.h
+++ b/quic/core/quic_connection_id.h
@@ -72,6 +72,11 @@
bool IsEmpty() const;
// Hash() is required to use connection IDs as keys in hash tables.
+ // During the lifetime of a process, the output of Hash() is guaranteed to be
+ // the same for connection IDs that are equal to one another. Note however
+ // that this property is not guaranteed across process lifetimes. This makes
+ // Hash() suitable for data structures such as hash tables but not for sending
+ // a hash over the network.
size_t Hash() const;
// Generates an ASCII string that represents
@@ -112,6 +117,11 @@
QUIC_EXPORT_PRIVATE QuicConnectionId EmptyQuicConnectionId();
// QuicConnectionIdHash can be passed as hash argument to hash tables.
+// During the lifetime of a process, the output of QuicConnectionIdHash is
+// guaranteed to be the same for connection IDs that are equal to one another.
+// Note however that this property is not guaranteed across process lifetimes.
+// This makes QuicConnectionIdHash suitable for data structures such as hash
+// tables but not for sending a hash over the network.
class QuicConnectionIdHash {
public:
size_t operator()(QuicConnectionId const& connection_id) const noexcept {
diff --git a/quic/core/quic_connection_id_test.cc b/quic/core/quic_connection_id_test.cc
index 1d290fc..64afaf8 100644
--- a/quic/core/quic_connection_id_test.cc
+++ b/quic/core/quic_connection_id_test.cc
@@ -89,6 +89,17 @@
EXPECT_NE(connection_id64_1.Hash(), connection_id64_2.Hash());
EXPECT_NE(connection_id64_1.Hash(), connection_id64_3.Hash());
EXPECT_NE(connection_id64_2.Hash(), connection_id64_3.Hash());
+
+ // Verify that any two all-zero connection IDs of different lengths never
+ // have the same hash.
+ const char connection_id_bytes[kQuicMaxConnectionIdLength] = {};
+ for (uint8_t i = 0; i < kQuicMaxConnectionIdLength - 1; ++i) {
+ QuicConnectionId connection_id_i(connection_id_bytes, i);
+ for (uint8_t j = i + 1; j < kQuicMaxConnectionIdLength; ++j) {
+ QuicConnectionId connection_id_j(connection_id_bytes, j);
+ EXPECT_NE(connection_id_i.Hash(), connection_id_j.Hash());
+ }
+ }
}
TEST_F(QuicConnectionIdTest, AssignAndCopy) {
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index f04d142..6b5b943 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -4065,6 +4065,54 @@
EXPECT_EQ(QuicPacketNumber(1u), stop_waiting()->least_unacked);
}
+// Regression test of b/133771183.
+TEST_P(QuicConnectionTest, RtoWithNoDataToRetransmit) {
+ if (!connection_.session_decides_what_to_write()) {
+ return;
+ }
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SetMaxTailLossProbes(0);
+
+ SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr);
+ // Connection is cwnd limited.
+ CongestionBlockWrites();
+ // Stream gets reset.
+ SendRstStream(3, QUIC_ERROR_PROCESSING_STREAM, 3);
+ // Simulate the retransmission alarm firing.
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ // RTO fires, but there is no packet to be RTOed.
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ } else {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ }
+ connection_.GetRetransmissionAlarm()->Fire();
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ 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)) {
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite())
+ .WillRepeatedly(Return(false));
+ } else {
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
+ }
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1);
+ } else {
+ // Since there is a buffered RST_STREAM, no retransmittable frame is bundled
+ // with ACKs.
+ EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(0);
+ }
+ // Receives packets 1 - 40.
+ for (size_t i = 1; i <= 40; ++i) {
+ ProcessDataPacket(i);
+ }
+}
+
TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
use_tagging_decrypter();
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index e718602..442fb09 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -87,9 +87,6 @@
// Minimum size of the CWND, in packets, when doing bandwidth resumption.
const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
-// Maximum number of tracked packets.
-const QuicPacketCount kMaxTrackedPackets = 10000;
-
// Default size of the socket receive buffer in bytes.
const QuicByteCount kDefaultSocketReceiveBuffer = 1024 * 1024;
diff --git a/quic/core/quic_flow_controller.cc b/quic/core/quic_flow_controller.cc
index 3fb5d75..dbc5100 100644
--- a/quic/core/quic_flow_controller.cc
+++ b/quic/core/quic_flow_controller.cc
@@ -21,6 +21,13 @@
#define ENDPOINT \
(perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+std::string QuicFlowController::LogLabel() {
+ if (is_connection_flow_controller_) {
+ return "connection";
+ }
+ return QuicStrCat("stream ", id_);
+}
+
QuicFlowController::QuicFlowController(
QuicSession* session,
QuicStreamId id,
@@ -51,7 +58,7 @@
QuicUtils::GetInvalidStreamId(
session_->connection()->transport_version()) == id_);
- QUIC_DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "Created flow controller for " << LogLabel()
<< ", setting initial receive window offset to: "
<< receive_window_offset_
<< ", max receive window to: " << receive_window_size_
@@ -62,8 +69,8 @@
void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) {
bytes_consumed_ += bytes_consumed;
- QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed "
- << bytes_consumed_ << " bytes.";
+ QUIC_DVLOG(1) << ENDPOINT << LogLabel() << " consumed " << bytes_consumed_
+ << " bytes.";
MaybeSendWindowUpdate();
}
@@ -75,7 +82,7 @@
return false;
}
- QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << LogLabel()
<< " highest byte offset increased from "
<< highest_received_byte_offset_ << " to " << new_offset;
highest_received_byte_offset_ = new_offset;
@@ -84,7 +91,7 @@
void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) {
if (bytes_sent_ + bytes_sent > send_window_offset_) {
- QUIC_BUG << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
+ QUIC_BUG << ENDPOINT << LogLabel() << " Trying to send an extra "
<< bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
<< ", and send_window_offset_ = " << send_window_offset_;
bytes_sent_ = send_window_offset_;
@@ -99,13 +106,13 @@
}
bytes_sent_ += bytes_sent;
- QUIC_DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent " << bytes_sent_
+ QUIC_DVLOG(1) << ENDPOINT << LogLabel() << " sent " << bytes_sent_
<< " bytes.";
}
bool QuicFlowController::FlowControlViolation() {
if (highest_received_byte_offset_ > receive_window_offset_) {
- QUIC_DLOG(INFO) << ENDPOINT << "Flow control violation on stream " << id_
+ QUIC_DLOG(INFO) << ENDPOINT << "Flow control violation on " << LogLabel()
<< ", receive window offset: " << receive_window_offset_
<< ", highest received byte offset: "
<< highest_received_byte_offset_;
@@ -128,7 +135,7 @@
QuicTime prev = prev_window_update_time_;
prev_window_update_time_ = now;
if (!prev.IsInitialized()) {
- QUIC_DVLOG(1) << ENDPOINT << "first window update for stream " << id_;
+ QUIC_DVLOG(1) << ENDPOINT << "first window update for " << LogLabel();
return;
}
@@ -140,7 +147,7 @@
QuicTime::Delta rtt =
connection_->sent_packet_manager().GetRttStats()->smoothed_rtt();
if (rtt.IsZero()) {
- QUIC_DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_;
+ QUIC_DVLOG(1) << ENDPOINT << "rtt zero for " << LogLabel();
return;
}
@@ -157,7 +164,7 @@
IncreaseWindowSize();
if (receive_window_size_ > old_window) {
- QUIC_DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "New max window increase for " << LogLabel()
<< " after " << since_last.ToMicroseconds()
<< " us, and RTT is " << rtt.ToMicroseconds()
<< "us. max wndw: " << receive_window_size_;
@@ -168,7 +175,7 @@
} else {
// TODO(ckrasic) - add a varz to track this (?).
QUIC_LOG_FIRST_N(INFO, 1)
- << ENDPOINT << "Max window at limit for stream " << id_ << " after "
+ << ENDPOINT << "Max window at limit for " << LogLabel() << " after "
<< since_last.ToMicroseconds() << " us, and RTT is "
<< rtt.ToMicroseconds() << "us. Limit size: " << receive_window_size_;
}
@@ -199,7 +206,7 @@
}
if (available_window >= threshold) {
- QUIC_DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for " << LogLabel()
<< ", available window: " << available_window
<< " >= threshold: " << threshold;
return;
@@ -214,7 +221,7 @@
// Update our receive window.
receive_window_offset_ += (receive_window_size_ - available_window);
- QUIC_DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for " << LogLabel()
<< ", consumed bytes: " << bytes_consumed_
<< ", available window: " << available_window
<< ", and threshold: " << WindowUpdateThreshold()
@@ -229,8 +236,7 @@
last_blocked_send_window_offset_ >= send_window_offset_) {
return false;
}
- QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id_
- << " is flow control blocked. "
+ QUIC_DLOG(INFO) << ENDPOINT << LogLabel() << " is flow control blocked. "
<< "Send window: " << SendWindowSize()
<< ", bytes sent: " << bytes_sent_
<< ", send limit: " << send_window_offset_;
@@ -250,7 +256,7 @@
return false;
}
- QUIC_DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for " << LogLabel()
<< " with new offset " << new_send_window_offset
<< " current offset: " << send_window_offset_
<< " bytes_sent: " << bytes_sent_;
@@ -286,7 +292,7 @@
void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) {
DCHECK_LE(size, receive_window_size_limit_);
- QUIC_DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for stream " << id_
+ QUIC_DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for " << LogLabel()
<< ": " << size;
if (receive_window_size_ != receive_window_offset_) {
QUIC_BUG << "receive_window_size_:" << receive_window_size_
diff --git a/quic/core/quic_flow_controller.h b/quic/core/quic_flow_controller.h
index 4de292c..e627c8c 100644
--- a/quic/core/quic_flow_controller.h
+++ b/quic/core/quic_flow_controller.h
@@ -121,6 +121,10 @@
// Double the window size as long as we haven't hit the max window size.
void IncreaseWindowSize();
+ // Returns "stream $ID" (where $ID is set to |id_|) or "connection" based on
+ // |is_connection_flow_controller_|.
+ std::string LogLabel();
+
// The parent session/connection, used to send connection close on flow
// control violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
// Not owned.
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 5324206..1280f2e 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -556,7 +556,8 @@
if (VersionHasIetfQuicFrames(version)) {
return QuicDataWriter::GetVarInt62Len(frame.stream_id) +
QuicDataWriter::GetVarInt62Len(frame.byte_offset) +
- kQuicFrameTypeSize + kQuicIetfQuicErrorCodeSize;
+ kQuicFrameTypeSize +
+ QuicDataWriter::GetVarInt62Len(frame.ietf_error_code);
}
return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize +
kQuicErrorCodeSize;
@@ -665,7 +666,7 @@
// static
size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) {
return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id) +
- sizeof(QuicApplicationErrorCode);
+ QuicDataWriter::GetVarInt62Len(frame.application_error_code);
}
// static
@@ -5812,7 +5813,7 @@
set_detailed_error("Writing reset-stream stream id failed.");
return false;
}
- if (!writer->WriteUInt16(frame.ietf_error_code)) {
+ if (!writer->WriteVarInt62(static_cast<uint64_t>(frame.ietf_error_code))) {
set_detailed_error("Writing reset-stream error code failed.");
return false;
}
@@ -5833,10 +5834,18 @@
return false;
}
- if (!reader->ReadUInt16(&frame->ietf_error_code)) {
+ uint64_t error_code;
+ if (!reader->ReadVarInt62(&error_code)) {
set_detailed_error("Unable to read rst stream error code.");
return false;
}
+ if (error_code > 0xffff) {
+ frame->ietf_error_code = 0xffff;
+ QUIC_DLOG(ERROR) << "Reset stream error code (" << error_code
+ << ") > 0xffff";
+ } else {
+ frame->ietf_error_code = static_cast<uint16_t>(error_code);
+ }
if (!reader->ReadVarInt62(&frame->byte_offset)) {
set_detailed_error("Unable to read rst stream sent byte offset.");
@@ -5853,10 +5862,20 @@
return false;
}
- if (!reader->ReadUInt16(&stop_sending_frame->application_error_code)) {
+ uint64_t error_code;
+ if (!reader->ReadVarInt62(&error_code)) {
set_detailed_error("Unable to read stop sending application error code.");
return false;
}
+ // TODO(fkastenholz): when error codes go to uint64_t, remove this.
+ if (error_code > 0xffff) {
+ stop_sending_frame->application_error_code = 0xffff;
+ QUIC_DLOG(ERROR) << "Stop sending error code (" << error_code
+ << ") > 0xffff";
+ } else {
+ stop_sending_frame->application_error_code =
+ static_cast<uint16_t>(error_code);
+ }
return true;
}
@@ -5867,7 +5886,8 @@
set_detailed_error("Can not write stop sending stream id");
return false;
}
- if (!writer->WriteUInt16(stop_sending_frame.application_error_code)) {
+ if (!writer->WriteVarInt62(
+ static_cast<uint64_t>(stop_sending_frame.application_error_code))) {
set_detailed_error("Can not write application error code");
return false;
}
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 29ae36f..690e911 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -4544,7 +4544,7 @@
{kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
// application error code
{"Unable to read rst stream error code.",
- {0x00, 0x01}}, // Not varint62 encoded
+ {kVarInt62OneByte + 0x01}},
// Final Offset
{"Unable to read rst stream sent byte offset.",
{kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}
@@ -7801,8 +7801,8 @@
0x04,
// stream id
kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
- // error code (not VarInt32 encoded)
- 0x00, 0x01,
+ // error code
+ kVarInt62OneByte + 0x01,
// sent byte offset
kVarInt62EightBytes + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
};
@@ -11650,7 +11650,7 @@
{"Unable to read stop sending stream id.",
{kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04}},
{"Unable to read stop sending application error code.",
- {0x76, 0x54}},
+ {kVarInt62FourBytes + 0x00, 0x00, 0x76, 0x54}},
};
// clang-format on
@@ -11701,7 +11701,7 @@
// Stream ID
kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
// Application error code
- 0xff, 0xff
+ kVarInt62FourBytes + 0x00, 0x00, 0xff, 0xff
};
// clang-format on
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc
index 9d07e49..dbbacdd 100644
--- a/quic/core/quic_ietf_framer_test.cc
+++ b/quic/core/quic_ietf_framer_test.cc
@@ -457,9 +457,10 @@
// Write the frame to the packet buffer.
EXPECT_TRUE(QuicFramerPeer::AppendIetfResetStreamFrame(
&framer_, transmit_frame, &writer));
- // Check that the size of the serialzed frame is in the allowed range.
- EXPECT_LT(3u, writer.length());
- EXPECT_GT(19u, writer.length());
+ // Check that the size of the serialzed frame is in the allowed range (3 to
+ // 24 bytes, inclusive).
+ EXPECT_LT(2u, writer.length());
+ EXPECT_GT(25u, writer.length());
// Now set up a reader to read in the thing in.
QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER);
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index a4aa08e..e7cd1a5 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -120,10 +120,15 @@
loss_removes_from_inflight_(
GetQuicReloadableFlag(quic_loss_removes_from_inflight)),
ignore_tlpr_if_no_pending_stream_data_(
- GetQuicReloadableFlag(quic_ignore_tlpr_if_no_pending_stream_data)) {
+ GetQuicReloadableFlag(quic_ignore_tlpr_if_no_pending_stream_data)),
+ fix_rto_retransmission_(
+ GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
if (loss_removes_from_inflight_) {
QUIC_RELOADABLE_FLAG_COUNT(quic_loss_removes_from_inflight);
}
+ if (fix_rto_retransmission_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission);
+ }
SetSendAlgorithm(congestion_control_type);
}
@@ -276,6 +281,7 @@
}
void QuicSentPacketManager::PostProcessNewlyAckedPackets(
+ QuicPacketNumber ack_packet_number,
const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
bool rtt_updated,
@@ -321,9 +327,9 @@
}
if (debug_delegate_ != nullptr) {
- debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time,
- LargestAcked(ack_frame), rtt_updated,
- GetLeastUnacked());
+ debug_delegate_->OnIncomingAck(ack_packet_number, ack_frame,
+ ack_receive_time, LargestAcked(ack_frame),
+ rtt_updated, GetLeastUnacked());
}
// Remove packets below least unacked from all_packets_acked_ and
// last_ack_frame_.
@@ -803,7 +809,7 @@
if (session_decides_what_to_write()) {
has_retransmissions = it->state != OUTSTANDING;
}
- if (it->in_flight && !has_retransmissions &&
+ if (!fix_rto_retransmission_ && it->in_flight && !has_retransmissions &&
!unacked_packets_.HasRetransmittableFrames(*it)) {
// Log only for non-retransmittable data.
// Retransmittable data is marked as lost during loss detection, and will
@@ -825,6 +831,13 @@
for (QuicPacketNumber retransmission : retransmissions) {
MarkForRetransmission(retransmission, RTO_RETRANSMISSION);
}
+ if (fix_rto_retransmission_ && retransmissions.empty()) {
+ QUIC_BUG_IF(pending_timer_transmission_count_ != 0);
+ // No packets to be RTO retransmitted, raise up a credit to allow
+ // connection to send.
+ QUIC_CODE_COUNT(no_packets_to_be_rto_retransmitted);
+ pending_timer_transmission_count_ = 1;
+ }
}
}
@@ -1158,6 +1171,7 @@
AckResult QuicSentPacketManager::OnAckFrameEnd(
QuicTime ack_receive_time,
+ QuicPacketNumber ack_packet_number,
EncryptionLevel ack_decrypted_level) {
QuicByteCount prior_bytes_in_flight = unacked_packets_.bytes_in_flight();
// Reverse packets_acked_ so that it is in ascending order.
@@ -1218,7 +1232,8 @@
acked_packet.receive_timestamp);
}
const bool acked_new_packet = !packets_acked_.empty();
- PostProcessNewlyAckedPackets(last_ack_frame_, ack_receive_time, rtt_updated_,
+ PostProcessNewlyAckedPackets(ack_packet_number, last_ack_frame_,
+ ack_receive_time, rtt_updated_,
prior_bytes_in_flight);
return acked_new_packet ? PACKETS_NEWLY_ACKED : NO_PACKETS_NEWLY_ACKED;
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index b90d977..b08704d 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -57,7 +57,8 @@
TransmissionType /*transmission_type*/,
QuicByteCount /*byte_size*/) {}
- virtual void OnIncomingAck(const QuicAckFrame& /*ack_frame*/,
+ virtual void OnIncomingAck(QuicPacketNumber /*ack_packet_number*/,
+ const QuicAckFrame& /*ack_frame*/,
QuicTime /*ack_receive_time*/,
QuicPacketNumber /*largest_observed*/,
bool /*rtt_updated*/,
@@ -278,6 +279,7 @@
// Called when an ack frame is parsed completely.
AckResult OnAckFrameEnd(QuicTime ack_receive_time,
+ QuicPacketNumber ack_packet_number,
EncryptionLevel ack_decrypted_level);
// Called to enable/disable letting session decide what to write.
@@ -389,6 +391,8 @@
return ignore_tlpr_if_no_pending_stream_data_;
}
+ bool fix_rto_retransmission() const { return fix_rto_retransmission_; }
+
private:
friend class test::QuicConnectionPeer;
friend class test::QuicSentPacketManagerPeer;
@@ -493,7 +497,8 @@
QuicTransmissionInfo* transmission_info);
// Called after packets have been marked handled with last received ack frame.
- void PostProcessNewlyAckedPackets(const QuicAckFrame& ack_frame,
+ void PostProcessNewlyAckedPackets(QuicPacketNumber ack_packet_number,
+ const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
bool rtt_updated,
QuicByteCount prior_bytes_in_flight);
@@ -634,6 +639,9 @@
// Latched value of quic_ignore_tlpr_if_no_pending_stream_data.
const bool ignore_tlpr_if_no_pending_stream_data_;
+
+ // Latched value of quic_fix_rto_retransmission.
+ const bool fix_rto_retransmission_;
};
} // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 075690e..4fce40f 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -404,7 +404,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
}
@@ -436,7 +437,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// There should no longer be a pending retransmission.
EXPECT_FALSE(manager_.HasPendingRetransmissions());
@@ -491,7 +493,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
}
@@ -508,7 +511,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
}
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
@@ -526,7 +530,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
SendDataPacket(3);
SendDataPacket(4);
@@ -540,7 +545,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
ExpectAck(4);
manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(),
@@ -548,7 +554,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3),
+ ENCRYPTION_INITIAL));
ExpectAckAndLoss(true, 5, 2);
if (manager_.session_decides_what_to_write()) {
@@ -563,7 +570,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
@@ -600,7 +608,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
uint64_t unacked[] = {2};
@@ -638,7 +647,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
// Frames in packets 2 and 3 are acked.
EXPECT_CALL(notifier_, IsFrameOutstanding(_))
@@ -667,7 +677,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
uint64_t unacked2[] = {2};
VerifyUnackedPackets(unacked2, QUIC_ARRAYSIZE(unacked2));
@@ -689,7 +700,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
uint64_t unacked[] = {2};
@@ -723,7 +735,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
}
SendDataPacket(3);
@@ -737,7 +750,8 @@
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
}
@@ -753,7 +767,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
// Ack 3 will not cause 5 be considered as a spurious retransmission. Ack
// 5 will cause 5 be considered as a spurious retransmission as no new
@@ -766,7 +781,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4),
+ ENCRYPTION_INITIAL));
}
}
}
@@ -792,7 +808,8 @@
QuicTime::Delta::FromMilliseconds(5), clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(1), manager_.largest_packet_peer_knows_is_acked());
SendAckPacket(3, 3);
@@ -804,7 +821,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(3u),
manager_.largest_packet_peer_knows_is_acked());
}
@@ -819,7 +837,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -836,7 +855,8 @@
QuicTime::Delta::FromMilliseconds(11), clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -852,7 +872,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -868,7 +889,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
}
@@ -919,7 +941,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_TRUE(manager_.HasInFlightPackets());
@@ -941,7 +964,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasPendingRetransmissions());
EXPECT_FALSE(manager_.HasInFlightPackets());
@@ -1048,7 +1072,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(103), QuicPacketNumber(104));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// All packets before 103 should be lost.
if (manager_.session_decides_what_to_write()) {
// Packet 104 is still in flight.
@@ -1134,7 +1159,8 @@
manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(6));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasUnackedCryptoPackets());
}
@@ -1206,7 +1232,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(8), QuicPacketNumber(10));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
if (manager_.session_decides_what_to_write()) {
EXPECT_CALL(notifier_, HasUnackedCryptoData())
.WillRepeatedly(Return(false));
@@ -1252,7 +1279,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasUnackedCryptoPackets());
if (GetQuicReloadableFlag(quic_loss_removes_from_inflight)) {
@@ -1378,7 +1406,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
VerifyUnackedPackets(nullptr, 0);
VerifyRetransmittablePackets(nullptr, 0);
}
@@ -1441,7 +1470,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) {
@@ -1550,7 +1580,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(102), QuicPacketNumber(103));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
@@ -1595,7 +1626,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// The original packet and newest should be outstanding.
EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight());
@@ -1643,7 +1675,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// The first two packets should still be outstanding.
EXPECT_EQ(2 * kDefaultLength, manager_.GetBytesInFlight());
@@ -1955,7 +1988,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_FALSE(manager_.HasPendingRetransmissions());
EXPECT_EQ(5 * kDefaultLength, manager_.GetBytesInFlight());
@@ -2090,7 +2124,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10));
EXPECT_CALL(*loss_algorithm, GetLossTimeout())
@@ -2575,7 +2610,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, OnAckRangeSlowPath) {
@@ -2597,7 +2633,8 @@
// Make sure empty range does not harm.
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// Ack [4, 8), [9, 13), [14, 21).
uint64_t acked2[] = {4, 7, 9, 12, 14, 17, 18, 19, 20};
@@ -2608,7 +2645,8 @@
manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13));
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, TolerateReneging) {
@@ -2628,7 +2666,8 @@
manager_.OnAckRange(QuicPacketNumber(10), QuicPacketNumber(12));
manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(7));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// Making sure reneged ACK does not harm. Ack [4, 8), [9, 13).
uint64_t acked2[] = {4, 7, 9, 12};
@@ -2638,7 +2677,8 @@
manager_.OnAckRange(QuicPacketNumber(9), QuicPacketNumber(13));
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(8));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(16), manager_.GetLargestObserved());
}
@@ -2660,7 +2700,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
EXPECT_EQ(QuicPacketNumber(1),
manager_.GetLargestAckedPacket(ENCRYPTION_INITIAL));
EXPECT_FALSE(
@@ -2680,7 +2721,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(2),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_FALSE(
@@ -2691,7 +2733,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(3),
+ ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_FALSE(
@@ -2713,7 +2756,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(5), QuicPacketNumber(6));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_FORWARD_SECURE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(4),
+ ENCRYPTION_FORWARD_SECURE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(5),
@@ -2740,7 +2784,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(4), QuicPacketNumber(9));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_FORWARD_SECURE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(5),
+ ENCRYPTION_FORWARD_SECURE));
EXPECT_EQ(QuicPacketNumber(3),
manager_.GetLargestAckedPacket(ENCRYPTION_HANDSHAKE));
EXPECT_EQ(QuicPacketNumber(8),
@@ -2762,7 +2807,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
}
TEST_P(QuicSentPacketManagerTest, PacketsGetAckedInWrongPacketNumberSpace2) {
@@ -2778,7 +2824,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_ACKED_IN_WRONG_PACKET_NUMBER_SPACE,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_HANDSHAKE));
}
TEST_P(QuicSentPacketManagerTest,
@@ -2792,7 +2839,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
// Send packets 2 and 3.
SendDataPacket(2, ENCRYPTION_HANDSHAKE);
@@ -2806,7 +2854,8 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_HANDSHAKE));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_HANDSHAKE));
}
// Regression test for b/133771183.
@@ -2848,7 +2897,8 @@
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(5));
manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1),
+ ENCRYPTION_INITIAL));
uint64_t acked2[] = {5, 6};
uint64_t loss[] = {2};
@@ -2865,7 +2915,39 @@
clock_.Now());
manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(7));
EXPECT_EQ(PACKETS_NEWLY_ACKED,
- manager_.OnAckFrameEnd(clock_.Now(), ENCRYPTION_INITIAL));
+ manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2),
+ ENCRYPTION_INITIAL));
+}
+
+TEST_P(QuicSentPacketManagerTest, RtoFiresNoPacketToRetransmit) {
+ if (!manager_.session_decides_what_to_write()) {
+ return;
+ }
+ // Send 10 packets.
+ for (size_t i = 1; i <= 10; ++i) {
+ SendDataPacket(i);
+ }
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+ .Times(2)
+ .WillOnce(WithArgs<1>(Invoke(
+ [this](TransmissionType type) { RetransmitDataPacket(11, type); })))
+ .WillOnce(WithArgs<1>(Invoke(
+ [this](TransmissionType type) { RetransmitDataPacket(12, type); })));
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(1u, stats_.rto_count);
+ EXPECT_EQ(0u, manager_.pending_timer_transmission_count());
+
+ // RTO fires again, but there is no packet to be RTO retransmitted.
+ EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false));
+ EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0);
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(2u, stats_.rto_count);
+ if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+ // Verify a credit is raised up.
+ EXPECT_EQ(1u, manager_.pending_timer_transmission_count());
+ } else {
+ EXPECT_EQ(0u, manager_.pending_timer_transmission_count());
+ }
}
} // namespace
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 750f256..b2d0bce 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1071,7 +1071,7 @@
void QuicSession::HandleRstOnValidNonexistentStream(
const QuicRstStreamFrame& frame) {
// If the stream is neither originally in active streams nor created in
- // GetOrCreateDynamicStream(), it could be a closed stream in which case its
+ // GetOrCreateStream(), it could be a closed stream in which case its
// final received byte offset need to be updated.
if (IsClosedStream(frame.stream_id)) {
// The RST frame contains the final byte offset for the stream: we can now
@@ -1224,7 +1224,42 @@
stream_id)) {
return GetMutableCryptoStream();
}
- return GetOrCreateDynamicStream(stream_id);
+
+ StreamMap::iterator it = stream_map_.find(stream_id);
+ if (it != stream_map_.end()) {
+ return it->second.get();
+ }
+
+ if (IsClosedStream(stream_id)) {
+ return nullptr;
+ }
+
+ if (!IsIncomingStream(stream_id)) {
+ HandleFrameOnNonexistentOutgoingStream(stream_id);
+ return nullptr;
+ }
+
+ // TODO(fkastenholz): If we are creating a new stream and we have
+ // sent a goaway, we should ignore the stream creation. Need to
+ // add code to A) test if goaway was sent ("if (goaway_sent_)") and
+ // B) reject stream creation ("return nullptr")
+
+ if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
+ return nullptr;
+ }
+
+ if (!VersionHasIetfQuicFrames(connection_->transport_version())) {
+ // TODO(fayang): Let LegacyQuicStreamIdManager count open streams and make
+ // CanOpenIncomingStream interface consistent with that of v99.
+ if (!stream_id_manager_.CanOpenIncomingStream(
+ GetNumOpenIncomingStreams())) {
+ // Refuse to open the stream.
+ SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ return nullptr;
+ }
+ }
+
+ return CreateIncomingStream(stream_id);
}
void QuicSession::StreamDraining(QuicStreamId stream_id) {
@@ -1278,6 +1313,7 @@
QuicStream* QuicSession::GetOrCreateDynamicStream(
const QuicStreamId stream_id) {
+ DCHECK(!GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream));
StreamMap::iterator it = stream_map_.find(stream_id);
if (it != stream_map_.end()) {
return it->second.get();
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 5ef497d..24060e8 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -370,6 +370,7 @@
// such stream exists, and |stream_id| is a peer-created stream id,
// then a new stream is created and returned. In all other cases, nullptr is
// returned.
+ // Caller does not own the returned stream.
QuicStream* GetOrCreateStream(const QuicStreamId stream_id);
// Mark a stream as draining.
@@ -475,6 +476,8 @@
// returned. However if |stream_id| is a locally-created id and no such stream
// exists, the connection is closed.
// Caller does not own the returned stream.
+ // TODO(renjietang): Remove this method after
+ // quic_inline_getorcreatedynamicstream is deprecated.
QuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id);
// Performs the work required to close |stream_id|. If |locally_reset|
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 0f8420d..49316dd 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -187,7 +187,7 @@
max_open_incoming_bidirectional_streams() &&
!VersionHasIetfQuicFrames(connection()->transport_version())) {
// No need to do this test for version 99; it's done by
- // QuicSession::GetOrCreateDynamicStream.
+ // QuicSession::GetOrCreateStream.
connection()->CloseConnection(
QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -232,8 +232,8 @@
return QuicSession::IsClosedStream(id);
}
- QuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) {
- return QuicSession::GetOrCreateDynamicStream(stream_id);
+ QuicStream* GetOrCreateStream(QuicStreamId stream_id) {
+ return QuicSession::GetOrCreateStream(stream_id);
}
bool ShouldKeepConnectionAlive() const override {
@@ -531,30 +531,30 @@
}
TEST_P(QuicSessionTestServer, AvailableBidirectionalStreams) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(3)) != nullptr);
// Smaller bidirectional streams should be available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedBidirectionalId(1)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedBidirectionalId(2)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(2)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(1)) != nullptr);
}
TEST_P(QuicSessionTestServer, AvailableUnidirectionalStreams) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(3)) != nullptr);
// Smaller unidirectional streams should be available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedUnidirectionalId(1)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthClientInitiatedUnidirectionalId(2)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(2)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(1)) != nullptr);
}
@@ -613,15 +613,15 @@
TEST_P(QuicSessionTestServer, IsClosedBidirectionalStreamPeerCreated) {
QuicStreamId stream_id1 = GetNthClientInitiatedBidirectionalId(0);
QuicStreamId stream_id2 = GetNthClientInitiatedBidirectionalId(1);
- session_.GetOrCreateDynamicStream(stream_id1);
- session_.GetOrCreateDynamicStream(stream_id2);
+ session_.GetOrCreateStream(stream_id1);
+ session_.GetOrCreateStream(stream_id2);
CheckClosedStreams();
CloseStream(stream_id1);
CheckClosedStreams();
CloseStream(stream_id2);
// Create a stream, and make another available.
- QuicStream* stream3 = session_.GetOrCreateDynamicStream(
+ QuicStream* stream3 = session_.GetOrCreateStream(
stream_id2 +
2 * QuicUtils::StreamIdDelta(connection_->transport_version()));
CheckClosedStreams();
@@ -633,15 +633,15 @@
TEST_P(QuicSessionTestServer, IsClosedUnidirectionalStreamPeerCreated) {
QuicStreamId stream_id1 = GetNthClientInitiatedUnidirectionalId(0);
QuicStreamId stream_id2 = GetNthClientInitiatedUnidirectionalId(1);
- session_.GetOrCreateDynamicStream(stream_id1);
- session_.GetOrCreateDynamicStream(stream_id2);
+ session_.GetOrCreateStream(stream_id1);
+ session_.GetOrCreateStream(stream_id2);
CheckClosedStreams();
CloseStream(stream_id1);
CheckClosedStreams();
CloseStream(stream_id2);
// Create a stream, and make another available.
- QuicStream* stream3 = session_.GetOrCreateDynamicStream(
+ QuicStream* stream3 = session_.GetOrCreateStream(
stream_id2 +
2 * QuicUtils::StreamIdDelta(connection_->transport_version()));
CheckClosedStreams();
@@ -652,28 +652,26 @@
TEST_P(QuicSessionTestServer, MaximumAvailableOpenedBidirectionalStreams) {
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
- session_.GetOrCreateDynamicStream(stream_id);
+ session_.GetOrCreateStream(stream_id);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_NE(
- nullptr,
- session_.GetOrCreateDynamicStream(GetNthClientInitiatedBidirectionalId(
- session_.max_open_incoming_bidirectional_streams() - 1)));
+ EXPECT_NE(nullptr,
+ session_.GetOrCreateStream(GetNthClientInitiatedBidirectionalId(
+ session_.max_open_incoming_bidirectional_streams() - 1)));
}
TEST_P(QuicSessionTestServer, MaximumAvailableOpenedUnidirectionalStreams) {
QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0);
- session_.GetOrCreateDynamicStream(stream_id);
+ session_.GetOrCreateStream(stream_id);
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_NE(
- nullptr,
- session_.GetOrCreateDynamicStream(GetNthClientInitiatedUnidirectionalId(
- session_.max_open_incoming_unidirectional_streams() - 1)));
+ EXPECT_NE(nullptr,
+ session_.GetOrCreateStream(GetNthClientInitiatedUnidirectionalId(
+ session_.max_open_incoming_unidirectional_streams() - 1)));
}
TEST_P(QuicSessionTestServer, TooManyAvailableBidirectionalStreams) {
QuicStreamId stream_id1 = GetNthClientInitiatedBidirectionalId(0);
QuicStreamId stream_id2;
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id1));
// A stream ID which is too large to create.
stream_id2 = GetNthClientInitiatedBidirectionalId(
session_.MaxAvailableBidirectionalStreams() + 2);
@@ -686,13 +684,13 @@
EXPECT_CALL(*connection_,
CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
}
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2));
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id2));
}
TEST_P(QuicSessionTestServer, TooManyAvailableUnidirectionalStreams) {
QuicStreamId stream_id1 = GetNthClientInitiatedUnidirectionalId(0);
QuicStreamId stream_id2;
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id1));
// A stream ID which is too large to create.
stream_id2 = GetNthClientInitiatedUnidirectionalId(
session_.MaxAvailableUnidirectionalStreams() + 2);
@@ -705,7 +703,7 @@
EXPECT_CALL(*connection_,
CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
}
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2));
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(stream_id2));
}
TEST_P(QuicSessionTestServer, ManyAvailableBidirectionalStreams) {
@@ -720,21 +718,21 @@
}
// Create a stream at the start of the range.
QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
// Create the largest stream ID of a threatened total of 200 streams.
// GetNth... starts at 0, so for 200 streams, get the 199th.
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(199)));
if (VersionHasIetfQuicFrames(transport_version())) {
// If IETF QUIC, check to make sure that creating bidirectional
// streams does not mess up the unidirectional streams.
stream_id = GetNthClientInitiatedUnidirectionalId(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
// Now try to get the last possible unidirectional stream.
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(49)));
// and this should fail because it exceeds the unidirectional limit
// (but not the bi-)
@@ -746,7 +744,7 @@
))
.Times(1);
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(199)));
}
}
@@ -763,20 +761,20 @@
}
// Create one stream.
QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
// Create the largest stream ID of a threatened total of 200 streams.
// GetNth... starts at 0, so for 200 streams, get the 199th.
EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedUnidirectionalId(199)));
if (VersionHasIetfQuicFrames(transport_version())) {
// If IETF QUIC, check to make sure that creating unidirectional
// streams does not mess up the bidirectional streams.
stream_id = GetNthClientInitiatedBidirectionalId(0);
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id));
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(stream_id));
// Now try to get the last possible bidirectional stream.
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_NE(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(49)));
// and this should fail because it exceeds the bnidirectional limit
// (but not the uni-)
@@ -791,7 +789,7 @@
CloseConnection(QUIC_INVALID_STREAM_ID, error_detail,
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET))
.Times(1);
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(
+ EXPECT_EQ(nullptr, session_.GetOrCreateStream(
GetNthClientInitiatedBidirectionalId(199)));
}
}
@@ -1186,7 +1184,7 @@
EXPECT_CALL(*connection_,
OnStreamReset(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY))
.Times(0);
- EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId));
+ EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId));
}
TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) {
@@ -1821,16 +1819,16 @@
::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSessionTestClient, AvailableBidirectionalStreamsClient) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(2)) != nullptr);
// Smaller bidirectional streams should be available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedBidirectionalId(0)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedBidirectionalId(1)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(0)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedBidirectionalId(1)) != nullptr);
// And 5 should be not available.
EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(
@@ -1838,16 +1836,16 @@
}
TEST_P(QuicSessionTestClient, AvailableUnidirectionalStreamsClient) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedUnidirectionalId(2)) != nullptr);
// Smaller unidirectional streams should be available.
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedUnidirectionalId(0)));
EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(
&session_, GetNthServerInitiatedUnidirectionalId(1)));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedUnidirectionalId(0)) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(
+ ASSERT_TRUE(session_.GetOrCreateStream(
GetNthServerInitiatedUnidirectionalId(1)) != nullptr);
// And 5 should be not available.
EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(
diff --git a/quic/core/quic_trace_visitor.cc b/quic/core/quic_trace_visitor.cc
index f15e149..42ee003 100644
--- a/quic/core/quic_trace_visitor.cc
+++ b/quic/core/quic_trace_visitor.cc
@@ -225,6 +225,7 @@
}
void QuicTraceVisitor::OnIncomingAck(
+ QuicPacketNumber /*ack_packet_number*/,
const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
QuicPacketNumber /*largest_observed*/,
diff --git a/quic/core/quic_trace_visitor.h b/quic/core/quic_trace_visitor.h
index 8021865..0494d87 100644
--- a/quic/core/quic_trace_visitor.h
+++ b/quic/core/quic_trace_visitor.h
@@ -23,7 +23,8 @@
TransmissionType transmission_type,
QuicTime sent_time) override;
- void OnIncomingAck(const QuicAckFrame& ack_frame,
+ void OnIncomingAck(QuicPacketNumber ack_packet_number,
+ const QuicAckFrame& ack_frame,
QuicTime ack_receive_time,
QuicPacketNumber largest_observed,
bool rtt_updated,
diff --git a/quic/test_tools/quic_server_session_base_peer.h b/quic/test_tools/quic_server_session_base_peer.h
index b29fe46..ab5b1f0 100644
--- a/quic/test_tools/quic_server_session_base_peer.h
+++ b/quic/test_tools/quic_server_session_base_peer.h
@@ -14,9 +14,9 @@
class QuicServerSessionBasePeer {
public:
- static QuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s,
- QuicStreamId id) {
- return s->GetOrCreateDynamicStream(id);
+ static QuicStream* GetOrCreateStream(QuicServerSessionBase* s,
+ QuicStreamId id) {
+ return s->GetOrCreateStream(id);
}
static void SetCryptoStream(QuicServerSessionBase* s,
QuicCryptoServerStream* crypto_stream) {
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc
index 0dfba43..e78b059 100644
--- a/quic/test_tools/quic_session_peer.cc
+++ b/quic/test_tools/quic_session_peer.cc
@@ -118,9 +118,9 @@
}
// static
-QuicStream* QuicSessionPeer::GetOrCreateDynamicStream(QuicSession* session,
- QuicStreamId stream_id) {
- return session->GetOrCreateDynamicStream(stream_id);
+QuicStream* QuicSessionPeer::GetOrCreateStream(QuicSession* session,
+ QuicStreamId stream_id) {
+ return session->GetOrCreateStream(stream_id);
}
// static
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h
index 9ca8530..f027eb5 100644
--- a/quic/test_tools/quic_session_peer.h
+++ b/quic/test_tools/quic_session_peer.h
@@ -52,8 +52,8 @@
static QuicCryptoStream* GetMutableCryptoStream(QuicSession* session);
static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session);
- static QuicStream* GetOrCreateDynamicStream(QuicSession* session,
- QuicStreamId stream_id);
+ static QuicStream* GetOrCreateStream(QuicSession* session,
+ QuicStreamId stream_id);
static std::map<QuicStreamId, QuicStreamOffset>&
GetLocallyClosedStreamsHighestOffset(QuicSession* session);
static QuicSession::StreamMap& stream_map(QuicSession* session);
diff --git a/quic/test_tools/quic_spdy_session_peer.cc b/quic/test_tools/quic_spdy_session_peer.cc
index be0849b..68552a8 100644
--- a/quic/test_tools/quic_spdy_session_peer.cc
+++ b/quic/test_tools/quic_spdy_session_peer.cc
@@ -16,15 +16,13 @@
return session->headers_stream();
}
-void QuicSpdySessionPeer::SetUnownedHeadersStream(
- QuicSpdySession* session,
- QuicHeadersStream* headers_stream) {
+void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session,
+ QuicHeadersStream* headers_stream) {
for (auto& it : session->stream_map()) {
if (it.first == QuicUtils::GetHeadersStreamId(
session->connection()->transport_version())) {
it.second.reset(headers_stream);
- session->unowned_headers_stream_ =
- static_cast<QuicHeadersStream*>(it.second.get());
+ session->headers_stream_ = static_cast<QuicHeadersStream*>(it.second.get());
break;
}
}
diff --git a/quic/test_tools/quic_spdy_session_peer.h b/quic/test_tools/quic_spdy_session_peer.h
index f97b264..aacf712 100644
--- a/quic/test_tools/quic_spdy_session_peer.h
+++ b/quic/test_tools/quic_spdy_session_peer.h
@@ -24,8 +24,8 @@
QuicSpdySessionPeer() = delete;
static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session);
- static void SetUnownedHeadersStream(QuicSpdySession* session,
- QuicHeadersStream* headers_stream);
+ static void SetHeadersStream(QuicSpdySession* session,
+ QuicHeadersStream* headers_stream);
static const spdy::SpdyFramer& GetSpdyFramer(QuicSpdySession* session);
static void SetHpackEncoderDebugVisitor(
QuicSpdySession* session,
diff --git a/quic/tools/quic_client_base.cc b/quic/tools/quic_client_base.cc
index b03f7cc..e53911d 100644
--- a/quic/tools/quic_client_base.cc
+++ b/quic/tools/quic_client_base.cc
@@ -85,6 +85,10 @@
break;
}
}
+ if (max_allowed_push_id_ > 0 &&
+ dynamic_cast<QuicSpdyClientSession*>(session()))
+ static_cast<QuicSpdyClientSession*>(session())->set_max_allowed_push_id(
+ max_allowed_push_id_);
return session()->connection()->connected();
}
diff --git a/quic/tools/quic_client_base.h b/quic/tools/quic_client_base.h
index fb15b86..a54c621 100644
--- a/quic/tools/quic_client_base.h
+++ b/quic/tools/quic_client_base.h
@@ -211,6 +211,9 @@
crypto_config_.set_pre_shared_key(key);
}
+ // Set the max promise id for the client session.
+ void set_max_allowed_push_id(QuicStreamId max) { max_allowed_push_id_ = max; }
+
protected:
// TODO(rch): Move GetNumSentClientHellosFromSession and
// GetNumReceivedServerConfigUpdatesFromSession into a new/better
@@ -329,6 +332,9 @@
// The network helper used to create sockets and manage the event loop.
// Not owned by this class.
std::unique_ptr<NetworkHelper> network_helper_;
+
+ // The max promise id to set on the client session when created.
+ QuicStreamId max_allowed_push_id_;
};
} // namespace quic
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc
index eeb9ce3..9bc3573 100644
--- a/quic/tools/quic_simple_server_session_test.cc
+++ b/quic/tools/quic_simple_server_session_test.cc
@@ -522,12 +522,12 @@
}
TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
- // Tests that calling GetOrCreateDynamicStream() on an outgoing stream not
+ // Tests that calling GetOrCreateStream() on an outgoing stream not
// promised yet should result close connection.
EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID,
"Data for nonexistent stream", _));
EXPECT_EQ(nullptr,
- QuicSessionPeer::GetOrCreateDynamicStream(
+ QuicSessionPeer::GetOrCreateStream(
session_.get(), GetNthServerInitiatedUnidirectionalId(1)));
}