12c593315Sopenharmony_ci/* 22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library 32c593315Sopenharmony_ci * 42c593315Sopenharmony_ci * Copyright (c) 2016 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_live_check.h" 262c593315Sopenharmony_ci#include "shrpx_worker.h" 272c593315Sopenharmony_ci#include "shrpx_connect_blocker.h" 282c593315Sopenharmony_ci#include "shrpx_tls.h" 292c593315Sopenharmony_ci#include "shrpx_log.h" 302c593315Sopenharmony_ci 312c593315Sopenharmony_cinamespace shrpx { 322c593315Sopenharmony_ci 332c593315Sopenharmony_cinamespace { 342c593315Sopenharmony_ciconstexpr size_t MAX_BUFFER_SIZE = 4_k; 352c593315Sopenharmony_ci} // namespace 362c593315Sopenharmony_ci 372c593315Sopenharmony_cinamespace { 382c593315Sopenharmony_civoid readcb(struct ev_loop *loop, ev_io *w, int revents) { 392c593315Sopenharmony_ci int rv; 402c593315Sopenharmony_ci auto conn = static_cast<Connection *>(w->data); 412c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(conn->data); 422c593315Sopenharmony_ci 432c593315Sopenharmony_ci rv = live_check->do_read(); 442c593315Sopenharmony_ci if (rv != 0) { 452c593315Sopenharmony_ci live_check->on_failure(); 462c593315Sopenharmony_ci return; 472c593315Sopenharmony_ci } 482c593315Sopenharmony_ci} 492c593315Sopenharmony_ci} // namespace 502c593315Sopenharmony_ci 512c593315Sopenharmony_cinamespace { 522c593315Sopenharmony_civoid writecb(struct ev_loop *loop, ev_io *w, int revents) { 532c593315Sopenharmony_ci int rv; 542c593315Sopenharmony_ci auto conn = static_cast<Connection *>(w->data); 552c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(conn->data); 562c593315Sopenharmony_ci 572c593315Sopenharmony_ci rv = live_check->do_write(); 582c593315Sopenharmony_ci if (rv != 0) { 592c593315Sopenharmony_ci live_check->on_failure(); 602c593315Sopenharmony_ci return; 612c593315Sopenharmony_ci } 622c593315Sopenharmony_ci} 632c593315Sopenharmony_ci} // namespace 642c593315Sopenharmony_ci 652c593315Sopenharmony_cinamespace { 662c593315Sopenharmony_civoid timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { 672c593315Sopenharmony_ci auto conn = static_cast<Connection *>(w->data); 682c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(conn->data); 692c593315Sopenharmony_ci 702c593315Sopenharmony_ci if (w == &conn->rt && !conn->expired_rt()) { 712c593315Sopenharmony_ci return; 722c593315Sopenharmony_ci } 732c593315Sopenharmony_ci 742c593315Sopenharmony_ci live_check->on_failure(); 752c593315Sopenharmony_ci} 762c593315Sopenharmony_ci} // namespace 772c593315Sopenharmony_ci 782c593315Sopenharmony_cinamespace { 792c593315Sopenharmony_civoid backoff_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) { 802c593315Sopenharmony_ci int rv; 812c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(w->data); 822c593315Sopenharmony_ci 832c593315Sopenharmony_ci rv = live_check->initiate_connection(); 842c593315Sopenharmony_ci if (rv != 0) { 852c593315Sopenharmony_ci live_check->on_failure(); 862c593315Sopenharmony_ci return; 872c593315Sopenharmony_ci } 882c593315Sopenharmony_ci} 892c593315Sopenharmony_ci} // namespace 902c593315Sopenharmony_ci 912c593315Sopenharmony_cinamespace { 922c593315Sopenharmony_civoid settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { 932c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(w->data); 942c593315Sopenharmony_ci 952c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 962c593315Sopenharmony_ci LOG(INFO) << "SETTINGS timeout"; 972c593315Sopenharmony_ci } 982c593315Sopenharmony_ci 992c593315Sopenharmony_ci live_check->on_failure(); 1002c593315Sopenharmony_ci} 1012c593315Sopenharmony_ci} // namespace 1022c593315Sopenharmony_ci 1032c593315Sopenharmony_ciLiveCheck::LiveCheck(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker, 1042c593315Sopenharmony_ci DownstreamAddr *addr, std::mt19937 &gen) 1052c593315Sopenharmony_ci : conn_(loop, -1, nullptr, worker->get_mcpool(), 1062c593315Sopenharmony_ci worker->get_downstream_config()->timeout.write, 1072c593315Sopenharmony_ci worker->get_downstream_config()->timeout.read, {}, {}, writecb, 1082c593315Sopenharmony_ci readcb, timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold, 1092c593315Sopenharmony_ci get_config()->tls.dyn_rec.idle_timeout, Proto::NONE), 1102c593315Sopenharmony_ci wb_(worker->get_mcpool()), 1112c593315Sopenharmony_ci gen_(gen), 1122c593315Sopenharmony_ci read_(&LiveCheck::noop), 1132c593315Sopenharmony_ci write_(&LiveCheck::noop), 1142c593315Sopenharmony_ci worker_(worker), 1152c593315Sopenharmony_ci ssl_ctx_(ssl_ctx), 1162c593315Sopenharmony_ci addr_(addr), 1172c593315Sopenharmony_ci session_(nullptr), 1182c593315Sopenharmony_ci raddr_(nullptr), 1192c593315Sopenharmony_ci success_count_(0), 1202c593315Sopenharmony_ci fail_count_(0), 1212c593315Sopenharmony_ci settings_ack_received_(false), 1222c593315Sopenharmony_ci session_closing_(false) { 1232c593315Sopenharmony_ci ev_timer_init(&backoff_timer_, backoff_timeoutcb, 0., 0.); 1242c593315Sopenharmony_ci backoff_timer_.data = this; 1252c593315Sopenharmony_ci 1262c593315Sopenharmony_ci // SETTINGS ACK must be received in a short timeout. Otherwise, we 1272c593315Sopenharmony_ci // assume that connection is broken. 1282c593315Sopenharmony_ci ev_timer_init(&settings_timer_, settings_timeout_cb, 0., 0.); 1292c593315Sopenharmony_ci settings_timer_.data = this; 1302c593315Sopenharmony_ci} 1312c593315Sopenharmony_ci 1322c593315Sopenharmony_ciLiveCheck::~LiveCheck() { 1332c593315Sopenharmony_ci disconnect(); 1342c593315Sopenharmony_ci 1352c593315Sopenharmony_ci ev_timer_stop(conn_.loop, &backoff_timer_); 1362c593315Sopenharmony_ci} 1372c593315Sopenharmony_ci 1382c593315Sopenharmony_civoid LiveCheck::disconnect() { 1392c593315Sopenharmony_ci if (dns_query_) { 1402c593315Sopenharmony_ci auto dns_tracker = worker_->get_dns_tracker(); 1412c593315Sopenharmony_ci 1422c593315Sopenharmony_ci dns_tracker->cancel(dns_query_.get()); 1432c593315Sopenharmony_ci } 1442c593315Sopenharmony_ci 1452c593315Sopenharmony_ci dns_query_.reset(); 1462c593315Sopenharmony_ci // We can reuse resolved_addr_ 1472c593315Sopenharmony_ci raddr_ = nullptr; 1482c593315Sopenharmony_ci 1492c593315Sopenharmony_ci conn_.rlimit.stopw(); 1502c593315Sopenharmony_ci conn_.wlimit.stopw(); 1512c593315Sopenharmony_ci 1522c593315Sopenharmony_ci ev_timer_stop(conn_.loop, &settings_timer_); 1532c593315Sopenharmony_ci 1542c593315Sopenharmony_ci read_ = write_ = &LiveCheck::noop; 1552c593315Sopenharmony_ci 1562c593315Sopenharmony_ci conn_.disconnect(); 1572c593315Sopenharmony_ci 1582c593315Sopenharmony_ci nghttp2_session_del(session_); 1592c593315Sopenharmony_ci session_ = nullptr; 1602c593315Sopenharmony_ci 1612c593315Sopenharmony_ci settings_ack_received_ = false; 1622c593315Sopenharmony_ci session_closing_ = false; 1632c593315Sopenharmony_ci 1642c593315Sopenharmony_ci wb_.reset(); 1652c593315Sopenharmony_ci} 1662c593315Sopenharmony_ci 1672c593315Sopenharmony_ci// Use the similar backoff algorithm described in 1682c593315Sopenharmony_ci// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md 1692c593315Sopenharmony_cinamespace { 1702c593315Sopenharmony_ciconstexpr size_t MAX_BACKOFF_EXP = 10; 1712c593315Sopenharmony_ciconstexpr auto MULTIPLIER = 1.6; 1722c593315Sopenharmony_ciconstexpr auto JITTER = 0.2; 1732c593315Sopenharmony_ci} // namespace 1742c593315Sopenharmony_ci 1752c593315Sopenharmony_civoid LiveCheck::schedule() { 1762c593315Sopenharmony_ci auto base_backoff = 1772c593315Sopenharmony_ci util::int_pow(MULTIPLIER, std::min(fail_count_, MAX_BACKOFF_EXP)); 1782c593315Sopenharmony_ci auto dist = std::uniform_real_distribution<>(-JITTER * base_backoff, 1792c593315Sopenharmony_ci JITTER * base_backoff); 1802c593315Sopenharmony_ci 1812c593315Sopenharmony_ci auto &downstreamconf = *get_config()->conn.downstream; 1822c593315Sopenharmony_ci 1832c593315Sopenharmony_ci auto backoff = 1842c593315Sopenharmony_ci std::min(downstreamconf.timeout.max_backoff, base_backoff + dist(gen_)); 1852c593315Sopenharmony_ci 1862c593315Sopenharmony_ci ev_timer_set(&backoff_timer_, backoff, 0.); 1872c593315Sopenharmony_ci ev_timer_start(conn_.loop, &backoff_timer_); 1882c593315Sopenharmony_ci} 1892c593315Sopenharmony_ci 1902c593315Sopenharmony_ciint LiveCheck::do_read() { return read_(*this); } 1912c593315Sopenharmony_ci 1922c593315Sopenharmony_ciint LiveCheck::do_write() { return write_(*this); } 1932c593315Sopenharmony_ci 1942c593315Sopenharmony_ciint LiveCheck::initiate_connection() { 1952c593315Sopenharmony_ci int rv; 1962c593315Sopenharmony_ci 1972c593315Sopenharmony_ci auto worker_blocker = worker_->get_connect_blocker(); 1982c593315Sopenharmony_ci if (worker_blocker->blocked()) { 1992c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 2002c593315Sopenharmony_ci LOG(INFO) << "Worker wide backend connection was blocked temporarily"; 2012c593315Sopenharmony_ci } 2022c593315Sopenharmony_ci return -1; 2032c593315Sopenharmony_ci } 2042c593315Sopenharmony_ci 2052c593315Sopenharmony_ci if (!dns_query_ && addr_->tls) { 2062c593315Sopenharmony_ci assert(ssl_ctx_); 2072c593315Sopenharmony_ci 2082c593315Sopenharmony_ci auto ssl = tls::create_ssl(ssl_ctx_); 2092c593315Sopenharmony_ci if (!ssl) { 2102c593315Sopenharmony_ci return -1; 2112c593315Sopenharmony_ci } 2122c593315Sopenharmony_ci 2132c593315Sopenharmony_ci switch (addr_->proto) { 2142c593315Sopenharmony_ci case Proto::HTTP1: 2152c593315Sopenharmony_ci tls::setup_downstream_http1_alpn(ssl); 2162c593315Sopenharmony_ci break; 2172c593315Sopenharmony_ci case Proto::HTTP2: 2182c593315Sopenharmony_ci tls::setup_downstream_http2_alpn(ssl); 2192c593315Sopenharmony_ci break; 2202c593315Sopenharmony_ci default: 2212c593315Sopenharmony_ci assert(0); 2222c593315Sopenharmony_ci } 2232c593315Sopenharmony_ci 2242c593315Sopenharmony_ci conn_.set_ssl(ssl); 2252c593315Sopenharmony_ci conn_.tls.client_session_cache = &addr_->tls_session_cache; 2262c593315Sopenharmony_ci } 2272c593315Sopenharmony_ci 2282c593315Sopenharmony_ci if (addr_->dns) { 2292c593315Sopenharmony_ci if (!dns_query_) { 2302c593315Sopenharmony_ci auto dns_query = std::make_unique<DNSQuery>( 2312c593315Sopenharmony_ci addr_->host, [this](DNSResolverStatus status, const Address *result) { 2322c593315Sopenharmony_ci int rv; 2332c593315Sopenharmony_ci 2342c593315Sopenharmony_ci if (status == DNSResolverStatus::OK) { 2352c593315Sopenharmony_ci *this->resolved_addr_ = *result; 2362c593315Sopenharmony_ci } 2372c593315Sopenharmony_ci rv = this->initiate_connection(); 2382c593315Sopenharmony_ci if (rv != 0) { 2392c593315Sopenharmony_ci this->on_failure(); 2402c593315Sopenharmony_ci } 2412c593315Sopenharmony_ci }); 2422c593315Sopenharmony_ci auto dns_tracker = worker_->get_dns_tracker(); 2432c593315Sopenharmony_ci 2442c593315Sopenharmony_ci if (!resolved_addr_) { 2452c593315Sopenharmony_ci resolved_addr_ = std::make_unique<Address>(); 2462c593315Sopenharmony_ci } 2472c593315Sopenharmony_ci 2482c593315Sopenharmony_ci switch (dns_tracker->resolve(resolved_addr_.get(), dns_query.get())) { 2492c593315Sopenharmony_ci case DNSResolverStatus::ERROR: 2502c593315Sopenharmony_ci return -1; 2512c593315Sopenharmony_ci case DNSResolverStatus::RUNNING: 2522c593315Sopenharmony_ci dns_query_ = std::move(dns_query); 2532c593315Sopenharmony_ci return 0; 2542c593315Sopenharmony_ci case DNSResolverStatus::OK: 2552c593315Sopenharmony_ci break; 2562c593315Sopenharmony_ci default: 2572c593315Sopenharmony_ci assert(0); 2582c593315Sopenharmony_ci } 2592c593315Sopenharmony_ci } else { 2602c593315Sopenharmony_ci switch (dns_query_->status) { 2612c593315Sopenharmony_ci case DNSResolverStatus::ERROR: 2622c593315Sopenharmony_ci dns_query_.reset(); 2632c593315Sopenharmony_ci return -1; 2642c593315Sopenharmony_ci case DNSResolverStatus::OK: 2652c593315Sopenharmony_ci dns_query_.reset(); 2662c593315Sopenharmony_ci break; 2672c593315Sopenharmony_ci default: 2682c593315Sopenharmony_ci assert(0); 2692c593315Sopenharmony_ci } 2702c593315Sopenharmony_ci } 2712c593315Sopenharmony_ci 2722c593315Sopenharmony_ci util::set_port(*resolved_addr_, addr_->port); 2732c593315Sopenharmony_ci raddr_ = resolved_addr_.get(); 2742c593315Sopenharmony_ci } else { 2752c593315Sopenharmony_ci raddr_ = &addr_->addr; 2762c593315Sopenharmony_ci } 2772c593315Sopenharmony_ci 2782c593315Sopenharmony_ci conn_.fd = util::create_nonblock_socket(raddr_->su.storage.ss_family); 2792c593315Sopenharmony_ci 2802c593315Sopenharmony_ci if (conn_.fd == -1) { 2812c593315Sopenharmony_ci auto error = errno; 2822c593315Sopenharmony_ci LOG(WARN) << "socket() failed; addr=" << util::to_numeric_addr(raddr_) 2832c593315Sopenharmony_ci << ", errno=" << error; 2842c593315Sopenharmony_ci return -1; 2852c593315Sopenharmony_ci } 2862c593315Sopenharmony_ci 2872c593315Sopenharmony_ci rv = connect(conn_.fd, &raddr_->su.sa, raddr_->len); 2882c593315Sopenharmony_ci if (rv != 0 && errno != EINPROGRESS) { 2892c593315Sopenharmony_ci auto error = errno; 2902c593315Sopenharmony_ci LOG(WARN) << "connect() failed; addr=" << util::to_numeric_addr(raddr_) 2912c593315Sopenharmony_ci << ", errno=" << error; 2922c593315Sopenharmony_ci 2932c593315Sopenharmony_ci close(conn_.fd); 2942c593315Sopenharmony_ci conn_.fd = -1; 2952c593315Sopenharmony_ci 2962c593315Sopenharmony_ci return -1; 2972c593315Sopenharmony_ci } 2982c593315Sopenharmony_ci 2992c593315Sopenharmony_ci if (addr_->tls) { 3002c593315Sopenharmony_ci auto sni_name = 3012c593315Sopenharmony_ci addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni}; 3022c593315Sopenharmony_ci if (!util::numeric_host(sni_name.c_str())) { 3032c593315Sopenharmony_ci SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str()); 3042c593315Sopenharmony_ci } 3052c593315Sopenharmony_ci 3062c593315Sopenharmony_ci auto session = tls::reuse_tls_session(addr_->tls_session_cache); 3072c593315Sopenharmony_ci if (session) { 3082c593315Sopenharmony_ci SSL_set_session(conn_.tls.ssl, session); 3092c593315Sopenharmony_ci SSL_SESSION_free(session); 3102c593315Sopenharmony_ci } 3112c593315Sopenharmony_ci 3122c593315Sopenharmony_ci conn_.prepare_client_handshake(); 3132c593315Sopenharmony_ci } 3142c593315Sopenharmony_ci 3152c593315Sopenharmony_ci write_ = &LiveCheck::connected; 3162c593315Sopenharmony_ci 3172c593315Sopenharmony_ci ev_io_set(&conn_.wev, conn_.fd, EV_WRITE); 3182c593315Sopenharmony_ci ev_io_set(&conn_.rev, conn_.fd, EV_READ); 3192c593315Sopenharmony_ci 3202c593315Sopenharmony_ci conn_.wlimit.startw(); 3212c593315Sopenharmony_ci 3222c593315Sopenharmony_ci auto &downstreamconf = *get_config()->conn.downstream; 3232c593315Sopenharmony_ci 3242c593315Sopenharmony_ci conn_.wt.repeat = downstreamconf.timeout.connect; 3252c593315Sopenharmony_ci ev_timer_again(conn_.loop, &conn_.wt); 3262c593315Sopenharmony_ci 3272c593315Sopenharmony_ci return 0; 3282c593315Sopenharmony_ci} 3292c593315Sopenharmony_ci 3302c593315Sopenharmony_ciint LiveCheck::connected() { 3312c593315Sopenharmony_ci auto sock_error = util::get_socket_error(conn_.fd); 3322c593315Sopenharmony_ci if (sock_error != 0) { 3332c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 3342c593315Sopenharmony_ci LOG(INFO) << "Backend connect failed; addr=" 3352c593315Sopenharmony_ci << util::to_numeric_addr(raddr_) << ": errno=" << sock_error; 3362c593315Sopenharmony_ci } 3372c593315Sopenharmony_ci 3382c593315Sopenharmony_ci return -1; 3392c593315Sopenharmony_ci } 3402c593315Sopenharmony_ci 3412c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 3422c593315Sopenharmony_ci LOG(INFO) << "Connection established"; 3432c593315Sopenharmony_ci } 3442c593315Sopenharmony_ci 3452c593315Sopenharmony_ci auto &downstreamconf = *get_config()->conn.downstream; 3462c593315Sopenharmony_ci 3472c593315Sopenharmony_ci // Reset timeout for write. Previously, we set timeout for connect. 3482c593315Sopenharmony_ci conn_.wt.repeat = downstreamconf.timeout.write; 3492c593315Sopenharmony_ci ev_timer_again(conn_.loop, &conn_.wt); 3502c593315Sopenharmony_ci 3512c593315Sopenharmony_ci conn_.rlimit.startw(); 3522c593315Sopenharmony_ci conn_.again_rt(); 3532c593315Sopenharmony_ci 3542c593315Sopenharmony_ci if (conn_.tls.ssl) { 3552c593315Sopenharmony_ci read_ = &LiveCheck::tls_handshake; 3562c593315Sopenharmony_ci write_ = &LiveCheck::tls_handshake; 3572c593315Sopenharmony_ci 3582c593315Sopenharmony_ci return do_write(); 3592c593315Sopenharmony_ci } 3602c593315Sopenharmony_ci 3612c593315Sopenharmony_ci if (addr_->proto == Proto::HTTP2) { 3622c593315Sopenharmony_ci // For HTTP/2, we try to read SETTINGS ACK from server to make 3632c593315Sopenharmony_ci // sure it is really alive, and serving HTTP/2. 3642c593315Sopenharmony_ci read_ = &LiveCheck::read_clear; 3652c593315Sopenharmony_ci write_ = &LiveCheck::write_clear; 3662c593315Sopenharmony_ci 3672c593315Sopenharmony_ci if (connection_made() != 0) { 3682c593315Sopenharmony_ci return -1; 3692c593315Sopenharmony_ci } 3702c593315Sopenharmony_ci 3712c593315Sopenharmony_ci return 0; 3722c593315Sopenharmony_ci } 3732c593315Sopenharmony_ci 3742c593315Sopenharmony_ci on_success(); 3752c593315Sopenharmony_ci 3762c593315Sopenharmony_ci return 0; 3772c593315Sopenharmony_ci} 3782c593315Sopenharmony_ci 3792c593315Sopenharmony_ciint LiveCheck::tls_handshake() { 3802c593315Sopenharmony_ci conn_.last_read = std::chrono::steady_clock::now(); 3812c593315Sopenharmony_ci 3822c593315Sopenharmony_ci ERR_clear_error(); 3832c593315Sopenharmony_ci 3842c593315Sopenharmony_ci auto rv = conn_.tls_handshake(); 3852c593315Sopenharmony_ci 3862c593315Sopenharmony_ci if (rv == SHRPX_ERR_INPROGRESS) { 3872c593315Sopenharmony_ci return 0; 3882c593315Sopenharmony_ci } 3892c593315Sopenharmony_ci 3902c593315Sopenharmony_ci if (rv < 0) { 3912c593315Sopenharmony_ci return rv; 3922c593315Sopenharmony_ci } 3932c593315Sopenharmony_ci 3942c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 3952c593315Sopenharmony_ci LOG(INFO) << "SSL/TLS handshake completed"; 3962c593315Sopenharmony_ci } 3972c593315Sopenharmony_ci 3982c593315Sopenharmony_ci if (!get_config()->tls.insecure && 3992c593315Sopenharmony_ci tls::check_cert(conn_.tls.ssl, addr_, raddr_) != 0) { 4002c593315Sopenharmony_ci return -1; 4012c593315Sopenharmony_ci } 4022c593315Sopenharmony_ci 4032c593315Sopenharmony_ci // Check negotiated ALPN 4042c593315Sopenharmony_ci 4052c593315Sopenharmony_ci const unsigned char *next_proto = nullptr; 4062c593315Sopenharmony_ci unsigned int next_proto_len = 0; 4072c593315Sopenharmony_ci 4082c593315Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG 4092c593315Sopenharmony_ci SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len); 4102c593315Sopenharmony_ci#endif // !OPENSSL_NO_NEXTPROTONEG 4112c593315Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10002000L 4122c593315Sopenharmony_ci if (next_proto == nullptr) { 4132c593315Sopenharmony_ci SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len); 4142c593315Sopenharmony_ci } 4152c593315Sopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L 4162c593315Sopenharmony_ci 4172c593315Sopenharmony_ci auto proto = StringRef{next_proto, next_proto_len}; 4182c593315Sopenharmony_ci 4192c593315Sopenharmony_ci switch (addr_->proto) { 4202c593315Sopenharmony_ci case Proto::HTTP1: 4212c593315Sopenharmony_ci if (proto.empty() || proto == StringRef::from_lit("http/1.1")) { 4222c593315Sopenharmony_ci break; 4232c593315Sopenharmony_ci } 4242c593315Sopenharmony_ci return -1; 4252c593315Sopenharmony_ci case Proto::HTTP2: 4262c593315Sopenharmony_ci if (util::check_h2_is_selected(proto)) { 4272c593315Sopenharmony_ci // For HTTP/2, we try to read SETTINGS ACK from server to make 4282c593315Sopenharmony_ci // sure it is really alive, and serving HTTP/2. 4292c593315Sopenharmony_ci read_ = &LiveCheck::read_tls; 4302c593315Sopenharmony_ci write_ = &LiveCheck::write_tls; 4312c593315Sopenharmony_ci 4322c593315Sopenharmony_ci if (connection_made() != 0) { 4332c593315Sopenharmony_ci return -1; 4342c593315Sopenharmony_ci } 4352c593315Sopenharmony_ci 4362c593315Sopenharmony_ci return 0; 4372c593315Sopenharmony_ci } 4382c593315Sopenharmony_ci return -1; 4392c593315Sopenharmony_ci default: 4402c593315Sopenharmony_ci break; 4412c593315Sopenharmony_ci } 4422c593315Sopenharmony_ci 4432c593315Sopenharmony_ci on_success(); 4442c593315Sopenharmony_ci 4452c593315Sopenharmony_ci return 0; 4462c593315Sopenharmony_ci} 4472c593315Sopenharmony_ci 4482c593315Sopenharmony_ciint LiveCheck::read_tls() { 4492c593315Sopenharmony_ci conn_.last_read = std::chrono::steady_clock::now(); 4502c593315Sopenharmony_ci 4512c593315Sopenharmony_ci std::array<uint8_t, 4_k> buf; 4522c593315Sopenharmony_ci 4532c593315Sopenharmony_ci ERR_clear_error(); 4542c593315Sopenharmony_ci 4552c593315Sopenharmony_ci for (;;) { 4562c593315Sopenharmony_ci auto nread = conn_.read_tls(buf.data(), buf.size()); 4572c593315Sopenharmony_ci 4582c593315Sopenharmony_ci if (nread == 0) { 4592c593315Sopenharmony_ci return 0; 4602c593315Sopenharmony_ci } 4612c593315Sopenharmony_ci 4622c593315Sopenharmony_ci if (nread < 0) { 4632c593315Sopenharmony_ci return nread; 4642c593315Sopenharmony_ci } 4652c593315Sopenharmony_ci 4662c593315Sopenharmony_ci if (on_read(buf.data(), nread) != 0) { 4672c593315Sopenharmony_ci return -1; 4682c593315Sopenharmony_ci } 4692c593315Sopenharmony_ci } 4702c593315Sopenharmony_ci} 4712c593315Sopenharmony_ci 4722c593315Sopenharmony_ciint LiveCheck::write_tls() { 4732c593315Sopenharmony_ci conn_.last_read = std::chrono::steady_clock::now(); 4742c593315Sopenharmony_ci 4752c593315Sopenharmony_ci ERR_clear_error(); 4762c593315Sopenharmony_ci 4772c593315Sopenharmony_ci struct iovec iov; 4782c593315Sopenharmony_ci 4792c593315Sopenharmony_ci for (;;) { 4802c593315Sopenharmony_ci if (wb_.rleft() > 0) { 4812c593315Sopenharmony_ci auto iovcnt = wb_.riovec(&iov, 1); 4822c593315Sopenharmony_ci if (iovcnt != 1) { 4832c593315Sopenharmony_ci assert(0); 4842c593315Sopenharmony_ci return -1; 4852c593315Sopenharmony_ci } 4862c593315Sopenharmony_ci auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len); 4872c593315Sopenharmony_ci 4882c593315Sopenharmony_ci if (nwrite == 0) { 4892c593315Sopenharmony_ci return 0; 4902c593315Sopenharmony_ci } 4912c593315Sopenharmony_ci 4922c593315Sopenharmony_ci if (nwrite < 0) { 4932c593315Sopenharmony_ci return nwrite; 4942c593315Sopenharmony_ci } 4952c593315Sopenharmony_ci 4962c593315Sopenharmony_ci wb_.drain(nwrite); 4972c593315Sopenharmony_ci 4982c593315Sopenharmony_ci continue; 4992c593315Sopenharmony_ci } 5002c593315Sopenharmony_ci 5012c593315Sopenharmony_ci if (on_write() != 0) { 5022c593315Sopenharmony_ci return -1; 5032c593315Sopenharmony_ci } 5042c593315Sopenharmony_ci 5052c593315Sopenharmony_ci if (wb_.rleft() == 0) { 5062c593315Sopenharmony_ci conn_.start_tls_write_idle(); 5072c593315Sopenharmony_ci break; 5082c593315Sopenharmony_ci } 5092c593315Sopenharmony_ci } 5102c593315Sopenharmony_ci 5112c593315Sopenharmony_ci conn_.wlimit.stopw(); 5122c593315Sopenharmony_ci ev_timer_stop(conn_.loop, &conn_.wt); 5132c593315Sopenharmony_ci 5142c593315Sopenharmony_ci if (settings_ack_received_) { 5152c593315Sopenharmony_ci on_success(); 5162c593315Sopenharmony_ci } 5172c593315Sopenharmony_ci 5182c593315Sopenharmony_ci return 0; 5192c593315Sopenharmony_ci} 5202c593315Sopenharmony_ci 5212c593315Sopenharmony_ciint LiveCheck::read_clear() { 5222c593315Sopenharmony_ci conn_.last_read = std::chrono::steady_clock::now(); 5232c593315Sopenharmony_ci 5242c593315Sopenharmony_ci std::array<uint8_t, 4_k> buf; 5252c593315Sopenharmony_ci 5262c593315Sopenharmony_ci for (;;) { 5272c593315Sopenharmony_ci auto nread = conn_.read_clear(buf.data(), buf.size()); 5282c593315Sopenharmony_ci 5292c593315Sopenharmony_ci if (nread == 0) { 5302c593315Sopenharmony_ci return 0; 5312c593315Sopenharmony_ci } 5322c593315Sopenharmony_ci 5332c593315Sopenharmony_ci if (nread < 0) { 5342c593315Sopenharmony_ci return nread; 5352c593315Sopenharmony_ci } 5362c593315Sopenharmony_ci 5372c593315Sopenharmony_ci if (on_read(buf.data(), nread) != 0) { 5382c593315Sopenharmony_ci return -1; 5392c593315Sopenharmony_ci } 5402c593315Sopenharmony_ci } 5412c593315Sopenharmony_ci} 5422c593315Sopenharmony_ci 5432c593315Sopenharmony_ciint LiveCheck::write_clear() { 5442c593315Sopenharmony_ci conn_.last_read = std::chrono::steady_clock::now(); 5452c593315Sopenharmony_ci 5462c593315Sopenharmony_ci struct iovec iov; 5472c593315Sopenharmony_ci 5482c593315Sopenharmony_ci for (;;) { 5492c593315Sopenharmony_ci if (wb_.rleft() > 0) { 5502c593315Sopenharmony_ci auto iovcnt = wb_.riovec(&iov, 1); 5512c593315Sopenharmony_ci if (iovcnt != 1) { 5522c593315Sopenharmony_ci assert(0); 5532c593315Sopenharmony_ci return -1; 5542c593315Sopenharmony_ci } 5552c593315Sopenharmony_ci auto nwrite = conn_.write_clear(iov.iov_base, iov.iov_len); 5562c593315Sopenharmony_ci 5572c593315Sopenharmony_ci if (nwrite == 0) { 5582c593315Sopenharmony_ci return 0; 5592c593315Sopenharmony_ci } 5602c593315Sopenharmony_ci 5612c593315Sopenharmony_ci if (nwrite < 0) { 5622c593315Sopenharmony_ci return nwrite; 5632c593315Sopenharmony_ci } 5642c593315Sopenharmony_ci 5652c593315Sopenharmony_ci wb_.drain(nwrite); 5662c593315Sopenharmony_ci 5672c593315Sopenharmony_ci continue; 5682c593315Sopenharmony_ci } 5692c593315Sopenharmony_ci 5702c593315Sopenharmony_ci if (on_write() != 0) { 5712c593315Sopenharmony_ci return -1; 5722c593315Sopenharmony_ci } 5732c593315Sopenharmony_ci 5742c593315Sopenharmony_ci if (wb_.rleft() == 0) { 5752c593315Sopenharmony_ci break; 5762c593315Sopenharmony_ci } 5772c593315Sopenharmony_ci } 5782c593315Sopenharmony_ci 5792c593315Sopenharmony_ci conn_.wlimit.stopw(); 5802c593315Sopenharmony_ci ev_timer_stop(conn_.loop, &conn_.wt); 5812c593315Sopenharmony_ci 5822c593315Sopenharmony_ci if (settings_ack_received_) { 5832c593315Sopenharmony_ci on_success(); 5842c593315Sopenharmony_ci } 5852c593315Sopenharmony_ci 5862c593315Sopenharmony_ci return 0; 5872c593315Sopenharmony_ci} 5882c593315Sopenharmony_ci 5892c593315Sopenharmony_ciint LiveCheck::on_read(const uint8_t *data, size_t len) { 5902c593315Sopenharmony_ci ssize_t rv; 5912c593315Sopenharmony_ci 5922c593315Sopenharmony_ci rv = nghttp2_session_mem_recv(session_, data, len); 5932c593315Sopenharmony_ci if (rv < 0) { 5942c593315Sopenharmony_ci LOG(ERROR) << "nghttp2_session_mem_recv() returned error: " 5952c593315Sopenharmony_ci << nghttp2_strerror(rv); 5962c593315Sopenharmony_ci return -1; 5972c593315Sopenharmony_ci } 5982c593315Sopenharmony_ci 5992c593315Sopenharmony_ci if (settings_ack_received_ && !session_closing_) { 6002c593315Sopenharmony_ci session_closing_ = true; 6012c593315Sopenharmony_ci rv = nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR); 6022c593315Sopenharmony_ci if (rv != 0) { 6032c593315Sopenharmony_ci return -1; 6042c593315Sopenharmony_ci } 6052c593315Sopenharmony_ci } 6062c593315Sopenharmony_ci 6072c593315Sopenharmony_ci if (nghttp2_session_want_read(session_) == 0 && 6082c593315Sopenharmony_ci nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) { 6092c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 6102c593315Sopenharmony_ci LOG(INFO) << "No more read/write for this session"; 6112c593315Sopenharmony_ci } 6122c593315Sopenharmony_ci 6132c593315Sopenharmony_ci // If we have SETTINGS ACK already, we treat this success. 6142c593315Sopenharmony_ci if (settings_ack_received_) { 6152c593315Sopenharmony_ci return 0; 6162c593315Sopenharmony_ci } 6172c593315Sopenharmony_ci 6182c593315Sopenharmony_ci return -1; 6192c593315Sopenharmony_ci } 6202c593315Sopenharmony_ci 6212c593315Sopenharmony_ci signal_write(); 6222c593315Sopenharmony_ci 6232c593315Sopenharmony_ci return 0; 6242c593315Sopenharmony_ci} 6252c593315Sopenharmony_ci 6262c593315Sopenharmony_ciint LiveCheck::on_write() { 6272c593315Sopenharmony_ci for (;;) { 6282c593315Sopenharmony_ci const uint8_t *data; 6292c593315Sopenharmony_ci auto datalen = nghttp2_session_mem_send(session_, &data); 6302c593315Sopenharmony_ci 6312c593315Sopenharmony_ci if (datalen < 0) { 6322c593315Sopenharmony_ci LOG(ERROR) << "nghttp2_session_mem_send() returned error: " 6332c593315Sopenharmony_ci << nghttp2_strerror(datalen); 6342c593315Sopenharmony_ci return -1; 6352c593315Sopenharmony_ci } 6362c593315Sopenharmony_ci if (datalen == 0) { 6372c593315Sopenharmony_ci break; 6382c593315Sopenharmony_ci } 6392c593315Sopenharmony_ci wb_.append(data, datalen); 6402c593315Sopenharmony_ci 6412c593315Sopenharmony_ci if (wb_.rleft() >= MAX_BUFFER_SIZE) { 6422c593315Sopenharmony_ci break; 6432c593315Sopenharmony_ci } 6442c593315Sopenharmony_ci } 6452c593315Sopenharmony_ci 6462c593315Sopenharmony_ci if (nghttp2_session_want_read(session_) == 0 && 6472c593315Sopenharmony_ci nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) { 6482c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 6492c593315Sopenharmony_ci LOG(INFO) << "No more read/write for this session"; 6502c593315Sopenharmony_ci } 6512c593315Sopenharmony_ci 6522c593315Sopenharmony_ci if (settings_ack_received_) { 6532c593315Sopenharmony_ci return 0; 6542c593315Sopenharmony_ci } 6552c593315Sopenharmony_ci 6562c593315Sopenharmony_ci return -1; 6572c593315Sopenharmony_ci } 6582c593315Sopenharmony_ci 6592c593315Sopenharmony_ci return 0; 6602c593315Sopenharmony_ci} 6612c593315Sopenharmony_ci 6622c593315Sopenharmony_civoid LiveCheck::on_failure() { 6632c593315Sopenharmony_ci ++fail_count_; 6642c593315Sopenharmony_ci 6652c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 6662c593315Sopenharmony_ci LOG(INFO) << "Liveness check for " << addr_->host << ":" << addr_->port 6672c593315Sopenharmony_ci << " failed " << fail_count_ << " time(s) in a row"; 6682c593315Sopenharmony_ci } 6692c593315Sopenharmony_ci 6702c593315Sopenharmony_ci disconnect(); 6712c593315Sopenharmony_ci 6722c593315Sopenharmony_ci schedule(); 6732c593315Sopenharmony_ci} 6742c593315Sopenharmony_ci 6752c593315Sopenharmony_civoid LiveCheck::on_success() { 6762c593315Sopenharmony_ci ++success_count_; 6772c593315Sopenharmony_ci fail_count_ = 0; 6782c593315Sopenharmony_ci 6792c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 6802c593315Sopenharmony_ci LOG(INFO) << "Liveness check for " << addr_->host << ":" << addr_->port 6812c593315Sopenharmony_ci << " succeeded " << success_count_ << " time(s) in a row"; 6822c593315Sopenharmony_ci } 6832c593315Sopenharmony_ci 6842c593315Sopenharmony_ci if (success_count_ < addr_->rise) { 6852c593315Sopenharmony_ci disconnect(); 6862c593315Sopenharmony_ci 6872c593315Sopenharmony_ci schedule(); 6882c593315Sopenharmony_ci 6892c593315Sopenharmony_ci return; 6902c593315Sopenharmony_ci } 6912c593315Sopenharmony_ci 6922c593315Sopenharmony_ci LOG(NOTICE) << util::to_numeric_addr(&addr_->addr) << " is considered online"; 6932c593315Sopenharmony_ci 6942c593315Sopenharmony_ci addr_->connect_blocker->online(); 6952c593315Sopenharmony_ci 6962c593315Sopenharmony_ci success_count_ = 0; 6972c593315Sopenharmony_ci fail_count_ = 0; 6982c593315Sopenharmony_ci 6992c593315Sopenharmony_ci disconnect(); 7002c593315Sopenharmony_ci} 7012c593315Sopenharmony_ci 7022c593315Sopenharmony_ciint LiveCheck::noop() { return 0; } 7032c593315Sopenharmony_ci 7042c593315Sopenharmony_civoid LiveCheck::start_settings_timer() { 7052c593315Sopenharmony_ci auto &downstreamconf = get_config()->http2.downstream; 7062c593315Sopenharmony_ci 7072c593315Sopenharmony_ci ev_timer_set(&settings_timer_, downstreamconf.timeout.settings, 0.); 7082c593315Sopenharmony_ci ev_timer_start(conn_.loop, &settings_timer_); 7092c593315Sopenharmony_ci} 7102c593315Sopenharmony_ci 7112c593315Sopenharmony_civoid LiveCheck::stop_settings_timer() { 7122c593315Sopenharmony_ci ev_timer_stop(conn_.loop, &settings_timer_); 7132c593315Sopenharmony_ci} 7142c593315Sopenharmony_ci 7152c593315Sopenharmony_civoid LiveCheck::settings_ack_received() { settings_ack_received_ = true; } 7162c593315Sopenharmony_ci 7172c593315Sopenharmony_cinamespace { 7182c593315Sopenharmony_ciint on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame, 7192c593315Sopenharmony_ci void *user_data) { 7202c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(user_data); 7212c593315Sopenharmony_ci 7222c593315Sopenharmony_ci if (frame->hd.type != NGHTTP2_SETTINGS || 7232c593315Sopenharmony_ci (frame->hd.flags & NGHTTP2_FLAG_ACK)) { 7242c593315Sopenharmony_ci return 0; 7252c593315Sopenharmony_ci } 7262c593315Sopenharmony_ci 7272c593315Sopenharmony_ci live_check->start_settings_timer(); 7282c593315Sopenharmony_ci 7292c593315Sopenharmony_ci return 0; 7302c593315Sopenharmony_ci} 7312c593315Sopenharmony_ci} // namespace 7322c593315Sopenharmony_ci 7332c593315Sopenharmony_cinamespace { 7342c593315Sopenharmony_ciint on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame, 7352c593315Sopenharmony_ci void *user_data) { 7362c593315Sopenharmony_ci auto live_check = static_cast<LiveCheck *>(user_data); 7372c593315Sopenharmony_ci 7382c593315Sopenharmony_ci if (frame->hd.type != NGHTTP2_SETTINGS || 7392c593315Sopenharmony_ci (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) { 7402c593315Sopenharmony_ci return 0; 7412c593315Sopenharmony_ci } 7422c593315Sopenharmony_ci 7432c593315Sopenharmony_ci live_check->stop_settings_timer(); 7442c593315Sopenharmony_ci live_check->settings_ack_received(); 7452c593315Sopenharmony_ci 7462c593315Sopenharmony_ci return 0; 7472c593315Sopenharmony_ci} 7482c593315Sopenharmony_ci} // namespace 7492c593315Sopenharmony_ci 7502c593315Sopenharmony_ciint LiveCheck::connection_made() { 7512c593315Sopenharmony_ci int rv; 7522c593315Sopenharmony_ci 7532c593315Sopenharmony_ci nghttp2_session_callbacks *callbacks; 7542c593315Sopenharmony_ci rv = nghttp2_session_callbacks_new(&callbacks); 7552c593315Sopenharmony_ci if (rv != 0) { 7562c593315Sopenharmony_ci return -1; 7572c593315Sopenharmony_ci } 7582c593315Sopenharmony_ci 7592c593315Sopenharmony_ci nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, 7602c593315Sopenharmony_ci on_frame_send_callback); 7612c593315Sopenharmony_ci nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, 7622c593315Sopenharmony_ci on_frame_recv_callback); 7632c593315Sopenharmony_ci 7642c593315Sopenharmony_ci rv = nghttp2_session_client_new(&session_, callbacks, this); 7652c593315Sopenharmony_ci 7662c593315Sopenharmony_ci nghttp2_session_callbacks_del(callbacks); 7672c593315Sopenharmony_ci 7682c593315Sopenharmony_ci if (rv != 0) { 7692c593315Sopenharmony_ci return -1; 7702c593315Sopenharmony_ci } 7712c593315Sopenharmony_ci 7722c593315Sopenharmony_ci rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, nullptr, 0); 7732c593315Sopenharmony_ci if (rv != 0) { 7742c593315Sopenharmony_ci return -1; 7752c593315Sopenharmony_ci } 7762c593315Sopenharmony_ci 7772c593315Sopenharmony_ci auto must_terminate = 7782c593315Sopenharmony_ci addr_->tls && !nghttp2::tls::check_http2_requirement(conn_.tls.ssl); 7792c593315Sopenharmony_ci 7802c593315Sopenharmony_ci if (must_terminate) { 7812c593315Sopenharmony_ci if (LOG_ENABLED(INFO)) { 7822c593315Sopenharmony_ci LOG(INFO) << "TLSv1.2 was not negotiated. HTTP/2 must not be negotiated."; 7832c593315Sopenharmony_ci } 7842c593315Sopenharmony_ci 7852c593315Sopenharmony_ci rv = nghttp2_session_terminate_session(session_, 7862c593315Sopenharmony_ci NGHTTP2_INADEQUATE_SECURITY); 7872c593315Sopenharmony_ci if (rv != 0) { 7882c593315Sopenharmony_ci return -1; 7892c593315Sopenharmony_ci } 7902c593315Sopenharmony_ci } 7912c593315Sopenharmony_ci 7922c593315Sopenharmony_ci signal_write(); 7932c593315Sopenharmony_ci 7942c593315Sopenharmony_ci return 0; 7952c593315Sopenharmony_ci} 7962c593315Sopenharmony_ci 7972c593315Sopenharmony_civoid LiveCheck::signal_write() { conn_.wlimit.startw(); } 7982c593315Sopenharmony_ci 7992c593315Sopenharmony_ci} // namespace shrpx 800