12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2021 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_quic_connection_handler.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#include <openssl/rand.h>
282c593315Sopenharmony_ci
292c593315Sopenharmony_ci#include <ngtcp2/ngtcp2.h>
302c593315Sopenharmony_ci#include <ngtcp2/ngtcp2_crypto.h>
312c593315Sopenharmony_ci
322c593315Sopenharmony_ci#include "shrpx_worker.h"
332c593315Sopenharmony_ci#include "shrpx_client_handler.h"
342c593315Sopenharmony_ci#include "shrpx_log.h"
352c593315Sopenharmony_ci#include "shrpx_http3_upstream.h"
362c593315Sopenharmony_ci#include "shrpx_connection_handler.h"
372c593315Sopenharmony_ci
382c593315Sopenharmony_cinamespace shrpx {
392c593315Sopenharmony_ci
402c593315Sopenharmony_cinamespace {
412c593315Sopenharmony_civoid stateless_reset_bucket_regen_timercb(struct ev_loop *loop, ev_timer *w,
422c593315Sopenharmony_ci                                          int revents) {
432c593315Sopenharmony_ci  auto quic_conn_handler = static_cast<QUICConnectionHandler *>(w->data);
442c593315Sopenharmony_ci
452c593315Sopenharmony_ci  quic_conn_handler->on_stateless_reset_bucket_regen();
462c593315Sopenharmony_ci}
472c593315Sopenharmony_ci} // namespace
482c593315Sopenharmony_ci
492c593315Sopenharmony_ciQUICConnectionHandler::QUICConnectionHandler(Worker *worker)
502c593315Sopenharmony_ci    : worker_{worker},
512c593315Sopenharmony_ci      stateless_reset_bucket_{SHRPX_QUIC_STATELESS_RESET_BURST} {
522c593315Sopenharmony_ci  ev_timer_init(&stateless_reset_bucket_regen_timer_,
532c593315Sopenharmony_ci                stateless_reset_bucket_regen_timercb, 0., 1.);
542c593315Sopenharmony_ci  stateless_reset_bucket_regen_timer_.data = this;
552c593315Sopenharmony_ci}
562c593315Sopenharmony_ci
572c593315Sopenharmony_ciQUICConnectionHandler::~QUICConnectionHandler() {
582c593315Sopenharmony_ci  ev_timer_stop(worker_->get_loop(), &stateless_reset_bucket_regen_timer_);
592c593315Sopenharmony_ci}
602c593315Sopenharmony_ci
612c593315Sopenharmony_ciint QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
622c593315Sopenharmony_ci                                         const Address &remote_addr,
632c593315Sopenharmony_ci                                         const Address &local_addr,
642c593315Sopenharmony_ci                                         const ngtcp2_pkt_info &pi,
652c593315Sopenharmony_ci                                         const uint8_t *data, size_t datalen) {
662c593315Sopenharmony_ci  int rv;
672c593315Sopenharmony_ci  ngtcp2_version_cid vc;
682c593315Sopenharmony_ci
692c593315Sopenharmony_ci  rv = ngtcp2_pkt_decode_version_cid(&vc, data, datalen, SHRPX_QUIC_SCIDLEN);
702c593315Sopenharmony_ci  switch (rv) {
712c593315Sopenharmony_ci  case 0:
722c593315Sopenharmony_ci    break;
732c593315Sopenharmony_ci  case NGTCP2_ERR_VERSION_NEGOTIATION:
742c593315Sopenharmony_ci    send_version_negotiation(faddr, vc.version, vc.dcid, vc.dcidlen, vc.scid,
752c593315Sopenharmony_ci                             vc.scidlen, remote_addr, local_addr);
762c593315Sopenharmony_ci
772c593315Sopenharmony_ci    return 0;
782c593315Sopenharmony_ci  default:
792c593315Sopenharmony_ci    return 0;
802c593315Sopenharmony_ci  }
812c593315Sopenharmony_ci
822c593315Sopenharmony_ci  auto config = get_config();
832c593315Sopenharmony_ci
842c593315Sopenharmony_ci  ngtcp2_cid dcid_key;
852c593315Sopenharmony_ci  ngtcp2_cid_init(&dcid_key, vc.dcid, vc.dcidlen);
862c593315Sopenharmony_ci
872c593315Sopenharmony_ci  auto conn_handler = worker_->get_connection_handler();
882c593315Sopenharmony_ci
892c593315Sopenharmony_ci  ClientHandler *handler;
902c593315Sopenharmony_ci
912c593315Sopenharmony_ci  auto &quicconf = config->quic;
922c593315Sopenharmony_ci
932c593315Sopenharmony_ci  auto it = connections_.find(dcid_key);
942c593315Sopenharmony_ci  if (it == std::end(connections_)) {
952c593315Sopenharmony_ci    auto cwit = close_waits_.find(dcid_key);
962c593315Sopenharmony_ci    if (cwit != std::end(close_waits_)) {
972c593315Sopenharmony_ci      auto cw = (*cwit).second;
982c593315Sopenharmony_ci
992c593315Sopenharmony_ci      cw->handle_packet(faddr, remote_addr, local_addr, pi, data, datalen);
1002c593315Sopenharmony_ci
1012c593315Sopenharmony_ci      return 0;
1022c593315Sopenharmony_ci    }
1032c593315Sopenharmony_ci
1042c593315Sopenharmony_ci    if (data[0] & 0x80) {
1052c593315Sopenharmony_ci      if (generate_quic_hashed_connection_id(dcid_key, remote_addr, local_addr,
1062c593315Sopenharmony_ci                                             dcid_key) != 0) {
1072c593315Sopenharmony_ci        return 0;
1082c593315Sopenharmony_ci      }
1092c593315Sopenharmony_ci
1102c593315Sopenharmony_ci      it = connections_.find(dcid_key);
1112c593315Sopenharmony_ci      if (it == std::end(connections_)) {
1122c593315Sopenharmony_ci        auto cwit = close_waits_.find(dcid_key);
1132c593315Sopenharmony_ci        if (cwit != std::end(close_waits_)) {
1142c593315Sopenharmony_ci          auto cw = (*cwit).second;
1152c593315Sopenharmony_ci
1162c593315Sopenharmony_ci          cw->handle_packet(faddr, remote_addr, local_addr, pi, data, datalen);
1172c593315Sopenharmony_ci
1182c593315Sopenharmony_ci          return 0;
1192c593315Sopenharmony_ci        }
1202c593315Sopenharmony_ci      }
1212c593315Sopenharmony_ci    }
1222c593315Sopenharmony_ci  }
1232c593315Sopenharmony_ci
1242c593315Sopenharmony_ci  if (it == std::end(connections_)) {
1252c593315Sopenharmony_ci    std::array<uint8_t, SHRPX_QUIC_DECRYPTED_DCIDLEN> decrypted_dcid;
1262c593315Sopenharmony_ci
1272c593315Sopenharmony_ci    auto &qkms = conn_handler->get_quic_keying_materials();
1282c593315Sopenharmony_ci    const QUICKeyingMaterial *qkm = nullptr;
1292c593315Sopenharmony_ci
1302c593315Sopenharmony_ci    if (vc.dcidlen == SHRPX_QUIC_SCIDLEN) {
1312c593315Sopenharmony_ci      qkm = select_quic_keying_material(
1322c593315Sopenharmony_ci          *qkms.get(), vc.dcid[0] & SHRPX_QUIC_DCID_KM_ID_MASK);
1332c593315Sopenharmony_ci
1342c593315Sopenharmony_ci      if (decrypt_quic_connection_id(decrypted_dcid.data(),
1352c593315Sopenharmony_ci                                     vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
1362c593315Sopenharmony_ci                                     qkm->cid_encryption_key.data()) != 0) {
1372c593315Sopenharmony_ci        return 0;
1382c593315Sopenharmony_ci      }
1392c593315Sopenharmony_ci
1402c593315Sopenharmony_ci      if (qkm != &qkms->keying_materials.front() ||
1412c593315Sopenharmony_ci          !std::equal(std::begin(decrypted_dcid),
1422c593315Sopenharmony_ci                      std::begin(decrypted_dcid) + SHRPX_QUIC_CID_PREFIXLEN,
1432c593315Sopenharmony_ci                      worker_->get_cid_prefix())) {
1442c593315Sopenharmony_ci        auto quic_lwp =
1452c593315Sopenharmony_ci            conn_handler->match_quic_lingering_worker_process_cid_prefix(
1462c593315Sopenharmony_ci                decrypted_dcid.data(), decrypted_dcid.size());
1472c593315Sopenharmony_ci        if (quic_lwp) {
1482c593315Sopenharmony_ci          if (conn_handler->forward_quic_packet_to_lingering_worker_process(
1492c593315Sopenharmony_ci                  quic_lwp, remote_addr, local_addr, pi, data, datalen) == 0) {
1502c593315Sopenharmony_ci            return 0;
1512c593315Sopenharmony_ci          }
1522c593315Sopenharmony_ci
1532c593315Sopenharmony_ci          return 0;
1542c593315Sopenharmony_ci        }
1552c593315Sopenharmony_ci      }
1562c593315Sopenharmony_ci    }
1572c593315Sopenharmony_ci
1582c593315Sopenharmony_ci    // new connection
1592c593315Sopenharmony_ci
1602c593315Sopenharmony_ci    auto &upstreamconf = config->conn.upstream;
1612c593315Sopenharmony_ci    if (worker_->get_worker_stat()->num_connections >=
1622c593315Sopenharmony_ci        upstreamconf.worker_connections) {
1632c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
1642c593315Sopenharmony_ci        LOG(INFO) << "Too many connections >="
1652c593315Sopenharmony_ci                  << upstreamconf.worker_connections;
1662c593315Sopenharmony_ci      }
1672c593315Sopenharmony_ci
1682c593315Sopenharmony_ci      return 0;
1692c593315Sopenharmony_ci    }
1702c593315Sopenharmony_ci
1712c593315Sopenharmony_ci    ngtcp2_pkt_hd hd;
1722c593315Sopenharmony_ci    ngtcp2_cid odcid, *podcid = nullptr;
1732c593315Sopenharmony_ci    const uint8_t *token = nullptr;
1742c593315Sopenharmony_ci    size_t tokenlen = 0;
1752c593315Sopenharmony_ci    ngtcp2_token_type token_type = NGTCP2_TOKEN_TYPE_UNKNOWN;
1762c593315Sopenharmony_ci
1772c593315Sopenharmony_ci    switch (ngtcp2_accept(&hd, data, datalen)) {
1782c593315Sopenharmony_ci    case 0: {
1792c593315Sopenharmony_ci      // If we get Initial and it has the CID prefix of this worker,
1802c593315Sopenharmony_ci      // it is likely that client is intentionally use the prefix.
1812c593315Sopenharmony_ci      // Just drop it.
1822c593315Sopenharmony_ci      if (vc.dcidlen == SHRPX_QUIC_SCIDLEN) {
1832c593315Sopenharmony_ci        if (qkm != &qkms->keying_materials.front()) {
1842c593315Sopenharmony_ci          qkm = &qkms->keying_materials.front();
1852c593315Sopenharmony_ci
1862c593315Sopenharmony_ci          if (decrypt_quic_connection_id(decrypted_dcid.data(),
1872c593315Sopenharmony_ci                                         vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
1882c593315Sopenharmony_ci                                         qkm->cid_encryption_key.data()) != 0) {
1892c593315Sopenharmony_ci            return 0;
1902c593315Sopenharmony_ci          }
1912c593315Sopenharmony_ci        }
1922c593315Sopenharmony_ci
1932c593315Sopenharmony_ci        if (std::equal(std::begin(decrypted_dcid),
1942c593315Sopenharmony_ci                       std::begin(decrypted_dcid) + SHRPX_QUIC_CID_PREFIXLEN,
1952c593315Sopenharmony_ci                       worker_->get_cid_prefix())) {
1962c593315Sopenharmony_ci          return 0;
1972c593315Sopenharmony_ci        }
1982c593315Sopenharmony_ci      }
1992c593315Sopenharmony_ci
2002c593315Sopenharmony_ci      if (worker_->get_graceful_shutdown()) {
2012c593315Sopenharmony_ci        send_connection_close(faddr, hd.version, hd.dcid, hd.scid, remote_addr,
2022c593315Sopenharmony_ci                              local_addr, NGTCP2_CONNECTION_REFUSED,
2032c593315Sopenharmony_ci                              datalen * 3);
2042c593315Sopenharmony_ci        return 0;
2052c593315Sopenharmony_ci      }
2062c593315Sopenharmony_ci
2072c593315Sopenharmony_ci      if (hd.tokenlen == 0) {
2082c593315Sopenharmony_ci        if (quicconf.upstream.require_token) {
2092c593315Sopenharmony_ci          send_retry(faddr, vc.version, vc.dcid, vc.dcidlen, vc.scid,
2102c593315Sopenharmony_ci                     vc.scidlen, remote_addr, local_addr, datalen * 3);
2112c593315Sopenharmony_ci
2122c593315Sopenharmony_ci          return 0;
2132c593315Sopenharmony_ci        }
2142c593315Sopenharmony_ci
2152c593315Sopenharmony_ci        break;
2162c593315Sopenharmony_ci      }
2172c593315Sopenharmony_ci
2182c593315Sopenharmony_ci      switch (hd.token[0]) {
2192c593315Sopenharmony_ci      case NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY: {
2202c593315Sopenharmony_ci        if (vc.dcidlen != SHRPX_QUIC_SCIDLEN) {
2212c593315Sopenharmony_ci          // Initial packets with Retry token must have DCID chosen by
2222c593315Sopenharmony_ci          // server.
2232c593315Sopenharmony_ci          return 0;
2242c593315Sopenharmony_ci        }
2252c593315Sopenharmony_ci
2262c593315Sopenharmony_ci        auto qkm = select_quic_keying_material(
2272c593315Sopenharmony_ci            *qkms.get(), vc.dcid[0] & SHRPX_QUIC_DCID_KM_ID_MASK);
2282c593315Sopenharmony_ci
2292c593315Sopenharmony_ci        if (verify_retry_token(odcid, hd.token, hd.tokenlen, hd.version,
2302c593315Sopenharmony_ci                               hd.dcid, &remote_addr.su.sa, remote_addr.len,
2312c593315Sopenharmony_ci                               qkm->secret.data(), qkm->secret.size()) != 0) {
2322c593315Sopenharmony_ci          if (LOG_ENABLED(INFO)) {
2332c593315Sopenharmony_ci            LOG(INFO) << "Failed to validate Retry token from remote="
2342c593315Sopenharmony_ci                      << util::to_numeric_addr(&remote_addr);
2352c593315Sopenharmony_ci          }
2362c593315Sopenharmony_ci
2372c593315Sopenharmony_ci          // 2nd Retry packet is not allowed, so send CONNECTION_CLOSE
2382c593315Sopenharmony_ci          // with INVALID_TOKEN.
2392c593315Sopenharmony_ci          send_connection_close(faddr, hd.version, hd.dcid, hd.scid,
2402c593315Sopenharmony_ci                                remote_addr, local_addr, NGTCP2_INVALID_TOKEN,
2412c593315Sopenharmony_ci                                datalen * 3);
2422c593315Sopenharmony_ci          return 0;
2432c593315Sopenharmony_ci        }
2442c593315Sopenharmony_ci
2452c593315Sopenharmony_ci        if (LOG_ENABLED(INFO)) {
2462c593315Sopenharmony_ci          LOG(INFO) << "Successfully validated Retry token from remote="
2472c593315Sopenharmony_ci                    << util::to_numeric_addr(&remote_addr);
2482c593315Sopenharmony_ci        }
2492c593315Sopenharmony_ci
2502c593315Sopenharmony_ci        podcid = &odcid;
2512c593315Sopenharmony_ci        token = hd.token;
2522c593315Sopenharmony_ci        tokenlen = hd.tokenlen;
2532c593315Sopenharmony_ci        token_type = NGTCP2_TOKEN_TYPE_RETRY;
2542c593315Sopenharmony_ci
2552c593315Sopenharmony_ci        break;
2562c593315Sopenharmony_ci      }
2572c593315Sopenharmony_ci      case NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR: {
2582c593315Sopenharmony_ci        // If a token is a regular token, it must be at least
2592c593315Sopenharmony_ci        // NGTCP2_MIN_INITIAL_DCIDLEN bytes long.
2602c593315Sopenharmony_ci        if (vc.dcidlen < NGTCP2_MIN_INITIAL_DCIDLEN) {
2612c593315Sopenharmony_ci          return 0;
2622c593315Sopenharmony_ci        }
2632c593315Sopenharmony_ci
2642c593315Sopenharmony_ci        if (hd.tokenlen != NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + 1) {
2652c593315Sopenharmony_ci          if (LOG_ENABLED(INFO)) {
2662c593315Sopenharmony_ci            LOG(INFO) << "Failed to validate token from remote="
2672c593315Sopenharmony_ci                      << util::to_numeric_addr(&remote_addr);
2682c593315Sopenharmony_ci          }
2692c593315Sopenharmony_ci
2702c593315Sopenharmony_ci          if (quicconf.upstream.require_token) {
2712c593315Sopenharmony_ci            send_retry(faddr, vc.version, vc.dcid, vc.dcidlen, vc.scid,
2722c593315Sopenharmony_ci                       vc.scidlen, remote_addr, local_addr, datalen * 3);
2732c593315Sopenharmony_ci
2742c593315Sopenharmony_ci            return 0;
2752c593315Sopenharmony_ci          }
2762c593315Sopenharmony_ci
2772c593315Sopenharmony_ci          break;
2782c593315Sopenharmony_ci        }
2792c593315Sopenharmony_ci
2802c593315Sopenharmony_ci        auto qkm = select_quic_keying_material(
2812c593315Sopenharmony_ci            *qkms.get(), hd.token[NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN]);
2822c593315Sopenharmony_ci
2832c593315Sopenharmony_ci        if (verify_token(hd.token, hd.tokenlen - 1, &remote_addr.su.sa,
2842c593315Sopenharmony_ci                         remote_addr.len, qkm->secret.data(),
2852c593315Sopenharmony_ci                         qkm->secret.size()) != 0) {
2862c593315Sopenharmony_ci          if (LOG_ENABLED(INFO)) {
2872c593315Sopenharmony_ci            LOG(INFO) << "Failed to validate token from remote="
2882c593315Sopenharmony_ci                      << util::to_numeric_addr(&remote_addr);
2892c593315Sopenharmony_ci          }
2902c593315Sopenharmony_ci
2912c593315Sopenharmony_ci          if (quicconf.upstream.require_token) {
2922c593315Sopenharmony_ci            send_retry(faddr, vc.version, vc.dcid, vc.dcidlen, vc.scid,
2932c593315Sopenharmony_ci                       vc.scidlen, remote_addr, local_addr, datalen * 3);
2942c593315Sopenharmony_ci
2952c593315Sopenharmony_ci            return 0;
2962c593315Sopenharmony_ci          }
2972c593315Sopenharmony_ci
2982c593315Sopenharmony_ci          break;
2992c593315Sopenharmony_ci        }
3002c593315Sopenharmony_ci
3012c593315Sopenharmony_ci        if (LOG_ENABLED(INFO)) {
3022c593315Sopenharmony_ci          LOG(INFO) << "Successfully validated token from remote="
3032c593315Sopenharmony_ci                    << util::to_numeric_addr(&remote_addr);
3042c593315Sopenharmony_ci        }
3052c593315Sopenharmony_ci
3062c593315Sopenharmony_ci        token = hd.token;
3072c593315Sopenharmony_ci        tokenlen = hd.tokenlen;
3082c593315Sopenharmony_ci        token_type = NGTCP2_TOKEN_TYPE_NEW_TOKEN;
3092c593315Sopenharmony_ci
3102c593315Sopenharmony_ci        break;
3112c593315Sopenharmony_ci      }
3122c593315Sopenharmony_ci      default:
3132c593315Sopenharmony_ci        if (quicconf.upstream.require_token) {
3142c593315Sopenharmony_ci          send_retry(faddr, vc.version, vc.dcid, vc.dcidlen, vc.scid,
3152c593315Sopenharmony_ci                     vc.scidlen, remote_addr, local_addr, datalen * 3);
3162c593315Sopenharmony_ci
3172c593315Sopenharmony_ci          return 0;
3182c593315Sopenharmony_ci        }
3192c593315Sopenharmony_ci
3202c593315Sopenharmony_ci        break;
3212c593315Sopenharmony_ci      }
3222c593315Sopenharmony_ci
3232c593315Sopenharmony_ci      break;
3242c593315Sopenharmony_ci    }
3252c593315Sopenharmony_ci    default:
3262c593315Sopenharmony_ci      if (!config->single_thread && !(data[0] & 0x80) &&
3272c593315Sopenharmony_ci          vc.dcidlen == SHRPX_QUIC_SCIDLEN &&
3282c593315Sopenharmony_ci          !std::equal(std::begin(decrypted_dcid),
3292c593315Sopenharmony_ci                      std::begin(decrypted_dcid) + SHRPX_QUIC_CID_PREFIXLEN,
3302c593315Sopenharmony_ci                      worker_->get_cid_prefix())) {
3312c593315Sopenharmony_ci        if (conn_handler->forward_quic_packet(faddr, remote_addr, local_addr,
3322c593315Sopenharmony_ci                                              pi, decrypted_dcid.data(), data,
3332c593315Sopenharmony_ci                                              datalen) == 0) {
3342c593315Sopenharmony_ci          return 0;
3352c593315Sopenharmony_ci        }
3362c593315Sopenharmony_ci      }
3372c593315Sopenharmony_ci
3382c593315Sopenharmony_ci      if (!(data[0] & 0x80)) {
3392c593315Sopenharmony_ci        // TODO Must be rate limited
3402c593315Sopenharmony_ci        send_stateless_reset(faddr, vc.dcid, vc.dcidlen, remote_addr,
3412c593315Sopenharmony_ci                             local_addr);
3422c593315Sopenharmony_ci      }
3432c593315Sopenharmony_ci
3442c593315Sopenharmony_ci      return 0;
3452c593315Sopenharmony_ci    }
3462c593315Sopenharmony_ci
3472c593315Sopenharmony_ci    handler = handle_new_connection(faddr, remote_addr, local_addr, hd, podcid,
3482c593315Sopenharmony_ci                                    token, tokenlen, token_type);
3492c593315Sopenharmony_ci    if (handler == nullptr) {
3502c593315Sopenharmony_ci      return 0;
3512c593315Sopenharmony_ci    }
3522c593315Sopenharmony_ci  } else {
3532c593315Sopenharmony_ci    handler = (*it).second;
3542c593315Sopenharmony_ci  }
3552c593315Sopenharmony_ci
3562c593315Sopenharmony_ci  if (handler->read_quic(faddr, remote_addr, local_addr, pi, data, datalen) !=
3572c593315Sopenharmony_ci      0) {
3582c593315Sopenharmony_ci    delete handler;
3592c593315Sopenharmony_ci    return 0;
3602c593315Sopenharmony_ci  }
3612c593315Sopenharmony_ci
3622c593315Sopenharmony_ci  handler->signal_write();
3632c593315Sopenharmony_ci
3642c593315Sopenharmony_ci  return 0;
3652c593315Sopenharmony_ci}
3662c593315Sopenharmony_ci
3672c593315Sopenharmony_ciClientHandler *QUICConnectionHandler::handle_new_connection(
3682c593315Sopenharmony_ci    const UpstreamAddr *faddr, const Address &remote_addr,
3692c593315Sopenharmony_ci    const Address &local_addr, const ngtcp2_pkt_hd &hd, const ngtcp2_cid *odcid,
3702c593315Sopenharmony_ci    const uint8_t *token, size_t tokenlen, ngtcp2_token_type token_type) {
3712c593315Sopenharmony_ci  std::array<char, NI_MAXHOST> host;
3722c593315Sopenharmony_ci  std::array<char, NI_MAXSERV> service;
3732c593315Sopenharmony_ci  int rv;
3742c593315Sopenharmony_ci
3752c593315Sopenharmony_ci  rv = getnameinfo(&remote_addr.su.sa, remote_addr.len, host.data(),
3762c593315Sopenharmony_ci                   host.size(), service.data(), service.size(),
3772c593315Sopenharmony_ci                   NI_NUMERICHOST | NI_NUMERICSERV);
3782c593315Sopenharmony_ci  if (rv != 0) {
3792c593315Sopenharmony_ci    LOG(ERROR) << "getnameinfo() failed: " << gai_strerror(rv);
3802c593315Sopenharmony_ci
3812c593315Sopenharmony_ci    return nullptr;
3822c593315Sopenharmony_ci  }
3832c593315Sopenharmony_ci
3842c593315Sopenharmony_ci  auto ssl_ctx = worker_->get_quic_sv_ssl_ctx();
3852c593315Sopenharmony_ci
3862c593315Sopenharmony_ci  assert(ssl_ctx);
3872c593315Sopenharmony_ci
3882c593315Sopenharmony_ci  auto ssl = tls::create_ssl(ssl_ctx);
3892c593315Sopenharmony_ci  if (ssl == nullptr) {
3902c593315Sopenharmony_ci    return nullptr;
3912c593315Sopenharmony_ci  }
3922c593315Sopenharmony_ci
3932c593315Sopenharmony_ci#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
3942c593315Sopenharmony_ci  assert(SSL_is_quic(ssl));
3952c593315Sopenharmony_ci#endif // OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
3962c593315Sopenharmony_ci
3972c593315Sopenharmony_ci  SSL_set_accept_state(ssl);
3982c593315Sopenharmony_ci
3992c593315Sopenharmony_ci  auto config = get_config();
4002c593315Sopenharmony_ci  auto &quicconf = config->quic;
4012c593315Sopenharmony_ci
4022c593315Sopenharmony_ci  if (quicconf.upstream.early_data) {
4032c593315Sopenharmony_ci#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
4042c593315Sopenharmony_ci    SSL_set_quic_early_data_enabled(ssl, 1);
4052c593315Sopenharmony_ci#else  // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
4062c593315Sopenharmony_ci    SSL_set_early_data_enabled(ssl, 1);
4072c593315Sopenharmony_ci#endif // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
4082c593315Sopenharmony_ci  }
4092c593315Sopenharmony_ci
4102c593315Sopenharmony_ci  // Disable TLS session ticket if we don't have working ticket
4112c593315Sopenharmony_ci  // keys.
4122c593315Sopenharmony_ci  if (!worker_->get_ticket_keys()) {
4132c593315Sopenharmony_ci    SSL_set_options(ssl, SSL_OP_NO_TICKET);
4142c593315Sopenharmony_ci  }
4152c593315Sopenharmony_ci
4162c593315Sopenharmony_ci  auto handler = std::make_unique<ClientHandler>(
4172c593315Sopenharmony_ci      worker_, faddr->fd, ssl, StringRef{host.data()},
4182c593315Sopenharmony_ci      StringRef{service.data()}, remote_addr.su.sa.sa_family, faddr);
4192c593315Sopenharmony_ci
4202c593315Sopenharmony_ci  auto upstream = std::make_unique<Http3Upstream>(handler.get());
4212c593315Sopenharmony_ci  if (upstream->init(faddr, remote_addr, local_addr, hd, odcid, token, tokenlen,
4222c593315Sopenharmony_ci                     token_type) != 0) {
4232c593315Sopenharmony_ci    return nullptr;
4242c593315Sopenharmony_ci  }
4252c593315Sopenharmony_ci
4262c593315Sopenharmony_ci  handler->setup_http3_upstream(std::move(upstream));
4272c593315Sopenharmony_ci
4282c593315Sopenharmony_ci  return handler.release();
4292c593315Sopenharmony_ci}
4302c593315Sopenharmony_ci
4312c593315Sopenharmony_cinamespace {
4322c593315Sopenharmony_ciuint32_t generate_reserved_version(const Address &addr, uint32_t version) {
4332c593315Sopenharmony_ci  uint32_t h = 0x811C9DC5u;
4342c593315Sopenharmony_ci  const uint8_t *p = reinterpret_cast<const uint8_t *>(&addr.su.sa);
4352c593315Sopenharmony_ci  const uint8_t *ep = p + addr.len;
4362c593315Sopenharmony_ci
4372c593315Sopenharmony_ci  for (; p != ep; ++p) {
4382c593315Sopenharmony_ci    h ^= *p;
4392c593315Sopenharmony_ci    h *= 0x01000193u;
4402c593315Sopenharmony_ci  }
4412c593315Sopenharmony_ci
4422c593315Sopenharmony_ci  version = htonl(version);
4432c593315Sopenharmony_ci  p = (const uint8_t *)&version;
4442c593315Sopenharmony_ci  ep = p + sizeof(version);
4452c593315Sopenharmony_ci
4462c593315Sopenharmony_ci  for (; p != ep; ++p) {
4472c593315Sopenharmony_ci    h ^= *p;
4482c593315Sopenharmony_ci    h *= 0x01000193u;
4492c593315Sopenharmony_ci  }
4502c593315Sopenharmony_ci
4512c593315Sopenharmony_ci  h &= 0xf0f0f0f0u;
4522c593315Sopenharmony_ci  h |= 0x0a0a0a0au;
4532c593315Sopenharmony_ci
4542c593315Sopenharmony_ci  return h;
4552c593315Sopenharmony_ci}
4562c593315Sopenharmony_ci} // namespace
4572c593315Sopenharmony_ci
4582c593315Sopenharmony_ciint QUICConnectionHandler::send_retry(
4592c593315Sopenharmony_ci    const UpstreamAddr *faddr, uint32_t version, const uint8_t *ini_dcid,
4602c593315Sopenharmony_ci    size_t ini_dcidlen, const uint8_t *ini_scid, size_t ini_scidlen,
4612c593315Sopenharmony_ci    const Address &remote_addr, const Address &local_addr, size_t max_pktlen) {
4622c593315Sopenharmony_ci  std::array<char, NI_MAXHOST> host;
4632c593315Sopenharmony_ci  std::array<char, NI_MAXSERV> port;
4642c593315Sopenharmony_ci
4652c593315Sopenharmony_ci  if (getnameinfo(&remote_addr.su.sa, remote_addr.len, host.data(), host.size(),
4662c593315Sopenharmony_ci                  port.data(), port.size(),
4672c593315Sopenharmony_ci                  NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
4682c593315Sopenharmony_ci    return -1;
4692c593315Sopenharmony_ci  }
4702c593315Sopenharmony_ci
4712c593315Sopenharmony_ci  auto config = get_config();
4722c593315Sopenharmony_ci  auto &quicconf = config->quic;
4732c593315Sopenharmony_ci
4742c593315Sopenharmony_ci  auto conn_handler = worker_->get_connection_handler();
4752c593315Sopenharmony_ci  auto &qkms = conn_handler->get_quic_keying_materials();
4762c593315Sopenharmony_ci  auto &qkm = qkms->keying_materials.front();
4772c593315Sopenharmony_ci
4782c593315Sopenharmony_ci  ngtcp2_cid retry_scid;
4792c593315Sopenharmony_ci
4802c593315Sopenharmony_ci  if (generate_quic_retry_connection_id(retry_scid, SHRPX_QUIC_SCIDLEN,
4812c593315Sopenharmony_ci                                        quicconf.server_id.data(), qkm.id,
4822c593315Sopenharmony_ci                                        qkm.cid_encryption_key.data()) != 0) {
4832c593315Sopenharmony_ci    return -1;
4842c593315Sopenharmony_ci  }
4852c593315Sopenharmony_ci
4862c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN> token;
4872c593315Sopenharmony_ci  size_t tokenlen;
4882c593315Sopenharmony_ci
4892c593315Sopenharmony_ci  ngtcp2_cid idcid, iscid;
4902c593315Sopenharmony_ci  ngtcp2_cid_init(&idcid, ini_dcid, ini_dcidlen);
4912c593315Sopenharmony_ci  ngtcp2_cid_init(&iscid, ini_scid, ini_scidlen);
4922c593315Sopenharmony_ci
4932c593315Sopenharmony_ci  if (generate_retry_token(token.data(), tokenlen, version, &remote_addr.su.sa,
4942c593315Sopenharmony_ci                           remote_addr.len, retry_scid, idcid,
4952c593315Sopenharmony_ci                           qkm.secret.data(), qkm.secret.size()) != 0) {
4962c593315Sopenharmony_ci    return -1;
4972c593315Sopenharmony_ci  }
4982c593315Sopenharmony_ci
4992c593315Sopenharmony_ci  std::vector<uint8_t> buf;
5002c593315Sopenharmony_ci  buf.resize(std::min(max_pktlen, static_cast<size_t>(256)));
5012c593315Sopenharmony_ci
5022c593315Sopenharmony_ci  auto nwrite =
5032c593315Sopenharmony_ci      ngtcp2_crypto_write_retry(buf.data(), buf.size(), version, &iscid,
5042c593315Sopenharmony_ci                                &retry_scid, &idcid, token.data(), tokenlen);
5052c593315Sopenharmony_ci  if (nwrite < 0) {
5062c593315Sopenharmony_ci    LOG(ERROR) << "ngtcp2_crypto_write_retry: " << ngtcp2_strerror(nwrite);
5072c593315Sopenharmony_ci    return -1;
5082c593315Sopenharmony_ci  }
5092c593315Sopenharmony_ci
5102c593315Sopenharmony_ci  buf.resize(nwrite);
5112c593315Sopenharmony_ci
5122c593315Sopenharmony_ci  quic_send_packet(faddr, &remote_addr.su.sa, remote_addr.len,
5132c593315Sopenharmony_ci                   &local_addr.su.sa, local_addr.len, ngtcp2_pkt_info{},
5142c593315Sopenharmony_ci                   buf.data(), buf.size(), 0);
5152c593315Sopenharmony_ci
5162c593315Sopenharmony_ci  if (generate_quic_hashed_connection_id(idcid, remote_addr, local_addr,
5172c593315Sopenharmony_ci                                         idcid) != 0) {
5182c593315Sopenharmony_ci    return -1;
5192c593315Sopenharmony_ci  }
5202c593315Sopenharmony_ci
5212c593315Sopenharmony_ci  auto d =
5222c593315Sopenharmony_ci      static_cast<ev_tstamp>(NGTCP2_DEFAULT_INITIAL_RTT * 3) / NGTCP2_SECONDS;
5232c593315Sopenharmony_ci
5242c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
5252c593315Sopenharmony_ci    LOG(INFO) << "Enter close-wait period " << d << "s with " << buf.size()
5262c593315Sopenharmony_ci              << " bytes sentinel packet";
5272c593315Sopenharmony_ci  }
5282c593315Sopenharmony_ci
5292c593315Sopenharmony_ci  auto cw = std::make_unique<CloseWait>(worker_, std::vector<ngtcp2_cid>{idcid},
5302c593315Sopenharmony_ci                                        std::move(buf), d);
5312c593315Sopenharmony_ci
5322c593315Sopenharmony_ci  add_close_wait(cw.release());
5332c593315Sopenharmony_ci
5342c593315Sopenharmony_ci  return 0;
5352c593315Sopenharmony_ci}
5362c593315Sopenharmony_ci
5372c593315Sopenharmony_ciint QUICConnectionHandler::send_version_negotiation(
5382c593315Sopenharmony_ci    const UpstreamAddr *faddr, uint32_t version, const uint8_t *ini_dcid,
5392c593315Sopenharmony_ci    size_t ini_dcidlen, const uint8_t *ini_scid, size_t ini_scidlen,
5402c593315Sopenharmony_ci    const Address &remote_addr, const Address &local_addr) {
5412c593315Sopenharmony_ci  std::array<uint32_t, 2> sv{
5422c593315Sopenharmony_ci      generate_reserved_version(remote_addr, version),
5432c593315Sopenharmony_ci      NGTCP2_PROTO_VER_V1,
5442c593315Sopenharmony_ci  };
5452c593315Sopenharmony_ci
5462c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_MAX_UDP_PAYLOAD_SIZE> buf;
5472c593315Sopenharmony_ci
5482c593315Sopenharmony_ci  uint8_t rand_byte;
5492c593315Sopenharmony_ci  util::random_bytes(&rand_byte, &rand_byte + 1, worker_->get_randgen());
5502c593315Sopenharmony_ci
5512c593315Sopenharmony_ci  auto nwrite = ngtcp2_pkt_write_version_negotiation(
5522c593315Sopenharmony_ci      buf.data(), buf.size(), rand_byte, ini_scid, ini_scidlen, ini_dcid,
5532c593315Sopenharmony_ci      ini_dcidlen, sv.data(), sv.size());
5542c593315Sopenharmony_ci  if (nwrite < 0) {
5552c593315Sopenharmony_ci    LOG(ERROR) << "ngtcp2_pkt_write_version_negotiation: "
5562c593315Sopenharmony_ci               << ngtcp2_strerror(nwrite);
5572c593315Sopenharmony_ci    return -1;
5582c593315Sopenharmony_ci  }
5592c593315Sopenharmony_ci
5602c593315Sopenharmony_ci  return quic_send_packet(faddr, &remote_addr.su.sa, remote_addr.len,
5612c593315Sopenharmony_ci                          &local_addr.su.sa, local_addr.len, ngtcp2_pkt_info{},
5622c593315Sopenharmony_ci                          buf.data(), nwrite, 0);
5632c593315Sopenharmony_ci}
5642c593315Sopenharmony_ci
5652c593315Sopenharmony_ciint QUICConnectionHandler::send_stateless_reset(const UpstreamAddr *faddr,
5662c593315Sopenharmony_ci                                                const uint8_t *dcid,
5672c593315Sopenharmony_ci                                                size_t dcidlen,
5682c593315Sopenharmony_ci                                                const Address &remote_addr,
5692c593315Sopenharmony_ci                                                const Address &local_addr) {
5702c593315Sopenharmony_ci  if (stateless_reset_bucket_ == 0) {
5712c593315Sopenharmony_ci    if (LOG_ENABLED(INFO)) {
5722c593315Sopenharmony_ci      LOG(INFO) << "Stateless Reset bucket has been depleted";
5732c593315Sopenharmony_ci    }
5742c593315Sopenharmony_ci
5752c593315Sopenharmony_ci    return 0;
5762c593315Sopenharmony_ci  }
5772c593315Sopenharmony_ci
5782c593315Sopenharmony_ci  --stateless_reset_bucket_;
5792c593315Sopenharmony_ci
5802c593315Sopenharmony_ci  if (!ev_is_active(&stateless_reset_bucket_regen_timer_)) {
5812c593315Sopenharmony_ci    ev_timer_again(worker_->get_loop(), &stateless_reset_bucket_regen_timer_);
5822c593315Sopenharmony_ci  }
5832c593315Sopenharmony_ci
5842c593315Sopenharmony_ci  int rv;
5852c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_STATELESS_RESET_TOKENLEN> token;
5862c593315Sopenharmony_ci  ngtcp2_cid cid;
5872c593315Sopenharmony_ci
5882c593315Sopenharmony_ci  ngtcp2_cid_init(&cid, dcid, dcidlen);
5892c593315Sopenharmony_ci
5902c593315Sopenharmony_ci  auto conn_handler = worker_->get_connection_handler();
5912c593315Sopenharmony_ci  auto &qkms = conn_handler->get_quic_keying_materials();
5922c593315Sopenharmony_ci  auto &qkm = qkms->keying_materials.front();
5932c593315Sopenharmony_ci
5942c593315Sopenharmony_ci  rv = generate_quic_stateless_reset_token(token.data(), cid, qkm.secret.data(),
5952c593315Sopenharmony_ci                                           qkm.secret.size());
5962c593315Sopenharmony_ci  if (rv != 0) {
5972c593315Sopenharmony_ci    return -1;
5982c593315Sopenharmony_ci  }
5992c593315Sopenharmony_ci
6002c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_MIN_STATELESS_RESET_RANDLEN> rand_bytes;
6012c593315Sopenharmony_ci
6022c593315Sopenharmony_ci  if (RAND_bytes(rand_bytes.data(), rand_bytes.size()) != 1) {
6032c593315Sopenharmony_ci    return -1;
6042c593315Sopenharmony_ci  }
6052c593315Sopenharmony_ci
6062c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_MAX_UDP_PAYLOAD_SIZE> buf;
6072c593315Sopenharmony_ci
6082c593315Sopenharmony_ci  auto nwrite =
6092c593315Sopenharmony_ci      ngtcp2_pkt_write_stateless_reset(buf.data(), buf.size(), token.data(),
6102c593315Sopenharmony_ci                                       rand_bytes.data(), rand_bytes.size());
6112c593315Sopenharmony_ci  if (nwrite < 0) {
6122c593315Sopenharmony_ci    LOG(ERROR) << "ngtcp2_pkt_write_stateless_reset: "
6132c593315Sopenharmony_ci               << ngtcp2_strerror(nwrite);
6142c593315Sopenharmony_ci    return -1;
6152c593315Sopenharmony_ci  }
6162c593315Sopenharmony_ci
6172c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
6182c593315Sopenharmony_ci    LOG(INFO) << "Send stateless_reset to remote="
6192c593315Sopenharmony_ci              << util::to_numeric_addr(&remote_addr)
6202c593315Sopenharmony_ci              << " dcid=" << util::format_hex(dcid, dcidlen);
6212c593315Sopenharmony_ci  }
6222c593315Sopenharmony_ci
6232c593315Sopenharmony_ci  return quic_send_packet(faddr, &remote_addr.su.sa, remote_addr.len,
6242c593315Sopenharmony_ci                          &local_addr.su.sa, local_addr.len, ngtcp2_pkt_info{},
6252c593315Sopenharmony_ci                          buf.data(), nwrite, 0);
6262c593315Sopenharmony_ci}
6272c593315Sopenharmony_ci
6282c593315Sopenharmony_ciint QUICConnectionHandler::send_connection_close(
6292c593315Sopenharmony_ci    const UpstreamAddr *faddr, uint32_t version, const ngtcp2_cid &ini_dcid,
6302c593315Sopenharmony_ci    const ngtcp2_cid &ini_scid, const Address &remote_addr,
6312c593315Sopenharmony_ci    const Address &local_addr, uint64_t error_code, size_t max_pktlen) {
6322c593315Sopenharmony_ci  std::array<uint8_t, NGTCP2_MAX_UDP_PAYLOAD_SIZE> buf;
6332c593315Sopenharmony_ci
6342c593315Sopenharmony_ci  max_pktlen = std::min(max_pktlen, buf.size());
6352c593315Sopenharmony_ci
6362c593315Sopenharmony_ci  auto nwrite = ngtcp2_crypto_write_connection_close(
6372c593315Sopenharmony_ci      buf.data(), max_pktlen, version, &ini_scid, &ini_dcid, error_code,
6382c593315Sopenharmony_ci      nullptr, 0);
6392c593315Sopenharmony_ci  if (nwrite < 0) {
6402c593315Sopenharmony_ci    LOG(ERROR) << "ngtcp2_crypto_write_connection_close failed";
6412c593315Sopenharmony_ci    return -1;
6422c593315Sopenharmony_ci  }
6432c593315Sopenharmony_ci
6442c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
6452c593315Sopenharmony_ci    LOG(INFO) << "Send Initial CONNECTION_CLOSE with error_code=" << log::hex
6462c593315Sopenharmony_ci              << error_code << log::dec
6472c593315Sopenharmony_ci              << " to remote=" << util::to_numeric_addr(&remote_addr)
6482c593315Sopenharmony_ci              << " dcid=" << util::format_hex(ini_scid.data, ini_scid.datalen)
6492c593315Sopenharmony_ci              << " scid=" << util::format_hex(ini_dcid.data, ini_dcid.datalen);
6502c593315Sopenharmony_ci  }
6512c593315Sopenharmony_ci
6522c593315Sopenharmony_ci  return quic_send_packet(faddr, &remote_addr.su.sa, remote_addr.len,
6532c593315Sopenharmony_ci                          &local_addr.su.sa, local_addr.len, ngtcp2_pkt_info{},
6542c593315Sopenharmony_ci                          buf.data(), nwrite, 0);
6552c593315Sopenharmony_ci}
6562c593315Sopenharmony_ci
6572c593315Sopenharmony_civoid QUICConnectionHandler::add_connection_id(const ngtcp2_cid &cid,
6582c593315Sopenharmony_ci                                              ClientHandler *handler) {
6592c593315Sopenharmony_ci  connections_.emplace(cid, handler);
6602c593315Sopenharmony_ci}
6612c593315Sopenharmony_ci
6622c593315Sopenharmony_civoid QUICConnectionHandler::remove_connection_id(const ngtcp2_cid &cid) {
6632c593315Sopenharmony_ci  connections_.erase(cid);
6642c593315Sopenharmony_ci}
6652c593315Sopenharmony_ci
6662c593315Sopenharmony_civoid QUICConnectionHandler::add_close_wait(CloseWait *cw) {
6672c593315Sopenharmony_ci  for (auto &cid : cw->scids) {
6682c593315Sopenharmony_ci    close_waits_.emplace(cid, cw);
6692c593315Sopenharmony_ci  }
6702c593315Sopenharmony_ci}
6712c593315Sopenharmony_ci
6722c593315Sopenharmony_civoid QUICConnectionHandler::remove_close_wait(const CloseWait *cw) {
6732c593315Sopenharmony_ci  for (auto &cid : cw->scids) {
6742c593315Sopenharmony_ci    close_waits_.erase(cid);
6752c593315Sopenharmony_ci  }
6762c593315Sopenharmony_ci}
6772c593315Sopenharmony_ci
6782c593315Sopenharmony_civoid QUICConnectionHandler::on_stateless_reset_bucket_regen() {
6792c593315Sopenharmony_ci  assert(stateless_reset_bucket_ < SHRPX_QUIC_STATELESS_RESET_BURST);
6802c593315Sopenharmony_ci
6812c593315Sopenharmony_ci  if (++stateless_reset_bucket_ == SHRPX_QUIC_STATELESS_RESET_BURST) {
6822c593315Sopenharmony_ci    ev_timer_stop(worker_->get_loop(), &stateless_reset_bucket_regen_timer_);
6832c593315Sopenharmony_ci  }
6842c593315Sopenharmony_ci}
6852c593315Sopenharmony_ci
6862c593315Sopenharmony_cistatic void close_wait_timeoutcb(struct ev_loop *loop, ev_timer *w,
6872c593315Sopenharmony_ci                                 int revents) {
6882c593315Sopenharmony_ci  auto cw = static_cast<CloseWait *>(w->data);
6892c593315Sopenharmony_ci
6902c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
6912c593315Sopenharmony_ci    LOG(INFO) << "close-wait period finished";
6922c593315Sopenharmony_ci  }
6932c593315Sopenharmony_ci
6942c593315Sopenharmony_ci  auto quic_conn_handler = cw->worker->get_quic_connection_handler();
6952c593315Sopenharmony_ci  quic_conn_handler->remove_close_wait(cw);
6962c593315Sopenharmony_ci
6972c593315Sopenharmony_ci  delete cw;
6982c593315Sopenharmony_ci}
6992c593315Sopenharmony_ci
7002c593315Sopenharmony_ciCloseWait::CloseWait(Worker *worker, std::vector<ngtcp2_cid> scids,
7012c593315Sopenharmony_ci                     std::vector<uint8_t> pkt, ev_tstamp period)
7022c593315Sopenharmony_ci    : worker{worker},
7032c593315Sopenharmony_ci      scids{std::move(scids)},
7042c593315Sopenharmony_ci      pkt{std::move(pkt)},
7052c593315Sopenharmony_ci      bytes_recv{0},
7062c593315Sopenharmony_ci      bytes_sent{0},
7072c593315Sopenharmony_ci      num_pkts_recv{0},
7082c593315Sopenharmony_ci      next_pkts_recv{1} {
7092c593315Sopenharmony_ci  ++worker->get_worker_stat()->num_close_waits;
7102c593315Sopenharmony_ci
7112c593315Sopenharmony_ci  ev_timer_init(&timer, close_wait_timeoutcb, period, 0.);
7122c593315Sopenharmony_ci  timer.data = this;
7132c593315Sopenharmony_ci
7142c593315Sopenharmony_ci  ev_timer_start(worker->get_loop(), &timer);
7152c593315Sopenharmony_ci}
7162c593315Sopenharmony_ci
7172c593315Sopenharmony_ciCloseWait::~CloseWait() {
7182c593315Sopenharmony_ci  auto loop = worker->get_loop();
7192c593315Sopenharmony_ci
7202c593315Sopenharmony_ci  ev_timer_stop(loop, &timer);
7212c593315Sopenharmony_ci
7222c593315Sopenharmony_ci  auto worker_stat = worker->get_worker_stat();
7232c593315Sopenharmony_ci  --worker_stat->num_close_waits;
7242c593315Sopenharmony_ci
7252c593315Sopenharmony_ci  if (worker->get_graceful_shutdown() && worker_stat->num_connections == 0 &&
7262c593315Sopenharmony_ci      worker_stat->num_close_waits == 0) {
7272c593315Sopenharmony_ci    ev_break(loop);
7282c593315Sopenharmony_ci  }
7292c593315Sopenharmony_ci}
7302c593315Sopenharmony_ci
7312c593315Sopenharmony_ciint CloseWait::handle_packet(const UpstreamAddr *faddr,
7322c593315Sopenharmony_ci                             const Address &remote_addr,
7332c593315Sopenharmony_ci                             const Address &local_addr,
7342c593315Sopenharmony_ci                             const ngtcp2_pkt_info &pi, const uint8_t *data,
7352c593315Sopenharmony_ci                             size_t datalen) {
7362c593315Sopenharmony_ci  if (pkt.empty()) {
7372c593315Sopenharmony_ci    return 0;
7382c593315Sopenharmony_ci  }
7392c593315Sopenharmony_ci
7402c593315Sopenharmony_ci  ++num_pkts_recv;
7412c593315Sopenharmony_ci  bytes_recv += datalen;
7422c593315Sopenharmony_ci
7432c593315Sopenharmony_ci  if (bytes_sent + pkt.size() > 3 * bytes_recv ||
7442c593315Sopenharmony_ci      next_pkts_recv > num_pkts_recv) {
7452c593315Sopenharmony_ci    return 0;
7462c593315Sopenharmony_ci  }
7472c593315Sopenharmony_ci
7482c593315Sopenharmony_ci  if (quic_send_packet(faddr, &remote_addr.su.sa, remote_addr.len,
7492c593315Sopenharmony_ci                       &local_addr.su.sa, local_addr.len, ngtcp2_pkt_info{},
7502c593315Sopenharmony_ci                       pkt.data(), pkt.size(), 0) != 0) {
7512c593315Sopenharmony_ci    return -1;
7522c593315Sopenharmony_ci  }
7532c593315Sopenharmony_ci
7542c593315Sopenharmony_ci  next_pkts_recv *= 2;
7552c593315Sopenharmony_ci  bytes_sent += pkt.size();
7562c593315Sopenharmony_ci
7572c593315Sopenharmony_ci  return 0;
7582c593315Sopenharmony_ci}
7592c593315Sopenharmony_ci
7602c593315Sopenharmony_ci} // namespace shrpx
761