blob: 92d9a067da7852428ed569543500ce630dbf47ad [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.
45 virtual void OnError(QuicErrorCode error_code,
46 std::string error_details) = 0;
47
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 ", using_default_max_streams_: ", using_default_max_streams_,
76 ", incoming_actual_max_streams_: ", incoming_actual_max_streams_,
77 ", incoming_advertised_max_streams_: ",
78 incoming_advertised_max_streams_,
fkastenholz3c4eabf2019-04-22 07:49:59 -070079 ", incoming_stream_count_: ", incoming_stream_count_,
80 ", available_streams_.size(): ", available_streams_.size(),
81 ", largest_peer_created_stream_id_: ", largest_peer_created_stream_id_,
82 ", max_streams_window_: ", max_streams_window_, " }");
QUICHE teama6ef0a62019-03-07 20:34:33 -050083 }
84
fkastenholz3c4eabf2019-04-22 07:49:59 -070085 // Processes the MAX_STREAMS frame, invoked from
86 // QuicSession::OnMaxStreamsFrame. It has the same semantics as the
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 // QuicFramerVisitorInterface, returning true if the framer should continue
88 // processing the packet, false if not.
fkastenholz3c4eabf2019-04-22 07:49:59 -070089 bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -050090
fkastenholz3c4eabf2019-04-22 07:49:59 -070091 // Processes the STREAMS_BLOCKED frame, invoked from
92 // QuicSession::OnStreamsBlockedFrame. It has the same semantics as the
QUICHE teama6ef0a62019-03-07 20:34:33 -050093 // QuicFramerVisitorInterface, returning true if the framer should continue
94 // processing the packet, false if not.
fkastenholz3c4eabf2019-04-22 07:49:59 -070095 bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -050096
fkastenholz3c4eabf2019-04-22 07:49:59 -070097 // Indicates whether the next outgoing stream ID can be allocated or not.
QUICHE teama6ef0a62019-03-07 20:34:33 -050098 bool CanOpenNextOutgoingStream();
99
fkastenholz3c4eabf2019-04-22 07:49:59 -0700100 // Generate and send a MAX_STREAMS frame.
101 void SendMaxStreamsFrame();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500102
fkastenholz3c4eabf2019-04-22 07:49:59 -0700103 // Invoked to deal with releasing a stream. Does nothing if the stream is
104 // outgoing. If the stream is incoming, the number of streams that the peer
105 // can open will be updated and a MAX_STREAMS frame, informing the peer of
106 // the additional streams, may be sent.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500107 void OnStreamClosed(QuicStreamId stream_id);
108
fkastenholz3c4eabf2019-04-22 07:49:59 -0700109 // Returns the next outgoing stream id. Applications must call
110 // CanOpenNextOutgoingStream() first. A QUIC_BUG is logged if this method
111 // allocates a stream ID past the peer specified limit.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 QuicStreamId GetNextOutgoingStreamId();
113
renjietang52e13382019-12-16 15:58:04 -0800114 void SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115
fkastenholz3c4eabf2019-04-22 07:49:59 -0700116 // Sets the maximum number of outgoing streams to max_open_streams.
117 // Used when configuration has been done and we have an initial
118 // maximum stream count from the peer. Note that if the stream count is such
119 // that it would result in stream ID values that are greater than the
120 // implementation limit, it pegs the count at the implementation limit.
renjietang52e13382019-12-16 15:58:04 -0800121 bool SetMaxOpenOutgoingStreams(QuicStreamCount max_open_streams);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122
fkastenholz3c4eabf2019-04-22 07:49:59 -0700123 // Checks if the incoming stream ID exceeds the MAX_STREAMS limit. If the
124 // limit is exceeded, closes the connection and returns false. Uses the
125 // actual maximium, not the most recently advertised value, in order to
126 // enforce the Google-QUIC number of open streams behavior.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500127 // This method should be called exactly once for each incoming stream
128 // creation.
129 bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id);
130
131 // Returns true if |id| is still available.
132 bool IsAvailableStream(QuicStreamId id) const;
133
134 // Return true if given stream is peer initiated.
135 bool IsIncomingStream(QuicStreamId id) const;
136
renjietang52e13382019-12-16 15:58:04 -0800137 QuicStreamCount incoming_initial_max_open_streams() const {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700138 return incoming_initial_max_open_streams_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700140
141 QuicStreamCount max_streams_window() const { return max_streams_window_; }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500142
143 QuicStreamId next_outgoing_stream_id() const {
144 return next_outgoing_stream_id_;
145 }
146
fkastenholz3c4eabf2019-04-22 07:49:59 -0700147 // Number of streams that the peer believes that it can still create.
renjietang52e13382019-12-16 15:58:04 -0800148 QuicStreamCount available_incoming_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149
150 void set_largest_peer_created_stream_id(
151 QuicStreamId largest_peer_created_stream_id) {
152 largest_peer_created_stream_id_ = largest_peer_created_stream_id;
153 }
154
renjietang686ce582019-10-17 14:28:16 -0700155 QuicStreamId largest_peer_created_stream_id() const {
156 return largest_peer_created_stream_id_;
157 }
158
fkastenholz3c4eabf2019-04-22 07:49:59 -0700159 // These are the limits for outgoing and incoming streams,
160 // respectively. For incoming there are two limits, what has
161 // been advertised to the peer and what is actually available.
162 // The advertised incoming amount should never be more than the actual
163 // incoming one.
164 QuicStreamCount outgoing_max_streams() const { return outgoing_max_streams_; }
165 QuicStreamCount incoming_actual_max_streams() const {
166 return incoming_actual_max_streams_;
167 }
168 QuicStreamCount incoming_advertised_max_streams() const {
169 return incoming_advertised_max_streams_;
170 }
171 // Number of streams that have been opened (including those that have been
172 // opened and then closed. Must never exceed outgoing_max_streams
173 QuicStreamCount outgoing_stream_count() { return outgoing_stream_count_; }
174
175 // Perspective (CLIENT/SERVER) of this node and the peer, respectively.
176 Perspective perspective() const;
177 Perspective peer_perspective() const;
178
fkastenholz56055be2019-09-17 11:17:37 -0700179 // Called when session has been configured. Causes the Stream ID manager to
180 // send out any pending MAX_STREAMS and STREAMS_BLOCKED frames.
181 void OnConfigNegotiated();
182
QUICHE teama6ef0a62019-03-07 20:34:33 -0500183 private:
184 friend class test::QuicSessionPeer;
185 friend class test::QuicStreamIdManagerPeer;
186
fkastenholz3c4eabf2019-04-22 07:49:59 -0700187 // Check whether the MAX_STREAMS window has opened up enough and, if so,
188 // generate and send a MAX_STREAMS frame.
189 void MaybeSendMaxStreamsFrame();
190
191 // Get what should be the first incoming/outgoing stream ID that
192 // this stream id manager will manage, taking into account directionality and
193 // client/server perspective.
194 QuicStreamId GetFirstOutgoingStreamId() const;
195 QuicStreamId GetFirstIncomingStreamId() const;
196
197 void CalculateIncomingMaxStreamsWindow();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500198
199 // Back reference to the session containing this Stream ID Manager.
200 // needed to access various session methods, such as perspective()
rcha8b56e42019-09-20 10:41:48 -0700201 DelegateInterface* delegate_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202
fkastenholz3c4eabf2019-04-22 07:49:59 -0700203 // Whether this stream id manager is for unidrectional (true) or bidirectional
204 // (false) streams.
rcha8b56e42019-09-20 10:41:48 -0700205 const bool unidirectional_;
206
207 // Is this manager a client or a server.
208 const Perspective perspective_;
209
210 // Transport version used for this manager.
211 const QuicTransportVersion transport_version_;
212
rcha8b56e42019-09-20 10:41:48 -0700213 // True if the config has been negotiated_;
214 bool is_config_negotiated_;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700215
216 // This is the number of streams that this node can initiate.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700217 // This limit is:
218 // - Initiated to a value specified in the constructor
219 // - May be updated when the config is received.
220 // - Is updated whenever a MAX STREAMS frame is received.
221 QuicStreamCount outgoing_max_streams_;
222
QUICHE teama6ef0a62019-03-07 20:34:33 -0500223 // The ID to use for the next outgoing stream.
224 QuicStreamId next_outgoing_stream_id_;
225
fkastenholz3c4eabf2019-04-22 07:49:59 -0700226 // The number of outgoing streams that have ever been opened, including those
227 // that have been closed. This number must never be larger than
228 // outgoing_max_streams_.
229 QuicStreamCount outgoing_stream_count_;
230
fkastenholz3c4eabf2019-04-22 07:49:59 -0700231 // Set to true while the default (from the constructor) outgoing stream limit
232 // is in use. It is set to false when either a MAX STREAMS frame is received
233 // or the transport negotiation completes and sets the stream limit (this is
234 // equivalent to a MAX_STREAMS frame).
235 // Necessary because outgoing_max_streams_ is a "best guess"
236 // until we receive an authoritative value from the peer.
237 // outgoing_max_streams_ is initialized in the constructor
238 // to some hard-coded value, which may or may not be consistent
renjietang216dc012019-08-27 11:28:27 -0700239 // with what the peer wants.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700240 bool using_default_max_streams_;
241
242 // FOR INCOMING STREAMS
243
244 // The maximum number of streams that can be opened by the peer.
245 QuicStreamCount incoming_actual_max_streams_;
246 QuicStreamCount incoming_advertised_max_streams_;
247
248 // Initial maximum on the number of open streams allowed.
249 QuicStreamCount incoming_initial_max_open_streams_;
250
fkastenholz3c4eabf2019-04-22 07:49:59 -0700251 // This is the number of streams that have been created -- some are still
252 // open, the others have been closed. It is the number that is compared
253 // against MAX_STREAMS when deciding whether to accept a new stream or not.
254 QuicStreamCount incoming_stream_count_;
255
QUICHE teama6ef0a62019-03-07 20:34:33 -0500256 // Set of stream ids that are less than the largest stream id that has been
257 // received, but are nonetheless available to be created.
258 QuicUnorderedSet<QuicStreamId> available_streams_;
259
260 QuicStreamId largest_peer_created_stream_id_;
261
fkastenholz3c4eabf2019-04-22 07:49:59 -0700262 // When incoming streams close the local node sends MAX_STREAMS frames. It
263 // does so only when the peer can open fewer than |max_stream_id_window_|
264 // streams. That is, when |incoming_actual_max_streams_| -
265 // |incoming_advertised_max_streams_| is less than the window.
266 // max_streams_window_ is set to 1/2 of the initial number of incoming streams
267 // that are allowed (as set in the constructor).
268 QuicStreamId max_streams_window_;
fkastenholz56055be2019-09-17 11:17:37 -0700269
270 // MAX_STREAMS and STREAMS_BLOCKED frames are not sent before the session has
271 // been configured. Instead, the relevant information is stored in
272 // |pending_max_streams_| and |pending_streams_blocked_| and sent when
273 // OnConfigNegotiated() is invoked.
274 bool pending_max_streams_;
275 QuicStreamId pending_streams_blocked_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500276};
QUICHE teama6ef0a62019-03-07 20:34:33 -0500277} // namespace quic
278
279#endif // QUICHE_QUIC_CORE_QUIC_STREAM_ID_MANAGER_H_