blob: f68401a13b35b806f4f83ed0c74fa86bc8c0d5d1 [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#include "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
5
vasilvv872e7a32019-03-12 16:42:44 -07006#include <string>
7
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include "net/third_party/quiche/src/quic/core/quic_connection.h"
9#include "net/third_party/quiche/src/quic/core/quic_constants.h"
10#include "net/third_party/quiche/src/quic/core/quic_session.h"
11#include "net/third_party/quiche/src/quic/core/quic_utils.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050016
17namespace quic {
18
19#define ENDPOINT \
20 (session_->perspective() == Perspective::IS_SERVER ? " Server: " \
21 : " Client: ")
22
23QuicStreamIdManager::QuicStreamIdManager(
24 QuicSession* session,
fkastenholz3c4eabf2019-04-22 07:49:59 -070025 bool unidirectional,
26 QuicStreamCount max_allowed_outgoing_streams,
27 QuicStreamCount max_allowed_incoming_streams)
QUICHE teama6ef0a62019-03-07 20:34:33 -050028 : session_(session),
fkastenholz3c4eabf2019-04-22 07:49:59 -070029 unidirectional_(unidirectional),
30 outgoing_max_streams_(max_allowed_outgoing_streams),
31 next_outgoing_stream_id_(GetFirstOutgoingStreamId()),
32 outgoing_stream_count_(0),
33 outgoing_static_stream_count_(0),
34 using_default_max_streams_(true),
35 incoming_actual_max_streams_(max_allowed_incoming_streams),
36 // Advertised max starts at actual because it's communicated in the
37 // handshake.
38 incoming_advertised_max_streams_(max_allowed_incoming_streams),
39 incoming_initial_max_open_streams_(max_allowed_incoming_streams),
40 incoming_static_stream_count_(0),
41 incoming_stream_count_(0),
42 largest_peer_created_stream_id_(
43 QuicUtils::GetInvalidStreamId(transport_version())),
44 max_streams_window_(0) {
45 CalculateIncomingMaxStreamsWindow();
QUICHE teama6ef0a62019-03-07 20:34:33 -050046}
47
48QuicStreamIdManager::~QuicStreamIdManager() {
QUICHE teama6ef0a62019-03-07 20:34:33 -050049}
50
fkastenholz3c4eabf2019-04-22 07:49:59 -070051bool QuicStreamIdManager::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
52 // Ensure that the frame has the correct directionality.
53 DCHECK_EQ(frame.unidirectional, unidirectional_);
54 QUIC_CODE_COUNT_N(quic_max_streams_received, 2, 2);
55 const QuicStreamCount current_outgoing_max_streams = outgoing_max_streams_;
56
57 // Set the limit to be exactly the stream count in the frame.
58 if (!ConfigureMaxOpenOutgoingStreams(frame.stream_count)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050059 return false;
60 }
fkastenholz3c4eabf2019-04-22 07:49:59 -070061 // If we were at the previous limit and this MAX_STREAMS frame
62 // increased the limit, inform the application that new streams are
63 // available.
64 if (outgoing_stream_count_ == current_outgoing_max_streams &&
65 current_outgoing_max_streams < outgoing_max_streams_) {
66 session_->OnCanCreateNewOutgoingStream();
QUICHE teama6ef0a62019-03-07 20:34:33 -050067 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 return true;
69}
70
fkastenholz3c4eabf2019-04-22 07:49:59 -070071// The peer sends a streams blocked frame when it can not open any more
72// streams because it has runs into the limit.
73bool QuicStreamIdManager::OnStreamsBlockedFrame(
74 const QuicStreamsBlockedFrame& frame) {
75 // Ensure that the frame has the correct directionality.
76 DCHECK_EQ(frame.unidirectional, unidirectional_);
77 QUIC_CODE_COUNT_N(quic_streams_blocked_received, 2, 2);
QUICHE teama6ef0a62019-03-07 20:34:33 -050078
fkastenholz3c4eabf2019-04-22 07:49:59 -070079 if (frame.stream_count > incoming_advertised_max_streams_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050080 // Peer thinks it can send more streams that we've told it.
81 // This is a protocol error.
82 // TODO(fkastenholz): revise when proper IETF Connection Close support is
83 // done.
fkastenholz3c4eabf2019-04-22 07:49:59 -070084 QUIC_CODE_COUNT(quic_streams_blocked_too_big);
QUICHE teama6ef0a62019-03-07 20:34:33 -050085 session_->connection()->CloseConnection(
fkastenholz3c4eabf2019-04-22 07:49:59 -070086 QUIC_STREAMS_BLOCKED_ERROR, "Invalid stream count specified",
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
88 return false;
89 }
fkastenholz3c4eabf2019-04-22 07:49:59 -070090 if (frame.stream_count < incoming_actual_max_streams_) {
91 // Peer thinks it's blocked on a stream count that is less than our current
92 // max. Inform the peer of the correct stream count. Sending a MAX_STREAMS
93 // frame in this case is not controlled by the window.
94 SendMaxStreamsFrame();
QUICHE teama6ef0a62019-03-07 20:34:33 -050095 }
fkastenholz3c4eabf2019-04-22 07:49:59 -070096 QUIC_CODE_COUNT(quic_streams_blocked_id_correct);
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 return true;
98}
99
fkastenholz3c4eabf2019-04-22 07:49:59 -0700100// Used when configuration has been done and we have an initial
101// maximum stream count from the peer.
102bool QuicStreamIdManager::ConfigureMaxOpenOutgoingStreams(
103 size_t max_open_streams) {
104 if (using_default_max_streams_) {
105 // This is the first MAX_STREAMS/transport negotiation we've received. Treat
106 // this a bit differently than later ones. The difference is that
107 // outgoing_max_streams_ is currently an estimate. The MAX_STREAMS frame or
108 // transport negotiation is authoritative and can reduce
109 // outgoing_max_streams_ -- so long as outgoing_max_streams_ is not set to
110 // be less than the number of existing outgoing streams. If that happens,
111 // close the connection.
112 if (max_open_streams < outgoing_stream_count_) {
113 session_->connection()->CloseConnection(
114 QUIC_MAX_STREAMS_ERROR,
115 "Stream limit less than existing stream count",
116 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
117 return false;
118 }
119 using_default_max_streams_ = false;
120 } else if (max_open_streams <= outgoing_max_streams_) {
121 // Is not the 1st MAX_STREAMS or negotiation.
122 // Only update the stream count if it would increase the limit.
123 // If it decreases the limit, or doesn't change it, then do not update.
124 // Note that this handles the case of receiving a count of 0 in the frame
125 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126 }
127
fkastenholz3c4eabf2019-04-22 07:49:59 -0700128 // This implementation only supports 32 bit Stream IDs, so limit max streams
129 // if it would exceed the max 32 bits can express.
130 outgoing_max_streams_ = std::min(
131 static_cast<QuicStreamCount>(max_open_streams),
132 QuicUtils::GetMaxStreamCount(unidirectional_, session_->perspective()));
133
134 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500135}
136
fkastenholz3c4eabf2019-04-22 07:49:59 -0700137void QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) {
138 QUIC_BUG_IF(!using_default_max_streams_);
139 AdjustMaxOpenOutgoingStreams(max_open_streams);
140}
141
142// Adjust the outgoing stream limit - max_open_streams is the limit, not
143// including static streams. If the new stream limit wraps, will peg
144// the limit at the implementation max.
145// TODO(fkastenholz): AdjustMax is cognizant of the number of static streams and
146// sets the maximum to be max_streams + number_of_statics. This should
147// eventually be removed from IETF QUIC.
148void QuicStreamIdManager::AdjustMaxOpenOutgoingStreams(
149 size_t max_open_streams) {
150 if ((outgoing_static_stream_count_ + max_open_streams) < max_open_streams) {
151 // New limit causes us to wrap, set limit to be the implementation maximum.
152 ConfigureMaxOpenOutgoingStreams(
153 QuicUtils::GetMaxStreamCount(unidirectional_, perspective()));
154 return;
155 }
156 // Does not wrap, set limit to what is requested.
157 ConfigureMaxOpenOutgoingStreams(outgoing_static_stream_count_ +
158 max_open_streams);
159}
160
161void QuicStreamIdManager::SetMaxOpenIncomingStreams(size_t max_open_streams) {
162 QuicStreamCount implementation_max =
163 QuicUtils::GetMaxStreamCount(unidirectional_, perspective());
164 QuicStreamCount new_max =
165 std::min(implementation_max,
166 static_cast<QuicStreamCount>(max_open_streams +
167 incoming_static_stream_count_));
168 if (new_max < max_open_streams) {
169 // wrapped around ...
170 new_max = implementation_max;
171 }
172 if (new_max < incoming_stream_count_) {
173 session_->connection()->CloseConnection(
174 QUIC_MAX_STREAMS_ERROR, "Stream limit less than existing stream count",
175 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
176 return;
177 }
178 incoming_actual_max_streams_ = new_max;
179 incoming_advertised_max_streams_ = new_max;
180 incoming_initial_max_open_streams_ =
181 std::min(max_open_streams, static_cast<size_t>(implementation_max));
182 CalculateIncomingMaxStreamsWindow();
183}
184
185void QuicStreamIdManager::MaybeSendMaxStreamsFrame() {
186 if ((incoming_advertised_max_streams_ - incoming_stream_count_) >
187 max_streams_window_) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500188 // window too large, no advertisement
189 return;
190 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700191 SendMaxStreamsFrame();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500192}
193
fkastenholz3c4eabf2019-04-22 07:49:59 -0700194void QuicStreamIdManager::SendMaxStreamsFrame() {
195 incoming_advertised_max_streams_ = incoming_actual_max_streams_;
196 session_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500197}
198
199void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700200 DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500201 if (!IsIncomingStream(stream_id)) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700202 // Nothing to do for outgoing streams.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500203 return;
204 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700205 // If the stream is inbound, we can increase the actual stream limit and maybe
206 // advertise the new limit to the peer. Have to check to make sure that we do
207 // not exceed the maximum.
208 if (incoming_actual_max_streams_ ==
209 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500210 // Reached the maximum stream id value that the implementation
211 // supports. Nothing can be done here.
212 return;
213 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700214 // One stream closed ... another can be opened.
215 incoming_actual_max_streams_++;
216 MaybeSendMaxStreamsFrame();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500217}
218
219QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700220 // TODO(fkastenholz): Should we close the connection?
221 QUIC_BUG_IF(outgoing_stream_count_ >= outgoing_max_streams_)
222 << "Attempt to allocate a new outgoing stream that would exceed the "
223 "limit";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500224 QuicStreamId id = next_outgoing_stream_id_;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700225 next_outgoing_stream_id_ += QuicUtils::StreamIdDelta(transport_version());
226 outgoing_stream_count_++;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500227 return id;
228}
229
230bool QuicStreamIdManager::CanOpenNextOutgoingStream() {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700231 DCHECK_EQ(QUIC_VERSION_99, transport_version());
232 if (outgoing_stream_count_ < outgoing_max_streams_) {
233 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500234 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700235 // Next stream ID would exceed the limit, need to inform the peer.
236 session_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_);
237 QUIC_CODE_COUNT(quic_reached_outgoing_stream_id_limit);
238 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500239}
240
fkastenholz3c4eabf2019-04-22 07:49:59 -0700241bool QuicStreamIdManager::RegisterStaticStream(QuicStreamId stream_id) {
242 DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
243 if (IsIncomingStream(stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244 // This code is predicated on static stream ids being allocated densely, in
245 // order, and starting with the first stream allowed. QUIC_BUG if this is
246 // not so.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247 // This is a stream id for a stream that is started by the peer, deal with
248 // the incoming stream ids. Increase the floor and adjust everything
249 // accordingly.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700250
251 QUIC_BUG_IF(incoming_actual_max_streams_ >
252 QuicUtils::GetMaxStreamCount(unidirectional_, perspective()));
253
254 // If we have reached the limit on stream creation, do not create
255 // the static stream; return false.
256 if (incoming_stream_count_ >=
257 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
258 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500259 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700260
261 if (incoming_actual_max_streams_ <
262 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
263 incoming_actual_max_streams_++;
264 }
265 if (incoming_advertised_max_streams_ <
266 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
267 incoming_advertised_max_streams_++;
268 }
269 incoming_stream_count_++;
270 incoming_static_stream_count_++;
271 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500272 }
273
fkastenholz3c4eabf2019-04-22 07:49:59 -0700274 QUIC_BUG_IF(!using_default_max_streams_)
275 << "Attempted to allocate static stream (id " << stream_id
276 << ") after receiving a MAX_STREAMS frame";
277
278 // If we have reached the limit on stream creation, do not create
279 // the static stream; return false.
280 if (outgoing_max_streams_ >=
281 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
282 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500283 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700284
285 // This is a stream id for a stream that is started by this node
286 if (perspective() == Perspective::IS_CLIENT &&
287 stream_id == QuicUtils::GetCryptoStreamId(transport_version())) {
288 // TODO(fkastenholz): When crypto is moved into the CRYPTO_STREAM
289 // and streamID 0 is no longer special, this needs to be removed.
290 // Stream-id-0 seems not be allocated via get-next-stream-id,
291 // which would increment outgoing_stream_count_, so increment
292 // the count here to account for it.
293 // Do not need to update next_outgoing_stream_id_ because it is
294 // initiated to 4 (that is, it skips the crypto stream ID).
295 if (outgoing_stream_count_ >=
296 QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) {
297 // Already at the implementation limit, return false...
298 return false;
299 }
300 outgoing_stream_count_++;
301 }
302
303 // Increase the outgoing_max_streams_ limit to reflect the semantic that
304 // outgoing_max_streams_ was inialized to a "maximum request/response" count
305 // and only becomes a maximum stream count when we receive the first
306 // MAX_STREAMS.
307 outgoing_max_streams_++;
308 outgoing_static_stream_count_++;
309 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500310}
311
fkastenholz3c4eabf2019-04-22 07:49:59 -0700312// Stream_id is the id of a new incoming stream. Check if it can be
313// created (doesn't violate limits, etc).
QUICHE teama6ef0a62019-03-07 20:34:33 -0500314bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
315 const QuicStreamId stream_id) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700316 DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id), unidirectional_);
317
QUICHE teama6ef0a62019-03-07 20:34:33 -0500318 available_streams_.erase(stream_id);
319
320 if (largest_peer_created_stream_id_ !=
fkastenholz3c4eabf2019-04-22 07:49:59 -0700321 QuicUtils::GetInvalidStreamId(transport_version()) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500322 stream_id <= largest_peer_created_stream_id_) {
323 return true;
324 }
325
fkastenholz3c4eabf2019-04-22 07:49:59 -0700326 QuicStreamCount stream_count_increment;
327 if (largest_peer_created_stream_id_ !=
328 QuicUtils::GetInvalidStreamId(transport_version())) {
329 stream_count_increment = (stream_id - largest_peer_created_stream_id_) /
330 QuicUtils::StreamIdDelta(transport_version());
331 } else {
332 // Largest_peer_created_stream_id is the invalid ID,
333 // which means that the peer has not created any stream IDs.
334 // The "+1" is because the first stream ID has not yet
335 // been used. For example, if the FirstIncoming ID is 1
336 // and stream_id is 1, then we want the increment to be 1.
337 stream_count_increment = ((stream_id - GetFirstIncomingStreamId()) /
338 QuicUtils::StreamIdDelta(transport_version())) +
339 1;
340 }
341
342 // If already at, or over, the limit, close the connection/etc.
343 if (((incoming_stream_count_ + stream_count_increment) >
344 incoming_advertised_max_streams_) ||
345 ((incoming_stream_count_ + stream_count_increment) <
346 incoming_stream_count_)) {
347 // This stream would exceed the limit. do not increase.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348 QUIC_DLOG(INFO) << ENDPOINT
349 << "Failed to create a new incoming stream with id:"
fkastenholz3c4eabf2019-04-22 07:49:59 -0700350 << stream_id << ", reaching MAX_STREAMS limit: "
351 << incoming_advertised_max_streams_ << ".";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500352 session_->connection()->CloseConnection(
353 QUIC_INVALID_STREAM_ID,
fkastenholz3c4eabf2019-04-22 07:49:59 -0700354 QuicStrCat("Stream id ", stream_id, " would exceed stream count limit ",
355 incoming_advertised_max_streams_),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500356 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
357 return false;
358 }
359
fkastenholz3c4eabf2019-04-22 07:49:59 -0700360 QuicStreamId id = GetFirstIncomingStreamId();
361 if (largest_peer_created_stream_id_ !=
362 QuicUtils::GetInvalidStreamId(transport_version())) {
363 id = largest_peer_created_stream_id_ +
364 QuicUtils::StreamIdDelta(transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700366
367 for (; id < stream_id; id += QuicUtils::StreamIdDelta(transport_version())) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500368 available_streams_.insert(id);
369 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700370 incoming_stream_count_ += stream_count_increment;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500371 largest_peer_created_stream_id_ = stream_id;
372 return true;
373}
374
375bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700376 DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500377 if (!IsIncomingStream(id)) {
378 // Stream IDs under next_ougoing_stream_id_ are either open or previously
379 // open but now closed.
380 return id >= next_outgoing_stream_id_;
381 }
382 // For peer created streams, we also need to consider available streams.
383 return largest_peer_created_stream_id_ ==
fkastenholz3c4eabf2019-04-22 07:49:59 -0700384 QuicUtils::GetInvalidStreamId(transport_version()) ||
QUICHE teama6ef0a62019-03-07 20:34:33 -0500385 id > largest_peer_created_stream_id_ ||
386 QuicContainsKey(available_streams_, id);
387}
388
389bool QuicStreamIdManager::IsIncomingStream(QuicStreamId id) const {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700390 DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id), unidirectional_);
391 // The 0x1 bit in the stream id indicates whether the stream id is
392 // server- or client- initiated. Next_OUTGOING_stream_id_ has that bit
393 // set based on whether this node is a server or client. Thus, if the stream
394 // id in question has the 0x1 bit set opposite of next_OUTGOING_stream_id_,
395 // then that stream id is incoming -- it is for streams initiated by the peer.
396 return (id & 0x1) != (next_outgoing_stream_id_ & 0x1);
397}
398
399QuicStreamId QuicStreamIdManager::GetFirstOutgoingStreamId() const {
400 return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
401 transport_version(), perspective())
402 : QuicUtils::GetFirstBidirectionalStreamId(
403 transport_version(), perspective());
404}
405
406QuicStreamId QuicStreamIdManager::GetFirstIncomingStreamId() const {
407 return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
408 transport_version(), peer_perspective())
409 : QuicUtils::GetFirstBidirectionalStreamId(
410 transport_version(), peer_perspective());
411}
412
413Perspective QuicStreamIdManager::perspective() const {
414 return session_->perspective();
415}
416
417Perspective QuicStreamIdManager::peer_perspective() const {
418 return (perspective() == Perspective::IS_SERVER) ? Perspective::IS_CLIENT
419 : Perspective::IS_SERVER;
420}
421
422QuicTransportVersion QuicStreamIdManager::transport_version() const {
423 return session_->connection()->transport_version();
424}
425
426size_t QuicStreamIdManager::available_incoming_streams() {
427 return incoming_advertised_max_streams_ - incoming_stream_count_;
428}
429
430void QuicStreamIdManager::CalculateIncomingMaxStreamsWindow() {
431 max_streams_window_ = incoming_actual_max_streams_ / kMaxStreamsWindowDivisor;
432 if (max_streams_window_ == 0) {
433 max_streams_window_ = 1;
434 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500435}
436
437} // namespace quic