Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/legacy_quic_stream_id_manager.cc b/quic/core/legacy_quic_stream_id_manager.cc
new file mode 100644
index 0000000..6fb662a
--- /dev/null
+++ b/quic/core/legacy_quic_stream_id_manager.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h"
+
+#include "net/third_party/quiche/src/quic/core/quic_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
+
+namespace quic {
+
+#define ENDPOINT \
+ (session_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+LegacyQuicStreamIdManager::LegacyQuicStreamIdManager(
+ QuicSession* session,
+ size_t max_open_outgoing_streams,
+ size_t max_open_incoming_streams)
+ : session_(session),
+ max_open_outgoing_streams_(max_open_outgoing_streams),
+ max_open_incoming_streams_(max_open_incoming_streams),
+ next_outgoing_stream_id_(
+ QuicUtils::GetCryptoStreamId(
+ session->connection()->transport_version()) +
+ (session->perspective() == Perspective::IS_SERVER ? 1 : 2)),
+ largest_peer_created_stream_id_(
+ session->perspective() == Perspective::IS_SERVER
+ ? QuicUtils::GetCryptoStreamId(
+ session->connection()->transport_version())
+ : QuicUtils::GetInvalidStreamId(
+ session->connection()->transport_version())) {}
+
+LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {
+ QUIC_LOG_IF(WARNING,
+ session_->num_locally_closed_incoming_streams_highest_offset() >
+ max_open_incoming_streams_)
+ << "Surprisingly high number of locally closed peer initiated streams"
+ "still waiting for final byte offset: "
+ << session_->num_locally_closed_incoming_streams_highest_offset();
+ QUIC_LOG_IF(WARNING,
+ session_->GetNumLocallyClosedOutgoingStreamsHighestOffset() >
+ max_open_outgoing_streams_)
+ << "Surprisingly high number of locally closed self initiated streams"
+ "still waiting for final byte offset: "
+ << session_->GetNumLocallyClosedOutgoingStreamsHighestOffset();
+}
+
+bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream(
+ size_t current_num_open_outgoing_streams) const {
+ if (current_num_open_outgoing_streams >= max_open_outgoing_streams_) {
+ QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
+ << "Already " << current_num_open_outgoing_streams
+ << " open.";
+ return false;
+ }
+ return true;
+}
+
+bool LegacyQuicStreamIdManager::CanOpenIncomingStream(
+ size_t current_num_open_incoming_streams) const {
+ // Check if the new number of open streams would cause the number of
+ // open streams to exceed the limit.
+ return current_num_open_incoming_streams < max_open_incoming_streams_;
+}
+
+bool LegacyQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
+ const QuicStreamId stream_id) {
+ available_streams_.erase(stream_id);
+
+ if (largest_peer_created_stream_id_ !=
+ QuicUtils::GetInvalidStreamId(
+ session_->connection()->transport_version()) &&
+ stream_id <= largest_peer_created_stream_id_) {
+ return true;
+ }
+
+ // Check if the new number of available streams would cause the number of
+ // available streams to exceed the limit. Note that the peer can create
+ // only alternately-numbered streams.
+ size_t additional_available_streams =
+ (stream_id - largest_peer_created_stream_id_) / 2 - 1;
+ size_t new_num_available_streams =
+ GetNumAvailableStreams() + additional_available_streams;
+ if (new_num_available_streams > MaxAvailableStreams()) {
+ QUIC_DLOG(INFO) << ENDPOINT
+ << "Failed to create a new incoming stream with id:"
+ << stream_id << ". There are already "
+ << GetNumAvailableStreams()
+ << " streams available, which would become "
+ << new_num_available_streams << ", which exceeds the limit "
+ << MaxAvailableStreams() << ".";
+ session_->connection()->CloseConnection(
+ QUIC_TOO_MANY_AVAILABLE_STREAMS,
+ QuicStrCat(new_num_available_streams, " above ", MaxAvailableStreams()),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ for (QuicStreamId id = largest_peer_created_stream_id_ + 2; id < stream_id;
+ id += 2) {
+ available_streams_.insert(id);
+ }
+ largest_peer_created_stream_id_ = stream_id;
+
+ return true;
+}
+
+QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() {
+ QuicStreamId id = next_outgoing_stream_id_;
+ next_outgoing_stream_id_ += 2;
+ return id;
+}
+
+bool LegacyQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
+ if (!IsIncomingStream(id)) {
+ // Stream IDs under next_ougoing_stream_id_ are either open or previously
+ // open but now closed.
+ return id >= next_outgoing_stream_id_;
+ }
+ // For peer created streams, we also need to consider available streams.
+ return largest_peer_created_stream_id_ ==
+ QuicUtils::GetInvalidStreamId(
+ session_->connection()->transport_version()) ||
+ id > largest_peer_created_stream_id_ ||
+ QuicContainsKey(available_streams_, id);
+}
+
+bool LegacyQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const {
+ return id % 2 != next_outgoing_stream_id_ % 2;
+}
+
+size_t LegacyQuicStreamIdManager::GetNumAvailableStreams() const {
+ return available_streams_.size();
+}
+
+size_t LegacyQuicStreamIdManager::MaxAvailableStreams() const {
+ return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
+}
+
+} // namespace quic