Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_stream_id_manager.h b/quic/core/quic_stream_id_manager.h
new file mode 100644
index 0000000..95951c0
--- /dev/null
+++ b/quic/core/quic_stream_id_manager.h
@@ -0,0 +1,239 @@
+// 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.
+#ifndef QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_
+#define QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_
+
+#include "base/macros.h"
+#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
+namespace quic {
+
+namespace test {
+class QuicSessionPeer;
+class QuicStreamIdManagerPeer;
+} // namespace test
+
+class QuicSession;
+
+// Amount to increment a stream ID value to get the next stream ID in
+// the stream ID space.
+const QuicStreamId kV99StreamIdIncrement = 4;
+
+// This constant controls the size of the window when deciding whether
+// to generate a MAX STREAM ID frame or not. See the discussion of the
+// window, below, for more details.
+const int kMaxStreamIdWindowDivisor = 2;
+
+// This class manages the stream ids for Version 99/IETF QUIC.
+// TODO(fkastenholz): Expand to support bi- and uni-directional stream ids
+// TODO(fkastenholz): Roll in pre-version-99 management
+class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
+ public:
+ QuicStreamIdManager(QuicSession* session,
+ QuicStreamId next_outgoing_stream_id,
+ QuicStreamId largest_peer_created_stream_id,
+ QuicStreamId first_incoming_dynamic_stream_id,
+ size_t max_allowed_outgoing_streams,
+ size_t max_allowed_incoming_streams);
+
+ ~QuicStreamIdManager();
+
+ // Generate a string suitable for sending to the log/etc to show current state
+ // of the stream ID manager.
+ QuicString DebugString() const {
+ return QuicStrCat(
+ " { max_allowed_outgoing_stream_id: ", max_allowed_outgoing_stream_id_,
+ ", actual_max_allowed_incoming_stream_id_: ",
+ actual_max_allowed_incoming_stream_id_,
+ ", advertised_max_allowed_incoming_stream_id_: ",
+ advertised_max_allowed_incoming_stream_id_,
+ ", max_stream_id_window_: ", max_stream_id_window_,
+ ", max_allowed_outgoing_streams_: ", max_allowed_outgoing_streams_,
+ ", max_allowed_incoming_streams_: ", max_allowed_incoming_streams_,
+ ", available_incoming_streams_: ", available_incoming_streams_,
+ ", first_incoming_dynamic_stream_id_: ",
+ first_incoming_dynamic_stream_id_,
+ ", first_outgoing_dynamic_stream_id_: ",
+ first_outgoing_dynamic_stream_id_, " }");
+ }
+
+ // Processes the MAX STREAM ID frame, invoked from
+ // QuicSession::OnMaxStreamIdFrame. It has the same semantics as the
+ // QuicFramerVisitorInterface, returning true if the framer should continue
+ // processing the packet, false if not.
+ bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame);
+
+ // Processes the STREAM ID BLOCKED frame, invoked from
+ // QuicSession::OnStreamIdBlockedFrame. It has the same semantics as the
+ // QuicFramerVisitorInterface, returning true if the framer should continue
+ // processing the packet, false if not.
+ bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame);
+
+ // Indicates whether the next outgoing stream ID can be allocated or not. The
+ // test is whether it will exceed the maximum-stream-id or not.
+ bool CanOpenNextOutgoingStream();
+
+ // Generate and send a MAX_STREAM_ID frame.
+ void SendMaxStreamIdFrame();
+
+ // Invoked to deal with releasing a stream ID.
+ void OnStreamClosed(QuicStreamId stream_id);
+
+ // Returns the next outgoing stream id. If it fails (due to running into the
+ // max_allowed_outgoing_stream_id limit) then it returns an invalid stream id.
+ QuicStreamId GetNextOutgoingStreamId();
+
+ // Initialize the maximum allowed incoming stream id and number of streams.
+ void SetMaxOpenIncomingStreams(size_t max_streams);
+
+ // Initialize the maximum allowed outgoing stream id, number of streams, and
+ // MAX_STREAM_ID advertisement window.
+ void SetMaxOpenOutgoingStreams(size_t max_streams);
+
+ // Register a new stream as a static stream. This is used so that the
+ // advertised maximum stream ID can be calculated based on the start of the
+ // dynamic stream space. This method will take any stream ID, one that either
+ // this node or the peer will initiate.
+ void RegisterStaticStream(QuicStreamId stream_id);
+
+ // Check that an incoming stream id is valid -- is below the maximum allowed
+ // stream ID. Note that this method uses the actual maximum, not the most
+ // recently advertised maximum this helps preserve the Google-QUIC semantic
+ // that we actually care about the number of open streams, not the maximum
+ // stream ID. Returns true if the stream ID is valid. If the stream ID fails
+ // the test, will close the connection (per the protocol specification) and
+ // return false. This method also maintains state with regard to the number of
+ // streams that the peer can open (used for generating MAX_STREAM_ID frames).
+ // This method should be called exactly once for each incoming stream
+ // creation.
+ bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id);
+
+ // Returns true if |id| is still available.
+ bool IsAvailableStream(QuicStreamId id) const;
+
+ // Return true if given stream is peer initiated.
+ bool IsIncomingStream(QuicStreamId id) const;
+
+ size_t max_allowed_outgoing_streams() const {
+ return max_allowed_outgoing_streams_;
+ }
+ size_t max_allowed_incoming_streams() const {
+ return max_allowed_incoming_streams_;
+ }
+ QuicStreamId max_allowed_outgoing_stream_id() const {
+ return max_allowed_outgoing_stream_id_;
+ }
+ QuicStreamId advertised_max_allowed_incoming_stream_id() const {
+ return advertised_max_allowed_incoming_stream_id_;
+ }
+ QuicStreamId actual_max_allowed_incoming_stream_id() const {
+ return actual_max_allowed_incoming_stream_id_;
+ }
+ QuicStreamId max_stream_id_window() const { return max_stream_id_window_; }
+
+ QuicStreamId next_outgoing_stream_id() const {
+ return next_outgoing_stream_id_;
+ }
+
+ QuicStreamId first_incoming_dynamic_stream_id() {
+ return first_incoming_dynamic_stream_id_;
+ }
+ QuicStreamId first_outgoing_dynamic_stream_id() {
+ return first_outgoing_dynamic_stream_id_;
+ }
+ size_t available_incoming_streams() { return available_incoming_streams_; }
+
+ void set_max_allowed_incoming_streams(size_t stream_count) {
+ max_allowed_incoming_streams_ = stream_count;
+ }
+
+ void set_largest_peer_created_stream_id(
+ QuicStreamId largest_peer_created_stream_id) {
+ largest_peer_created_stream_id_ = largest_peer_created_stream_id;
+ }
+
+ private:
+ friend class test::QuicSessionPeer;
+ friend class test::QuicStreamIdManagerPeer;
+
+ // Check whether the MAX_STREAM_ID window has opened up enough and, if so,
+ // generate and send a MAX_STREAM_ID frame.
+ void MaybeSendMaxStreamIdFrame();
+
+ // Back reference to the session containing this Stream ID Manager.
+ // needed to access various session methods, such as perspective()
+ QuicSession* session_;
+
+ // The ID to use for the next outgoing stream.
+ QuicStreamId next_outgoing_stream_id_;
+
+ // Set of stream ids that are less than the largest stream id that has been
+ // received, but are nonetheless available to be created.
+ QuicUnorderedSet<QuicStreamId> available_streams_;
+
+ QuicStreamId largest_peer_created_stream_id_;
+
+ // The maximum stream ID value that we can use. This is initialized based on,
+ // first, the default number of open streams we can do, updated per the number
+ // of streams we receive in the transport parameters, and then finally is
+ // modified whenever a MAX_STREAM_ID frame is received from the peer.
+ QuicStreamId max_allowed_outgoing_stream_id_;
+
+ // Unlike for streams this node initiates, for incoming streams, there are two
+ // maxima; the actual maximum which is the limit the peer must obey and the
+ // maximum that was most recently advertised to the peer in a MAX_STREAM_ID
+ // frame.
+ //
+ // The advertised maximum is never larger than the actual maximum. The actual
+ // maximum increases whenever an incoming stream is closed. The advertised
+ // maximum increases (to the actual maximum) whenever a MAX_STREAM_ID is sent.
+ //
+ // The peer is granted some leeway, incoming streams are accepted as long as
+ // their stream id is not greater than the actual maximum. The protocol
+ // specifies that the advertised maximum is the limit. This implmentation uses
+ // the actual maximum in order to support Google-QUIC semantics, where it's
+ // the number of open streams, not their ID number, that is the real limit.
+ QuicStreamId actual_max_allowed_incoming_stream_id_;
+ QuicStreamId advertised_max_allowed_incoming_stream_id_;
+
+ // max_stream_id_window_ is set to max_allowed_outgoing_streams_ / 2
+ // (half of the number of streams that are allowed). The local node
+ // does not send a MAX_STREAM_ID frame to the peer until the local node
+ // believes that the peer can open fewer than |max_stream_id_window_|
+ // streams. When that is so, the local node sends a MAX_STREAM_ID every time
+ // an inbound stream is closed.
+ QuicStreamId max_stream_id_window_;
+
+ // Maximum number of outgoing and incoming streams that are allowed to be
+ // concurrently opened. Initialized as part of configuration.
+ size_t max_allowed_outgoing_streams_;
+ size_t max_allowed_incoming_streams_;
+
+ // Keep track of the first dynamic stream id (which is the largest static
+ // stream id plus one id). For Google QUIC, static streams are not counted
+ // against the stream count limit. When the number of static streams
+ // increases, the maximum stream id has to increase by a corresponding amount.
+ // These are used as floors from which the relevant maximum is
+ // calculated. Keeping the "first dynamic" rather than the "last static" has
+ // some implementation advantages.
+ QuicStreamId first_incoming_dynamic_stream_id_;
+ QuicStreamId first_outgoing_dynamic_stream_id_;
+
+ // Number of streams that that this node believes that the
+ // peer can open. It is initialized to the same value as
+ // max_allowed_incoming_streams_. It is decremented every
+ // time a new incoming stream is detected. A MAX_STREAM_ID
+ // is sent whenver a stream closes and this counter is less
+ // than the window. When that happens, it is incremented by
+ // the number of streams we make available (the actual max
+ // stream ID - the most recently advertised one)
+ size_t available_incoming_streams_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_