| // Copyright (c) 2019 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/third_party/quiche/src/quic/qbone/qbone_session_base.h" |
| |
| #include <utility> |
| |
| #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" |
| #include "net/third_party/quiche/src/quic/core/quic_types.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h" |
| #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h" |
| |
| namespace quic { |
| |
| #define ENDPOINT \ |
| (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ") |
| |
| QboneSessionBase::QboneSessionBase( |
| QuicConnection* connection, |
| Visitor* owner, |
| const QuicConfig& config, |
| const ParsedQuicVersionVector& supported_versions, |
| QbonePacketWriter* writer) |
| : QuicSession(connection, |
| owner, |
| config, |
| supported_versions, |
| /*num_expected_unidirectional_static_streams = */ 0) { |
| set_writer(writer); |
| const uint32_t max_streams = |
| (std::numeric_limits<uint32_t>::max() / kMaxAvailableStreamsMultiplier) - |
| 1; |
| this->config()->SetMaxIncomingBidirectionalStreamsToSend(max_streams); |
| if (VersionHasIetfQuicFrames(transport_version())) { |
| ConfigureMaxIncomingDynamicStreamsToSend(max_streams); |
| } |
| } |
| |
| QboneSessionBase::~QboneSessionBase() { |
| // Clear out the streams before leaving this destructor to avoid calling |
| // QuicSession::UnregisterStreamPriority |
| stream_map().clear(); |
| closed_streams()->clear(); |
| } |
| |
| void QboneSessionBase::Initialize() { |
| crypto_stream_ = CreateCryptoStream(); |
| QuicSession::Initialize(); |
| } |
| |
| const QuicCryptoStream* QboneSessionBase::GetCryptoStream() const { |
| return crypto_stream_.get(); |
| } |
| |
| QuicCryptoStream* QboneSessionBase::GetMutableCryptoStream() { |
| return crypto_stream_.get(); |
| } |
| |
| QuicStream* QboneSessionBase::CreateOutgoingStream() { |
| return ActivateDataStream( |
| CreateDataStream(GetNextOutgoingUnidirectionalStreamId())); |
| } |
| |
| void QboneSessionBase::CloseStream(QuicStreamId stream_id) { |
| if (IsClosedStream(stream_id)) { |
| // When CloseStream has been called recursively (via |
| // QuicStream::OnClose), the stream is already closed so return. |
| return; |
| } |
| QuicSession::CloseStream(stream_id); |
| } |
| |
| void QboneSessionBase::OnStreamFrame(const QuicStreamFrame& frame) { |
| if (frame.offset == 0 && frame.fin && frame.data_length > 0) { |
| ++num_ephemeral_packets_; |
| ProcessPacketFromPeer( |
| QuicStringPiece(frame.data_buffer, frame.data_length)); |
| flow_controller()->AddBytesConsumed(frame.data_length); |
| return; |
| } |
| QuicSession::OnStreamFrame(frame); |
| } |
| |
| void QboneSessionBase::OnMessageReceived(QuicStringPiece message) { |
| ++num_message_packets_; |
| ProcessPacketFromPeer(message); |
| } |
| |
| QuicStream* QboneSessionBase::CreateIncomingStream(QuicStreamId id) { |
| return ActivateDataStream(CreateDataStream(id)); |
| } |
| |
| QuicStream* QboneSessionBase::CreateIncomingStream(PendingStream* /*pending*/) { |
| QUIC_NOTREACHED(); |
| return nullptr; |
| } |
| |
| bool QboneSessionBase::ShouldKeepConnectionAlive() const { |
| // Qbone connections stay alive until they're explicitly closed. |
| return true; |
| } |
| |
| std::unique_ptr<QuicStream> QboneSessionBase::CreateDataStream( |
| QuicStreamId id) { |
| if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) { |
| // Encryption not active so no stream created |
| return nullptr; |
| } |
| |
| if (IsIncomingStream(id)) { |
| ++num_streamed_packets_; |
| return std::make_unique<QboneReadOnlyStream>(id, this); |
| } |
| |
| return std::make_unique<QboneWriteOnlyStream>(id, this); |
| } |
| |
| QuicStream* QboneSessionBase::ActivateDataStream( |
| std::unique_ptr<QuicStream> stream) { |
| // Transfer ownership of the data stream to the session via ActivateStream(). |
| QuicStream* raw = stream.get(); |
| if (stream) { |
| // Make QuicSession take ownership of the stream. |
| ActivateStream(std::move(stream)); |
| } |
| return raw; |
| } |
| |
| void QboneSessionBase::SendPacketToPeer(QuicStringPiece packet) { |
| if (crypto_stream_ == nullptr) { |
| QUIC_BUG << "Attempting to send packet before encryption established"; |
| return; |
| } |
| |
| if (send_packets_as_messages_) { |
| QuicMemSlice slice(connection()->helper()->GetStreamSendBufferAllocator(), |
| packet.size()); |
| memcpy(const_cast<char*>(slice.data()), packet.data(), packet.size()); |
| if (SendMessage(QuicMemSliceSpan(&slice)).status == |
| MESSAGE_STATUS_SUCCESS) { |
| return; |
| } |
| // If SendMessage() fails for any reason, fall back to ephemeral streams. |
| num_fallback_to_stream_++; |
| } |
| |
| // Qbone streams are ephemeral. |
| QuicStream* stream = CreateOutgoingStream(); |
| if (!stream) { |
| QUIC_BUG << "Failed to create an outgoing QBONE stream."; |
| return; |
| } |
| |
| QboneWriteOnlyStream* qbone_stream = |
| static_cast<QboneWriteOnlyStream*>(stream); |
| qbone_stream->WritePacketToQuicStream(packet); |
| } |
| |
| uint64_t QboneSessionBase::GetNumEphemeralPackets() const { |
| return num_ephemeral_packets_; |
| } |
| |
| uint64_t QboneSessionBase::GetNumStreamedPackets() const { |
| return num_streamed_packets_; |
| } |
| |
| uint64_t QboneSessionBase::GetNumMessagePackets() const { |
| return num_message_packets_; |
| } |
| |
| uint64_t QboneSessionBase::GetNumFallbackToStream() const { |
| return num_fallback_to_stream_; |
| } |
| |
| void QboneSessionBase::set_writer(QbonePacketWriter* writer) { |
| writer_ = writer; |
| testing::testvalue::Adjust("quic_QbonePacketWriter", &writer_); |
| } |
| |
| } // namespace quic |