blob: 0e422ef12cdc46f511d934e7c1da4850e3e408c1 [file] [log] [blame]
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "quiche/quic/core/legacy_quic_stream_id_manager.h"
#include "quiche/quic/core/quic_session.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_utils.h"
#include "quiche/quic/core/quic_versions.h"
namespace quic {
LegacyQuicStreamIdManager::LegacyQuicStreamIdManager(
Perspective perspective, QuicTransportVersion transport_version,
size_t max_open_outgoing_streams, size_t max_open_incoming_streams)
: perspective_(perspective),
transport_version_(transport_version),
max_open_outgoing_streams_(max_open_outgoing_streams),
max_open_incoming_streams_(max_open_incoming_streams),
next_outgoing_stream_id_(QuicUtils::GetFirstBidirectionalStreamId(
transport_version_, perspective_)),
largest_peer_created_stream_id_(
perspective_ == Perspective::IS_SERVER
? (QuicVersionUsesCryptoFrames(transport_version_)
? QuicUtils::GetInvalidStreamId(transport_version_)
: QuicUtils::GetCryptoStreamId(transport_version_))
: QuicUtils::GetInvalidStreamId(transport_version_)),
num_open_incoming_streams_(0),
num_open_outgoing_streams_(0) {}
LegacyQuicStreamIdManager::~LegacyQuicStreamIdManager() {}
bool LegacyQuicStreamIdManager::CanOpenNextOutgoingStream() const {
QUICHE_DCHECK_LE(num_open_outgoing_streams_, max_open_outgoing_streams_);
QUIC_DLOG_IF(INFO, num_open_outgoing_streams_ == max_open_outgoing_streams_)
<< "Failed to create a new outgoing stream. "
<< "Already " << num_open_outgoing_streams_ << " open.";
return num_open_outgoing_streams_ < max_open_outgoing_streams_;
}
bool LegacyQuicStreamIdManager::CanOpenIncomingStream() const {
return num_open_incoming_streams_ < max_open_incoming_streams_;
}
bool LegacyQuicStreamIdManager::MaybeIncreaseLargestPeerStreamId(
const QuicStreamId stream_id) {
available_streams_.erase(stream_id);
if (largest_peer_created_stream_id_ !=
QuicUtils::GetInvalidStreamId(transport_version_) &&
stream_id <= largest_peer_created_stream_id_) {
return true;
}
// Check if the new number of available streams would cause the number of
// available streams to exceed the limit. Note that the peer can create
// only alternately-numbered streams.
size_t additional_available_streams =
(stream_id - largest_peer_created_stream_id_) / 2 - 1;
if (largest_peer_created_stream_id_ ==
QuicUtils::GetInvalidStreamId(transport_version_)) {
additional_available_streams = (stream_id + 1) / 2 - 1;
}
size_t new_num_available_streams =
GetNumAvailableStreams() + additional_available_streams;
if (new_num_available_streams > MaxAvailableStreams()) {
QUIC_DLOG(INFO) << perspective_
<< "Failed to create a new incoming stream with id:"
<< stream_id << ". There are already "
<< GetNumAvailableStreams()
<< " streams available, which would become "
<< new_num_available_streams << ", which exceeds the limit "
<< MaxAvailableStreams() << ".";
return false;
}
QuicStreamId first_available_stream = largest_peer_created_stream_id_ + 2;
if (largest_peer_created_stream_id_ ==
QuicUtils::GetInvalidStreamId(transport_version_)) {
first_available_stream = QuicUtils::GetFirstBidirectionalStreamId(
transport_version_, QuicUtils::InvertPerspective(perspective_));
}
for (QuicStreamId id = first_available_stream; id < stream_id; id += 2) {
available_streams_.insert(id);
}
largest_peer_created_stream_id_ = stream_id;
return true;
}
QuicStreamId LegacyQuicStreamIdManager::GetNextOutgoingStreamId() {
QuicStreamId id = next_outgoing_stream_id_;
next_outgoing_stream_id_ += 2;
return id;
}
void LegacyQuicStreamIdManager::ActivateStream(bool is_incoming) {
if (is_incoming) {
++num_open_incoming_streams_;
return;
}
++num_open_outgoing_streams_;
}
void LegacyQuicStreamIdManager::OnStreamClosed(bool is_incoming) {
if (is_incoming) {
QUIC_BUG_IF(quic_bug_12720_1, num_open_incoming_streams_ == 0);
--num_open_incoming_streams_;
return;
}
QUIC_BUG_IF(quic_bug_12720_2, num_open_outgoing_streams_ == 0);
--num_open_outgoing_streams_;
}
bool LegacyQuicStreamIdManager::IsAvailableStream(QuicStreamId id) const {
if (!IsIncomingStream(id)) {
// Stream IDs under next_ougoing_stream_id_ are either open or previously
// open but now closed.
return id >= next_outgoing_stream_id_;
}
// For peer created streams, we also need to consider available streams.
return largest_peer_created_stream_id_ ==
QuicUtils::GetInvalidStreamId(transport_version_) ||
id > largest_peer_created_stream_id_ ||
available_streams_.contains(id);
}
bool LegacyQuicStreamIdManager::IsIncomingStream(QuicStreamId id) const {
return id % 2 != next_outgoing_stream_id_ % 2;
}
size_t LegacyQuicStreamIdManager::GetNumAvailableStreams() const {
return available_streams_.size();
}
size_t LegacyQuicStreamIdManager::MaxAvailableStreams() const {
return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
}
} // namespace quic