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