| // Copyright 2023 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/quic_generic_session.h" |
| |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "absl/strings/string_view.h" |
| #include "quiche/quic/core/http/web_transport_stream_adapter.h" |
| #include "quiche/quic/core/quic_crypto_client_stream.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" |
| #include "quiche/quic/platform/api/quic_bug_tracker.h" |
| #include "quiche/quic/platform/api/quic_logging.h" |
| #include "quiche/common/simple_buffer_allocator.h" |
| #include "quiche/web_transport/web_transport.h" |
| |
| namespace quic { |
| |
| namespace { |
| |
| class NoOpProofHandler : public QuicCryptoClientStream::ProofHandler { |
| public: |
| void OnProofValid(const QuicCryptoClientConfig::CachedState&) override {} |
| void OnProofVerifyDetailsAvailable(const ProofVerifyDetails&) override {} |
| }; |
| |
| class NoOpServerCryptoHelper : public QuicCryptoServerStreamBase::Helper { |
| public: |
| bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/, |
| const QuicSocketAddress& /*client_address*/, |
| const QuicSocketAddress& /*peer_address*/, |
| const QuicSocketAddress& /*self_address*/, |
| std::string* /*error_details*/) const override { |
| return true; |
| } |
| }; |
| |
| } // namespace |
| |
| ParsedQuicVersionVector GetQuicVersionsForGenericSession() { |
| return {ParsedQuicVersion::RFCv1()}; |
| } |
| |
| // QuicGenericStream is a stream that provides a general-purpose implementation |
| // of a webtransport::Stream interface. |
| class QUIC_EXPORT_PRIVATE QuicGenericStream : public QuicStream { |
| public: |
| QuicGenericStream(QuicStreamId id, QuicSession* session) |
| : QuicStream(id, session, /*is_static=*/false, |
| QuicUtils::GetStreamType( |
| id, session->connection()->perspective(), |
| session->IsIncomingStream(id), session->version())), |
| adapter_(session, this, sequencer()) {} |
| |
| WebTransportStreamAdapter* adapter() { return &adapter_; } |
| |
| // QuicSession method implementations. |
| void OnDataAvailable() override { adapter_.OnDataAvailable(); } |
| void OnCanWriteNewData() override { adapter_.OnCanWriteNewData(); } |
| |
| private: |
| WebTransportStreamAdapter adapter_; |
| }; |
| |
| QuicGenericSessionBase::QuicGenericSessionBase( |
| QuicConnection* connection, bool owns_connection, Visitor* owner, |
| const QuicConfig& config, std::string alpn, WebTransportVisitor* visitor, |
| bool owns_visitor, |
| std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer) |
| : QuicSession(connection, owner, config, GetQuicVersionsForGenericSession(), |
| /*num_expected_unidirectional_static_streams=*/0, |
| std::move(datagram_observer)), |
| alpn_(std::move(alpn)), |
| visitor_(visitor), |
| owns_connection_(owns_connection), |
| owns_visitor_(owns_visitor) {} |
| |
| QuicGenericSessionBase::~QuicGenericSessionBase() { |
| if (owns_connection_) { |
| DeleteConnection(); |
| } |
| if (owns_visitor_) { |
| delete visitor_; |
| visitor_ = nullptr; |
| } |
| } |
| |
| QuicStream* QuicGenericSessionBase::CreateIncomingStream(QuicStreamId id) { |
| QUIC_DVLOG(1) << "Creating incoming QuicGenricStream " << id; |
| QuicGenericStream* stream = CreateStream(id); |
| if (stream->type() == BIDIRECTIONAL) { |
| incoming_bidirectional_streams_.push_back(id); |
| visitor_->OnIncomingBidirectionalStreamAvailable(); |
| } else { |
| incoming_unidirectional_streams_.push_back(id); |
| visitor_->OnIncomingUnidirectionalStreamAvailable(); |
| } |
| return stream; |
| } |
| |
| void QuicGenericSessionBase::OnTlsHandshakeComplete() { |
| QuicSession::OnTlsHandshakeComplete(); |
| visitor_->OnSessionReady(); |
| } |
| |
| webtransport::Stream* |
| QuicGenericSessionBase::AcceptIncomingBidirectionalStream() { |
| while (!incoming_bidirectional_streams_.empty()) { |
| webtransport::Stream* stream = |
| GetStreamById(incoming_bidirectional_streams_.front()); |
| incoming_bidirectional_streams_.pop_front(); |
| if (stream != nullptr) { |
| return stream; |
| } |
| } |
| return nullptr; |
| } |
| |
| webtransport::Stream* |
| QuicGenericSessionBase::AcceptIncomingUnidirectionalStream() { |
| while (!incoming_unidirectional_streams_.empty()) { |
| webtransport::Stream* stream = |
| GetStreamById(incoming_unidirectional_streams_.front()); |
| incoming_unidirectional_streams_.pop_front(); |
| if (stream != nullptr) { |
| return stream; |
| } |
| } |
| return nullptr; |
| } |
| |
| webtransport::Stream* |
| QuicGenericSessionBase::OpenOutgoingBidirectionalStream() { |
| if (!CanOpenNextOutgoingBidirectionalStream()) { |
| QUIC_BUG(QuicGenericSessionBase_flow_control_violation_bidi) |
| << "Attempted to open a stream in violation of flow control"; |
| return nullptr; |
| } |
| return CreateStream(GetNextOutgoingBidirectionalStreamId())->adapter(); |
| } |
| |
| webtransport::Stream* |
| QuicGenericSessionBase::OpenOutgoingUnidirectionalStream() { |
| if (!CanOpenNextOutgoingUnidirectionalStream()) { |
| QUIC_BUG(QuicGenericSessionBase_flow_control_violation_unidi) |
| << "Attempted to open a stream in violation of flow control"; |
| return nullptr; |
| } |
| return CreateStream(GetNextOutgoingUnidirectionalStreamId())->adapter(); |
| } |
| |
| QuicGenericStream* QuicGenericSessionBase::CreateStream(QuicStreamId id) { |
| auto stream = std::make_unique<QuicGenericStream>(id, this); |
| QuicGenericStream* stream_ptr = stream.get(); |
| ActivateStream(std::move(stream)); |
| return stream_ptr; |
| } |
| |
| void QuicGenericSessionBase::OnMessageReceived(absl::string_view message) { |
| visitor_->OnDatagramReceived(message); |
| } |
| |
| void QuicGenericSessionBase::OnCanCreateNewOutgoingStream(bool unidirectional) { |
| if (unidirectional) { |
| visitor_->OnCanCreateNewOutgoingUnidirectionalStream(); |
| } else { |
| visitor_->OnCanCreateNewOutgoingBidirectionalStream(); |
| } |
| } |
| |
| webtransport::Stream* QuicGenericSessionBase::GetStreamById( |
| webtransport::StreamId id) { |
| QuicStream* stream = GetActiveStream(id); |
| if (stream == nullptr) { |
| return nullptr; |
| } |
| return static_cast<QuicGenericStream*>(stream)->adapter(); |
| } |
| |
| webtransport::DatagramStatus QuicGenericSessionBase::SendOrQueueDatagram( |
| absl::string_view datagram) { |
| quiche::QuicheBuffer buffer = quiche::QuicheBuffer::Copy( |
| quiche::SimpleBufferAllocator::Get(), datagram); |
| return MessageStatusToWebTransportStatus( |
| datagram_queue()->SendOrQueueDatagram( |
| quiche::QuicheMemSlice(std::move(buffer)))); |
| } |
| |
| QuicGenericClientSession::QuicGenericClientSession( |
| QuicConnection* connection, bool owns_connection, Visitor* owner, |
| const QuicConfig& config, std::string host, uint16_t port, std::string alpn, |
| webtransport::SessionVisitor* visitor, bool owns_visitor, |
| std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer, |
| QuicCryptoClientConfig* crypto_config) |
| : QuicGenericSessionBase(connection, owns_connection, owner, config, |
| std::move(alpn), visitor, owns_visitor, |
| std::move(datagram_observer)) { |
| static NoOpProofHandler* handler = new NoOpProofHandler(); |
| crypto_stream_ = std::make_unique<QuicCryptoClientStream>( |
| QuicServerId(std::move(host), port), this, |
| crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config, |
| /*proof_handler=*/handler, /*has_application_state=*/false); |
| } |
| |
| QuicGenericServerSession::QuicGenericServerSession( |
| QuicConnection* connection, bool owns_connection, Visitor* owner, |
| const QuicConfig& config, std::string alpn, |
| webtransport::SessionVisitor* visitor, bool owns_visitor, |
| std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer, |
| QuicCryptoServerConfig* crypto_config, |
| QuicCompressedCertsCache* compressed_certs_cache) |
| : QuicGenericSessionBase(connection, owns_connection, owner, config, |
| std::move(alpn), visitor, owns_visitor, |
| std::move(datagram_observer)) { |
| static NoOpServerCryptoHelper* helper = new NoOpServerCryptoHelper(); |
| crypto_stream_ = CreateCryptoServerStream( |
| crypto_config, compressed_certs_cache, this, helper); |
| } |
| |
| } // namespace quic |