xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_stream_id_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #include "quiche/quic/core/quic_stream_id_manager.h"
5 
6 #include <cstdint>
7 #include <string>
8 
9 #include "absl/strings/str_cat.h"
10 #include "quiche/quic/core/quic_connection.h"
11 #include "quiche/quic/core/quic_constants.h"
12 #include "quiche/quic/core/quic_session.h"
13 #include "quiche/quic/core/quic_utils.h"
14 #include "quiche/quic/core/quic_versions.h"
15 #include "quiche/quic/platform/api/quic_flag_utils.h"
16 #include "quiche/quic/platform/api/quic_flags.h"
17 #include "quiche/quic/platform/api/quic_logging.h"
18 
19 namespace quic {
20 
21 #define ENDPOINT \
22   (perspective_ == Perspective::IS_SERVER ? " Server: " : " Client: ")
23 
QuicStreamIdManager(DelegateInterface * delegate,bool unidirectional,Perspective perspective,ParsedQuicVersion version,QuicStreamCount max_allowed_outgoing_streams,QuicStreamCount max_allowed_incoming_streams)24 QuicStreamIdManager::QuicStreamIdManager(
25     DelegateInterface* delegate, bool unidirectional, Perspective perspective,
26     ParsedQuicVersion version, QuicStreamCount max_allowed_outgoing_streams,
27     QuicStreamCount max_allowed_incoming_streams)
28     : delegate_(delegate),
29       unidirectional_(unidirectional),
30       perspective_(perspective),
31       version_(version),
32       outgoing_max_streams_(max_allowed_outgoing_streams),
33       next_outgoing_stream_id_(GetFirstOutgoingStreamId()),
34       outgoing_stream_count_(0),
35       incoming_actual_max_streams_(max_allowed_incoming_streams),
36       incoming_advertised_max_streams_(max_allowed_incoming_streams),
37       incoming_initial_max_open_streams_(max_allowed_incoming_streams),
38       incoming_stream_count_(0),
39       largest_peer_created_stream_id_(
40           QuicUtils::GetInvalidStreamId(version.transport_version)),
41       stop_increasing_incoming_max_streams_(false) {}
42 
~QuicStreamIdManager()43 QuicStreamIdManager::~QuicStreamIdManager() {}
44 
OnStreamsBlockedFrame(const QuicStreamsBlockedFrame & frame,std::string * error_details)45 bool QuicStreamIdManager::OnStreamsBlockedFrame(
46     const QuicStreamsBlockedFrame& frame, std::string* error_details) {
47   QUICHE_DCHECK_EQ(frame.unidirectional, unidirectional_);
48   if (frame.stream_count > incoming_advertised_max_streams_) {
49     // Peer thinks it can send more streams that we've told it.
50     *error_details = absl::StrCat(
51         "StreamsBlockedFrame's stream count ", frame.stream_count,
52         " exceeds incoming max stream ", incoming_advertised_max_streams_);
53     return false;
54   }
55   QUICHE_DCHECK_LE(incoming_advertised_max_streams_,
56                    incoming_actual_max_streams_);
57   if (incoming_advertised_max_streams_ == incoming_actual_max_streams_) {
58     // We have told peer about current max.
59     return true;
60   }
61   if (frame.stream_count < incoming_actual_max_streams_ &&
62       delegate_->CanSendMaxStreams()) {
63     // Peer thinks it's blocked on a stream count that is less than our current
64     // max. Inform the peer of the correct stream count.
65     SendMaxStreamsFrame();
66   }
67   return true;
68 }
69 
MaybeAllowNewOutgoingStreams(QuicStreamCount max_open_streams)70 bool QuicStreamIdManager::MaybeAllowNewOutgoingStreams(
71     QuicStreamCount max_open_streams) {
72   if (max_open_streams <= outgoing_max_streams_) {
73     // Only update the stream count if it would increase the limit.
74     return false;
75   }
76 
77   // This implementation only supports 32 bit Stream IDs, so limit max streams
78   // if it would exceed the max 32 bits can express.
79   outgoing_max_streams_ =
80       std::min(max_open_streams, QuicUtils::GetMaxStreamCount());
81 
82   return true;
83 }
84 
SetMaxOpenIncomingStreams(QuicStreamCount max_open_streams)85 void QuicStreamIdManager::SetMaxOpenIncomingStreams(
86     QuicStreamCount max_open_streams) {
87   QUIC_BUG_IF(quic_bug_12413_1, incoming_stream_count_ > 0)
88       << "non-zero incoming stream count " << incoming_stream_count_
89       << " when setting max incoming stream to " << max_open_streams;
90   QUIC_DLOG_IF(WARNING, incoming_initial_max_open_streams_ != max_open_streams)
91       << absl::StrCat(unidirectional_ ? "unidirectional " : "bidirectional: ",
92                       "incoming stream limit changed from ",
93                       incoming_initial_max_open_streams_, " to ",
94                       max_open_streams);
95   incoming_actual_max_streams_ = max_open_streams;
96   incoming_advertised_max_streams_ = max_open_streams;
97   incoming_initial_max_open_streams_ = max_open_streams;
98 }
99 
MaybeSendMaxStreamsFrame()100 void QuicStreamIdManager::MaybeSendMaxStreamsFrame() {
101   int divisor = GetQuicFlag(quic_max_streams_window_divisor);
102 
103   if (divisor > 0) {
104     if ((incoming_advertised_max_streams_ - incoming_stream_count_) >
105         (incoming_initial_max_open_streams_ / divisor)) {
106       // window too large, no advertisement
107       return;
108     }
109   }
110   if (delegate_->CanSendMaxStreams() &&
111       incoming_advertised_max_streams_ < incoming_actual_max_streams_) {
112     SendMaxStreamsFrame();
113   }
114 }
115 
SendMaxStreamsFrame()116 void QuicStreamIdManager::SendMaxStreamsFrame() {
117   QUIC_BUG_IF(quic_bug_12413_2,
118               incoming_advertised_max_streams_ >= incoming_actual_max_streams_);
119   incoming_advertised_max_streams_ = incoming_actual_max_streams_;
120   delegate_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_);
121 }
122 
OnStreamClosed(QuicStreamId stream_id)123 void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) {
124   QUICHE_DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_),
125                    unidirectional_);
126   if (QuicUtils::IsOutgoingStreamId(version_, stream_id, perspective_)) {
127     // Nothing to do for outgoing streams.
128     return;
129   }
130   // If the stream is inbound, we can increase the actual stream limit and maybe
131   // advertise the new limit to the peer.
132   if (incoming_actual_max_streams_ == QuicUtils::GetMaxStreamCount()) {
133     // Reached the maximum stream id value that the implementation
134     // supports. Nothing can be done here.
135     return;
136   }
137   if (!stop_increasing_incoming_max_streams_) {
138     // One stream closed, and another one can be opened.
139     incoming_actual_max_streams_++;
140     MaybeSendMaxStreamsFrame();
141   }
142 }
143 
GetNextOutgoingStreamId()144 QuicStreamId QuicStreamIdManager::GetNextOutgoingStreamId() {
145   QUIC_BUG_IF(quic_bug_12413_3, outgoing_stream_count_ >= outgoing_max_streams_)
146       << "Attempt to allocate a new outgoing stream that would exceed the "
147          "limit ("
148       << outgoing_max_streams_ << ")";
149   QuicStreamId id = next_outgoing_stream_id_;
150   next_outgoing_stream_id_ +=
151       QuicUtils::StreamIdDelta(version_.transport_version);
152   outgoing_stream_count_++;
153   return id;
154 }
155 
CanOpenNextOutgoingStream() const156 bool QuicStreamIdManager::CanOpenNextOutgoingStream() const {
157   QUICHE_DCHECK(VersionHasIetfQuicFrames(version_.transport_version));
158   return outgoing_stream_count_ < outgoing_max_streams_;
159 }
160 
MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id,std::string * error_details)161 bool QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
162     const QuicStreamId stream_id, std::string* error_details) {
163   // |stream_id| must be an incoming stream of the right directionality.
164   QUICHE_DCHECK_NE(QuicUtils::IsBidirectionalStreamId(stream_id, version_),
165                    unidirectional_);
166   QUICHE_DCHECK_NE(QuicUtils::IsServerInitiatedStreamId(
167                        version_.transport_version, stream_id),
168                    perspective_ == Perspective::IS_SERVER);
169   if (available_streams_.erase(stream_id) == 1) {
170     // stream_id is available.
171     return true;
172   }
173 
174   if (largest_peer_created_stream_id_ !=
175       QuicUtils::GetInvalidStreamId(version_.transport_version)) {
176     QUICHE_DCHECK_GT(stream_id, largest_peer_created_stream_id_);
177   }
178 
179   // Calculate increment of incoming_stream_count_ by creating stream_id.
180   const QuicStreamCount delta =
181       QuicUtils::StreamIdDelta(version_.transport_version);
182   const QuicStreamId least_new_stream_id =
183       largest_peer_created_stream_id_ ==
184               QuicUtils::GetInvalidStreamId(version_.transport_version)
185           ? GetFirstIncomingStreamId()
186           : largest_peer_created_stream_id_ + delta;
187   const QuicStreamCount stream_count_increment =
188       (stream_id - least_new_stream_id) / delta + 1;
189 
190   if (incoming_stream_count_ + stream_count_increment >
191       incoming_advertised_max_streams_) {
192     QUIC_DLOG(INFO) << ENDPOINT
193                     << "Failed to create a new incoming stream with id:"
194                     << stream_id << ", reaching MAX_STREAMS limit: "
195                     << incoming_advertised_max_streams_ << ".";
196     *error_details = absl::StrCat("Stream id ", stream_id,
197                                   " would exceed stream count limit ",
198                                   incoming_advertised_max_streams_);
199     return false;
200   }
201 
202   for (QuicStreamId id = least_new_stream_id; id < stream_id; id += delta) {
203     available_streams_.insert(id);
204   }
205   incoming_stream_count_ += stream_count_increment;
206   largest_peer_created_stream_id_ = stream_id;
207   return true;
208 }
209 
IsAvailableStream(QuicStreamId id) const210 bool QuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
211   QUICHE_DCHECK_NE(QuicUtils::IsBidirectionalStreamId(id, version_),
212                    unidirectional_);
213   if (QuicUtils::IsOutgoingStreamId(version_, id, perspective_)) {
214     // Stream IDs under next_ougoing_stream_id_ are either open or previously
215     // open but now closed.
216     return id >= next_outgoing_stream_id_;
217   }
218   // For peer created streams, we also need to consider available streams.
219   return largest_peer_created_stream_id_ ==
220              QuicUtils::GetInvalidStreamId(version_.transport_version) ||
221          id > largest_peer_created_stream_id_ ||
222          available_streams_.contains(id);
223 }
224 
GetFirstOutgoingStreamId() const225 QuicStreamId QuicStreamIdManager::GetFirstOutgoingStreamId() const {
226   return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
227                                  version_.transport_version, perspective_)
228                            : QuicUtils::GetFirstBidirectionalStreamId(
229                                  version_.transport_version, perspective_);
230 }
231 
GetFirstIncomingStreamId() const232 QuicStreamId QuicStreamIdManager::GetFirstIncomingStreamId() const {
233   return (unidirectional_) ? QuicUtils::GetFirstUnidirectionalStreamId(
234                                  version_.transport_version,
235                                  QuicUtils::InvertPerspective(perspective_))
236                            : QuicUtils::GetFirstBidirectionalStreamId(
237                                  version_.transport_version,
238                                  QuicUtils::InvertPerspective(perspective_));
239 }
240 
available_incoming_streams() const241 QuicStreamCount QuicStreamIdManager::available_incoming_streams() const {
242   return incoming_advertised_max_streams_ - incoming_stream_count_;
243 }
244 
245 }  // namespace quic
246