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