1 // Copyright 2023 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
5 #include "quiche/quic/core/quic_generic_session.h"
6
7 #include <cstdint>
8 #include <memory>
9 #include <string>
10 #include <utility>
11
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/http/web_transport_stream_adapter.h"
14 #include "quiche/quic/core/quic_crypto_client_stream.h"
15 #include "quiche/quic/core/quic_session.h"
16 #include "quiche/quic/core/quic_types.h"
17 #include "quiche/quic/core/quic_utils.h"
18 #include "quiche/quic/core/quic_versions.h"
19 #include "quiche/quic/platform/api/quic_bug_tracker.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 #include "quiche/common/simple_buffer_allocator.h"
22 #include "quiche/web_transport/web_transport.h"
23
24 namespace quic {
25
26 namespace {
27
28 class NoOpProofHandler : public QuicCryptoClientStream::ProofHandler {
29 public:
OnProofValid(const QuicCryptoClientConfig::CachedState &)30 void OnProofValid(const QuicCryptoClientConfig::CachedState&) override {}
OnProofVerifyDetailsAvailable(const ProofVerifyDetails &)31 void OnProofVerifyDetailsAvailable(const ProofVerifyDetails&) override {}
32 };
33
34 class NoOpServerCryptoHelper : public QuicCryptoServerStreamBase::Helper {
35 public:
CanAcceptClientHello(const CryptoHandshakeMessage &,const QuicSocketAddress &,const QuicSocketAddress &,const QuicSocketAddress &,std::string *) const36 bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/,
37 const QuicSocketAddress& /*client_address*/,
38 const QuicSocketAddress& /*peer_address*/,
39 const QuicSocketAddress& /*self_address*/,
40 std::string* /*error_details*/) const override {
41 return true;
42 }
43 };
44
45 } // namespace
46
GetQuicVersionsForGenericSession()47 ParsedQuicVersionVector GetQuicVersionsForGenericSession() {
48 return {ParsedQuicVersion::RFCv1()};
49 }
50
51 // QuicGenericStream is a stream that provides a general-purpose implementation
52 // of a webtransport::Stream interface.
53 class QUICHE_EXPORT QuicGenericStream : public QuicStream {
54 public:
QuicGenericStream(QuicStreamId id,QuicSession * session)55 QuicGenericStream(QuicStreamId id, QuicSession* session)
56 : QuicStream(id, session, /*is_static=*/false,
57 QuicUtils::GetStreamType(
58 id, session->connection()->perspective(),
59 session->IsIncomingStream(id), session->version())),
60 adapter_(session, this, sequencer()) {}
61
adapter()62 WebTransportStreamAdapter* adapter() { return &adapter_; }
63
64 // QuicSession method implementations.
OnDataAvailable()65 void OnDataAvailable() override { adapter_.OnDataAvailable(); }
OnCanWriteNewData()66 void OnCanWriteNewData() override { adapter_.OnCanWriteNewData(); }
67
68 private:
69 WebTransportStreamAdapter adapter_;
70 };
71
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)72 QuicGenericSessionBase::QuicGenericSessionBase(
73 QuicConnection* connection, bool owns_connection, Visitor* owner,
74 const QuicConfig& config, std::string alpn, WebTransportVisitor* visitor,
75 bool owns_visitor,
76 std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer)
77 : QuicSession(connection, owner, config, GetQuicVersionsForGenericSession(),
78 /*num_expected_unidirectional_static_streams=*/0,
79 std::move(datagram_observer)),
80 alpn_(std::move(alpn)),
81 visitor_(visitor),
82 owns_connection_(owns_connection),
83 owns_visitor_(owns_visitor) {}
84
~QuicGenericSessionBase()85 QuicGenericSessionBase::~QuicGenericSessionBase() {
86 if (owns_connection_) {
87 DeleteConnection();
88 }
89 if (owns_visitor_) {
90 delete visitor_;
91 visitor_ = nullptr;
92 }
93 }
94
CreateIncomingStream(QuicStreamId id)95 QuicStream* QuicGenericSessionBase::CreateIncomingStream(QuicStreamId id) {
96 QUIC_DVLOG(1) << "Creating incoming QuicGenricStream " << id;
97 QuicGenericStream* stream = CreateStream(id);
98 if (stream->type() == BIDIRECTIONAL) {
99 incoming_bidirectional_streams_.push_back(id);
100 visitor_->OnIncomingBidirectionalStreamAvailable();
101 } else {
102 incoming_unidirectional_streams_.push_back(id);
103 visitor_->OnIncomingUnidirectionalStreamAvailable();
104 }
105 return stream;
106 }
107
OnTlsHandshakeComplete()108 void QuicGenericSessionBase::OnTlsHandshakeComplete() {
109 QuicSession::OnTlsHandshakeComplete();
110 visitor_->OnSessionReady();
111 }
112
113 webtransport::Stream*
AcceptIncomingBidirectionalStream()114 QuicGenericSessionBase::AcceptIncomingBidirectionalStream() {
115 while (!incoming_bidirectional_streams_.empty()) {
116 webtransport::Stream* stream =
117 GetStreamById(incoming_bidirectional_streams_.front());
118 incoming_bidirectional_streams_.pop_front();
119 if (stream != nullptr) {
120 return stream;
121 }
122 }
123 return nullptr;
124 }
125
126 webtransport::Stream*
AcceptIncomingUnidirectionalStream()127 QuicGenericSessionBase::AcceptIncomingUnidirectionalStream() {
128 while (!incoming_unidirectional_streams_.empty()) {
129 webtransport::Stream* stream =
130 GetStreamById(incoming_unidirectional_streams_.front());
131 incoming_unidirectional_streams_.pop_front();
132 if (stream != nullptr) {
133 return stream;
134 }
135 }
136 return nullptr;
137 }
138
139 webtransport::Stream*
OpenOutgoingBidirectionalStream()140 QuicGenericSessionBase::OpenOutgoingBidirectionalStream() {
141 if (!CanOpenNextOutgoingBidirectionalStream()) {
142 QUIC_BUG(QuicGenericSessionBase_flow_control_violation_bidi)
143 << "Attempted to open a stream in violation of flow control";
144 return nullptr;
145 }
146 return CreateStream(GetNextOutgoingBidirectionalStreamId())->adapter();
147 }
148
149 webtransport::Stream*
OpenOutgoingUnidirectionalStream()150 QuicGenericSessionBase::OpenOutgoingUnidirectionalStream() {
151 if (!CanOpenNextOutgoingUnidirectionalStream()) {
152 QUIC_BUG(QuicGenericSessionBase_flow_control_violation_unidi)
153 << "Attempted to open a stream in violation of flow control";
154 return nullptr;
155 }
156 return CreateStream(GetNextOutgoingUnidirectionalStreamId())->adapter();
157 }
158
CreateStream(QuicStreamId id)159 QuicGenericStream* QuicGenericSessionBase::CreateStream(QuicStreamId id) {
160 auto stream = std::make_unique<QuicGenericStream>(id, this);
161 QuicGenericStream* stream_ptr = stream.get();
162 ActivateStream(std::move(stream));
163 return stream_ptr;
164 }
165
OnMessageReceived(absl::string_view message)166 void QuicGenericSessionBase::OnMessageReceived(absl::string_view message) {
167 visitor_->OnDatagramReceived(message);
168 }
169
OnCanCreateNewOutgoingStream(bool unidirectional)170 void QuicGenericSessionBase::OnCanCreateNewOutgoingStream(bool unidirectional) {
171 if (unidirectional) {
172 visitor_->OnCanCreateNewOutgoingUnidirectionalStream();
173 } else {
174 visitor_->OnCanCreateNewOutgoingBidirectionalStream();
175 }
176 }
177
GetStreamById(webtransport::StreamId id)178 webtransport::Stream* QuicGenericSessionBase::GetStreamById(
179 webtransport::StreamId id) {
180 QuicStream* stream = GetActiveStream(id);
181 if (stream == nullptr) {
182 return nullptr;
183 }
184 return static_cast<QuicGenericStream*>(stream)->adapter();
185 }
186
SendOrQueueDatagram(absl::string_view datagram)187 webtransport::DatagramStatus QuicGenericSessionBase::SendOrQueueDatagram(
188 absl::string_view datagram) {
189 quiche::QuicheBuffer buffer = quiche::QuicheBuffer::Copy(
190 quiche::SimpleBufferAllocator::Get(), datagram);
191 return MessageStatusToWebTransportStatus(
192 datagram_queue()->SendOrQueueDatagram(
193 quiche::QuicheMemSlice(std::move(buffer))));
194 }
195
OnConnectionClosed(const QuicConnectionCloseFrame & frame,ConnectionCloseSource source)196 void QuicGenericSessionBase::OnConnectionClosed(
197 const QuicConnectionCloseFrame& frame, ConnectionCloseSource source) {
198 QuicSession::OnConnectionClosed(frame, source);
199 visitor_->OnSessionClosed(static_cast<webtransport::SessionErrorCode>(
200 frame.transport_close_frame_type),
201 frame.error_details);
202 }
203
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)204 QuicGenericClientSession::QuicGenericClientSession(
205 QuicConnection* connection, bool owns_connection, Visitor* owner,
206 const QuicConfig& config, std::string host, uint16_t port, std::string alpn,
207 webtransport::SessionVisitor* visitor, bool owns_visitor,
208 std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,
209 QuicCryptoClientConfig* crypto_config)
210 : QuicGenericSessionBase(connection, owns_connection, owner, config,
211 std::move(alpn), visitor, owns_visitor,
212 std::move(datagram_observer)) {
213 static NoOpProofHandler* handler = new NoOpProofHandler();
214 crypto_stream_ = std::make_unique<QuicCryptoClientStream>(
215 QuicServerId(std::move(host), port), this,
216 crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config,
217 /*proof_handler=*/handler, /*has_application_state=*/false);
218 }
219
QuicGenericClientSession(QuicConnection * connection,bool owns_connection,Visitor * owner,const QuicConfig & config,std::string host,uint16_t port,std::string alpn,CreateWebTransportSessionVisitorCallback create_visitor_callback,std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,QuicCryptoClientConfig * crypto_config)220 QuicGenericClientSession::QuicGenericClientSession(
221 QuicConnection* connection, bool owns_connection, Visitor* owner,
222 const QuicConfig& config, std::string host, uint16_t port, std::string alpn,
223 CreateWebTransportSessionVisitorCallback create_visitor_callback,
224 std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,
225 QuicCryptoClientConfig* crypto_config)
226 : QuicGenericClientSession(
227 connection, owns_connection, owner, config, std::move(host), port,
228 std::move(alpn), std::move(create_visitor_callback)(*this).release(),
229 /*owns_visitor=*/true, std::move(datagram_observer), crypto_config) {}
230
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,const QuicCryptoServerConfig * crypto_config,QuicCompressedCertsCache * compressed_certs_cache)231 QuicGenericServerSession::QuicGenericServerSession(
232 QuicConnection* connection, bool owns_connection, Visitor* owner,
233 const QuicConfig& config, std::string alpn,
234 webtransport::SessionVisitor* visitor, bool owns_visitor,
235 std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,
236 const QuicCryptoServerConfig* crypto_config,
237 QuicCompressedCertsCache* compressed_certs_cache)
238 : QuicGenericSessionBase(connection, owns_connection, owner, config,
239 std::move(alpn), visitor, owns_visitor,
240 std::move(datagram_observer)) {
241 static NoOpServerCryptoHelper* helper = new NoOpServerCryptoHelper();
242 crypto_stream_ = CreateCryptoServerStream(
243 crypto_config, compressed_certs_cache, this, helper);
244 }
245
QuicGenericServerSession(QuicConnection * connection,bool owns_connection,Visitor * owner,const QuicConfig & config,std::string alpn,CreateWebTransportSessionVisitorCallback create_visitor_callback,std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,const QuicCryptoServerConfig * crypto_config,QuicCompressedCertsCache * compressed_certs_cache)246 QuicGenericServerSession::QuicGenericServerSession(
247 QuicConnection* connection, bool owns_connection, Visitor* owner,
248 const QuicConfig& config, std::string alpn,
249 CreateWebTransportSessionVisitorCallback create_visitor_callback,
250 std::unique_ptr<QuicDatagramQueue::Observer> datagram_observer,
251 const QuicCryptoServerConfig* crypto_config,
252 QuicCompressedCertsCache* compressed_certs_cache)
253 : QuicGenericServerSession(
254 connection, owns_connection, owner, config, std::move(alpn),
255 std::move(create_visitor_callback)(*this).release(),
256 /*owns_visitor=*/true, std::move(datagram_observer), crypto_config,
257 compressed_certs_cache) {}
258
259 } // namespace quic
260