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. |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 4 | #include "quic/core/legacy_quic_stream_id_manager.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 5 | |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 6 | #include "quic/core/quic_session.h" |
| 7 | #include "quic/core/quic_types.h" |
| 8 | #include "quic/core/quic_utils.h" |
| 9 | #include "quic/core/quic_versions.h" |
| 10 | #include "quic/platform/api/quic_map_util.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 11 | |
| 12 | namespace quic { |
| 13 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 14 | LegacyQuicStreamIdManager::LegacyQuicStreamIdManager( |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 15 | Perspective perspective, |
| 16 | QuicTransportVersion transport_version, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 17 | size_t max_open_outgoing_streams, |
| 18 | size_t max_open_incoming_streams) |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 19 | : perspective_(perspective), |
| 20 | transport_version_(transport_version), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 21 | max_open_outgoing_streams_(max_open_outgoing_streams), |
| 22 | max_open_incoming_streams_(max_open_incoming_streams), |
renjietang | d1d0085 | 2019-09-06 10:43:12 -0700 | [diff] [blame] | 23 | next_outgoing_stream_id_( |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 24 | QuicUtils::GetFirstBidirectionalStreamId(transport_version_, |
| 25 | perspective_)), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 26 | largest_peer_created_stream_id_( |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 27 | perspective_ == Perspective::IS_SERVER |
| 28 | ? (QuicVersionUsesCryptoFrames(transport_version_) |
| 29 | ? QuicUtils::GetInvalidStreamId(transport_version_) |
| 30 | : QuicUtils::GetCryptoStreamId(transport_version_)) |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 31 | : QuicUtils::GetInvalidStreamId(transport_version_)), |
| 32 | num_open_incoming_streams_(0), |
fayang | bd94f4c | 2020-06-01 14:36:37 -0700 | [diff] [blame] | 33 | num_open_outgoing_streams_(0) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 34 | |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 35 | LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 36 | |
fayang | bd94f4c | 2020-06-01 14:36:37 -0700 | [diff] [blame] | 37 | bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream() const { |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 38 | QUICHE_DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_); |
fayang | bd94f4c | 2020-06-01 14:36:37 -0700 | [diff] [blame] | 39 | QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_) |
| 40 | << "Failed to create a new outgoing stream. " |
| 41 | << "Already " << num_open_outgoing_streams_ << " open."; |
| 42 | return num_open_outgoing_streams_ < max_open_outgoing_streams_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 43 | } |
| 44 | |
fayang | bd94f4c | 2020-06-01 14:36:37 -0700 | [diff] [blame] | 45 | bool LegacyQuicStreamIdManager::CanOpenIncomingStream() const { |
| 46 | return num_open_incoming_streams_ < max_open_incoming_streams_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | bool LegacyQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId( |
| 50 | const QuicStreamId stream_id) { |
| 51 | available_streams_.erase(stream_id); |
| 52 | |
| 53 | if (largest_peer_created_stream_id_ != |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 54 | QuicUtils::GetInvalidStreamId(transport_version_) && |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 55 | stream_id <= largest_peer_created_stream_id_) { |
| 56 | return true; |
| 57 | } |
| 58 | |
| 59 | // Check if the new number of available streams would cause the number of |
| 60 | // available streams to exceed the limit. Note that the peer can create |
| 61 | // only alternately-numbered streams. |
| 62 | size_t additional_available_streams = |
| 63 | (stream_id - largest_peer_created_stream_id_) / 2 - 1; |
nharper | f309f3e | 2019-06-26 21:49:26 -0700 | [diff] [blame] | 64 | if (largest_peer_created_stream_id_ == |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 65 | QuicUtils::GetInvalidStreamId(transport_version_)) { |
nharper | f309f3e | 2019-06-26 21:49:26 -0700 | [diff] [blame] | 66 | additional_available_streams = (stream_id + 1) / 2 - 1; |
| 67 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 68 | size_t new_num_available_streams = |
| 69 | GetNumAvailableStreams() + additional_available_streams; |
| 70 | if (new_num_available_streams > MaxAvailableStreams()) { |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 71 | QUIC_DLOG(INFO) << perspective_ |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 72 | << "Failed to create a new incoming stream with id:" |
| 73 | << stream_id << ". There are already " |
| 74 | << GetNumAvailableStreams() |
| 75 | << " streams available, which would become " |
| 76 | << new_num_available_streams << ", which exceeds the limit " |
| 77 | << MaxAvailableStreams() << "."; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 78 | return false; |
| 79 | } |
nharper | f309f3e | 2019-06-26 21:49:26 -0700 | [diff] [blame] | 80 | QuicStreamId first_available_stream = largest_peer_created_stream_id_ + 2; |
| 81 | if (largest_peer_created_stream_id_ == |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 82 | QuicUtils::GetInvalidStreamId(transport_version_)) { |
nharper | f309f3e | 2019-06-26 21:49:26 -0700 | [diff] [blame] | 83 | first_available_stream = QuicUtils::GetFirstBidirectionalStreamId( |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 84 | transport_version_, QuicUtils::InvertPerspective(perspective_)); |
nharper | f309f3e | 2019-06-26 21:49:26 -0700 | [diff] [blame] | 85 | } |
| 86 | for (QuicStreamId id = first_available_stream; id < stream_id; id += 2) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 87 | available_streams_.insert(id); |
| 88 | } |
| 89 | largest_peer_created_stream_id_ = stream_id; |
| 90 | |
| 91 | return true; |
| 92 | } |
| 93 | |
| 94 | QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() { |
| 95 | QuicStreamId id = next_outgoing_stream_id_; |
| 96 | next_outgoing_stream_id_ += 2; |
| 97 | return id; |
| 98 | } |
| 99 | |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 100 | void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) { |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 101 | if (is_incoming) { |
| 102 | ++num_open_incoming_streams_; |
| 103 | return; |
| 104 | } |
| 105 | ++num_open_outgoing_streams_; |
| 106 | } |
| 107 | |
| 108 | void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) { |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 109 | if (is_incoming) { |
QUICHE team | d6d05e5 | 2021-03-16 14:22:01 -0700 | [diff] [blame] | 110 | QUIC_BUG_IF(quic_bug_12720_1, num_open_incoming_streams_ == 0); |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 111 | --num_open_incoming_streams_; |
| 112 | return; |
| 113 | } |
QUICHE team | d6d05e5 | 2021-03-16 14:22:01 -0700 | [diff] [blame] | 114 | QUIC_BUG_IF(quic_bug_12720_2, num_open_outgoing_streams_ == 0); |
fayang | 01591ae | 2020-04-23 14:14:56 -0700 | [diff] [blame] | 115 | --num_open_outgoing_streams_; |
| 116 | } |
| 117 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 118 | bool LegacyQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const { |
| 119 | if (!IsIncomingStream(id)) { |
| 120 | // Stream IDs under next_ougoing_stream_id_ are either open or previously |
| 121 | // open but now closed. |
| 122 | return id >= next_outgoing_stream_id_; |
| 123 | } |
| 124 | // For peer created streams, we also need to consider available streams. |
| 125 | return largest_peer_created_stream_id_ == |
ianswett | c1f530d | 2019-12-10 05:14:30 -0800 | [diff] [blame] | 126 | QuicUtils::GetInvalidStreamId(transport_version_) || |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 127 | id > largest_peer_created_stream_id_ || |
| 128 | QuicContainsKey(available_streams_, id); |
| 129 | } |
| 130 | |
| 131 | bool LegacyQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const { |
| 132 | return id % 2 != next_outgoing_stream_id_ % 2; |
| 133 | } |
| 134 | |
| 135 | size_t LegacyQuicStreamIdManager::GetNumAvailableStreams() const { |
| 136 | return available_streams_.size(); |
| 137 | } |
| 138 | |
| 139 | size_t LegacyQuicStreamIdManager::MaxAvailableStreams() const { |
| 140 | return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier; |
| 141 | } |
| 142 | |
| 143 | } // namespace quic |