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