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