blob: c2719fbe40f2ff4eb7a536540a99dfa48b5d4bce [file] [log] [blame] [edit]
// Copyright 2025 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.
#ifndef QUICHE_QUIC_MASQUE_MASQUE_CONNECTION_POOL_H_
#define QUICHE_QUIC_MASQUE_MASQUE_CONNECTION_POOL_H_
#include <cstdint>
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "openssl/base.h"
#include "openssl/ssl.h"
#include "quiche/quic/core/crypto/proof_verifier.h"
#include "quiche/quic/core/io/quic_event_loop.h"
#include "quiche/quic/core/io/socket.h"
#include "quiche/quic/masque/masque_h2_connection.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/tools/quic_name_lookup.h"
#include "quiche/common/http/http_header_block.h"
#include "quiche/common/quiche_socket_address.h"
namespace quic {
class QUIC_NO_EXPORT MasqueConnectionPool : public MasqueH2Connection::Visitor {
public:
using RequestId = uint64_t;
struct Message {
quiche::HttpHeaderBlock headers;
std::string body;
};
// Default DNS resolver that uses the QuicNameLookup tool.
class QUIC_NO_EXPORT DnsResolver {
public:
virtual ~DnsResolver() = default;
// Address Resolution must be thread safe.
// Address family should be AF_UNSPEC, AF_INET, or AF_INET6.
virtual quiche::QuicheSocketAddress LookupAddress(
int address_family_for_lookup, absl::string_view host,
absl::string_view port) {
return tools::LookupAddress(address_family_for_lookup, std::string(host),
std::string(port));
}
quiche::QuicheSocketAddress LookupAddress(absl::string_view host,
absl::string_view port) {
return LookupAddress(AF_UNSPEC, host, port);
}
};
class QUIC_NO_EXPORT Visitor {
public:
virtual ~Visitor() = default;
virtual void OnResponse(MasqueConnectionPool* pool, RequestId request_id,
const absl::StatusOr<Message>& response) = 0;
};
// If the request fails immediately, the error will be returned. Otherwise, a
// request ID will be returned and the result (the response or an error) will
// be delivered later with that same request ID via Visitor::OnResponse.
absl::StatusOr<RequestId> SendRequest(const Message& request);
// `event_loop`, `ssl_ctx`, and `visitor` must outlive this object.
explicit MasqueConnectionPool(QuicEventLoop* event_loop, SSL_CTX* ssl_ctx,
bool disable_certificate_verification,
int address_family_for_lookup,
Visitor* visitor);
explicit MasqueConnectionPool(QuicEventLoop* event_loop, SSL_CTX* ssl_ctx,
bool disable_certificate_verification,
int address_family_for_lookup, Visitor* visitor,
std::shared_ptr<DnsResolver> dns_resolver);
QuicEventLoop* event_loop() { return event_loop_; }
SSL_CTX* ssl_ctx() { return ssl_ctx_; }
// From MasqueH2Connection::Visitor:
void OnConnectionReady(MasqueH2Connection* connection) override;
void OnConnectionFinished(MasqueH2Connection* connection) override;
void OnRequest(MasqueH2Connection* connection, int32_t stream_id,
const quiche::HttpHeaderBlock& headers,
const std::string& body) override;
void OnResponse(MasqueH2Connection* connection, int32_t stream_id,
const quiche::HttpHeaderBlock& headers,
const std::string& body) override;
virtual std::shared_ptr<DnsResolver> GetDnsResolver() {
return dns_resolver_;
}
static absl::StatusOr<bssl::UniquePtr<SSL_CTX>> CreateSslCtx(
const std::string& client_cert_file,
const std::string& client_cert_key_file);
static absl::StatusOr<bssl::UniquePtr<SSL_CTX>> CreateSslCtxFromData(
const std::string& client_cert_pem_data,
const std::string& client_cert_key_data);
private:
class ConnectionState : public QuicSocketEventListener {
public:
explicit ConnectionState(MasqueConnectionPool* connection_pool);
~ConnectionState() override;
bool SetupSocket(const std::string& authority,
bool disable_certificate_verification,
int address_family_for_lookup);
// From QuicSocketEventListener.
void OnSocketEvent(QuicEventLoop* event_loop, SocketFd fd,
QuicSocketEventMask events) override;
MasqueH2Connection* connection() { return connection_.get(); }
private:
static enum ssl_verify_result_t VerifyCallback(SSL* ssl,
uint8_t* out_alert);
enum ssl_verify_result_t VerifyCertificate(SSL* ssl, uint8_t* out_alert);
MasqueConnectionPool* connection_pool_; // Not owned.
std::string authority_;
std::string host_;
std::unique_ptr<ProofVerifier> proof_verifier_;
SocketFd socket_ = kInvalidSocketFd;
bssl::UniquePtr<SSL> ssl_;
std::unique_ptr<MasqueH2Connection> connection_;
};
struct PendingRequest {
Message request;
MasqueH2Connection* connection = nullptr; // Not owned.
int32_t stream_id = -1;
};
ConnectionState* GetOrCreateConnectionState(const std::string& authority);
void AttachConnectionToPendingRequests(const std::string& authority,
MasqueH2Connection* connection);
void SendPendingRequests(MasqueH2Connection* connection);
void FailPendingRequests(MasqueH2Connection* connection,
const absl::Status& error);
QuicEventLoop* event_loop_; // Not owned.
SSL_CTX* ssl_ctx_; // Not owned.
const bool disable_certificate_verification_;
const int address_family_for_lookup_;
Visitor* visitor_; // Not owned.
absl::flat_hash_map<std::string, std::unique_ptr<ConnectionState>>
connections_;
absl::flat_hash_map<RequestId, std::unique_ptr<PendingRequest>>
pending_requests_;
RequestId next_request_id_ = 0;
std::shared_ptr<DnsResolver> dns_resolver_;
};
} // namespace quic
#endif // QUICHE_QUIC_MASQUE_MASQUE_CONNECTION_POOL_H_