12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2012 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "shrpx_worker.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
282c593315Sopenharmony_ci#  include <unistd.h>
292c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
302c593315Sopenharmony_ci#include <netinet/udp.h>
312c593315Sopenharmony_ci
322c593315Sopenharmony_ci#include <cstdio>
332c593315Sopenharmony_ci#include <memory>
342c593315Sopenharmony_ci
352c593315Sopenharmony_ci#include <openssl/rand.h>
362c593315Sopenharmony_ci
372c593315Sopenharmony_ci#ifdef HAVE_LIBBPF
382c593315Sopenharmony_ci#  include <bpf/bpf.h>
392c593315Sopenharmony_ci#  include <bpf/libbpf.h>
402c593315Sopenharmony_ci#endif // HAVE_LIBBPF
412c593315Sopenharmony_ci
422c593315Sopenharmony_ci#include "shrpx_tls.h"
432c593315Sopenharmony_ci#include "shrpx_log.h"
442c593315Sopenharmony_ci#include "shrpx_client_handler.h"
452c593315Sopenharmony_ci#include "shrpx_http2_session.h"
462c593315Sopenharmony_ci#include "shrpx_log_config.h"
472c593315Sopenharmony_ci#include "shrpx_memcached_dispatcher.h"
482c593315Sopenharmony_ci#ifdef HAVE_MRUBY
492c593315Sopenharmony_ci#  include "shrpx_mruby.h"
502c593315Sopenharmony_ci#endif // HAVE_MRUBY
512c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
522c593315Sopenharmony_ci#  include "shrpx_quic_listener.h"
532c593315Sopenharmony_ci#endif // ENABLE_HTTP3
542c593315Sopenharmony_ci#include "shrpx_connection_handler.h"
552c593315Sopenharmony_ci#include "util.h"
562c593315Sopenharmony_ci#include "template.h"
572c593315Sopenharmony_ci#include "xsi_strerror.h"
582c593315Sopenharmony_ci
592c593315Sopenharmony_cinamespace shrpx {
602c593315Sopenharmony_ci
612c593315Sopenharmony_cinamespace {
622c593315Sopenharmony_civoid eventcb(struct ev_loop *loop, ev_async *w, int revents) {
632c593315Sopenharmony_ci  auto worker = static_cast<Worker *>(w->data);
642c593315Sopenharmony_ci  worker->process_events();
652c593315Sopenharmony_ci}
662c593315Sopenharmony_ci} // namespace
672c593315Sopenharmony_ci
682c593315Sopenharmony_cinamespace {
692c593315Sopenharmony_civoid mcpool_clear_cb(struct ev_loop *loop, ev_timer *w, int revents) {
702c593315Sopenharmony_ci  auto worker = static_cast<Worker *>(w->data);
712c593315Sopenharmony_ci  if (worker->get_worker_stat()->num_connections != 0) {
722c593315Sopenharmony_ci    return;
732c593315Sopenharmony_ci  }
742c593315Sopenharmony_ci  auto mcpool = worker->get_mcpool();
752c593315Sopenharmony_ci  if (mcpool->freelistsize == mcpool->poolsize) {
762c593315Sopenharmony_ci    worker->get_mcpool()->clear();
772c593315Sopenharmony_ci  }
782c593315Sopenharmony_ci}
792c593315Sopenharmony_ci} // namespace
802c593315Sopenharmony_ci
812c593315Sopenharmony_cinamespace {
822c593315Sopenharmony_civoid proc_wev_cb(struct ev_loop *loop, ev_timer *w, int revents) {
832c593315Sopenharmony_ci  auto worker = static_cast<Worker *>(w->data);
842c593315Sopenharmony_ci  worker->process_events();
852c593315Sopenharmony_ci}
862c593315Sopenharmony_ci} // namespace
872c593315Sopenharmony_ci
882c593315Sopenharmony_ciDownstreamAddrGroup::DownstreamAddrGroup() : retired{false} {}
892c593315Sopenharmony_ci
902c593315Sopenharmony_ciDownstreamAddrGroup::~DownstreamAddrGroup() {}
912c593315Sopenharmony_ci
922c593315Sopenharmony_ci// DownstreamKey is used to index SharedDownstreamAddr in order to
932c593315Sopenharmony_ci// find the same configuration.
942c593315Sopenharmony_ciusing DownstreamKey = std::tuple<
952c593315Sopenharmony_ci    std::vector<
962c593315Sopenharmony_ci        std::tuple<StringRef, StringRef, StringRef, size_t, size_t, Proto,
972c593315Sopenharmony_ci                   uint32_t, uint32_t, uint32_t, bool, bool, bool, bool>>,
982c593315Sopenharmony_ci    bool, SessionAffinity, StringRef, StringRef, SessionAffinityCookieSecure,
992c593315Sopenharmony_ci    SessionAffinityCookieStickiness, int64_t, int64_t, StringRef, bool>;
1002c593315Sopenharmony_ci
1012c593315Sopenharmony_cinamespace {
1022c593315Sopenharmony_ciDownstreamKey
1032c593315Sopenharmony_cicreate_downstream_key(const std::shared_ptr<SharedDownstreamAddr> &shared_addr,
1042c593315Sopenharmony_ci                      const StringRef &mruby_file) {
1052c593315Sopenharmony_ci  DownstreamKey dkey;
1062c593315Sopenharmony_ci
1072c593315Sopenharmony_ci  auto &addrs = std::get<0>(dkey);
1082c593315Sopenharmony_ci  addrs.resize(shared_addr->addrs.size());
1092c593315Sopenharmony_ci  auto p = std::begin(addrs);
1102c593315Sopenharmony_ci  for (auto &a : shared_addr->addrs) {
1112c593315Sopenharmony_ci    std::get<0>(*p) = a.host;
1122c593315Sopenharmony_ci    std::get<1>(*p) = a.sni;
1132c593315Sopenharmony_ci    std::get<2>(*p) = a.group;
1142c593315Sopenharmony_ci    std::get<3>(*p) = a.fall;
1152c593315Sopenharmony_ci    std::get<4>(*p) = a.rise;
1162c593315Sopenharmony_ci    std::get<5>(*p) = a.proto;
1172c593315Sopenharmony_ci    std::get<6>(*p) = a.port;
1182c593315Sopenharmony_ci    std::get<7>(*p) = a.weight;
1192c593315Sopenharmony_ci    std::get<8>(*p) = a.group_weight;
1202c593315Sopenharmony_ci    std::get<9>(*p) = a.host_unix;
1212c593315Sopenharmony_ci    std::get<10>(*p) = a.tls;
1222c593315Sopenharmony_ci    std::get<11>(*p) = a.dns;
1232c593315Sopenharmony_ci    std::get<12>(*p) = a.upgrade_scheme;
1242c593315Sopenharmony_ci    ++p;
1252c593315Sopenharmony_ci  }
1262c593315Sopenharmony_ci  std::sort(std::begin(addrs), std::end(addrs));
1272c593315Sopenharmony_ci
1282c593315Sopenharmony_ci  std::get<1>(dkey) = shared_addr->redirect_if_not_tls;
1292c593315Sopenharmony_ci
1302c593315Sopenharmony_ci  auto &affinity = shared_addr->affinity;
1312c593315Sopenharmony_ci  std::get<2>(dkey) = affinity.type;
1322c593315Sopenharmony_ci  std::get<3>(dkey) = affinity.cookie.name;
1332c593315Sopenharmony_ci  std::get<4>(dkey) = affinity.cookie.path;
1342c593315Sopenharmony_ci  std::get<5>(dkey) = affinity.cookie.secure;
1352c593315Sopenharmony_ci  std::get<6>(dkey) = affinity.cookie.stickiness;
1362c593315Sopenharmony_ci  auto &timeout = shared_addr->timeout;
1372c593315Sopenharmony_ci  std::get<7>(dkey) = timeout.read;
1382c593315Sopenharmony_ci  std::get<8>(dkey) = timeout.write;
1392c593315Sopenharmony_ci  std::get<9>(dkey) = mruby_file;
1402c593315Sopenharmony_ci  std::get<10>(dkey) = shared_addr->dnf;
1412c593315Sopenharmony_ci
1422c593315Sopenharmony_ci  return dkey;
1432c593315Sopenharmony_ci}
1442c593315Sopenharmony_ci} // namespace
1452c593315Sopenharmony_ci
1462c593315Sopenharmony_ciWorker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
1472c593315Sopenharmony_ci               SSL_CTX *tls_session_cache_memcached_ssl_ctx,
1482c593315Sopenharmony_ci               tls::CertLookupTree *cert_tree,
1492c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
1502c593315Sopenharmony_ci               SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *quic_cert_tree,
1512c593315Sopenharmony_ci               const uint8_t *cid_prefix, size_t cid_prefixlen,
1522c593315Sopenharmony_ci#  ifdef HAVE_LIBBPF
1532c593315Sopenharmony_ci               size_t index,
1542c593315Sopenharmony_ci#  endif // HAVE_LIBBPF
1552c593315Sopenharmony_ci#endif   // ENABLE_HTTP3
1562c593315Sopenharmony_ci               const std::shared_ptr<TicketKeys> &ticket_keys,
1572c593315Sopenharmony_ci               ConnectionHandler *conn_handler,
1582c593315Sopenharmony_ci               std::shared_ptr<DownstreamConfig> downstreamconf)
1592c593315Sopenharmony_ci    :
1602c593315Sopenharmony_ci#if defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF)
1612c593315Sopenharmony_ci      index_{index},
1622c593315Sopenharmony_ci#endif // ENABLE_HTTP3 && HAVE_LIBBPF
1632c593315Sopenharmony_ci      randgen_(util::make_mt19937()),
1642c593315Sopenharmony_ci      worker_stat_{},
1652c593315Sopenharmony_ci      dns_tracker_(loop, get_config()->conn.downstream->family),
1662c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
1672c593315Sopenharmony_ci      quic_upstream_addrs_{get_config()->conn.quic_listener.addrs},
1682c593315Sopenharmony_ci#endif // ENABLE_HTTP3
1692c593315Sopenharmony_ci      loop_(loop),
1702c593315Sopenharmony_ci      sv_ssl_ctx_(sv_ssl_ctx),
1712c593315Sopenharmony_ci      cl_ssl_ctx_(cl_ssl_ctx),
1722c593315Sopenharmony_ci      cert_tree_(cert_tree),
1732c593315Sopenharmony_ci      conn_handler_(conn_handler),
1742c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
1752c593315Sopenharmony_ci      quic_sv_ssl_ctx_{quic_sv_ssl_ctx},
1762c593315Sopenharmony_ci      quic_cert_tree_{quic_cert_tree},
1772c593315Sopenharmony_ci      quic_conn_handler_{this},
1782c593315Sopenharmony_ci#endif // ENABLE_HTTP3
1792c593315Sopenharmony_ci      ticket_keys_(ticket_keys),
1802c593315Sopenharmony_ci      connect_blocker_(
1812c593315Sopenharmony_ci          std::make_unique<ConnectBlocker>(randgen_, loop_, nullptr, nullptr)),
1822c593315Sopenharmony_ci      graceful_shutdown_(false) {
1832c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
1842c593315Sopenharmony_ci  std::copy_n(cid_prefix, cid_prefixlen, std::begin(cid_prefix_));
1852c593315Sopenharmony_ci#endif // ENABLE_HTTP3
1862c593315Sopenharmony_ci
1872c593315Sopenharmony_ci  ev_async_init(&w_, eventcb);
1882c593315Sopenharmony_ci  w_.data = this;
1892c593315Sopenharmony_ci  ev_async_start(loop_, &w_);
1902c593315Sopenharmony_ci
1912c593315Sopenharmony_ci  ev_timer_init(&mcpool_clear_timer_, mcpool_clear_cb, 0., 0.);
1922c593315Sopenharmony_ci  mcpool_clear_timer_.data = this;
1932c593315Sopenharmony_ci
1942c593315Sopenharmony_ci  ev_timer_init(&proc_wev_timer_, proc_wev_cb, 0., 0.);
1952c593315Sopenharmony_ci  proc_wev_timer_.data = this;
1962c593315Sopenharmony_ci
1972c593315Sopenharmony_ci  auto &session_cacheconf = get_config()->tls.session_cache;
1982c593315Sopenharmony_ci
1992c593315Sopenharmony_ci  if (!session_cacheconf.memcached.host.empty()) {
2002c593315Sopenharmony_ci    session_cache_memcached_dispatcher_ = std::make_unique<MemcachedDispatcher>(
2012c593315Sopenharmony_ci        &session_cacheconf.memcached.addr, loop,
2022c593315Sopenharmony_ci        tls_session_cache_memcached_ssl_ctx,
2032c593315Sopenharmony_ci        StringRef{session_cacheconf.memcached.host}, &mcpool_, randgen_);
2042c593315Sopenharmony_ci  }
2052c593315Sopenharmony_ci
2062c593315Sopenharmony_ci  replace_downstream_config(std::move(downstreamconf));
2072c593315Sopenharmony_ci}
2082c593315Sopenharmony_ci
2092c593315Sopenharmony_cinamespace {
2102c593315Sopenharmony_civoid ensure_enqueue_addr(
2112c593315Sopenharmony_ci    std::priority_queue<WeightGroupEntry, std::vector<WeightGroupEntry>,
2122c593315Sopenharmony_ci                        WeightGroupEntryGreater> &wgpq,
2132c593315Sopenharmony_ci    WeightGroup *wg, DownstreamAddr *addr) {
2142c593315Sopenharmony_ci  uint32_t cycle;
2152c593315Sopenharmony_ci  if (!wg->pq.empty()) {
2162c593315Sopenharmony_ci    auto &top = wg->pq.top();
2172c593315Sopenharmony_ci    cycle = top.cycle;
2182c593315Sopenharmony_ci  } else {
2192c593315Sopenharmony_ci    cycle = 0;
2202c593315Sopenharmony_ci  }
2212c593315Sopenharmony_ci
2222c593315Sopenharmony_ci  addr->cycle = cycle;
2232c593315Sopenharmony_ci  addr->pending_penalty = 0;
2242c593315Sopenharmony_ci  wg->pq.push(DownstreamAddrEntry{addr, addr->seq, addr->cycle});
2252c593315Sopenharmony_ci  addr->queued = true;
2262c593315Sopenharmony_ci
2272c593315Sopenharmony_ci  if (!wg->queued) {
2282c593315Sopenharmony_ci    if (!wgpq.empty()) {
2292c593315Sopenharmony_ci      auto &top = wgpq.top();
2302c593315Sopenharmony_ci      cycle = top.cycle;
2312c593315Sopenharmony_ci    } else {
2322c593315Sopenharmony_ci      cycle = 0;
2332c593315Sopenharmony_ci    }
2342c593315Sopenharmony_ci
2352c593315Sopenharmony_ci    wg->cycle = cycle;
2362c593315Sopenharmony_ci    wg->pending_penalty = 0;
2372c593315Sopenharmony_ci    wgpq.push(WeightGroupEntry{wg, wg->seq, wg->cycle});
2382c593315Sopenharmony_ci    wg->queued = true;
2392c593315Sopenharmony_ci  }
2402c593315Sopenharmony_ci}
2412c593315Sopenharmony_ci} // namespace
2422c593315Sopenharmony_ci
2432c593315Sopenharmony_civoid Worker::replace_downstream_config(
2442c593315Sopenharmony_ci    std::shared_ptr<DownstreamConfig> downstreamconf) {
2452c593315Sopenharmony_ci  for (auto &g : downstream_addr_groups_) {
2462c593315Sopenharmony_ci    g->retired = true;
2472c593315Sopenharmony_ci
2482c593315Sopenharmony_ci    auto &shared_addr = g->shared_addr;
2492c593315Sopenharmony_ci    for (auto &addr : shared_addr->addrs) {
2502c593315Sopenharmony_ci      addr.dconn_pool->remove_all();
2512c593315Sopenharmony_ci    }
2522c593315Sopenharmony_ci  }
2532c593315Sopenharmony_ci
2542c593315Sopenharmony_ci  downstreamconf_ = downstreamconf;
2552c593315Sopenharmony_ci
2562c593315Sopenharmony_ci  // Making a copy is much faster with multiple thread on
2572c593315Sopenharmony_ci  // backendconfig API call.
2582c593315Sopenharmony_ci  auto groups = downstreamconf->addr_groups;
2592c593315Sopenharmony_ci
2602c593315Sopenharmony_ci  downstream_addr_groups_ =
2612c593315Sopenharmony_ci      std::vector<std::shared_ptr<DownstreamAddrGroup>>(groups.size());
2622c593315Sopenharmony_ci
2632c593315Sopenharmony_ci  std::map<DownstreamKey, size_t> addr_groups_indexer;
2642c593315Sopenharmony_ci#ifdef HAVE_MRUBY
2652c593315Sopenharmony_ci  // TODO It is a bit less efficient because
2662c593315Sopenharmony_ci  // mruby::create_mruby_context returns std::unique_ptr and we cannot
2672c593315Sopenharmony_ci  // use std::make_shared.
2682c593315Sopenharmony_ci  std::map<StringRef, std::shared_ptr<mruby::MRubyContext>> shared_mruby_ctxs;
2692c593315Sopenharmony_ci#endif // HAVE_MRUBY
2702c593315Sopenharmony_ci
2712c593315Sopenharmony_ci  for (size_t i = 0; i < groups.size(); ++i) {
2722c593315Sopenharmony_ci    auto &src = groups[i];
2732c593315Sopenharmony_ci    auto &dst = downstream_addr_groups_[i];
2742c593315Sopenharmony_ci
2752c593315Sopenharmony_ci    dst = std::make_shared<DownstreamAddrGroup>();
2762c593315Sopenharmony_ci    dst->pattern =
2772c593315Sopenharmony_ci        ImmutableString{std::begin(src.pattern), std::end(src.pattern)};
2782c593315Sopenharmony_ci
2792c593315Sopenharmony_ci    auto shared_addr = std::make_shared<SharedDownstreamAddr>();
2802c593315Sopenharmony_ci
2812c593315Sopenharmony_ci    shared_addr->addrs.resize(src.addrs.size());
2822c593315Sopenharmony_ci    shared_addr->affinity.type = src.affinity.type;
2832c593315Sopenharmony_ci    if (src.affinity.type == SessionAffinity::COOKIE) {
2842c593315Sopenharmony_ci      shared_addr->affinity.cookie.name =
2852c593315Sopenharmony_ci          make_string_ref(shared_addr->balloc, src.affinity.cookie.name);
2862c593315Sopenharmony_ci      if (!src.affinity.cookie.path.empty()) {
2872c593315Sopenharmony_ci        shared_addr->affinity.cookie.path =
2882c593315Sopenharmony_ci            make_string_ref(shared_addr->balloc, src.affinity.cookie.path);
2892c593315Sopenharmony_ci      }
2902c593315Sopenharmony_ci      shared_addr->affinity.cookie.secure = src.affinity.cookie.secure;
2912c593315Sopenharmony_ci      shared_addr->affinity.cookie.stickiness = src.affinity.cookie.stickiness;
2922c593315Sopenharmony_ci    }
2932c593315Sopenharmony_ci    shared_addr->affinity_hash = src.affinity_hash;
2942c593315Sopenharmony_ci    shared_addr->affinity_hash_map = src.affinity_hash_map;
2952c593315Sopenharmony_ci    shared_addr->redirect_if_not_tls = src.redirect_if_not_tls;
2962c593315Sopenharmony_ci    shared_addr->dnf = src.dnf;
2972c593315Sopenharmony_ci    shared_addr->timeout.read = src.timeout.read;
2982c593315Sopenharmony_ci    shared_addr->timeout.write = src.timeout.write;
2992c593315Sopenharmony_ci
3002c593315Sopenharmony_ci    for (size_t j = 0; j < src.addrs.size(); ++j) {
3012c593315Sopenharmony_ci      auto &src_addr = src.addrs[j];
3022c593315Sopenharmony_ci      auto &dst_addr = shared_addr->addrs[j];
3032c593315Sopenharmony_ci
3042c593315Sopenharmony_ci      dst_addr.addr = src_addr.addr;
3052c593315Sopenharmony_ci      dst_addr.host = make_string_ref(shared_addr->balloc, src_addr.host);
3062c593315Sopenharmony_ci      dst_addr.hostport =
3072c593315Sopenharmony_ci          make_string_ref(shared_addr->balloc, src_addr.hostport);
3082c593315Sopenharmony_ci      dst_addr.port = src_addr.port;
3092c593315Sopenharmony_ci      dst_addr.host_unix = src_addr.host_unix;
3102c593315Sopenharmony_ci      dst_addr.weight = src_addr.weight;
3112c593315Sopenharmony_ci      dst_addr.group = make_string_ref(shared_addr->balloc, src_addr.group);
3122c593315Sopenharmony_ci      dst_addr.group_weight = src_addr.group_weight;
3132c593315Sopenharmony_ci      dst_addr.affinity_hash = src_addr.affinity_hash;
3142c593315Sopenharmony_ci      dst_addr.proto = src_addr.proto;
3152c593315Sopenharmony_ci      dst_addr.tls = src_addr.tls;
3162c593315Sopenharmony_ci      dst_addr.sni = make_string_ref(shared_addr->balloc, src_addr.sni);
3172c593315Sopenharmony_ci      dst_addr.fall = src_addr.fall;
3182c593315Sopenharmony_ci      dst_addr.rise = src_addr.rise;
3192c593315Sopenharmony_ci      dst_addr.dns = src_addr.dns;
3202c593315Sopenharmony_ci      dst_addr.upgrade_scheme = src_addr.upgrade_scheme;
3212c593315Sopenharmony_ci    }
3222c593315Sopenharmony_ci
3232c593315Sopenharmony_ci#ifdef HAVE_MRUBY
3242c593315Sopenharmony_ci    auto mruby_ctx_it = shared_mruby_ctxs.find(src.mruby_file);
3252c593315Sopenharmony_ci    if (mruby_ctx_it == std::end(shared_mruby_ctxs)) {
3262c593315Sopenharmony_ci      shared_addr->mruby_ctx = mruby::create_mruby_context(src.mruby_file);
3272c593315Sopenharmony_ci      assert(shared_addr->mruby_ctx);
3282c593315Sopenharmony_ci      shared_mruby_ctxs.emplace(src.mruby_file, shared_addr->mruby_ctx);
3292c593315Sopenharmony_ci    } else {
3302c593315Sopenharmony_ci      shared_addr->mruby_ctx = (*mruby_ctx_it).second;
3312c593315Sopenharmony_ci    }
3322c593315Sopenharmony_ci#endif // HAVE_MRUBY
3332c593315Sopenharmony_ci
3342c593315Sopenharmony_ci    // share the connection if patterns have the same set of backend
3352c593315Sopenharmony_ci    // addresses.
3362c593315Sopenharmony_ci
3372c593315Sopenharmony_ci    auto dkey = create_downstream_key(shared_addr, src.mruby_file);
3382c593315Sopenharmony_ci    auto it = addr_groups_indexer.find(dkey);
3392c593315Sopenharmony_ci
3402c593315Sopenharmony_ci    if (it == std::end(addr_groups_indexer)) {
3412c593315Sopenharmony_ci      auto shared_addr_ptr = shared_addr.get();
3422c593315Sopenharmony_ci
3432c593315Sopenharmony_ci      for (auto &addr : shared_addr->addrs) {
3442c593315Sopenharmony_ci        addr.connect_blocker = std::make_unique<ConnectBlocker>(
3452c593315Sopenharmony_ci            randgen_, loop_, nullptr, [shared_addr_ptr, &addr]() {
3462c593315Sopenharmony_ci              if (!addr.queued) {
3472c593315Sopenharmony_ci                if (!addr.wg) {
3482c593315Sopenharmony_ci                  return;
3492c593315Sopenharmony_ci                }
3502c593315Sopenharmony_ci                ensure_enqueue_addr(shared_addr_ptr->pq, addr.wg, &addr);
3512c593315Sopenharmony_ci              }
3522c593315Sopenharmony_ci            });
3532c593315Sopenharmony_ci
3542c593315Sopenharmony_ci        addr.live_check = std::make_unique<LiveCheck>(loop_, cl_ssl_ctx_, this,
3552c593315Sopenharmony_ci                                                      &addr, randgen_);
3562c593315Sopenharmony_ci      }
3572c593315Sopenharmony_ci
3582c593315Sopenharmony_ci      size_t seq = 0;
3592c593315Sopenharmony_ci      for (auto &addr : shared_addr->addrs) {
3602c593315Sopenharmony_ci        addr.dconn_pool = std::make_unique<DownstreamConnectionPool>();
3612c593315Sopenharmony_ci        addr.seq = seq++;
3622c593315Sopenharmony_ci      }
3632c593315Sopenharmony_ci
3642c593315Sopenharmony_ci      util::shuffle(std::begin(shared_addr->addrs),
3652c593315Sopenharmony_ci                    std::end(shared_addr->addrs), randgen_,
3662c593315Sopenharmony_ci                    [](auto i, auto j) { std::swap((*i).seq, (*j).seq); });
3672c593315Sopenharmony_ci
3682c593315Sopenharmony_ci      if (shared_addr->affinity.type == SessionAffinity::NONE) {
3692c593315Sopenharmony_ci        std::map<StringRef, WeightGroup *> wgs;
3702c593315Sopenharmony_ci        size_t num_wgs = 0;
3712c593315Sopenharmony_ci        for (auto &addr : shared_addr->addrs) {
3722c593315Sopenharmony_ci          if (wgs.find(addr.group) == std::end(wgs)) {
3732c593315Sopenharmony_ci            ++num_wgs;
3742c593315Sopenharmony_ci            wgs.emplace(addr.group, nullptr);
3752c593315Sopenharmony_ci          }
3762c593315Sopenharmony_ci        }
3772c593315Sopenharmony_ci
3782c593315Sopenharmony_ci        shared_addr->wgs = std::vector<WeightGroup>(num_wgs);
3792c593315Sopenharmony_ci
3802c593315Sopenharmony_ci        for (auto &addr : shared_addr->addrs) {
3812c593315Sopenharmony_ci          auto &wg = wgs[addr.group];
3822c593315Sopenharmony_ci          if (wg == nullptr) {
3832c593315Sopenharmony_ci            wg = &shared_addr->wgs[--num_wgs];
3842c593315Sopenharmony_ci            wg->seq = num_wgs;
3852c593315Sopenharmony_ci          }
3862c593315Sopenharmony_ci
3872c593315Sopenharmony_ci          wg->weight = addr.group_weight;
3882c593315Sopenharmony_ci          wg->pq.push(DownstreamAddrEntry{&addr, addr.seq, addr.cycle});
3892c593315Sopenharmony_ci          addr.queued = true;
3902c593315Sopenharmony_ci          addr.wg = wg;
3912c593315Sopenharmony_ci        }
3922c593315Sopenharmony_ci
3932c593315Sopenharmony_ci        assert(num_wgs == 0);
3942c593315Sopenharmony_ci
3952c593315Sopenharmony_ci        for (auto &kv : wgs) {
3962c593315Sopenharmony_ci          shared_addr->pq.push(
3972c593315Sopenharmony_ci              WeightGroupEntry{kv.second, kv.second->seq, kv.second->cycle});
3982c593315Sopenharmony_ci          kv.second->queued = true;
3992c593315Sopenharmony_ci        }
4002c593315Sopenharmony_ci      }
4012c593315Sopenharmony_ci
4022c593315Sopenharmony_ci      dst->shared_addr = shared_addr;
4032c593315Sopenharmony_ci
4042c593315Sopenharmony_ci      addr_groups_indexer.emplace(std::move(dkey), i);
4052c593315Sopenharmony_ci    } else {
4062c593315Sopenharmony_ci      auto &g = *(std::begin(downstream_addr_groups_) + (*it).second);
4072c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
4082c593315Sopenharmony_ci        LOG(INFO) << dst->pattern << " shares the same backend group with "
4092c593315Sopenharmony_ci                  << g->pattern;
4102c593315Sopenharmony_ci      }
4112c593315Sopenharmony_ci      dst->shared_addr = g->shared_addr;
4122c593315Sopenharmony_ci    }
4132c593315Sopenharmony_ci  }
4142c593315Sopenharmony_ci}
4152c593315Sopenharmony_ci
4162c593315Sopenharmony_ciWorker::~Worker() {
4172c593315Sopenharmony_ci  ev_async_stop(loop_, &w_);
4182c593315Sopenharmony_ci  ev_timer_stop(loop_, &mcpool_clear_timer_);
4192c593315Sopenharmony_ci  ev_timer_stop(loop_, &proc_wev_timer_);
4202c593315Sopenharmony_ci}
4212c593315Sopenharmony_ci
4222c593315Sopenharmony_civoid Worker::schedule_clear_mcpool() {
4232c593315Sopenharmony_ci  // libev manual says: "If the watcher is already active nothing will
4242c593315Sopenharmony_ci  // happen."  Since we don't change any timeout here, we don't have
4252c593315Sopenharmony_ci  // to worry about querying ev_is_active.
4262c593315Sopenharmony_ci  ev_timer_start(loop_, &mcpool_clear_timer_);
4272c593315Sopenharmony_ci}
4282c593315Sopenharmony_ci
4292c593315Sopenharmony_civoid Worker::wait() {
4302c593315Sopenharmony_ci#ifndef NOTHREADS
4312c593315Sopenharmony_ci  fut_.get();
4322c593315Sopenharmony_ci#endif // !NOTHREADS
4332c593315Sopenharmony_ci}
4342c593315Sopenharmony_ci
4352c593315Sopenharmony_civoid Worker::run_async() {
4362c593315Sopenharmony_ci#ifndef NOTHREADS
4372c593315Sopenharmony_ci  fut_ = std::async(std::launch::async, [this] {
4382c593315Sopenharmony_ci    (void)reopen_log_files(get_config()->logging);
4392c593315Sopenharmony_ci    ev_run(loop_);
4402c593315Sopenharmony_ci    delete_log_config();
4412c593315Sopenharmony_ci  });
4422c593315Sopenharmony_ci#endif // !NOTHREADS
4432c593315Sopenharmony_ci}
4442c593315Sopenharmony_ci
4452c593315Sopenharmony_civoid Worker::send(WorkerEvent event) {
4462c593315Sopenharmony_ci  {
4472c593315Sopenharmony_ci    std::lock_guard<std::mutex> g(m_);
4482c593315Sopenharmony_ci
4492c593315Sopenharmony_ci    q_.emplace_back(std::move(event));
4502c593315Sopenharmony_ci  }
4512c593315Sopenharmony_ci
4522c593315Sopenharmony_ci  ev_async_send(loop_, &w_);
4532c593315Sopenharmony_ci}
4542c593315Sopenharmony_ci
4552c593315Sopenharmony_civoid Worker::process_events() {
4562c593315Sopenharmony_ci  WorkerEvent wev;
4572c593315Sopenharmony_ci  {
4582c593315Sopenharmony_ci    std::lock_guard<std::mutex> g(m_);
4592c593315Sopenharmony_ci
4602c593315Sopenharmony_ci    // Process event one at a time.  This is important for
4612c593315Sopenharmony_ci    // WorkerEventType::NEW_CONNECTION event since accepting large
4622c593315Sopenharmony_ci    // number of new connections at once may delay time to 1st byte
4632c593315Sopenharmony_ci    // for existing connections.
4642c593315Sopenharmony_ci
4652c593315Sopenharmony_ci    if (q_.empty()) {
4662c593315Sopenharmony_ci      ev_timer_stop(loop_, &proc_wev_timer_);
4672c593315Sopenharmony_ci      return;
4682c593315Sopenharmony_ci    }
4692c593315Sopenharmony_ci
4702c593315Sopenharmony_ci    wev = std::move(q_.front());
4712c593315Sopenharmony_ci    q_.pop_front();
4722c593315Sopenharmony_ci  }
4732c593315Sopenharmony_ci
4742c593315Sopenharmony_ci  ev_timer_start(loop_, &proc_wev_timer_);
4752c593315Sopenharmony_ci
4762c593315Sopenharmony_ci  auto config = get_config();
4772c593315Sopenharmony_ci
4782c593315Sopenharmony_ci  auto worker_connections = config->conn.upstream.worker_connections;
4792c593315Sopenharmony_ci
4802c593315Sopenharmony_ci  switch (wev.type) {
4812c593315Sopenharmony_ci  case WorkerEventType::NEW_CONNECTION: {
4822c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
4832c593315Sopenharmony_ci      WLOG(INFO, this) << "WorkerEvent: client_fd=" << wev.client_fd
4842c593315Sopenharmony_ci                       << ", addrlen=" << wev.client_addrlen;
4852c593315Sopenharmony_ci    }
4862c593315Sopenharmony_ci
4872c593315Sopenharmony_ci    if (worker_stat_.num_connections >= worker_connections) {
4882c593315Sopenharmony_ci
4892c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
4902c593315Sopenharmony_ci        WLOG(INFO, this) << "Too many connections >= " << worker_connections;
4912c593315Sopenharmony_ci      }
4922c593315Sopenharmony_ci
4932c593315Sopenharmony_ci      close(wev.client_fd);
4942c593315Sopenharmony_ci
4952c593315Sopenharmony_ci      break;
4962c593315Sopenharmony_ci    }
4972c593315Sopenharmony_ci
4982c593315Sopenharmony_ci    auto client_handler =
4992c593315Sopenharmony_ci        tls::accept_connection(this, wev.client_fd, &wev.client_addr.sa,
5002c593315Sopenharmony_ci                               wev.client_addrlen, wev.faddr);
5012c593315Sopenharmony_ci    if (!client_handler) {
5022c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
5032c593315Sopenharmony_ci        WLOG(ERROR, this) << "ClientHandler creation failed";
5042c593315Sopenharmony_ci      }
5052c593315Sopenharmony_ci      close(wev.client_fd);
5062c593315Sopenharmony_ci      break;
5072c593315Sopenharmony_ci    }
5082c593315Sopenharmony_ci
5092c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
5102c593315Sopenharmony_ci      WLOG(INFO, this) << "CLIENT_HANDLER:" << client_handler << " created ";
5112c593315Sopenharmony_ci    }
5122c593315Sopenharmony_ci
5132c593315Sopenharmony_ci    break;
5142c593315Sopenharmony_ci  }
5152c593315Sopenharmony_ci  case WorkerEventType::REOPEN_LOG:
5162c593315Sopenharmony_ci    WLOG(NOTICE, this) << "Reopening log files: worker process (thread " << this
5172c593315Sopenharmony_ci                       << ")";
5182c593315Sopenharmony_ci
5192c593315Sopenharmony_ci    reopen_log_files(config->logging);
5202c593315Sopenharmony_ci
5212c593315Sopenharmony_ci    break;
5222c593315Sopenharmony_ci  case WorkerEventType::GRACEFUL_SHUTDOWN:
5232c593315Sopenharmony_ci    WLOG(NOTICE, this) << "Graceful shutdown commencing";
5242c593315Sopenharmony_ci
5252c593315Sopenharmony_ci    graceful_shutdown_ = true;
5262c593315Sopenharmony_ci
5272c593315Sopenharmony_ci    if (worker_stat_.num_connections == 0 &&
5282c593315Sopenharmony_ci        worker_stat_.num_close_waits == 0) {
5292c593315Sopenharmony_ci      ev_break(loop_);
5302c593315Sopenharmony_ci
5312c593315Sopenharmony_ci      return;
5322c593315Sopenharmony_ci    }
5332c593315Sopenharmony_ci
5342c593315Sopenharmony_ci    break;
5352c593315Sopenharmony_ci  case WorkerEventType::REPLACE_DOWNSTREAM:
5362c593315Sopenharmony_ci    WLOG(NOTICE, this) << "Replace downstream";
5372c593315Sopenharmony_ci
5382c593315Sopenharmony_ci    replace_downstream_config(wev.downstreamconf);
5392c593315Sopenharmony_ci
5402c593315Sopenharmony_ci    break;
5412c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
5422c593315Sopenharmony_ci  case WorkerEventType::QUIC_PKT_FORWARD: {
5432c593315Sopenharmony_ci    const UpstreamAddr *faddr;
5442c593315Sopenharmony_ci
5452c593315Sopenharmony_ci    if (wev.quic_pkt->upstream_addr_index == static_cast<size_t>(-1)) {
5462c593315Sopenharmony_ci      faddr = find_quic_upstream_addr(wev.quic_pkt->local_addr);
5472c593315Sopenharmony_ci      if (faddr == nullptr) {
5482c593315Sopenharmony_ci        LOG(ERROR) << "No suitable upstream address found";
5492c593315Sopenharmony_ci
5502c593315Sopenharmony_ci        break;
5512c593315Sopenharmony_ci      }
5522c593315Sopenharmony_ci    } else if (quic_upstream_addrs_.size() <=
5532c593315Sopenharmony_ci               wev.quic_pkt->upstream_addr_index) {
5542c593315Sopenharmony_ci      LOG(ERROR) << "upstream_addr_index is too large";
5552c593315Sopenharmony_ci
5562c593315Sopenharmony_ci      break;
5572c593315Sopenharmony_ci    } else {
5582c593315Sopenharmony_ci      faddr = &quic_upstream_addrs_[wev.quic_pkt->upstream_addr_index];
5592c593315Sopenharmony_ci    }
5602c593315Sopenharmony_ci
5612c593315Sopenharmony_ci    quic_conn_handler_.handle_packet(
5622c593315Sopenharmony_ci        faddr, wev.quic_pkt->remote_addr, wev.quic_pkt->local_addr,
5632c593315Sopenharmony_ci        wev.quic_pkt->pi, wev.quic_pkt->data.data(), wev.quic_pkt->data.size());
5642c593315Sopenharmony_ci
5652c593315Sopenharmony_ci    break;
5662c593315Sopenharmony_ci  }
5672c593315Sopenharmony_ci#endif // ENABLE_HTTP3
5682c593315Sopenharmony_ci  default:
5692c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
5702c593315Sopenharmony_ci      WLOG(INFO, this) << "unknown event type " << static_cast<int>(wev.type);
5712c593315Sopenharmony_ci    }
5722c593315Sopenharmony_ci  }
5732c593315Sopenharmony_ci}
5742c593315Sopenharmony_ci
5752c593315Sopenharmony_citls::CertLookupTree *Worker::get_cert_lookup_tree() const { return cert_tree_; }
5762c593315Sopenharmony_ci
5772c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
5782c593315Sopenharmony_citls::CertLookupTree *Worker::get_quic_cert_lookup_tree() const {
5792c593315Sopenharmony_ci  return quic_cert_tree_;
5802c593315Sopenharmony_ci}
5812c593315Sopenharmony_ci#endif // ENABLE_HTTP3
5822c593315Sopenharmony_ci
5832c593315Sopenharmony_cistd::shared_ptr<TicketKeys> Worker::get_ticket_keys() {
5842c593315Sopenharmony_ci#ifdef HAVE_ATOMIC_STD_SHARED_PTR
5852c593315Sopenharmony_ci  return std::atomic_load_explicit(&ticket_keys_, std::memory_order_acquire);
5862c593315Sopenharmony_ci#else  // !HAVE_ATOMIC_STD_SHARED_PTR
5872c593315Sopenharmony_ci  std::lock_guard<std::mutex> g(ticket_keys_m_);
5882c593315Sopenharmony_ci  return ticket_keys_;
5892c593315Sopenharmony_ci#endif // !HAVE_ATOMIC_STD_SHARED_PTR
5902c593315Sopenharmony_ci}
5912c593315Sopenharmony_ci
5922c593315Sopenharmony_civoid Worker::set_ticket_keys(std::shared_ptr<TicketKeys> ticket_keys) {
5932c593315Sopenharmony_ci#ifdef HAVE_ATOMIC_STD_SHARED_PTR
5942c593315Sopenharmony_ci  // This is single writer
5952c593315Sopenharmony_ci  std::atomic_store_explicit(&ticket_keys_, std::move(ticket_keys),
5962c593315Sopenharmony_ci                             std::memory_order_release);
5972c593315Sopenharmony_ci#else  // !HAVE_ATOMIC_STD_SHARED_PTR
5982c593315Sopenharmony_ci  std::lock_guard<std::mutex> g(ticket_keys_m_);
5992c593315Sopenharmony_ci  ticket_keys_ = std::move(ticket_keys);
6002c593315Sopenharmony_ci#endif // !HAVE_ATOMIC_STD_SHARED_PTR
6012c593315Sopenharmony_ci}
6022c593315Sopenharmony_ci
6032c593315Sopenharmony_ciWorkerStat *Worker::get_worker_stat() { return &worker_stat_; }
6042c593315Sopenharmony_ci
6052c593315Sopenharmony_cistruct ev_loop *Worker::get_loop() const {
6062c593315Sopenharmony_ci  return loop_;
6072c593315Sopenharmony_ci}
6082c593315Sopenharmony_ci
6092c593315Sopenharmony_ciSSL_CTX *Worker::get_sv_ssl_ctx() const { return sv_ssl_ctx_; }
6102c593315Sopenharmony_ci
6112c593315Sopenharmony_ciSSL_CTX *Worker::get_cl_ssl_ctx() const { return cl_ssl_ctx_; }
6122c593315Sopenharmony_ci
6132c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
6142c593315Sopenharmony_ciSSL_CTX *Worker::get_quic_sv_ssl_ctx() const { return quic_sv_ssl_ctx_; }
6152c593315Sopenharmony_ci#endif // ENABLE_HTTP3
6162c593315Sopenharmony_ci
6172c593315Sopenharmony_civoid Worker::set_graceful_shutdown(bool f) { graceful_shutdown_ = f; }
6182c593315Sopenharmony_ci
6192c593315Sopenharmony_cibool Worker::get_graceful_shutdown() const { return graceful_shutdown_; }
6202c593315Sopenharmony_ci
6212c593315Sopenharmony_ciMemchunkPool *Worker::get_mcpool() { return &mcpool_; }
6222c593315Sopenharmony_ci
6232c593315Sopenharmony_ciMemcachedDispatcher *Worker::get_session_cache_memcached_dispatcher() {
6242c593315Sopenharmony_ci  return session_cache_memcached_dispatcher_.get();
6252c593315Sopenharmony_ci}
6262c593315Sopenharmony_ci
6272c593315Sopenharmony_cistd::mt19937 &Worker::get_randgen() { return randgen_; }
6282c593315Sopenharmony_ci
6292c593315Sopenharmony_ci#ifdef HAVE_MRUBY
6302c593315Sopenharmony_ciint Worker::create_mruby_context() {
6312c593315Sopenharmony_ci  mruby_ctx_ = mruby::create_mruby_context(StringRef{get_config()->mruby_file});
6322c593315Sopenharmony_ci  if (!mruby_ctx_) {
6332c593315Sopenharmony_ci    return -1;
6342c593315Sopenharmony_ci  }
6352c593315Sopenharmony_ci
6362c593315Sopenharmony_ci  return 0;
6372c593315Sopenharmony_ci}
6382c593315Sopenharmony_ci
6392c593315Sopenharmony_cimruby::MRubyContext *Worker::get_mruby_context() const {
6402c593315Sopenharmony_ci  return mruby_ctx_.get();
6412c593315Sopenharmony_ci}
6422c593315Sopenharmony_ci#endif // HAVE_MRUBY
6432c593315Sopenharmony_ci
6442c593315Sopenharmony_cistd::vector<std::shared_ptr<DownstreamAddrGroup>> &
6452c593315Sopenharmony_ciWorker::get_downstream_addr_groups() {
6462c593315Sopenharmony_ci  return downstream_addr_groups_;
6472c593315Sopenharmony_ci}
6482c593315Sopenharmony_ci
6492c593315Sopenharmony_ciConnectBlocker *Worker::get_connect_blocker() const {
6502c593315Sopenharmony_ci  return connect_blocker_.get();
6512c593315Sopenharmony_ci}
6522c593315Sopenharmony_ci
6532c593315Sopenharmony_ciconst DownstreamConfig *Worker::get_downstream_config() const {
6542c593315Sopenharmony_ci  return downstreamconf_.get();
6552c593315Sopenharmony_ci}
6562c593315Sopenharmony_ci
6572c593315Sopenharmony_ciConnectionHandler *Worker::get_connection_handler() const {
6582c593315Sopenharmony_ci  return conn_handler_;
6592c593315Sopenharmony_ci}
6602c593315Sopenharmony_ci
6612c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
6622c593315Sopenharmony_ciQUICConnectionHandler *Worker::get_quic_connection_handler() {
6632c593315Sopenharmony_ci  return &quic_conn_handler_;
6642c593315Sopenharmony_ci}
6652c593315Sopenharmony_ci#endif // ENABLE_HTTP3
6662c593315Sopenharmony_ci
6672c593315Sopenharmony_ciDNSTracker *Worker::get_dns_tracker() { return &dns_tracker_; }
6682c593315Sopenharmony_ci
6692c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
6702c593315Sopenharmony_ci#  ifdef HAVE_LIBBPF
6712c593315Sopenharmony_cibool Worker::should_attach_bpf() const {
6722c593315Sopenharmony_ci  auto config = get_config();
6732c593315Sopenharmony_ci  auto &quicconf = config->quic;
6742c593315Sopenharmony_ci  auto &apiconf = config->api;
6752c593315Sopenharmony_ci
6762c593315Sopenharmony_ci  if (quicconf.bpf.disabled) {
6772c593315Sopenharmony_ci    return false;
6782c593315Sopenharmony_ci  }
6792c593315Sopenharmony_ci
6802c593315Sopenharmony_ci  if (!config->single_thread && apiconf.enabled) {
6812c593315Sopenharmony_ci    return index_ == 1;
6822c593315Sopenharmony_ci  }
6832c593315Sopenharmony_ci
6842c593315Sopenharmony_ci  return index_ == 0;
6852c593315Sopenharmony_ci}
6862c593315Sopenharmony_ci
6872c593315Sopenharmony_cibool Worker::should_update_bpf_map() const {
6882c593315Sopenharmony_ci  auto config = get_config();
6892c593315Sopenharmony_ci  auto &quicconf = config->quic;
6902c593315Sopenharmony_ci
6912c593315Sopenharmony_ci  return !quicconf.bpf.disabled;
6922c593315Sopenharmony_ci}
6932c593315Sopenharmony_ci
6942c593315Sopenharmony_ciuint32_t Worker::compute_sk_index() const {
6952c593315Sopenharmony_ci  auto config = get_config();
6962c593315Sopenharmony_ci  auto &apiconf = config->api;
6972c593315Sopenharmony_ci
6982c593315Sopenharmony_ci  if (!config->single_thread && apiconf.enabled) {
6992c593315Sopenharmony_ci    return index_ - 1;
7002c593315Sopenharmony_ci  }
7012c593315Sopenharmony_ci
7022c593315Sopenharmony_ci  return index_;
7032c593315Sopenharmony_ci}
7042c593315Sopenharmony_ci#  endif // HAVE_LIBBPF
7052c593315Sopenharmony_ci
7062c593315Sopenharmony_ciint Worker::setup_quic_server_socket() {
7072c593315Sopenharmony_ci  size_t n = 0;
7082c593315Sopenharmony_ci
7092c593315Sopenharmony_ci  for (auto &addr : quic_upstream_addrs_) {
7102c593315Sopenharmony_ci    assert(!addr.host_unix);
7112c593315Sopenharmony_ci    if (create_quic_server_socket(addr) != 0) {
7122c593315Sopenharmony_ci      return -1;
7132c593315Sopenharmony_ci    }
7142c593315Sopenharmony_ci
7152c593315Sopenharmony_ci    // Make sure that each endpoint has a unique address.
7162c593315Sopenharmony_ci    for (size_t i = 0; i < n; ++i) {
7172c593315Sopenharmony_ci      const auto &a = quic_upstream_addrs_[i];
7182c593315Sopenharmony_ci
7192c593315Sopenharmony_ci      if (addr.hostport == a.hostport) {
7202c593315Sopenharmony_ci        LOG(FATAL)
7212c593315Sopenharmony_ci            << "QUIC frontend endpoint must be unique: a duplicate found for "
7222c593315Sopenharmony_ci            << addr.hostport;
7232c593315Sopenharmony_ci
7242c593315Sopenharmony_ci        return -1;
7252c593315Sopenharmony_ci      }
7262c593315Sopenharmony_ci    }
7272c593315Sopenharmony_ci
7282c593315Sopenharmony_ci    ++n;
7292c593315Sopenharmony_ci
7302c593315Sopenharmony_ci    quic_listeners_.emplace_back(std::make_unique<QUICListener>(&addr, this));
7312c593315Sopenharmony_ci  }
7322c593315Sopenharmony_ci
7332c593315Sopenharmony_ci  return 0;
7342c593315Sopenharmony_ci}
7352c593315Sopenharmony_ci
7362c593315Sopenharmony_ciint Worker::create_quic_server_socket(UpstreamAddr &faddr) {
7372c593315Sopenharmony_ci  std::array<char, STRERROR_BUFSIZE> errbuf;
7382c593315Sopenharmony_ci  int fd = -1;
7392c593315Sopenharmony_ci  int rv;
7402c593315Sopenharmony_ci
7412c593315Sopenharmony_ci  auto service = util::utos(faddr.port);
7422c593315Sopenharmony_ci  addrinfo hints{};
7432c593315Sopenharmony_ci  hints.ai_family = faddr.family;
7442c593315Sopenharmony_ci  hints.ai_socktype = SOCK_DGRAM;
7452c593315Sopenharmony_ci  hints.ai_flags = AI_PASSIVE;
7462c593315Sopenharmony_ci#  ifdef AI_ADDRCONFIG
7472c593315Sopenharmony_ci  hints.ai_flags |= AI_ADDRCONFIG;
7482c593315Sopenharmony_ci#  endif // AI_ADDRCONFIG
7492c593315Sopenharmony_ci
7502c593315Sopenharmony_ci  auto node =
7512c593315Sopenharmony_ci      faddr.host == StringRef::from_lit("*") ? nullptr : faddr.host.c_str();
7522c593315Sopenharmony_ci
7532c593315Sopenharmony_ci  addrinfo *res, *rp;
7542c593315Sopenharmony_ci  rv = getaddrinfo(node, service.c_str(), &hints, &res);
7552c593315Sopenharmony_ci#  ifdef AI_ADDRCONFIG
7562c593315Sopenharmony_ci  if (rv != 0) {
7572c593315Sopenharmony_ci    // Retry without AI_ADDRCONFIG
7582c593315Sopenharmony_ci    hints.ai_flags &= ~AI_ADDRCONFIG;
7592c593315Sopenharmony_ci    rv = getaddrinfo(node, service.c_str(), &hints, &res);
7602c593315Sopenharmony_ci  }
7612c593315Sopenharmony_ci#  endif // AI_ADDRCONFIG
7622c593315Sopenharmony_ci  if (rv != 0) {
7632c593315Sopenharmony_ci    LOG(FATAL) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
7642c593315Sopenharmony_ci               << " address for " << faddr.host << ", port " << faddr.port
7652c593315Sopenharmony_ci               << ": " << gai_strerror(rv);
7662c593315Sopenharmony_ci    return -1;
7672c593315Sopenharmony_ci  }
7682c593315Sopenharmony_ci
7692c593315Sopenharmony_ci  auto res_d = defer(freeaddrinfo, res);
7702c593315Sopenharmony_ci
7712c593315Sopenharmony_ci  std::array<char, NI_MAXHOST> host;
7722c593315Sopenharmony_ci
7732c593315Sopenharmony_ci  for (rp = res; rp; rp = rp->ai_next) {
7742c593315Sopenharmony_ci    rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host.data(), host.size(),
7752c593315Sopenharmony_ci                     nullptr, 0, NI_NUMERICHOST);
7762c593315Sopenharmony_ci    if (rv != 0) {
7772c593315Sopenharmony_ci      LOG(WARN) << "getnameinfo() failed: " << gai_strerror(rv);
7782c593315Sopenharmony_ci      continue;
7792c593315Sopenharmony_ci    }
7802c593315Sopenharmony_ci
7812c593315Sopenharmony_ci#  ifdef SOCK_NONBLOCK
7822c593315Sopenharmony_ci    fd = socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
7832c593315Sopenharmony_ci                rp->ai_protocol);
7842c593315Sopenharmony_ci    if (fd == -1) {
7852c593315Sopenharmony_ci      auto error = errno;
7862c593315Sopenharmony_ci      LOG(WARN) << "socket() syscall failed: "
7872c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
7882c593315Sopenharmony_ci      continue;
7892c593315Sopenharmony_ci    }
7902c593315Sopenharmony_ci#  else  // !SOCK_NONBLOCK
7912c593315Sopenharmony_ci    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
7922c593315Sopenharmony_ci    if (fd == -1) {
7932c593315Sopenharmony_ci      auto error = errno;
7942c593315Sopenharmony_ci      LOG(WARN) << "socket() syscall failed: "
7952c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
7962c593315Sopenharmony_ci      continue;
7972c593315Sopenharmony_ci    }
7982c593315Sopenharmony_ci    util::make_socket_nonblocking(fd);
7992c593315Sopenharmony_ci    util::make_socket_closeonexec(fd);
8002c593315Sopenharmony_ci#  endif // !SOCK_NONBLOCK
8012c593315Sopenharmony_ci
8022c593315Sopenharmony_ci    int val = 1;
8032c593315Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
8042c593315Sopenharmony_ci                   static_cast<socklen_t>(sizeof(val))) == -1) {
8052c593315Sopenharmony_ci      auto error = errno;
8062c593315Sopenharmony_ci      LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
8072c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
8082c593315Sopenharmony_ci      close(fd);
8092c593315Sopenharmony_ci      continue;
8102c593315Sopenharmony_ci    }
8112c593315Sopenharmony_ci
8122c593315Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val,
8132c593315Sopenharmony_ci                   static_cast<socklen_t>(sizeof(val))) == -1) {
8142c593315Sopenharmony_ci      auto error = errno;
8152c593315Sopenharmony_ci      LOG(WARN) << "Failed to set SO_REUSEPORT option to listener socket: "
8162c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
8172c593315Sopenharmony_ci      close(fd);
8182c593315Sopenharmony_ci      continue;
8192c593315Sopenharmony_ci    }
8202c593315Sopenharmony_ci
8212c593315Sopenharmony_ci    if (faddr.family == AF_INET6) {
8222c593315Sopenharmony_ci#  ifdef IPV6_V6ONLY
8232c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
8242c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
8252c593315Sopenharmony_ci        auto error = errno;
8262c593315Sopenharmony_ci        LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
8272c593315Sopenharmony_ci                  << xsi_strerror(error, errbuf.data(), errbuf.size());
8282c593315Sopenharmony_ci        close(fd);
8292c593315Sopenharmony_ci        continue;
8302c593315Sopenharmony_ci      }
8312c593315Sopenharmony_ci#  endif // IPV6_V6ONLY
8322c593315Sopenharmony_ci
8332c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
8342c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
8352c593315Sopenharmony_ci        auto error = errno;
8362c593315Sopenharmony_ci        LOG(WARN)
8372c593315Sopenharmony_ci            << "Failed to set IPV6_RECVPKTINFO option to listener socket: "
8382c593315Sopenharmony_ci            << xsi_strerror(error, errbuf.data(), errbuf.size());
8392c593315Sopenharmony_ci        close(fd);
8402c593315Sopenharmony_ci        continue;
8412c593315Sopenharmony_ci      }
8422c593315Sopenharmony_ci
8432c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &val,
8442c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
8452c593315Sopenharmony_ci        auto error = errno;
8462c593315Sopenharmony_ci        LOG(WARN) << "Failed to set IPV6_RECVTCLASS option to listener socket: "
8472c593315Sopenharmony_ci                  << xsi_strerror(error, errbuf.data(), errbuf.size());
8482c593315Sopenharmony_ci        close(fd);
8492c593315Sopenharmony_ci        continue;
8502c593315Sopenharmony_ci      }
8512c593315Sopenharmony_ci
8522c593315Sopenharmony_ci#  if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
8532c593315Sopenharmony_ci      int mtu_disc = IPV6_PMTUDISC_DO;
8542c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_disc,
8552c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(mtu_disc))) == -1) {
8562c593315Sopenharmony_ci        auto error = errno;
8572c593315Sopenharmony_ci        LOG(WARN)
8582c593315Sopenharmony_ci            << "Failed to set IPV6_MTU_DISCOVER option to listener socket: "
8592c593315Sopenharmony_ci            << xsi_strerror(error, errbuf.data(), errbuf.size());
8602c593315Sopenharmony_ci        close(fd);
8612c593315Sopenharmony_ci        continue;
8622c593315Sopenharmony_ci      }
8632c593315Sopenharmony_ci#  endif // defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
8642c593315Sopenharmony_ci    } else {
8652c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val,
8662c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
8672c593315Sopenharmony_ci        auto error = errno;
8682c593315Sopenharmony_ci        LOG(WARN) << "Failed to set IP_PKTINFO option to listener socket: "
8692c593315Sopenharmony_ci                  << xsi_strerror(error, errbuf.data(), errbuf.size());
8702c593315Sopenharmony_ci        close(fd);
8712c593315Sopenharmony_ci        continue;
8722c593315Sopenharmony_ci      }
8732c593315Sopenharmony_ci
8742c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &val,
8752c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
8762c593315Sopenharmony_ci        auto error = errno;
8772c593315Sopenharmony_ci        LOG(WARN) << "Failed to set IP_RECVTOS option to listener socket: "
8782c593315Sopenharmony_ci                  << xsi_strerror(error, errbuf.data(), errbuf.size());
8792c593315Sopenharmony_ci        close(fd);
8802c593315Sopenharmony_ci        continue;
8812c593315Sopenharmony_ci      }
8822c593315Sopenharmony_ci
8832c593315Sopenharmony_ci#  if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
8842c593315Sopenharmony_ci      int mtu_disc = IP_PMTUDISC_DO;
8852c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_disc,
8862c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(mtu_disc))) == -1) {
8872c593315Sopenharmony_ci        auto error = errno;
8882c593315Sopenharmony_ci        LOG(WARN) << "Failed to set IP_MTU_DISCOVER option to listener socket: "
8892c593315Sopenharmony_ci                  << xsi_strerror(error, errbuf.data(), errbuf.size());
8902c593315Sopenharmony_ci        close(fd);
8912c593315Sopenharmony_ci        continue;
8922c593315Sopenharmony_ci      }
8932c593315Sopenharmony_ci#  endif // defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
8942c593315Sopenharmony_ci    }
8952c593315Sopenharmony_ci
8962c593315Sopenharmony_ci#  ifdef UDP_GRO
8972c593315Sopenharmony_ci    if (setsockopt(fd, IPPROTO_UDP, UDP_GRO, &val, sizeof(val)) == -1) {
8982c593315Sopenharmony_ci      auto error = errno;
8992c593315Sopenharmony_ci      LOG(WARN) << "Failed to set UDP_GRO option to listener socket: "
9002c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
9012c593315Sopenharmony_ci      close(fd);
9022c593315Sopenharmony_ci      continue;
9032c593315Sopenharmony_ci    }
9042c593315Sopenharmony_ci#  endif // UDP_GRO
9052c593315Sopenharmony_ci
9062c593315Sopenharmony_ci    if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
9072c593315Sopenharmony_ci      auto error = errno;
9082c593315Sopenharmony_ci      LOG(WARN) << "bind() syscall failed: "
9092c593315Sopenharmony_ci                << xsi_strerror(error, errbuf.data(), errbuf.size());
9102c593315Sopenharmony_ci      close(fd);
9112c593315Sopenharmony_ci      continue;
9122c593315Sopenharmony_ci    }
9132c593315Sopenharmony_ci
9142c593315Sopenharmony_ci#  ifdef HAVE_LIBBPF
9152c593315Sopenharmony_ci    auto config = get_config();
9162c593315Sopenharmony_ci
9172c593315Sopenharmony_ci    auto &quic_bpf_refs = conn_handler_->get_quic_bpf_refs();
9182c593315Sopenharmony_ci
9192c593315Sopenharmony_ci    if (should_attach_bpf()) {
9202c593315Sopenharmony_ci      auto &bpfconf = config->quic.bpf;
9212c593315Sopenharmony_ci
9222c593315Sopenharmony_ci      auto obj = bpf_object__open_file(bpfconf.prog_file.c_str(), nullptr);
9232c593315Sopenharmony_ci      if (!obj) {
9242c593315Sopenharmony_ci        auto error = errno;
9252c593315Sopenharmony_ci        LOG(FATAL) << "Failed to open bpf object file: "
9262c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9272c593315Sopenharmony_ci        close(fd);
9282c593315Sopenharmony_ci        return -1;
9292c593315Sopenharmony_ci      }
9302c593315Sopenharmony_ci
9312c593315Sopenharmony_ci      rv = bpf_object__load(obj);
9322c593315Sopenharmony_ci      if (rv != 0) {
9332c593315Sopenharmony_ci        auto error = errno;
9342c593315Sopenharmony_ci        LOG(FATAL) << "Failed to load bpf object file: "
9352c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9362c593315Sopenharmony_ci        close(fd);
9372c593315Sopenharmony_ci        return -1;
9382c593315Sopenharmony_ci      }
9392c593315Sopenharmony_ci
9402c593315Sopenharmony_ci      auto prog = bpf_object__find_program_by_name(obj, "select_reuseport");
9412c593315Sopenharmony_ci      if (!prog) {
9422c593315Sopenharmony_ci        auto error = errno;
9432c593315Sopenharmony_ci        LOG(FATAL) << "Failed to find sk_reuseport program: "
9442c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9452c593315Sopenharmony_ci        close(fd);
9462c593315Sopenharmony_ci        return -1;
9472c593315Sopenharmony_ci      }
9482c593315Sopenharmony_ci
9492c593315Sopenharmony_ci      auto &ref = quic_bpf_refs[faddr.index];
9502c593315Sopenharmony_ci
9512c593315Sopenharmony_ci      ref.obj = obj;
9522c593315Sopenharmony_ci
9532c593315Sopenharmony_ci      ref.reuseport_array =
9542c593315Sopenharmony_ci          bpf_object__find_map_by_name(obj, "reuseport_array");
9552c593315Sopenharmony_ci      if (!ref.reuseport_array) {
9562c593315Sopenharmony_ci        auto error = errno;
9572c593315Sopenharmony_ci        LOG(FATAL) << "Failed to get reuseport_array: "
9582c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9592c593315Sopenharmony_ci        close(fd);
9602c593315Sopenharmony_ci        return -1;
9612c593315Sopenharmony_ci      }
9622c593315Sopenharmony_ci
9632c593315Sopenharmony_ci      ref.cid_prefix_map = bpf_object__find_map_by_name(obj, "cid_prefix_map");
9642c593315Sopenharmony_ci      if (!ref.cid_prefix_map) {
9652c593315Sopenharmony_ci        auto error = errno;
9662c593315Sopenharmony_ci        LOG(FATAL) << "Failed to get cid_prefix_map: "
9672c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9682c593315Sopenharmony_ci        close(fd);
9692c593315Sopenharmony_ci        return -1;
9702c593315Sopenharmony_ci      }
9712c593315Sopenharmony_ci
9722c593315Sopenharmony_ci      auto sk_info = bpf_object__find_map_by_name(obj, "sk_info");
9732c593315Sopenharmony_ci      if (!sk_info) {
9742c593315Sopenharmony_ci        auto error = errno;
9752c593315Sopenharmony_ci        LOG(FATAL) << "Failed to get sk_info: "
9762c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9772c593315Sopenharmony_ci        close(fd);
9782c593315Sopenharmony_ci        return -1;
9792c593315Sopenharmony_ci      }
9802c593315Sopenharmony_ci
9812c593315Sopenharmony_ci      constexpr uint32_t zero = 0;
9822c593315Sopenharmony_ci      uint64_t num_socks = config->num_worker;
9832c593315Sopenharmony_ci
9842c593315Sopenharmony_ci      rv = bpf_map__update_elem(sk_info, &zero, sizeof(zero), &num_socks,
9852c593315Sopenharmony_ci                                sizeof(num_socks), BPF_ANY);
9862c593315Sopenharmony_ci      if (rv != 0) {
9872c593315Sopenharmony_ci        auto error = errno;
9882c593315Sopenharmony_ci        LOG(FATAL) << "Failed to update sk_info: "
9892c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
9902c593315Sopenharmony_ci        close(fd);
9912c593315Sopenharmony_ci        return -1;
9922c593315Sopenharmony_ci      }
9932c593315Sopenharmony_ci
9942c593315Sopenharmony_ci      constexpr uint32_t key_high_idx = 1;
9952c593315Sopenharmony_ci      constexpr uint32_t key_low_idx = 2;
9962c593315Sopenharmony_ci
9972c593315Sopenharmony_ci      auto &qkms = conn_handler_->get_quic_keying_materials();
9982c593315Sopenharmony_ci      auto &qkm = qkms->keying_materials.front();
9992c593315Sopenharmony_ci
10002c593315Sopenharmony_ci      rv = bpf_map__update_elem(sk_info, &key_high_idx, sizeof(key_high_idx),
10012c593315Sopenharmony_ci                                qkm.cid_encryption_key.data(),
10022c593315Sopenharmony_ci                                qkm.cid_encryption_key.size() / 2, BPF_ANY);
10032c593315Sopenharmony_ci      if (rv != 0) {
10042c593315Sopenharmony_ci        auto error = errno;
10052c593315Sopenharmony_ci        LOG(FATAL) << "Failed to update key_high_idx sk_info: "
10062c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
10072c593315Sopenharmony_ci        close(fd);
10082c593315Sopenharmony_ci        return -1;
10092c593315Sopenharmony_ci      }
10102c593315Sopenharmony_ci
10112c593315Sopenharmony_ci      rv = bpf_map__update_elem(sk_info, &key_low_idx, sizeof(key_low_idx),
10122c593315Sopenharmony_ci                                qkm.cid_encryption_key.data() +
10132c593315Sopenharmony_ci                                    qkm.cid_encryption_key.size() / 2,
10142c593315Sopenharmony_ci                                qkm.cid_encryption_key.size() / 2, BPF_ANY);
10152c593315Sopenharmony_ci      if (rv != 0) {
10162c593315Sopenharmony_ci        auto error = errno;
10172c593315Sopenharmony_ci        LOG(FATAL) << "Failed to update key_low_idx sk_info: "
10182c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
10192c593315Sopenharmony_ci        close(fd);
10202c593315Sopenharmony_ci        return -1;
10212c593315Sopenharmony_ci      }
10222c593315Sopenharmony_ci
10232c593315Sopenharmony_ci      auto prog_fd = bpf_program__fd(prog);
10242c593315Sopenharmony_ci
10252c593315Sopenharmony_ci      if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &prog_fd,
10262c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(prog_fd))) == -1) {
10272c593315Sopenharmony_ci        LOG(FATAL) << "Failed to attach bpf program: "
10282c593315Sopenharmony_ci                   << xsi_strerror(errno, errbuf.data(), errbuf.size());
10292c593315Sopenharmony_ci        close(fd);
10302c593315Sopenharmony_ci        return -1;
10312c593315Sopenharmony_ci      }
10322c593315Sopenharmony_ci    }
10332c593315Sopenharmony_ci
10342c593315Sopenharmony_ci    if (should_update_bpf_map()) {
10352c593315Sopenharmony_ci      const auto &ref = quic_bpf_refs[faddr.index];
10362c593315Sopenharmony_ci      auto sk_index = compute_sk_index();
10372c593315Sopenharmony_ci
10382c593315Sopenharmony_ci      rv = bpf_map__update_elem(ref.reuseport_array, &sk_index,
10392c593315Sopenharmony_ci                                sizeof(sk_index), &fd, sizeof(fd), BPF_NOEXIST);
10402c593315Sopenharmony_ci      if (rv != 0) {
10412c593315Sopenharmony_ci        auto error = errno;
10422c593315Sopenharmony_ci        LOG(FATAL) << "Failed to update reuseport_array: "
10432c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
10442c593315Sopenharmony_ci        close(fd);
10452c593315Sopenharmony_ci        return -1;
10462c593315Sopenharmony_ci      }
10472c593315Sopenharmony_ci
10482c593315Sopenharmony_ci      rv = bpf_map__update_elem(ref.cid_prefix_map, cid_prefix_.data(),
10492c593315Sopenharmony_ci                                cid_prefix_.size(), &sk_index, sizeof(sk_index),
10502c593315Sopenharmony_ci                                BPF_NOEXIST);
10512c593315Sopenharmony_ci      if (rv != 0) {
10522c593315Sopenharmony_ci        auto error = errno;
10532c593315Sopenharmony_ci        LOG(FATAL) << "Failed to update cid_prefix_map: "
10542c593315Sopenharmony_ci                   << xsi_strerror(error, errbuf.data(), errbuf.size());
10552c593315Sopenharmony_ci        close(fd);
10562c593315Sopenharmony_ci        return -1;
10572c593315Sopenharmony_ci      }
10582c593315Sopenharmony_ci    }
10592c593315Sopenharmony_ci#  endif // HAVE_LIBBPF
10602c593315Sopenharmony_ci
10612c593315Sopenharmony_ci    break;
10622c593315Sopenharmony_ci  }
10632c593315Sopenharmony_ci
10642c593315Sopenharmony_ci  if (!rp) {
10652c593315Sopenharmony_ci    LOG(FATAL) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
10662c593315Sopenharmony_ci               << " socket failed";
10672c593315Sopenharmony_ci
10682c593315Sopenharmony_ci    return -1;
10692c593315Sopenharmony_ci  }
10702c593315Sopenharmony_ci
10712c593315Sopenharmony_ci  faddr.fd = fd;
10722c593315Sopenharmony_ci  faddr.hostport = util::make_http_hostport(mod_config()->balloc,
10732c593315Sopenharmony_ci                                            StringRef{host.data()}, faddr.port);
10742c593315Sopenharmony_ci
10752c593315Sopenharmony_ci  LOG(NOTICE) << "Listening on " << faddr.hostport << ", quic";
10762c593315Sopenharmony_ci
10772c593315Sopenharmony_ci  return 0;
10782c593315Sopenharmony_ci}
10792c593315Sopenharmony_ci
10802c593315Sopenharmony_ciconst uint8_t *Worker::get_cid_prefix() const { return cid_prefix_.data(); }
10812c593315Sopenharmony_ci
10822c593315Sopenharmony_ciconst UpstreamAddr *Worker::find_quic_upstream_addr(const Address &local_addr) {
10832c593315Sopenharmony_ci  std::array<char, NI_MAXHOST> host;
10842c593315Sopenharmony_ci
10852c593315Sopenharmony_ci  auto rv = getnameinfo(&local_addr.su.sa, local_addr.len, host.data(),
10862c593315Sopenharmony_ci                        host.size(), nullptr, 0, NI_NUMERICHOST);
10872c593315Sopenharmony_ci  if (rv != 0) {
10882c593315Sopenharmony_ci    LOG(ERROR) << "getnameinfo: " << gai_strerror(rv);
10892c593315Sopenharmony_ci
10902c593315Sopenharmony_ci    return nullptr;
10912c593315Sopenharmony_ci  }
10922c593315Sopenharmony_ci
10932c593315Sopenharmony_ci  uint16_t port;
10942c593315Sopenharmony_ci
10952c593315Sopenharmony_ci  switch (local_addr.su.sa.sa_family) {
10962c593315Sopenharmony_ci  case AF_INET:
10972c593315Sopenharmony_ci    port = htons(local_addr.su.in.sin_port);
10982c593315Sopenharmony_ci
10992c593315Sopenharmony_ci    break;
11002c593315Sopenharmony_ci  case AF_INET6:
11012c593315Sopenharmony_ci    port = htons(local_addr.su.in6.sin6_port);
11022c593315Sopenharmony_ci
11032c593315Sopenharmony_ci    break;
11042c593315Sopenharmony_ci  default:
11052c593315Sopenharmony_ci    assert(0);
11062c593315Sopenharmony_ci    abort();
11072c593315Sopenharmony_ci  }
11082c593315Sopenharmony_ci
11092c593315Sopenharmony_ci  std::array<char, util::max_hostport> hostport_buf;
11102c593315Sopenharmony_ci
11112c593315Sopenharmony_ci  auto hostport = util::make_http_hostport(std::begin(hostport_buf),
11122c593315Sopenharmony_ci                                           StringRef{host.data()}, port);
11132c593315Sopenharmony_ci  const UpstreamAddr *fallback_faddr = nullptr;
11142c593315Sopenharmony_ci
11152c593315Sopenharmony_ci  for (auto &faddr : quic_upstream_addrs_) {
11162c593315Sopenharmony_ci    if (faddr.hostport == hostport) {
11172c593315Sopenharmony_ci      return &faddr;
11182c593315Sopenharmony_ci    }
11192c593315Sopenharmony_ci
11202c593315Sopenharmony_ci    if (faddr.port != port || faddr.family != local_addr.su.sa.sa_family) {
11212c593315Sopenharmony_ci      continue;
11222c593315Sopenharmony_ci    }
11232c593315Sopenharmony_ci
11242c593315Sopenharmony_ci    if (faddr.port == 443 || faddr.port == 80) {
11252c593315Sopenharmony_ci      switch (faddr.family) {
11262c593315Sopenharmony_ci      case AF_INET:
11272c593315Sopenharmony_ci        if (util::streq(faddr.hostport, StringRef::from_lit("0.0.0.0"))) {
11282c593315Sopenharmony_ci          fallback_faddr = &faddr;
11292c593315Sopenharmony_ci        }
11302c593315Sopenharmony_ci
11312c593315Sopenharmony_ci        break;
11322c593315Sopenharmony_ci      case AF_INET6:
11332c593315Sopenharmony_ci        if (util::streq(faddr.hostport, StringRef::from_lit("[::]"))) {
11342c593315Sopenharmony_ci          fallback_faddr = &faddr;
11352c593315Sopenharmony_ci        }
11362c593315Sopenharmony_ci
11372c593315Sopenharmony_ci        break;
11382c593315Sopenharmony_ci      default:
11392c593315Sopenharmony_ci        assert(0);
11402c593315Sopenharmony_ci      }
11412c593315Sopenharmony_ci    } else {
11422c593315Sopenharmony_ci      switch (faddr.family) {
11432c593315Sopenharmony_ci      case AF_INET:
11442c593315Sopenharmony_ci        if (util::starts_with(faddr.hostport,
11452c593315Sopenharmony_ci                              StringRef::from_lit("0.0.0.0:"))) {
11462c593315Sopenharmony_ci          fallback_faddr = &faddr;
11472c593315Sopenharmony_ci        }
11482c593315Sopenharmony_ci
11492c593315Sopenharmony_ci        break;
11502c593315Sopenharmony_ci      case AF_INET6:
11512c593315Sopenharmony_ci        if (util::starts_with(faddr.hostport, StringRef::from_lit("[::]:"))) {
11522c593315Sopenharmony_ci          fallback_faddr = &faddr;
11532c593315Sopenharmony_ci        }
11542c593315Sopenharmony_ci
11552c593315Sopenharmony_ci        break;
11562c593315Sopenharmony_ci      default:
11572c593315Sopenharmony_ci        assert(0);
11582c593315Sopenharmony_ci      }
11592c593315Sopenharmony_ci    }
11602c593315Sopenharmony_ci  }
11612c593315Sopenharmony_ci
11622c593315Sopenharmony_ci  return fallback_faddr;
11632c593315Sopenharmony_ci}
11642c593315Sopenharmony_ci#endif // ENABLE_HTTP3
11652c593315Sopenharmony_ci
11662c593315Sopenharmony_cinamespace {
11672c593315Sopenharmony_cisize_t match_downstream_addr_group_host(
11682c593315Sopenharmony_ci    const RouterConfig &routerconf, const StringRef &host,
11692c593315Sopenharmony_ci    const StringRef &path,
11702c593315Sopenharmony_ci    const std::vector<std::shared_ptr<DownstreamAddrGroup>> &groups,
11712c593315Sopenharmony_ci    size_t catch_all, BlockAllocator &balloc) {
11722c593315Sopenharmony_ci
11732c593315Sopenharmony_ci  const auto &router = routerconf.router;
11742c593315Sopenharmony_ci  const auto &rev_wildcard_router = routerconf.rev_wildcard_router;
11752c593315Sopenharmony_ci  const auto &wildcard_patterns = routerconf.wildcard_patterns;
11762c593315Sopenharmony_ci
11772c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
11782c593315Sopenharmony_ci    LOG(INFO) << "Perform mapping selection, using host=" << host
11792c593315Sopenharmony_ci              << ", path=" << path;
11802c593315Sopenharmony_ci  }
11812c593315Sopenharmony_ci
11822c593315Sopenharmony_ci  auto group = router.match(host, path);
11832c593315Sopenharmony_ci  if (group != -1) {
11842c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
11852c593315Sopenharmony_ci      LOG(INFO) << "Found pattern with query " << host << path
11862c593315Sopenharmony_ci                << ", matched pattern=" << groups[group]->pattern;
11872c593315Sopenharmony_ci    }
11882c593315Sopenharmony_ci    return group;
11892c593315Sopenharmony_ci  }
11902c593315Sopenharmony_ci
11912c593315Sopenharmony_ci  if (!wildcard_patterns.empty() && !host.empty()) {
11922c593315Sopenharmony_ci    auto rev_host_src = make_byte_ref(balloc, host.size() - 1);
11932c593315Sopenharmony_ci    auto ep =
11942c593315Sopenharmony_ci        std::copy(std::begin(host) + 1, std::end(host), rev_host_src.base);
11952c593315Sopenharmony_ci    std::reverse(rev_host_src.base, ep);
11962c593315Sopenharmony_ci    auto rev_host = StringRef{rev_host_src.base, ep};
11972c593315Sopenharmony_ci
11982c593315Sopenharmony_ci    ssize_t best_group = -1;
11992c593315Sopenharmony_ci    const RNode *last_node = nullptr;
12002c593315Sopenharmony_ci
12012c593315Sopenharmony_ci    for (;;) {
12022c593315Sopenharmony_ci      size_t nread = 0;
12032c593315Sopenharmony_ci      auto wcidx =
12042c593315Sopenharmony_ci          rev_wildcard_router.match_prefix(&nread, &last_node, rev_host);
12052c593315Sopenharmony_ci      if (wcidx == -1) {
12062c593315Sopenharmony_ci        break;
12072c593315Sopenharmony_ci      }
12082c593315Sopenharmony_ci
12092c593315Sopenharmony_ci      rev_host = StringRef{std::begin(rev_host) + nread, std::end(rev_host)};
12102c593315Sopenharmony_ci
12112c593315Sopenharmony_ci      auto &wc = wildcard_patterns[wcidx];
12122c593315Sopenharmony_ci      auto group = wc.router.match(StringRef{}, path);
12132c593315Sopenharmony_ci      if (group != -1) {
12142c593315Sopenharmony_ci        // We sorted wildcard_patterns in a way that first match is the
12152c593315Sopenharmony_ci        // longest host pattern.
12162c593315Sopenharmony_ci        if (LOG_ENABLED(INFO)) {
12172c593315Sopenharmony_ci          LOG(INFO) << "Found wildcard pattern with query " << host << path
12182c593315Sopenharmony_ci                    << ", matched pattern=" << groups[group]->pattern;
12192c593315Sopenharmony_ci        }
12202c593315Sopenharmony_ci
12212c593315Sopenharmony_ci        best_group = group;
12222c593315Sopenharmony_ci      }
12232c593315Sopenharmony_ci    }
12242c593315Sopenharmony_ci
12252c593315Sopenharmony_ci    if (best_group != -1) {
12262c593315Sopenharmony_ci      return best_group;
12272c593315Sopenharmony_ci    }
12282c593315Sopenharmony_ci  }
12292c593315Sopenharmony_ci
12302c593315Sopenharmony_ci  group = router.match(StringRef::from_lit(""), path);
12312c593315Sopenharmony_ci  if (group != -1) {
12322c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
12332c593315Sopenharmony_ci      LOG(INFO) << "Found pattern with query " << path
12342c593315Sopenharmony_ci                << ", matched pattern=" << groups[group]->pattern;
12352c593315Sopenharmony_ci    }
12362c593315Sopenharmony_ci    return group;
12372c593315Sopenharmony_ci  }
12382c593315Sopenharmony_ci
12392c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
12402c593315Sopenharmony_ci    LOG(INFO) << "None match.  Use catch-all pattern";
12412c593315Sopenharmony_ci  }
12422c593315Sopenharmony_ci  return catch_all;
12432c593315Sopenharmony_ci}
12442c593315Sopenharmony_ci} // namespace
12452c593315Sopenharmony_ci
12462c593315Sopenharmony_cisize_t match_downstream_addr_group(
12472c593315Sopenharmony_ci    const RouterConfig &routerconf, const StringRef &hostport,
12482c593315Sopenharmony_ci    const StringRef &raw_path,
12492c593315Sopenharmony_ci    const std::vector<std::shared_ptr<DownstreamAddrGroup>> &groups,
12502c593315Sopenharmony_ci    size_t catch_all, BlockAllocator &balloc) {
12512c593315Sopenharmony_ci  if (std::find(std::begin(hostport), std::end(hostport), '/') !=
12522c593315Sopenharmony_ci      std::end(hostport)) {
12532c593315Sopenharmony_ci    // We use '/' specially, and if '/' is included in host, it breaks
12542c593315Sopenharmony_ci    // our code.  Select catch-all case.
12552c593315Sopenharmony_ci    return catch_all;
12562c593315Sopenharmony_ci  }
12572c593315Sopenharmony_ci
12582c593315Sopenharmony_ci  auto fragment = std::find(std::begin(raw_path), std::end(raw_path), '#');
12592c593315Sopenharmony_ci  auto query = std::find(std::begin(raw_path), fragment, '?');
12602c593315Sopenharmony_ci  auto path = StringRef{std::begin(raw_path), query};
12612c593315Sopenharmony_ci
12622c593315Sopenharmony_ci  if (path.empty() || path[0] != '/') {
12632c593315Sopenharmony_ci    path = StringRef::from_lit("/");
12642c593315Sopenharmony_ci  }
12652c593315Sopenharmony_ci
12662c593315Sopenharmony_ci  if (hostport.empty()) {
12672c593315Sopenharmony_ci    return match_downstream_addr_group_host(routerconf, hostport, path, groups,
12682c593315Sopenharmony_ci                                            catch_all, balloc);
12692c593315Sopenharmony_ci  }
12702c593315Sopenharmony_ci
12712c593315Sopenharmony_ci  StringRef host;
12722c593315Sopenharmony_ci  if (hostport[0] == '[') {
12732c593315Sopenharmony_ci    // assume this is IPv6 numeric address
12742c593315Sopenharmony_ci    auto p = std::find(std::begin(hostport), std::end(hostport), ']');
12752c593315Sopenharmony_ci    if (p == std::end(hostport)) {
12762c593315Sopenharmony_ci      return catch_all;
12772c593315Sopenharmony_ci    }
12782c593315Sopenharmony_ci    if (p + 1 < std::end(hostport) && *(p + 1) != ':') {
12792c593315Sopenharmony_ci      return catch_all;
12802c593315Sopenharmony_ci    }
12812c593315Sopenharmony_ci    host = StringRef{std::begin(hostport), p + 1};
12822c593315Sopenharmony_ci  } else {
12832c593315Sopenharmony_ci    auto p = std::find(std::begin(hostport), std::end(hostport), ':');
12842c593315Sopenharmony_ci    if (p == std::begin(hostport)) {
12852c593315Sopenharmony_ci      return catch_all;
12862c593315Sopenharmony_ci    }
12872c593315Sopenharmony_ci    host = StringRef{std::begin(hostport), p};
12882c593315Sopenharmony_ci  }
12892c593315Sopenharmony_ci
12902c593315Sopenharmony_ci  if (std::find_if(std::begin(host), std::end(host), [](char c) {
12912c593315Sopenharmony_ci        return 'A' <= c || c <= 'Z';
12922c593315Sopenharmony_ci      }) != std::end(host)) {
12932c593315Sopenharmony_ci    auto low_host = make_byte_ref(balloc, host.size() + 1);
12942c593315Sopenharmony_ci    auto ep = std::copy(std::begin(host), std::end(host), low_host.base);
12952c593315Sopenharmony_ci    *ep = '\0';
12962c593315Sopenharmony_ci    util::inp_strlower(low_host.base, ep);
12972c593315Sopenharmony_ci    host = StringRef{low_host.base, ep};
12982c593315Sopenharmony_ci  }
12992c593315Sopenharmony_ci  return match_downstream_addr_group_host(routerconf, host, path, groups,
13002c593315Sopenharmony_ci                                          catch_all, balloc);
13012c593315Sopenharmony_ci}
13022c593315Sopenharmony_ci
13032c593315Sopenharmony_civoid downstream_failure(DownstreamAddr *addr, const Address *raddr) {
13042c593315Sopenharmony_ci  const auto &connect_blocker = addr->connect_blocker;
13052c593315Sopenharmony_ci
13062c593315Sopenharmony_ci  if (connect_blocker->in_offline()) {
13072c593315Sopenharmony_ci    return;
13082c593315Sopenharmony_ci  }
13092c593315Sopenharmony_ci
13102c593315Sopenharmony_ci  connect_blocker->on_failure();
13112c593315Sopenharmony_ci
13122c593315Sopenharmony_ci  if (addr->fall == 0) {
13132c593315Sopenharmony_ci    return;
13142c593315Sopenharmony_ci  }
13152c593315Sopenharmony_ci
13162c593315Sopenharmony_ci  auto fail_count = connect_blocker->get_fail_count();
13172c593315Sopenharmony_ci
13182c593315Sopenharmony_ci  if (fail_count >= addr->fall) {
13192c593315Sopenharmony_ci    if (raddr) {
13202c593315Sopenharmony_ci      LOG(WARN) << "Could not connect to " << util::to_numeric_addr(raddr)
13212c593315Sopenharmony_ci                << " " << fail_count
13222c593315Sopenharmony_ci                << " times in a row; considered as offline";
13232c593315Sopenharmony_ci    } else {
13242c593315Sopenharmony_ci      LOG(WARN) << "Could not connect to " << addr->host << ":" << addr->port
13252c593315Sopenharmony_ci                << " " << fail_count
13262c593315Sopenharmony_ci                << " times in a row; considered as offline";
13272c593315Sopenharmony_ci    }
13282c593315Sopenharmony_ci
13292c593315Sopenharmony_ci    connect_blocker->offline();
13302c593315Sopenharmony_ci
13312c593315Sopenharmony_ci    if (addr->rise) {
13322c593315Sopenharmony_ci      addr->live_check->schedule();
13332c593315Sopenharmony_ci    }
13342c593315Sopenharmony_ci  }
13352c593315Sopenharmony_ci}
13362c593315Sopenharmony_ci
13372c593315Sopenharmony_ci#ifdef ENABLE_HTTP3
13382c593315Sopenharmony_ciint create_cid_prefix(uint8_t *cid_prefix, const uint8_t *server_id) {
13392c593315Sopenharmony_ci  auto p = std::copy_n(server_id, SHRPX_QUIC_SERVER_IDLEN, cid_prefix);
13402c593315Sopenharmony_ci
13412c593315Sopenharmony_ci  if (RAND_bytes(p, SHRPX_QUIC_CID_PREFIXLEN - SHRPX_QUIC_SERVER_IDLEN) != 1) {
13422c593315Sopenharmony_ci    return -1;
13432c593315Sopenharmony_ci  }
13442c593315Sopenharmony_ci
13452c593315Sopenharmony_ci  return 0;
13462c593315Sopenharmony_ci}
13472c593315Sopenharmony_ci#endif // ENABLE_HTTP3
13482c593315Sopenharmony_ci
13492c593315Sopenharmony_ci} // namespace shrpx
1350