summaryrefslogtreecommitdiff
path: root/chromium/net/quic/quic_session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/quic_session.cc')
-rw-r--r--chromium/net/quic/quic_session.cc842
1 files changed, 0 insertions, 842 deletions
diff --git a/chromium/net/quic/quic_session.cc b/chromium/net/quic/quic_session.cc
deleted file mode 100644
index b232a1e71f6..00000000000
--- a/chromium/net/quic/quic_session.cc
+++ /dev/null
@@ -1,842 +0,0 @@
-// Copyright (c) 2012 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 "net/quic/quic_session.h"
-
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_flow_controller.h"
-#include "net/ssl/ssl_info.h"
-
-using base::IntToString;
-using base::StringPiece;
-using std::make_pair;
-using std::map;
-using std::max;
-using std::string;
-using std::vector;
-using net::SpdyPriority;
-
-namespace net {
-
-#define ENDPOINT \
- (perspective() == Perspective::IS_SERVER ? "Server: " : " Client: ")
-
-QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
- : connection_(connection),
- config_(config),
- max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection),
- max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()),
- next_outgoing_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 3),
- largest_peer_created_stream_id_(
- perspective() == Perspective::IS_SERVER ? 1 : 0),
- num_dynamic_incoming_streams_(0),
- num_draining_incoming_streams_(0),
- num_locally_closed_incoming_streams_highest_offset_(0),
- error_(QUIC_NO_ERROR),
- flow_controller_(connection_.get(),
- 0,
- perspective(),
- kMinimumFlowControlSendWindow,
- config_.GetInitialSessionFlowControlWindowToSend(),
- FLAGS_quic_enable_autotune_by_default
- ? perspective() == Perspective::IS_SERVER
- : false),
- currently_writing_stream_id_(0) {}
-
-void QuicSession::Initialize() {
- connection_->set_visitor(this);
- connection_->SetFromConfig(config_);
-
- DCHECK_EQ(kCryptoStreamId, GetCryptoStream()->id());
- static_stream_map_[kCryptoStreamId] = GetCryptoStream();
-}
-
-QuicSession::~QuicSession() {
- STLDeleteElements(&closed_streams_);
- STLDeleteValues(&dynamic_stream_map_);
-
- DLOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() >
- max_open_incoming_streams_)
- << "Surprisingly high number of locally closed peer initiated streams"
- "still waiting for final byte offset: "
- << num_locally_closed_incoming_streams_highest_offset();
- DLOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() >
- max_open_outgoing_streams_)
- << "Surprisingly high number of locally closed self initiated streams"
- "still waiting for final byte offset: "
- << GetNumLocallyClosedOutgoingStreamsHighestOffset();
-}
-
-void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
- // TODO(rch) deal with the error case of stream id 0.
- QuicStreamId stream_id = frame.stream_id;
- ReliableQuicStream* stream = GetOrCreateStream(stream_id);
- if (!stream) {
- // The stream no longer exists, but we may still be interested in the
- // final stream byte offset sent by the peer. A frame with a FIN can give
- // us this offset.
- if (frame.fin) {
- QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
- UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset);
- }
- return;
- }
- stream->OnStreamFrame(frame);
-}
-
-void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
- if (ContainsKey(static_stream_map_, frame.stream_id)) {
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- ReliableQuicStream* stream = GetOrCreateDynamicStream(frame.stream_id);
- if (!stream) {
- HandleRstOnValidNonexistentStream(frame);
- return; // Errors are handled by GetOrCreateStream.
- }
-
- stream->OnStreamReset(frame);
-}
-
-void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
- DCHECK(frame.last_good_stream_id < next_outgoing_stream_id_);
-}
-
-void QuicSession::OnConnectionClosed(QuicErrorCode error,
- const string& /*error_details*/,
- ConnectionCloseSource source) {
- DCHECK(!connection_->connected());
- if (error_ == QUIC_NO_ERROR) {
- error_ = error;
- }
-
- while (!dynamic_stream_map_.empty()) {
- StreamMap::iterator it = dynamic_stream_map_.begin();
- QuicStreamId id = it->first;
- it->second->OnConnectionClosed(error, source);
- // The stream should call CloseStream as part of OnConnectionClosed.
- if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
- QUIC_BUG << ENDPOINT << "Stream failed to close under OnConnectionClosed";
- CloseStream(id);
- }
- }
-}
-
-void QuicSession::OnSuccessfulVersionNegotiation(
- const QuicVersion& /*version*/) {}
-
-void QuicSession::OnPathDegrading() {}
-
-void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
- // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
- // assume that it still exists.
- QuicStreamId stream_id = frame.stream_id;
- if (stream_id == kConnectionLevelId) {
- // This is a window update that applies to the connection, rather than an
- // individual stream.
- DVLOG(1) << ENDPOINT << "Received connection level flow control window "
- "update with byte offset: "
- << frame.byte_offset;
- flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
- return;
- }
- ReliableQuicStream* stream = GetOrCreateStream(stream_id);
- if (stream) {
- stream->OnWindowUpdateFrame(frame);
- }
-}
-
-void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
- // TODO(rjshade): Compare our flow control receive windows for specified
- // streams: if we have a large window then maybe something
- // had gone wrong with the flow control accounting.
- DVLOG(1) << ENDPOINT
- << "Received BLOCKED frame with stream id: " << frame.stream_id;
-}
-
-void QuicSession::OnCanWrite() {
- // We limit the number of writes to the number of pending streams. If more
- // streams become pending, WillingAndAbleToWrite will be true, which will
- // cause the connection to request resumption before yielding to other
- // connections.
- size_t num_writes = write_blocked_streams_.NumBlockedStreams();
- if (flow_controller_.IsBlocked()) {
- // If we are connection level flow control blocked, then only allow the
- // crypto and headers streams to try writing as all other streams will be
- // blocked.
- num_writes = 0;
- if (write_blocked_streams_.crypto_stream_blocked()) {
- num_writes += 1;
- }
- if (write_blocked_streams_.headers_stream_blocked()) {
- num_writes += 1;
- }
- }
- if (num_writes == 0) {
- return;
- }
-
- QuicConnection::ScopedPacketBundler ack_bundler(
- connection_.get(), QuicConnection::SEND_ACK_IF_QUEUED);
- for (size_t i = 0; i < num_writes; ++i) {
- if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
- write_blocked_streams_.HasWriteBlockedDataStreams())) {
- // Writing one stream removed another!? Something's broken.
- QUIC_BUG << "WriteBlockedStream is missing";
- connection_->CloseConnection(QUIC_INTERNAL_ERROR,
- "WriteBlockedStream is missing",
- ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- if (!connection_->CanWriteStreamData()) {
- return;
- }
- currently_writing_stream_id_ = write_blocked_streams_.PopFront();
- ReliableQuicStream* stream =
- GetOrCreateStream(currently_writing_stream_id_);
- if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
- // If the stream can't write all bytes it'll re-add itself to the blocked
- // list.
- stream->OnCanWrite();
- }
- currently_writing_stream_id_ = 0;
- }
-}
-
-bool QuicSession::WillingAndAbleToWrite() const {
- // If the crypto or headers streams are blocked, we want to schedule a write -
- // they don't get blocked by connection level flow control. Otherwise only
- // schedule a write if we are not flow control blocked at the connection
- // level.
- return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
- (!flow_controller_.IsBlocked() &&
- write_blocked_streams_.HasWriteBlockedDataStreams());
-}
-
-bool QuicSession::HasPendingHandshake() const {
- return write_blocked_streams_.crypto_stream_blocked();
-}
-
-bool QuicSession::HasOpenDynamicStreams() const {
- return (dynamic_stream_map_.size() - draining_streams_.size() +
- locally_closed_streams_highest_offset_.size()) > 0;
-}
-
-void QuicSession::ProcessUdpPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicReceivedPacket& packet) {
- connection_->ProcessUdpPacket(self_address, peer_address, packet);
-}
-
-QuicConsumedData QuicSession::WritevData(
- ReliableQuicStream* stream,
- QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) {
- // This check is an attempt to deal with potential memory corruption
- // in which |id| ends up set to 1 (the crypto stream id). If this happen
- // it might end up resulting in unencrypted stream data being sent.
- // While this is impossible to avoid given sufficient corruption, this
- // seems like a reasonable mitigation.
- if (id == kCryptoStreamId && stream != GetCryptoStream()) {
- QUIC_BUG << "Stream id mismatch";
- connection_->CloseConnection(
- QUIC_INTERNAL_ERROR,
- "Non-crypto stream attempted to write data as crypto stream.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return QuicConsumedData(0, false);
- }
- if (!IsEncryptionEstablished() && id != kCryptoStreamId) {
- // Do not let streams write without encryption. The calling stream will end
- // up write blocked until OnCanWrite is next called.
- return QuicConsumedData(0, false);
- }
- QuicConsumedData data =
- connection_->SendStreamData(id, iov, offset, fin, ack_notifier_delegate);
- write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
- return data;
-}
-
-void QuicSession::SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written) {
- if (ContainsKey(static_stream_map_, id)) {
- QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
- return;
- }
-
- if (connection()->connected()) {
- // Only send a RST_STREAM frame if still connected.
- connection_->SendRstStream(id, error, bytes_written);
- }
- CloseStreamInner(id, true);
-}
-
-void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
- if (goaway_sent()) {
- return;
- }
-
- connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
-}
-
-void QuicSession::CloseStream(QuicStreamId stream_id) {
- CloseStreamInner(stream_id, false);
-}
-
-void QuicSession::InsertLocallyClosedStreamsHighestOffset(
- const QuicStreamId id,
- QuicStreamOffset offset) {
- locally_closed_streams_highest_offset_[id] = offset;
- if (IsIncomingStream(id)) {
- ++num_locally_closed_incoming_streams_highest_offset_;
- }
-}
-
-void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
- DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
-
- StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
- if (it == dynamic_stream_map_.end()) {
- // When CloseStreamInner has been called recursively (via
- // ReliableQuicStream::OnClose), the stream will already have been deleted
- // from stream_map_, so return immediately.
- DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
- return;
- }
- ReliableQuicStream* stream = it->second;
-
- // Tell the stream that a RST has been sent.
- if (locally_reset) {
- stream->set_rst_sent(true);
- }
-
- closed_streams_.push_back(it->second);
-
- // If we haven't received a FIN or RST for this stream, we need to keep track
- // of the how many bytes the stream's flow controller believes it has
- // received, for accurate connection level flow control accounting.
- if (!stream->HasFinalReceivedByteOffset()) {
- InsertLocallyClosedStreamsHighestOffset(
- stream_id, stream->flow_controller()->highest_received_byte_offset());
- }
-
- dynamic_stream_map_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_dynamic_incoming_streams_;
- }
-
- if (draining_streams_.find(stream_id) != draining_streams_.end() &&
- IsIncomingStream(stream_id)) {
- --num_draining_incoming_streams_;
- }
- draining_streams_.erase(stream_id);
-
- stream->OnClose();
- // Decrease the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(dynamic_stream_map_.size());
-}
-
-void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
- QuicStreamId stream_id,
- QuicStreamOffset final_byte_offset) {
- map<QuicStreamId, QuicStreamOffset>::iterator it =
- locally_closed_streams_highest_offset_.find(stream_id);
- if (it == locally_closed_streams_highest_offset_.end()) {
- return;
- }
-
- DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset
- << " for stream " << stream_id;
- QuicByteCount offset_diff = final_byte_offset - it->second;
- if (flow_controller_.UpdateHighestReceivedOffset(
- flow_controller_.highest_received_byte_offset() + offset_diff)) {
- // If the final offset violates flow control, close the connection now.
- if (flow_controller_.FlowControlViolation()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
- "Connection level flow control violation",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- }
-
- flow_controller_.AddBytesConsumed(offset_diff);
- locally_closed_streams_highest_offset_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_locally_closed_incoming_streams_highest_offset_;
- }
-}
-
-bool QuicSession::IsEncryptionEstablished() {
- return GetCryptoStream()->encryption_established();
-}
-
-bool QuicSession::IsCryptoHandshakeConfirmed() {
- return GetCryptoStream()->handshake_confirmed();
-}
-
-void QuicSession::OnConfigNegotiated() {
- connection_->SetFromConfig(config_);
-
- const QuicVersion version = connection()->version();
- uint32_t max_streams = 0;
- if (version > QUIC_VERSION_34 &&
- config_.HasReceivedMaxIncomingDynamicStreams()) {
- max_streams = config_.ReceivedMaxIncomingDynamicStreams();
- } else {
- max_streams = config_.MaxStreamsPerConnection();
- }
- set_max_open_outgoing_streams(max_streams);
- if (!FLAGS_quic_enable_autotune_by_default &&
- perspective() == Perspective::IS_SERVER) {
- if (config_.HasReceivedConnectionOptions()) {
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kAFCW)) {
- // The following variations change the initial receive flow control
- // window sizes.
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW5)) {
- AdjustInitialFlowControlWindows(32 * 1024);
- }
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
- AdjustInitialFlowControlWindows(64 * 1024);
- }
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
- AdjustInitialFlowControlWindows(128 * 1024);
- }
- EnableAutoTuneReceiveWindow();
- }
- }
- }
-
- if (version <= QUIC_VERSION_34) {
- // A small number of additional incoming streams beyond the limit should be
- // allowed. This helps avoid early connection termination when FIN/RSTs for
- // old streams are lost or arrive out of order.
- // Use a minimum number of additional streams, or a percentage increase,
- // whichever is larger.
- uint32_t max_incoming_streams =
- max(max_streams + kMaxStreamsMinimumIncrement,
- static_cast<uint32_t>(max_streams * kMaxStreamsMultiplier));
- set_max_open_incoming_streams(max_incoming_streams);
- } else {
- uint32_t max_incoming_streams_to_send =
- config_.GetMaxIncomingDynamicStreamsToSend();
- uint32_t max_incoming_streams =
- max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
- static_cast<uint32_t>(max_incoming_streams_to_send *
- kMaxStreamsMultiplier));
- set_max_open_incoming_streams(max_incoming_streams);
- }
-
- if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
- // Streams which were created before the SHLO was received (0-RTT
- // requests) are now informed of the peer's initial flow control window.
- OnNewStreamFlowControlWindow(
- config_.ReceivedInitialStreamFlowControlWindowBytes());
- }
- if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
- OnNewSessionFlowControlWindow(
- config_.ReceivedInitialSessionFlowControlWindowBytes());
- }
-}
-
-// TODO(ckrasic): remove the following two methods when deprecating
-// FLAGS_quic_enable_autotune_by_default.
-void QuicSession::EnableAutoTuneReceiveWindow() {
- DVLOG(1) << ENDPOINT << "Enable auto tune receive windows";
- flow_controller_.set_auto_tune_receive_window(true);
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->flow_controller()->set_auto_tune_receive_window(true);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->flow_controller()->set_auto_tune_receive_window(true);
- }
-}
-
-void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
- const float session_window_multiplier =
- config_.GetInitialStreamFlowControlWindowToSend()
- ? static_cast<float>(
- config_.GetInitialSessionFlowControlWindowToSend()) /
- config_.GetInitialStreamFlowControlWindowToSend()
- : 1.0;
- DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
- config_.SetInitialStreamFlowControlWindowToSend(stream_window);
- // Reduce the session window as well, motivation is reducing resource waste
- // and denial of service vulnerability, as with the stream window. Session
- // size is set according to the ratio between session and stream window size
- // previous to auto-tuning. Note that the ratio may change dynamically, since
- // auto-tuning acts independently for each flow controller.
- size_t session_window = session_window_multiplier * stream_window;
- DVLOG(1) << ENDPOINT << "Set session receive window to " << session_window;
- config_.SetInitialSessionFlowControlWindowToSend(session_window);
- flow_controller_.UpdateReceiveWindowSize(session_window);
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
- }
-}
-
-void QuicSession::HandleFrameOnNonexistentOutgoingStream(
- QuicStreamId stream_id) {
- DCHECK(!IsClosedStream(stream_id));
- // Received a frame for a locally-created stream that is not currently
- // active. This is an error.
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void QuicSession::HandleRstOnValidNonexistentStream(
- const QuicRstStreamFrame& frame) {
- // If the stream is neither originally in active streams nor created in
- // GetOrCreateDynamicStream(), it could be a closed stream in which case its
- // final received byte offset need to be updated.
- if (IsClosedStream(frame.stream_id)) {
- // The RST frame contains the final byte offset for the stream: we can now
- // update the connection level flow controller if needed.
- UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id,
- frame.byte_offset);
- }
-}
-
-void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
- if (new_window < kMinimumFlowControlSendWindow) {
- LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
- << new_window
- << ", below default: " << kMinimumFlowControlSendWindow;
- if (connection_->connected()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- return;
- }
-
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->UpdateSendWindowOffset(new_window);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->UpdateSendWindowOffset(new_window);
- }
-}
-
-void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
- if (new_window < kMinimumFlowControlSendWindow) {
- LOG(ERROR) << "Peer sent us an invalid session flow control send window: "
- << new_window
- << ", below default: " << kMinimumFlowControlSendWindow;
- if (connection_->connected()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- return;
- }
-
- flow_controller_.UpdateSendWindowOffset(new_window);
-}
-
-void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
- switch (event) {
- // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
- // to QuicSession since it is the glue.
- case ENCRYPTION_FIRST_ESTABLISHED:
- // Given any streams blocked by encryption a chance to write.
- OnCanWrite();
- break;
-
- case ENCRYPTION_REESTABLISHED:
- // Retransmit originally packets that were sent, since they can't be
- // decrypted by the peer.
- connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
- // Given any streams blocked by encryption a chance to write.
- OnCanWrite();
- break;
-
- case HANDSHAKE_CONFIRMED:
- QUIC_BUG_IF(!config_.negotiated())
- << ENDPOINT << "Handshake confirmed without parameter negotiation.";
- // Discard originally encrypted packets, since they can't be decrypted by
- // the peer.
- connection_->NeuterUnencryptedPackets();
- break;
-
- default:
- LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
- }
-}
-
-void QuicSession::OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& /*message*/) {}
-
-void QuicSession::OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& /*message*/) {}
-
-QuicConfig* QuicSession::config() {
- return &config_;
-}
-
-void QuicSession::ActivateStream(ReliableQuicStream* stream) {
- DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
- << ". activating " << stream->id();
- DCHECK(!ContainsKey(dynamic_stream_map_, stream->id()));
- DCHECK(!ContainsKey(static_stream_map_, stream->id()));
- dynamic_stream_map_[stream->id()] = stream;
- if (IsIncomingStream(stream->id())) {
- ++num_dynamic_incoming_streams_;
- }
- // Increase the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(dynamic_stream_map_.size());
-}
-
-QuicStreamId QuicSession::GetNextOutgoingStreamId() {
- QuicStreamId id = next_outgoing_stream_id_;
- next_outgoing_stream_id_ += 2;
- return id;
-}
-
-ReliableQuicStream* QuicSession::GetOrCreateStream(
- const QuicStreamId stream_id) {
- StreamMap::iterator it = static_stream_map_.find(stream_id);
- if (it != static_stream_map_.end()) {
- return it->second;
- }
- return GetOrCreateDynamicStream(stream_id);
-}
-
-void QuicSession::StreamDraining(QuicStreamId stream_id) {
- DCHECK(ContainsKey(dynamic_stream_map_, stream_id));
- if (!ContainsKey(draining_streams_, stream_id)) {
- draining_streams_.insert(stream_id);
- if (IsIncomingStream(stream_id)) {
- ++num_draining_incoming_streams_;
- }
- }
-}
-
-bool QuicSession::MaybeIncreaseLargestPeerStreamId(
- const QuicStreamId stream_id) {
- if (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;
- size_t new_num_available_streams =
- GetNumAvailableStreams() + additional_available_streams;
- if (new_num_available_streams > MaxAvailableStreams()) {
- DVLOG(1) << "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() << ".";
- string details = IntToString(new_num_available_streams) + " above " +
- IntToString(MaxAvailableStreams());
- connection()->CloseConnection(
- QUIC_TOO_MANY_AVAILABLE_STREAMS, details.c_str(),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- for (QuicStreamId id = largest_peer_created_stream_id_ + 2; id < stream_id;
- id += 2) {
- available_streams_.insert(id);
- }
- largest_peer_created_stream_id_ = stream_id;
-
- return true;
-}
-
-bool QuicSession::ShouldYield(QuicStreamId stream_id) {
- if (stream_id == currently_writing_stream_id_) {
- return false;
- }
- return write_blocked_streams()->ShouldYield(stream_id);
-}
-
-ReliableQuicStream* QuicSession::GetOrCreateDynamicStream(
- const QuicStreamId stream_id) {
- DCHECK(!ContainsKey(static_stream_map_, stream_id))
- << "Attempt to call GetOrCreateDynamicStream for a static stream";
-
- StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
- if (it != dynamic_stream_map_.end()) {
- return it->second;
- }
-
- if (IsClosedStream(stream_id)) {
- return nullptr;
- }
-
- if (!IsIncomingStream(stream_id)) {
- HandleFrameOnNonexistentOutgoingStream(stream_id);
- return nullptr;
- }
-
- available_streams_.erase(stream_id);
-
- if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
- return nullptr;
- }
- // Check if the new number of open streams would cause the number of
- // open streams to exceed the limit.
- if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
- if (connection()->version() <= QUIC_VERSION_27) {
- connection()->CloseConnection(
- QUIC_TOO_MANY_OPEN_STREAMS, "Old style stream rejection",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- } else {
- // Refuse to open the stream.
- SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
- }
- return nullptr;
- }
-
- return CreateIncomingDynamicStream(stream_id);
-}
-
-void QuicSession::set_max_open_incoming_streams(
- size_t max_open_incoming_streams) {
- DVLOG(1) << "Setting max_open_incoming_streams_ to "
- << max_open_incoming_streams;
- max_open_incoming_streams_ = max_open_incoming_streams;
- DVLOG(1) << "MaxAvailableStreams() became " << MaxAvailableStreams();
-}
-
-void QuicSession::set_max_open_outgoing_streams(
- size_t max_open_outgoing_streams) {
- DVLOG(1) << "Setting max_open_outgoing_streams_ to "
- << max_open_outgoing_streams;
- max_open_outgoing_streams_ = max_open_outgoing_streams;
-}
-
-bool QuicSession::goaway_sent() const {
- return connection_->goaway_sent();
-}
-
-bool QuicSession::goaway_received() const {
- return connection_->goaway_received();
-}
-
-bool QuicSession::IsClosedStream(QuicStreamId id) {
- DCHECK_NE(0u, id);
- if (IsOpenStream(id)) {
- // Stream is active
- return false;
- }
- if (!IsIncomingStream(id)) {
- // Locally created streams are strictly in-order. If the id is in the
- // range of created streams and it's not active, it must have been closed.
- return id < next_outgoing_stream_id_;
- }
- // For peer created streams, we also need to consider available streams.
- return id <= largest_peer_created_stream_id_ &&
- !ContainsKey(available_streams_, id);
-}
-
-bool QuicSession::IsOpenStream(QuicStreamId id) {
- DCHECK_NE(0u, id);
- if (ContainsKey(static_stream_map_, id) ||
- ContainsKey(dynamic_stream_map_, id)) {
- // Stream is active
- return true;
- }
- return false;
-}
-
-size_t QuicSession::GetNumOpenIncomingStreams() const {
- return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
-size_t QuicSession::GetNumOpenOutgoingStreams() const {
- return GetNumDynamicOutgoingStreams() - GetNumDrainingOutgoingStreams() +
- GetNumLocallyClosedOutgoingStreamsHighestOffset();
-}
-
-size_t QuicSession::GetNumActiveStreams() const {
- return dynamic_stream_map_.size() - draining_streams_.size();
-}
-
-size_t QuicSession::GetNumAvailableStreams() const {
- return available_streams_.size();
-}
-
-void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
- QUIC_BUG_IF(GetOrCreateStream(id) == nullptr) << "Marking unknown stream "
- << id << " blocked.";
-
- write_blocked_streams_.AddStream(id);
-}
-
-bool QuicSession::HasDataToWrite() const {
- return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
- write_blocked_streams_.HasWriteBlockedDataStreams() ||
- connection_->HasQueuedData();
-}
-
-void QuicSession::PostProcessAfterData() {
- STLDeleteElements(&closed_streams_);
- closed_streams_.clear();
-}
-
-size_t QuicSession::GetNumDynamicOutgoingStreams() const {
- return dynamic_stream_map_.size() - num_dynamic_incoming_streams_;
-}
-
-size_t QuicSession::GetNumDrainingOutgoingStreams() const {
- return draining_streams_.size() - num_draining_incoming_streams_;
-}
-
-size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
- return locally_closed_streams_highest_offset_.size() -
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
-bool QuicSession::IsConnectionFlowControlBlocked() const {
- return flow_controller_.IsBlocked();
-}
-
-bool QuicSession::IsStreamFlowControlBlocked() {
- for (auto const& kv : static_stream_map_) {
- if (kv.second->flow_controller()->IsBlocked()) {
- return true;
- }
- }
- for (auto const& kv : dynamic_stream_map_) {
- if (kv.second->flow_controller()->IsBlocked()) {
- return true;
- }
- }
- return false;
-}
-
-size_t QuicSession::MaxAvailableStreams() const {
- return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
-}
-
-bool QuicSession::IsIncomingStream(QuicStreamId id) const {
- return id % 2 != next_outgoing_stream_id_ % 2;
-}
-
-} // namespace net