LCOV - code coverage report
Current view: top level - source/common/http/http3 - conn_pool.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 110 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 15 0.0 %

          Line data    Source code
       1             : #include "source/common/http/http3/conn_pool.h"
       2             : 
       3             : #include <cstdint>
       4             : #include <memory>
       5             : 
       6             : #include "envoy/event/dispatcher.h"
       7             : 
       8             : #include "source/common/config/utility.h"
       9             : #include "source/common/http/utility.h"
      10             : #include "source/common/network/address_impl.h"
      11             : #include "source/common/network/utility.h"
      12             : #include "source/common/runtime/runtime_features.h"
      13             : #include "source/common/upstream/upstream_impl.h"
      14             : 
      15             : namespace Envoy {
      16             : namespace Http {
      17             : namespace Http3 {
      18             : namespace {
      19             : 
      20           0 : uint32_t getMaxStreams(const Upstream::ClusterInfo& cluster) {
      21           0 :   return PROTOBUF_GET_WRAPPED_OR_DEFAULT(cluster.http3Options().quic_protocol_options(),
      22           0 :                                          max_concurrent_streams, 100);
      23           0 : }
      24             : 
      25             : const Envoy::Ssl::ClientContextConfig&
      26           0 : getConfig(Network::UpstreamTransportSocketFactory& transport_socket_factory) {
      27           0 :   ASSERT(transport_socket_factory.clientContextConfig().has_value());
      28           0 :   return transport_socket_factory.clientContextConfig().value();
      29           0 : }
      30             : 
      31             : std::string sni(const Network::TransportSocketOptionsConstSharedPtr& options,
      32           0 :                 Upstream::HostConstSharedPtr host) {
      33           0 :   return options && options->serverNameOverride().has_value()
      34           0 :              ? options->serverNameOverride().value()
      35           0 :              : getConfig(host->transportSocketFactory()).serverNameIndication();
      36           0 : }
      37             : 
      38             : } // namespace
      39             : 
      40             : ActiveClient::ActiveClient(Envoy::Http::HttpConnPoolImplBase& parent,
      41             :                            Upstream::Host::CreateConnectionData& data)
      42             :     : MultiplexedActiveClientBase(
      43             :           parent, getMaxStreams(parent.host()->cluster()), getMaxStreams(parent.host()->cluster()),
      44             :           parent.host()->cluster().trafficStats()->upstream_cx_http3_total_, data),
      45           0 :       async_connect_callback_(parent_.dispatcher().createSchedulableCallback([this]() {
      46           0 :         if (state() != Envoy::ConnectionPool::ActiveClient::State::Connecting) {
      47           0 :           return;
      48           0 :         }
      49           0 :         codec_client_->connect();
      50           0 :         if (readyForStream()) {
      51             :           // This client can send early data, so check if there are any pending streams can be sent
      52             :           // as early data.
      53           0 :           parent_.onUpstreamReadyForEarlyData(*this);
      54           0 :         }
      55           0 :       })) {
      56           0 :   ASSERT(codec_client_);
      57           0 :   if (dynamic_cast<CodecClientProd*>(codec_client_.get()) == nullptr) {
      58             :     // Hasn't called connect() yet, schedule one for the next event loop.
      59           0 :     async_connect_callback_->scheduleCallbackNextIteration();
      60           0 :   }
      61           0 : }
      62             : 
      63           0 : void ActiveClient::onMaxStreamsChanged(uint32_t num_streams) {
      64           0 :   updateCapacity(num_streams);
      65           0 :   if (state() == ActiveClient::State::Busy && currentUnusedCapacity() != 0) {
      66           0 :     ENVOY_BUG(hasHandshakeCompleted(), "Received MAX_STREAM frame before handshake completed.");
      67           0 :     parent_.transitionActiveClientState(*this, ActiveClient::State::Ready);
      68             :     // If there's waiting streams, make sure the pool will now serve them.
      69           0 :     parent_.onUpstreamReady();
      70           0 :   } else if (currentUnusedCapacity() == 0 && state() == ActiveClient::State::ReadyForEarlyData) {
      71             :     // With HTTP/3 this can only happen during a rejected 0-RTT handshake.
      72           0 :     parent_.transitionActiveClientState(*this, ActiveClient::State::Busy);
      73           0 :   }
      74           0 : }
      75             : 
      76             : ConnectionPool::Cancellable* Http3ConnPoolImpl::newStream(Http::ResponseDecoder& response_decoder,
      77             :                                                           ConnectionPool::Callbacks& callbacks,
      78           0 :                                                           const Instance::StreamOptions& options) {
      79           0 :   ENVOY_BUG(options.can_use_http3_,
      80           0 :             "Trying to send request over h3 while alternate protocols is disabled.");
      81           0 :   return FixedHttpConnPoolImpl::newStream(response_decoder, callbacks, options);
      82           0 : }
      83             : 
      84             : Http3ConnPoolImpl::Http3ConnPoolImpl(
      85             :     Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
      86             :     Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options,
      87             :     const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options,
      88             :     Random::RandomGenerator& random_generator, Upstream::ClusterConnectivityState& state,
      89             :     CreateClientFn client_fn, CreateCodecFn codec_fn, std::vector<Http::Protocol> protocol,
      90             :     OptRef<PoolConnectResultCallback> connect_callback, Http::PersistentQuicInfo& quic_info)
      91             :     : FixedHttpConnPoolImpl(host, priority, dispatcher, options, transport_socket_options,
      92             :                             random_generator, state, client_fn, codec_fn, protocol, {}, nullptr),
      93             :       quic_info_(dynamic_cast<Quic::PersistentQuicInfoImpl&>(quic_info)),
      94             :       server_id_(sni(transport_socket_options, host),
      95             :                  static_cast<uint16_t>(host_->address()->ip()->port()), false),
      96           0 :       connect_callback_(connect_callback) {}
      97             : 
      98           0 : void Http3ConnPoolImpl::onConnected(Envoy::ConnectionPool::ActiveClient&) {
      99           0 :   if (connect_callback_ != absl::nullopt) {
     100           0 :     connect_callback_->onHandshakeComplete();
     101           0 :   }
     102           0 : }
     103             : 
     104           0 : void Http3ConnPoolImpl::onConnectFailed(Envoy::ConnectionPool::ActiveClient& client) {
     105           0 :   ASSERT(client.numActiveStreams() == 0);
     106           0 :   if (static_cast<ActiveClient&>(client).hasCreatedStream() && connect_callback_ != absl::nullopt) {
     107           0 :     connect_callback_->onZeroRttHandshakeFailed();
     108           0 :   }
     109           0 : }
     110             : 
     111             : // Make sure all connections are torn down before quic_info_ is deleted.
     112           0 : Http3ConnPoolImpl::~Http3ConnPoolImpl() { destructAllConnections(); }
     113             : 
     114             : std::unique_ptr<Network::ClientConnection>
     115             : Http3ConnPoolImpl::createClientConnection(Quic::QuicStatNames& quic_stat_names,
     116             :                                           OptRef<Http::HttpServerPropertiesCache> rtt_cache,
     117           0 :                                           Stats::Scope& scope) {
     118           0 :   std::shared_ptr<quic::QuicCryptoClientConfig> crypto_config =
     119           0 :       host_->transportSocketFactory().getCryptoConfig();
     120           0 :   if (crypto_config == nullptr) {
     121           0 :     return nullptr; // no secrets available yet.
     122           0 :   }
     123             : 
     124           0 :   auto upstream_local_address_selector = host()->cluster().getUpstreamLocalAddressSelector();
     125           0 :   auto upstream_local_address =
     126           0 :       upstream_local_address_selector->getUpstreamLocalAddress(host()->address(), socketOptions());
     127           0 :   auto source_address = upstream_local_address.address_;
     128             : 
     129           0 :   if (source_address == nullptr) {
     130           0 :     auto host_address = host()->address();
     131           0 :     source_address = Network::Utility::getLocalAddress(host_address->ip()->version());
     132           0 :   }
     133             : 
     134           0 :   return Quic::createQuicNetworkConnection(
     135           0 :       quic_info_, std::move(crypto_config), server_id_, dispatcher(), host()->address(),
     136           0 :       source_address, quic_stat_names, rtt_cache, scope, upstream_local_address.socket_options_,
     137           0 :       transportSocketOptions(), connection_id_generator_, host_->transportSocketFactory());
     138           0 : }
     139             : 
     140             : std::unique_ptr<Http3ConnPoolImpl>
     141             : allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator,
     142             :                  Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
     143             :                  const Network::ConnectionSocket::OptionsSharedPtr& options,
     144             :                  const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options,
     145             :                  Upstream::ClusterConnectivityState& state, Quic::QuicStatNames& quic_stat_names,
     146             :                  OptRef<Http::HttpServerPropertiesCache> rtt_cache, Stats::Scope& scope,
     147             :                  OptRef<PoolConnectResultCallback> connect_callback,
     148           0 :                  Http::PersistentQuicInfo& quic_info) {
     149           0 :   return std::make_unique<Http3ConnPoolImpl>(
     150           0 :       host, priority, dispatcher, options, transport_socket_options, random_generator, state,
     151           0 :       [&quic_stat_names, rtt_cache,
     152           0 :        &scope](HttpConnPoolImplBase* pool) -> ::Envoy::ConnectionPool::ActiveClientPtr {
     153           0 :         ENVOY_LOG_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::pool), debug,
     154           0 :                             "Creating Http/3 client");
     155             :         // If there's no ssl context, the secrets are not loaded. Fast-fail by returning null.
     156           0 :         auto factory = &pool->host()->transportSocketFactory();
     157           0 :         if (factory->sslCtx() == nullptr) {
     158           0 :           ENVOY_LOG_EVERY_POW_2_TO_LOGGER(Envoy::Logger::Registry::getLog(Envoy::Logger::Id::pool),
     159           0 :                                           warn,
     160           0 :                                           "Failed to create Http/3 client. Transport socket "
     161           0 :                                           "factory is not configured correctly.");
     162           0 :           return nullptr;
     163           0 :         }
     164           0 :         Http3ConnPoolImpl* h3_pool = reinterpret_cast<Http3ConnPoolImpl*>(pool);
     165           0 :         Upstream::Host::CreateConnectionData data{};
     166           0 :         data.host_description_ = pool->host();
     167           0 :         data.connection_ = h3_pool->createClientConnection(quic_stat_names, rtt_cache, scope);
     168           0 :         if (data.connection_ == nullptr) {
     169           0 :           ENVOY_LOG_EVERY_POW_2_TO_LOGGER(
     170           0 :               Envoy::Logger::Registry::getLog(Envoy::Logger::Id::pool), warn,
     171           0 :               "Failed to create Http/3 client. Failed to create quic network connection.");
     172           0 :           return nullptr;
     173           0 :         }
     174           0 :         auto client = std::make_unique<ActiveClient>(*pool, data);
     175           0 :         return client;
     176           0 :       },
     177           0 :       [](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) {
     178             :         // Because HTTP/3 codec client connect() can close connection inline and can raise 0-RTT
     179             :         // event inline, and both cases need to have network callbacks and http callbacks wired up
     180             :         // to propagate the event, so do not call connect() during codec client construction.
     181           0 :         CodecClientPtr codec = std::make_unique<NoConnectCodecClientProd>(
     182           0 :             CodecType::HTTP3, std::move(data.connection_), data.host_description_,
     183           0 :             pool->dispatcher(), pool->randomGenerator(), pool->transportSocketOptions());
     184           0 :         return codec;
     185           0 :       },
     186           0 :       std::vector<Protocol>{Protocol::Http3}, connect_callback, quic_info);
     187           0 : }
     188             : 
     189             : } // namespace Http3
     190             : } // namespace Http
     191             : } // namespace Envoy

Generated by: LCOV version 1.15