blob: 9fa26c61f7719d45950383c9f29db1673b614612 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
QUICHE teama6ef0a62019-03-07 20:34:33 -05007#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h"
8#include "net/third_party/quiche/src/quic/core/quic_types.h"
fkastenholz3c4eabf2019-04-22 07:49:59 -07009#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080011#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
13namespace quic {
14
15namespace test {
16class QuicSessionPeer;
17class QuicStreamIdManagerPeer;
18} // namespace test
19
QUICHE teama6ef0a62019-03-07 20:34:33 -050020// Amount to increment a stream ID value to get the next stream ID in
21// the stream ID space.
22const QuicStreamId kV99StreamIdIncrement = 4;
23
24// This constant controls the size of the window when deciding whether
fkastenholz3c4eabf2019-04-22 07:49:59 -070025// to generate a MAX_STREAMS frame or not. See the discussion of the
QUICHE teama6ef0a62019-03-07 20:34:33 -050026// window, below, for more details.
fkastenholz3c4eabf2019-04-22 07:49:59 -070027const int kMaxStreamsWindowDivisor = 2;
QUICHE teama6ef0a62019-03-07 20:34:33 -050028
29// This class manages the stream ids for Version 99/IETF QUIC.
QUICHE teama6ef0a62019-03-07 20:34:33 -050030class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
31 public:
dschinazif25169a2019-10-23 08:12:18 -070032 class QUIC_EXPORT_PRIVATE DelegateInterface {
rcha8b56e42019-09-20 10:41:48 -070033 public:
34 virtual ~DelegateInterface() = default;
35
36 // Called when new outgoing streams are available to be opened. This occurs
37 // when an extant, open, stream is moved to draining or closed.
38 // |unidirectional| indicates whether unidirectional or bidirectional
39 // streams are now available. If both become available at the same time then
40 // there will be two calls to this method, one with unidirectional==true,
41 // the other with it ==false.
42 virtual void OnCanCreateNewOutgoingStream(bool unidirectional) = 0;
43
44 // Closes the connection when an error is encountered.
renjietangff4b2b62020-02-12 16:52:32 -080045 virtual void OnStreamIdManagerError(QuicErrorCode error_code,
46 std::string error_details) = 0;
rcha8b56e42019-09-20 10:41:48 -070047
48 // Send a MAX_STREAMS frame.
49 virtual void SendMaxStreams(QuicStreamCount stream_count,
50 bool unidirectional) = 0;
51
52 // Send a STREAMS_BLOCKED frame.
53 virtual void SendStreamsBlocked(QuicStreamCount stream_count,
54 bool unidirectional) = 0;
55 };
56
57 QuicStreamIdManager(DelegateInterface* delegate,
fkastenholz3c4eabf2019-04-22 07:49:59 -070058 bool unidirectional,
rcha8b56e42019-09-20 10:41:48 -070059 Perspective perspective,
60 QuicTransportVersion transport_version,
fkastenholz3c4eabf2019-04-22 07:49:59 -070061 QuicStreamCount max_allowed_outgoing_streams,
62 QuicStreamCount max_allowed_incoming_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -050063
64 ~QuicStreamIdManager();
65
66 // Generate a string suitable for sending to the log/etc to show current state
67 // of the stream ID manager.
vasilvvc48c8712019-03-11 13:38:16 -070068 std::string DebugString() const {
dmcardlecf0bfcf2019-12-13 08:08:21 -080069 return quiche::QuicheStrCat(
fkastenholz3c4eabf2019-04-22 07:49:59 -070070 " { unidirectional_: ", unidirectional_,
71 ", perspective: ", perspective(),
72 ", outgoing_max_streams_: ", outgoing_max_streams_,
73 ", next_outgoing_stream_id_: ", next_outgoing_stream_id_,
74 ", outgoing_stream_count_: ", outgoing_stream_count_,
fkastenholz3c4eabf2019-04-22 07:49:59 -070075 ", incoming_actual_max_streams_: ", incoming_actual_max_streams_,
76 ", incoming_advertised_max_streams_: ",
77 incoming_advertised_max_streams_,
fkastenholz3c4eabf2019-04-22 07:49:59 -070078 ", incoming_stream_count_: ", incoming_stream_count_,
79 ", available_streams_.size(): ", available_streams_.size(),
80 ", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_,
81 ", max_streams_window_: ", max_streams_window_, " }");
QUICHE teama6ef0a62019-03-07 20:34:33 -050082 }
83
fkastenholz3c4eabf2019-04-22 07:49:59 -070084 // Processes the MAX_STREAMS frame, invoked from
85 // QuicSession::OnMaxStreamsFrame. It has the same semantics as the
QUICHE teama6ef0a62019-03-07 20:34:33 -050086 // QuicFramerVisitorInterface, returning true if the framer should continue
87 // processing the packet, false if not.
fkastenholz3c4eabf2019-04-22 07:49:59 -070088 bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -050089
fkastenholz3c4eabf2019-04-22 07:49:59 -070090 // Processes the STREAMS_BLOCKED frame, invoked from
91 // QuicSession::OnStreamsBlockedFrame. It has the same semantics as the
QUICHE teama6ef0a62019-03-07 20:34:33 -050092 // QuicFramerVisitorInterface, returning true if the framer should continue
93 // processing the packet, false if not.
fkastenholz3c4eabf2019-04-22 07:49:59 -070094 bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -050095
fkastenholz3c4eabf2019-04-22 07:49:59 -070096 // Indicates whether the next outgoing stream ID can be allocated or not.
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 bool CanOpenNextOutgoingStream();
98
fkastenholz3c4eabf2019-04-22 07:49:59 -070099 // Generate and send a MAX_STREAMS frame.
100 void SendMaxStreamsFrame();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500101
fkastenholz3c4eabf2019-04-22 07:49:59 -0700102 // Invoked to deal with releasing a stream. Does nothing if the stream is
103 // outgoing. If the stream is incoming, the number of streams that the peer
104 // can open will be updated and a MAX_STREAMS frame, informing the peer of
105 // the additional streams, may be sent.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500106 void OnStreamClosed(QuicStreamId stream_id);
107
fkastenholz3c4eabf2019-04-22 07:49:59 -0700108 // Returns the next outgoing stream id. Applications must call
109 // CanOpenNextOutgoingStream() first. A QUIC_BUG is logged if this method
110 // allocates a stream ID past the peer specified limit.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 QuicStreamId GetNextOutgoingStreamId();
112
renjietang52e13382019-12-16 15:58:04 -0800113 void SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500114
fkastenholz3c4eabf2019-04-22 07:49:59 -0700115 // Sets the maximum number of outgoing streams to max_open_streams.
116 // Used when configuration has been done and we have an initial
117 // maximum stream count from the peer. Note that if the stream count is such
118 // that it would result in stream ID values that are greater than the
119 // implementation limit, it pegs the count at the implementation limit.
renjietang52e13382019-12-16 15:58:04 -0800120 bool SetMaxOpenOutgoingStreams(QuicStreamCount max_open_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121
fkastenholz3c4eabf2019-04-22 07:49:59 -0700122 // Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the
123 // limit is exceeded, closes the connection and returns false. Uses the
124 // actual maximium, not the most recently advertised value, in order to
125 // enforce the Google-QUIC number of open streams behavior.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126 // This method should be called exactly once for each incoming stream
127 // creation.
128 bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id);
129
130 // Returns true if |id| is still available.
131 bool IsAvailableStream(QuicStreamId id) const;
132
133 // Return true if given stream is peer initiated.
134 bool IsIncomingStream(QuicStreamId id) const;
135
renjietang52e13382019-12-16 15:58:04 -0800136 QuicStreamCount incoming_initial_max_open_streams() const {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700137 return incoming_initial_max_open_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500138 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700139
140 QuicStreamCount max_streams_window() const { return max_streams_window_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500141
142 QuicStreamId next_outgoing_stream_id() const {
143 return next_outgoing_stream_id_;
144 }
145
fkastenholz3c4eabf2019-04-22 07:49:59 -0700146 // Number of streams that the peer believes that it can still create.
renjietang52e13382019-12-16 15:58:04 -0800147 QuicStreamCount available_incoming_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500148
149 void set_largest_peer_created_stream_id(
150 QuicStreamId largest_peer_created_stream_id) {
151 largest_peer_created_stream_id_ = largest_peer_created_stream_id;
152 }
153
renjietang686ce582019-10-17 14:28:16 -0700154 QuicStreamId largest_peer_created_stream_id() const {
155 return largest_peer_created_stream_id_;
156 }
157
fkastenholz3c4eabf2019-04-22 07:49:59 -0700158 // These are the limits for outgoing and incoming streams,
159 // respectively. For incoming there are two limits, what has
160 // been advertised to the peer and what is actually available.
161 // The advertised incoming amount should never be more than the actual
162 // incoming one.
163 QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; }
164 QuicStreamCount incoming_actual_max_streams() const {
165 return incoming_actual_max_streams_;
166 }
167 QuicStreamCount incoming_advertised_max_streams() const {
168 return incoming_advertised_max_streams_;
169 }
170 // Number of streams that have been opened (including those that have been
171 // opened and then closed. Must never exceed outgoing_max_streams
172 QuicStreamCount outgoing_stream_count() { return outgoing_stream_count_; }
173
174 // Perspective (CLIENT/SERVER) of this node and the peer, respectively.
175 Perspective perspective() const;
176 Perspective peer_perspective() const;
177
fkastenholz56055be2019-09-17 11:17:37 -0700178 // Called when session has been configured. Causes the Stream ID manager to
179 // send out any pending MAX_STREAMS and STREAMS_BLOCKED frames.
180 void OnConfigNegotiated();
181
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182 private:
183 friend class test::QuicSessionPeer;
184 friend class test::QuicStreamIdManagerPeer;
185
fkastenholz3c4eabf2019-04-22 07:49:59 -0700186 // Check whether the MAX_STREAMS window has opened up enough and, if so,
187 // generate and send a MAX_STREAMS frame.
188 void MaybeSendMaxStreamsFrame();
189
190 // Get what should be the first incoming/outgoing stream ID that
191 // this stream id manager will manage, taking into account directionality and
192 // client/server perspective.
193 QuicStreamId GetFirstOutgoingStreamId() const;
194 QuicStreamId GetFirstIncomingStreamId() const;
195
196 void CalculateIncomingMaxStreamsWindow();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500197
198 // Back reference to the session containing this Stream ID Manager.
199 // needed to access various session methods, such as perspective()
rcha8b56e42019-09-20 10:41:48 -0700200 DelegateInterface* delegate_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500201
fkastenholz3c4eabf2019-04-22 07:49:59 -0700202 // Whether this stream id manager is for unidrectional (true) or bidirectional
203 // (false) streams.
rcha8b56e42019-09-20 10:41:48 -0700204 const bool unidirectional_;
205
206 // Is this manager a client or a server.
207 const Perspective perspective_;
208
209 // Transport version used for this manager.
210 const QuicTransportVersion transport_version_;
211
rcha8b56e42019-09-20 10:41:48 -0700212 // True if the config has been negotiated_;
213 bool is_config_negotiated_;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700214
215 // This is the number of streams that this node can initiate.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700216 // This limit is:
217 // - Initiated to a value specified in the constructor
218 // - May be updated when the config is received.
219 // - Is updated whenever a MAX STREAMS frame is received.
220 QuicStreamCount outgoing_max_streams_;
221
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222 // The ID to use for the next outgoing stream.
223 QuicStreamId next_outgoing_stream_id_;
224
fkastenholz3c4eabf2019-04-22 07:49:59 -0700225 // The number of outgoing streams that have ever been opened, including those
226 // that have been closed. This number must never be larger than
227 // outgoing_max_streams_.
228 QuicStreamCount outgoing_stream_count_;
229
fkastenholz3c4eabf2019-04-22 07:49:59 -0700230 // FOR INCOMING STREAMS
231
232 // The maximum number of streams that can be opened by the peer.
233 QuicStreamCount incoming_actual_max_streams_;
234 QuicStreamCount incoming_advertised_max_streams_;
235
236 // Initial maximum on the number of open streams allowed.
237 QuicStreamCount incoming_initial_max_open_streams_;
238
fkastenholz3c4eabf2019-04-22 07:49:59 -0700239 // This is the number of streams that have been created -- some are still
240 // open, the others have been closed. It is the number that is compared
241 // against MAX_STREAMS when deciding whether to accept a new stream or not.
242 QuicStreamCount incoming_stream_count_;
243
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 // Set of stream ids that are less than the largest stream id that has been
245 // received, but are nonetheless available to be created.
246 QuicUnorderedSet<QuicStreamId> available_streams_;
247
248 QuicStreamId largest_peer_created_stream_id_;
249
fkastenholz3c4eabf2019-04-22 07:49:59 -0700250 // When incoming streams close the local node sends MAX_STREAMS frames. It
251 // does so only when the peer can open fewer than |max_stream_id_window_|
252 // streams. That is, when |incoming_actual_max_streams_| -
253 // |incoming_advertised_max_streams_| is less than the window.
254 // max_streams_window_ is set to 1/2 of the initial number of incoming streams
255 // that are allowed (as set in the constructor).
256 QuicStreamId max_streams_window_;
fkastenholz56055be2019-09-17 11:17:37 -0700257
258 // MAX_STREAMS and STREAMS_BLOCKED frames are not sent before the session has
259 // been configured. Instead, the relevant information is stored in
260 // |pending_max_streams_| and |pending_streams_blocked_| and sent when
261 // OnConfigNegotiated() is invoked.
262 bool pending_max_streams_;
263 QuicStreamId pending_streams_blocked_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500264};
QUICHE teama6ef0a62019-03-07 20:34:33 -0500265} // namespace quic
266
267#endif // QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_