QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2018 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | #ifndef QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_ |
| 5 | #define QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_ |
| 6 | |
vasilvv | cb250b9 | 2021-02-10 18:14:12 -0800 | [diff] [blame] | 7 | #include "absl/container/flat_hash_set.h" |
vasilvv | 9edb31e | 2020-12-03 19:32:58 -0800 | [diff] [blame] | 8 | #include "absl/strings/str_cat.h" |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 9 | #include "quic/core/frames/quic_frame.h" |
| 10 | #include "quic/core/quic_types.h" |
| 11 | #include "quic/core/quic_versions.h" |
| 12 | #include "quic/platform/api/quic_logging.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 13 | |
| 14 | namespace quic { |
| 15 | |
| 16 | namespace test { |
| 17 | class QuicSessionPeer; |
| 18 | class QuicStreamIdManagerPeer; |
| 19 | } // namespace test |
| 20 | |
renjietang | 5357041 | 2020-04-07 06:32:17 -0700 | [diff] [blame] | 21 | // This class manages the stream ids for IETF QUIC. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 22 | class QUIC_EXPORT_PRIVATE QuicStreamIdManager { |
| 23 | public: |
dschinazi | f25169a | 2019-10-23 08:12:18 -0700 | [diff] [blame] | 24 | class QUIC_EXPORT_PRIVATE DelegateInterface { |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 25 | public: |
| 26 | virtual ~DelegateInterface() = default; |
| 27 | |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 28 | // Send a MAX_STREAMS frame. |
| 29 | virtual void SendMaxStreams(QuicStreamCount stream_count, |
| 30 | bool unidirectional) = 0; |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 31 | }; |
| 32 | |
| 33 | QuicStreamIdManager(DelegateInterface* delegate, |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 34 | bool unidirectional, |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 35 | Perspective perspective, |
renjietang | 40038f5 | 2020-04-08 11:30:31 -0700 | [diff] [blame] | 36 | ParsedQuicVersion version, |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 37 | QuicStreamCount max_allowed_outgoing_streams, |
| 38 | QuicStreamCount max_allowed_incoming_streams); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 39 | |
| 40 | ~QuicStreamIdManager(); |
| 41 | |
| 42 | // Generate a string suitable for sending to the log/etc to show current state |
| 43 | // of the stream ID manager. |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 44 | std::string DebugString() const { |
vasilvv | 9edb31e | 2020-12-03 19:32:58 -0800 | [diff] [blame] | 45 | return absl::StrCat( |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 46 | " { unidirectional_: ", unidirectional_, |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 47 | ", perspective: ", perspective_, |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 48 | ", outgoing_max_streams_: ", outgoing_max_streams_, |
| 49 | ", next_outgoing_stream_id_: ", next_outgoing_stream_id_, |
| 50 | ", outgoing_stream_count_: ", outgoing_stream_count_, |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 51 | ", incoming_actual_max_streams_: ", incoming_actual_max_streams_, |
| 52 | ", incoming_advertised_max_streams_: ", |
| 53 | incoming_advertised_max_streams_, |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 54 | ", incoming_stream_count_: ", incoming_stream_count_, |
| 55 | ", available_streams_.size(): ", available_streams_.size(), |
| 56 | ", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_, |
renjietang | 2230585 | 2020-04-06 15:05:18 -0700 | [diff] [blame] | 57 | " }"); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 58 | } |
| 59 | |
renjietang | 7133ea9 | 2020-04-01 12:49:36 -0700 | [diff] [blame] | 60 | // Processes the STREAMS_BLOCKED frame. If error is encountered, populates |
| 61 | // |error_details| and returns false. |
| 62 | bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame, |
| 63 | std::string* error_details); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 64 | |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 65 | // Returns whether the next outgoing stream ID can be allocated or not. |
fayang | 769172b | 2020-03-19 14:27:39 -0700 | [diff] [blame] | 66 | bool CanOpenNextOutgoingStream() const; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 67 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 68 | // Generate and send a MAX_STREAMS frame. |
| 69 | void SendMaxStreamsFrame(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 70 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 71 | // Invoked to deal with releasing a stream. Does nothing if the stream is |
| 72 | // outgoing. If the stream is incoming, the number of streams that the peer |
| 73 | // can open will be updated and a MAX_STREAMS frame, informing the peer of |
| 74 | // the additional streams, may be sent. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 75 | void OnStreamClosed(QuicStreamId stream_id); |
| 76 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 77 | // Returns the next outgoing stream id. Applications must call |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 78 | // CanOpenNextOutgoingStream() first. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 79 | QuicStreamId GetNextOutgoingStreamId(); |
| 80 | |
renjietang | 52e1338 | 2019-12-16 15:58:04 -0800 | [diff] [blame] | 81 | void SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 82 | |
renjietang | ab9039a | 2020-03-30 14:53:19 -0700 | [diff] [blame] | 83 | // Called on |max_open_streams| outgoing streams can be created because of 1) |
| 84 | // config negotiated or 2) MAX_STREAMS received. Returns true if new |
| 85 | // streams can be created. |
| 86 | bool MaybeAllowNewOutgoingStreams(QuicStreamCount max_open_streams); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 87 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 88 | // Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 89 | // limit is exceeded, populates |error_detials| and returns false. |
renjietang | 7133ea9 | 2020-04-01 12:49:36 -0700 | [diff] [blame] | 90 | bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id, |
| 91 | std::string* error_details); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 92 | |
| 93 | // Returns true if |id| is still available. |
| 94 | bool IsAvailableStream(QuicStreamId id) const; |
| 95 | |
renjietang | 52e1338 | 2019-12-16 15:58:04 -0800 | [diff] [blame] | 96 | QuicStreamCount incoming_initial_max_open_streams() const { |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 97 | return incoming_initial_max_open_streams_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 98 | } |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 99 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 100 | QuicStreamId next_outgoing_stream_id() const { |
| 101 | return next_outgoing_stream_id_; |
| 102 | } |
| 103 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 104 | // Number of streams that the peer believes that it can still create. |
renjietang | 40038f5 | 2020-04-08 11:30:31 -0700 | [diff] [blame] | 105 | QuicStreamCount available_incoming_streams() const; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 106 | |
renjietang | 686ce58 | 2019-10-17 14:28:16 -0700 | [diff] [blame] | 107 | QuicStreamId largest_peer_created_stream_id() const { |
| 108 | return largest_peer_created_stream_id_; |
| 109 | } |
| 110 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 111 | QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; } |
| 112 | QuicStreamCount incoming_actual_max_streams() const { |
| 113 | return incoming_actual_max_streams_; |
| 114 | } |
| 115 | QuicStreamCount incoming_advertised_max_streams() const { |
| 116 | return incoming_advertised_max_streams_; |
| 117 | } |
renjietang | 40038f5 | 2020-04-08 11:30:31 -0700 | [diff] [blame] | 118 | QuicStreamCount outgoing_stream_count() const { |
| 119 | return outgoing_stream_count_; |
| 120 | } |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 121 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 122 | private: |
| 123 | friend class test::QuicSessionPeer; |
| 124 | friend class test::QuicStreamIdManagerPeer; |
| 125 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 126 | // Check whether the MAX_STREAMS window has opened up enough and, if so, |
| 127 | // generate and send a MAX_STREAMS frame. |
| 128 | void MaybeSendMaxStreamsFrame(); |
| 129 | |
| 130 | // Get what should be the first incoming/outgoing stream ID that |
| 131 | // this stream id manager will manage, taking into account directionality and |
| 132 | // client/server perspective. |
| 133 | QuicStreamId GetFirstOutgoingStreamId() const; |
| 134 | QuicStreamId GetFirstIncomingStreamId() const; |
| 135 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 136 | // Back reference to the session containing this Stream ID Manager. |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 137 | DelegateInterface* delegate_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 138 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 139 | // Whether this stream id manager is for unidrectional (true) or bidirectional |
| 140 | // (false) streams. |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 141 | const bool unidirectional_; |
| 142 | |
| 143 | // Is this manager a client or a server. |
| 144 | const Perspective perspective_; |
| 145 | |
renjietang | 40038f5 | 2020-04-08 11:30:31 -0700 | [diff] [blame] | 146 | // QUIC version used for this manager. |
| 147 | const ParsedQuicVersion version_; |
rch | a8b56e4 | 2019-09-20 10:41:48 -0700 | [diff] [blame] | 148 | |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 149 | // The number of streams that this node can initiate. |
| 150 | // This limit is first set when config is negotiated, but may be updated upon |
| 151 | // receiving MAX_STREAMS frame. |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 152 | QuicStreamCount outgoing_max_streams_; |
| 153 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 154 | // The ID to use for the next outgoing stream. |
| 155 | QuicStreamId next_outgoing_stream_id_; |
| 156 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 157 | // The number of outgoing streams that have ever been opened, including those |
| 158 | // that have been closed. This number must never be larger than |
| 159 | // outgoing_max_streams_. |
| 160 | QuicStreamCount outgoing_stream_count_; |
| 161 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 162 | // FOR INCOMING STREAMS |
| 163 | |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 164 | // The actual maximum number of streams that can be opened by the peer. |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 165 | QuicStreamCount incoming_actual_max_streams_; |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 166 | // Max incoming stream number that has been advertised to the peer and is <= |
| 167 | // incoming_actual_max_streams_. It is set to incoming_actual_max_streams_ |
| 168 | // when a MAX_STREAMS is sent. |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 169 | QuicStreamCount incoming_advertised_max_streams_; |
| 170 | |
| 171 | // Initial maximum on the number of open streams allowed. |
| 172 | QuicStreamCount incoming_initial_max_open_streams_; |
| 173 | |
renjietang | 7b51ec0 | 2020-04-07 16:07:09 -0700 | [diff] [blame] | 174 | // The number of streams that have been created, including open ones and |
| 175 | // closed ones. |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 176 | QuicStreamCount incoming_stream_count_; |
| 177 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 178 | // Set of stream ids that are less than the largest stream id that has been |
| 179 | // received, but are nonetheless available to be created. |
vasilvv | cb250b9 | 2021-02-10 18:14:12 -0800 | [diff] [blame] | 180 | absl::flat_hash_set<QuicStreamId> available_streams_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 181 | |
| 182 | QuicStreamId largest_peer_created_stream_id_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 183 | }; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 184 | } // namespace quic |
| 185 | |
| 186 | #endif // QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_ |