lsquic_pr_queue.c revision 92f6e17b
15392f7a3SLiteSpeed Tech/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech/*
35392f7a3SLiteSpeed Tech * lsquic_pr_queue.c -- packet request queue.
45392f7a3SLiteSpeed Tech */
55392f7a3SLiteSpeed Tech
65392f7a3SLiteSpeed Tech#include <assert.h>
75392f7a3SLiteSpeed Tech#include <errno.h>
85392f7a3SLiteSpeed Tech#include <inttypes.h>
95392f7a3SLiteSpeed Tech#include <netinet/in.h>
105392f7a3SLiteSpeed Tech#include <stdlib.h>
115392f7a3SLiteSpeed Tech#include <string.h>
125392f7a3SLiteSpeed Tech#include <sys/queue.h>
135392f7a3SLiteSpeed Tech#include <sys/socket.h>
145392f7a3SLiteSpeed Tech
155392f7a3SLiteSpeed Tech#include <openssl/aead.h>
165392f7a3SLiteSpeed Tech#include <openssl/rand.h>
175392f7a3SLiteSpeed Tech
185392f7a3SLiteSpeed Tech#include "lsquic.h"
195392f7a3SLiteSpeed Tech#include "lsquic_types.h"
205392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
215392f7a3SLiteSpeed Tech#include "lsquic_packet_common.h"
225392f7a3SLiteSpeed Tech#include "lsquic_packet_gquic.h"
235392f7a3SLiteSpeed Tech#include "lsquic_packet_out.h"
245392f7a3SLiteSpeed Tech#include "lsquic_packet_in.h"
255392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
265392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
275392f7a3SLiteSpeed Tech#include "lsquic_parse.h"
285392f7a3SLiteSpeed Tech#include "lsquic_malo.h"
295392f7a3SLiteSpeed Tech#include "lsquic_pr_queue.h"
305392f7a3SLiteSpeed Tech#include "lsquic_parse_common.h"
315392f7a3SLiteSpeed Tech#include "lsquic_tokgen.h"
325392f7a3SLiteSpeed Tech#include "lsquic_version.h"
335392f7a3SLiteSpeed Tech#include "lsquic_mm.h"
345392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h"
355392f7a3SLiteSpeed Tech#include "lsquic_sizes.h"
365392f7a3SLiteSpeed Tech#include "lsquic_handshake.h"
3792f6e17bSDmitri Tikhonov#include "lsquic_xxhash.h"
385392f7a3SLiteSpeed Tech
395392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_PRQ
405392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
415392f7a3SLiteSpeed Tech
425392f7a3SLiteSpeed Tech#define MAX(a, b) ((a) > (b) ? (a) : (b))
4392f6e17bSDmitri Tikhonov#define MIN(a, b) ((a) < (b) ? (a) : (b))
445392f7a3SLiteSpeed Tech
455392f7a3SLiteSpeed Tech
465392f7a3SLiteSpeed Techstatic const struct conn_iface evanescent_conn_iface;
475392f7a3SLiteSpeed Tech
485392f7a3SLiteSpeed Tech
495392f7a3SLiteSpeed Techstruct packet_req
505392f7a3SLiteSpeed Tech{
5192f6e17bSDmitri Tikhonov    struct lsquic_hash_elem     pr_hash_el;
525392f7a3SLiteSpeed Tech    lsquic_cid_t                pr_scid;
535392f7a3SLiteSpeed Tech    lsquic_cid_t                pr_dcid;
545392f7a3SLiteSpeed Tech    enum packet_req_type        pr_type;
5592f6e17bSDmitri Tikhonov    enum pr_flags {
565392f7a3SLiteSpeed Tech        PR_GQUIC    = 1 << 0,
575392f7a3SLiteSpeed Tech    }                           pr_flags;
585392f7a3SLiteSpeed Tech    enum lsquic_version         pr_version;
5992f6e17bSDmitri Tikhonov    unsigned                    pr_rst_sz;
605392f7a3SLiteSpeed Tech    struct network_path         pr_path;
615392f7a3SLiteSpeed Tech};
625392f7a3SLiteSpeed Tech
635392f7a3SLiteSpeed Tech
645392f7a3SLiteSpeed Techstruct evanescent_conn
655392f7a3SLiteSpeed Tech{
665392f7a3SLiteSpeed Tech    struct lsquic_conn          evc_conn;
675392f7a3SLiteSpeed Tech    struct packet_req          *evc_req;
685392f7a3SLiteSpeed Tech    struct pr_queue            *evc_queue;
695392f7a3SLiteSpeed Tech    struct lsquic_packet_out    evc_packet_out;
705392f7a3SLiteSpeed Tech    struct conn_cid_elem        evc_cces[1];
715392f7a3SLiteSpeed Tech    unsigned char               evc_buf[0];
725392f7a3SLiteSpeed Tech};
735392f7a3SLiteSpeed Tech
745392f7a3SLiteSpeed Tech
755392f7a3SLiteSpeed Tech/* [draft-ietf-quic-transport-22], Section 17.2.1 */
765392f7a3SLiteSpeed Tech#define IQUIC_VERNEG_SIZE (1 /* Type */ + 4 /* Version (zero tag) */ \
775392f7a3SLiteSpeed Tech                + 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
785392f7a3SLiteSpeed Tech                4 * N_LSQVER)
795392f7a3SLiteSpeed Tech
805392f7a3SLiteSpeed Tech
815392f7a3SLiteSpeed Techstruct pr_queue
825392f7a3SLiteSpeed Tech{
835392f7a3SLiteSpeed Tech    TAILQ_HEAD(, lsquic_conn)   prq_free_conns,
845392f7a3SLiteSpeed Tech                                prq_returned_conns;
855392f7a3SLiteSpeed Tech    struct malo                *prq_reqs_pool;
865392f7a3SLiteSpeed Tech    const struct lsquic_engine_public
875392f7a3SLiteSpeed Tech                               *prq_enpub;
8892f6e17bSDmitri Tikhonov    struct lsquic_hash         *prq_reqs_hash;
895392f7a3SLiteSpeed Tech    unsigned                    prq_max_reqs;
905392f7a3SLiteSpeed Tech    unsigned                    prq_nreqs;
915392f7a3SLiteSpeed Tech    unsigned                    prq_max_conns;
925392f7a3SLiteSpeed Tech    unsigned                    prq_nconns;
935392f7a3SLiteSpeed Tech    unsigned                    prq_verneg_g_sz;  /* Size of prq_verneg_g_buf */
945392f7a3SLiteSpeed Tech    unsigned                    prq_pubres_g_sz;  /* Size of prq_pubres_g_buf */
955392f7a3SLiteSpeed Tech
965392f7a3SLiteSpeed Tech    /* GQUIC version negotiation and stateless reset packets are generated
975392f7a3SLiteSpeed Tech     * once, when the Packet Request Queue is created.  For each request,
985392f7a3SLiteSpeed Tech     * these buffers are simply copied and the connection ID is replaced.
995392f7a3SLiteSpeed Tech     *
1005392f7a3SLiteSpeed Tech     * Since IETF QUIC uses variable-length connections IDs, we have to
1015392f7a3SLiteSpeed Tech     * generate packets every time.
1025392f7a3SLiteSpeed Tech     */
1035392f7a3SLiteSpeed Tech    unsigned char               prq_pubres_g_buf[GQUIC_RESET_SZ];
1045392f7a3SLiteSpeed Tech    unsigned char               prq_verneg_g_buf[1 + GQUIC_CID_LEN
1055392f7a3SLiteSpeed Tech                                                                + N_LSQVER * 4];
1065392f7a3SLiteSpeed Tech};
1075392f7a3SLiteSpeed Tech
1085392f7a3SLiteSpeed Tech
10992f6e17bSDmitri Tikhonovstatic int
11092f6e17bSDmitri Tikhonovcomp_reqs (const void *s1, const void *s2, size_t n)
11192f6e17bSDmitri Tikhonov{
11292f6e17bSDmitri Tikhonov    const struct packet_req *a, *b;
11392f6e17bSDmitri Tikhonov
11492f6e17bSDmitri Tikhonov    a = s1;
11592f6e17bSDmitri Tikhonov    b = s2;
11692f6e17bSDmitri Tikhonov    if (a->pr_type == b->pr_type && LSQUIC_CIDS_EQ(&a->pr_dcid, &b->pr_dcid))
11792f6e17bSDmitri Tikhonov        return 0;
11892f6e17bSDmitri Tikhonov    else
11992f6e17bSDmitri Tikhonov        return -1;
12092f6e17bSDmitri Tikhonov}
12192f6e17bSDmitri Tikhonov
12292f6e17bSDmitri Tikhonov
12392f6e17bSDmitri Tikhonovstatic unsigned
12492f6e17bSDmitri Tikhonovhash_req (const void *p, size_t len, unsigned seed)
12592f6e17bSDmitri Tikhonov{
12692f6e17bSDmitri Tikhonov    const struct packet_req *req;
12792f6e17bSDmitri Tikhonov
12892f6e17bSDmitri Tikhonov    req = p;
12992f6e17bSDmitri Tikhonov    return XXH32(req->pr_dcid.idbuf, req->pr_dcid.len, seed);
13092f6e17bSDmitri Tikhonov}
13192f6e17bSDmitri Tikhonov
13292f6e17bSDmitri Tikhonov
1335392f7a3SLiteSpeed Techstruct pr_queue *
1345392f7a3SLiteSpeed Techprq_create (unsigned max_elems, unsigned max_conns,
1355392f7a3SLiteSpeed Tech                        const struct lsquic_engine_public *enpub)
1365392f7a3SLiteSpeed Tech{
1375392f7a3SLiteSpeed Tech    const struct parse_funcs *pf;
1385392f7a3SLiteSpeed Tech    struct pr_queue *prq;
1395392f7a3SLiteSpeed Tech    struct malo *malo;
14092f6e17bSDmitri Tikhonov    struct lsquic_hash *hash;
1415392f7a3SLiteSpeed Tech    unsigned verneg_g_sz;
1425392f7a3SLiteSpeed Tech    ssize_t prst_g_sz;
1435392f7a3SLiteSpeed Tech    int len;
1445392f7a3SLiteSpeed Tech
1455392f7a3SLiteSpeed Tech    malo = lsquic_malo_create(sizeof(struct packet_req));
1465392f7a3SLiteSpeed Tech    if (!malo)
1475392f7a3SLiteSpeed Tech    {
1485392f7a3SLiteSpeed Tech        LSQ_WARN("malo_create failed: %s", strerror(errno));
1495392f7a3SLiteSpeed Tech        goto err0;
1505392f7a3SLiteSpeed Tech    }
1515392f7a3SLiteSpeed Tech
15292f6e17bSDmitri Tikhonov
15392f6e17bSDmitri Tikhonov    hash = lsquic_hash_create_ext(comp_reqs, hash_req);
15492f6e17bSDmitri Tikhonov    if (!hash)
15592f6e17bSDmitri Tikhonov    {
15692f6e17bSDmitri Tikhonov        LSQ_WARN("cannot create hash");
15792f6e17bSDmitri Tikhonov        goto err1;
15892f6e17bSDmitri Tikhonov    }
15992f6e17bSDmitri Tikhonov
1605392f7a3SLiteSpeed Tech    prq = malloc(sizeof(*prq));
1615392f7a3SLiteSpeed Tech    if (!prq)
1625392f7a3SLiteSpeed Tech    {
1635392f7a3SLiteSpeed Tech        LSQ_WARN("malloc failed: %s", strerror(errno));
16492f6e17bSDmitri Tikhonov        goto err2;
1655392f7a3SLiteSpeed Tech    }
1665392f7a3SLiteSpeed Tech
1675392f7a3SLiteSpeed Tech    const lsquic_cid_t cid = { .len = 8, };
1685392f7a3SLiteSpeed Tech    pf = select_pf_by_ver(LSQVER_039);
1695392f7a3SLiteSpeed Tech    len = lsquic_gquic_gen_ver_nego_pkt(prq->prq_verneg_g_buf,
1705392f7a3SLiteSpeed Tech                    sizeof(prq->prq_verneg_g_buf), &cid,
1715392f7a3SLiteSpeed Tech                    enpub->enp_settings.es_versions);
1725392f7a3SLiteSpeed Tech    assert(len > 0);
1735392f7a3SLiteSpeed Tech    if (len <= 0)
1745392f7a3SLiteSpeed Tech    {
1755392f7a3SLiteSpeed Tech        LSQ_ERROR("cannot generate version negotiation packet");
17692f6e17bSDmitri Tikhonov        goto err3;
1775392f7a3SLiteSpeed Tech    }
1785392f7a3SLiteSpeed Tech    verneg_g_sz = (unsigned) len;
1795392f7a3SLiteSpeed Tech
1805392f7a3SLiteSpeed Tech    prst_g_sz = pf->pf_generate_simple_prst(0 /* This is just placeholder */,
1815392f7a3SLiteSpeed Tech                                prq->prq_pubres_g_buf, sizeof(prq->prq_pubres_g_buf));
1825392f7a3SLiteSpeed Tech    if (prst_g_sz < 0)
1835392f7a3SLiteSpeed Tech    {
1845392f7a3SLiteSpeed Tech        LSQ_ERROR("cannot generate public reset packet");
18592f6e17bSDmitri Tikhonov        goto err3;
1865392f7a3SLiteSpeed Tech    }
1875392f7a3SLiteSpeed Tech
1885392f7a3SLiteSpeed Tech    TAILQ_INIT(&prq->prq_free_conns);
1895392f7a3SLiteSpeed Tech    TAILQ_INIT(&prq->prq_returned_conns);
19092f6e17bSDmitri Tikhonov    prq->prq_reqs_hash = hash;
1915392f7a3SLiteSpeed Tech    prq->prq_reqs_pool = malo;
1925392f7a3SLiteSpeed Tech    prq->prq_max_reqs = max_elems;
1935392f7a3SLiteSpeed Tech    prq->prq_nreqs = 0;
1945392f7a3SLiteSpeed Tech    prq->prq_max_conns = max_conns;
1955392f7a3SLiteSpeed Tech    prq->prq_nconns = 0;
1965392f7a3SLiteSpeed Tech    prq->prq_verneg_g_sz = verneg_g_sz;
1975392f7a3SLiteSpeed Tech    prq->prq_pubres_g_sz = (unsigned) prst_g_sz;
1985392f7a3SLiteSpeed Tech    prq->prq_enpub       = enpub;
1995392f7a3SLiteSpeed Tech
2005392f7a3SLiteSpeed Tech    LSQ_INFO("initialized queue of size %d", max_elems);
2015392f7a3SLiteSpeed Tech
2025392f7a3SLiteSpeed Tech    return prq;
2035392f7a3SLiteSpeed Tech
20492f6e17bSDmitri Tikhonov  err3:
2055392f7a3SLiteSpeed Tech    free(prq);
20692f6e17bSDmitri Tikhonov  err2:
20792f6e17bSDmitri Tikhonov    lsquic_hash_destroy(hash);
2085392f7a3SLiteSpeed Tech  err1:
2095392f7a3SLiteSpeed Tech    lsquic_malo_destroy(malo);
2105392f7a3SLiteSpeed Tech  err0:
2115392f7a3SLiteSpeed Tech    return NULL;
2125392f7a3SLiteSpeed Tech}
2135392f7a3SLiteSpeed Tech
2145392f7a3SLiteSpeed Tech
2155392f7a3SLiteSpeed Techvoid
2165392f7a3SLiteSpeed Techprq_destroy (struct pr_queue *prq)
2175392f7a3SLiteSpeed Tech{
2185392f7a3SLiteSpeed Tech    struct lsquic_conn *conn;
2195392f7a3SLiteSpeed Tech
2205392f7a3SLiteSpeed Tech    LSQ_INFO("destroy");
2215392f7a3SLiteSpeed Tech    while ((conn = TAILQ_FIRST(&prq->prq_free_conns)))
2225392f7a3SLiteSpeed Tech    {
2235392f7a3SLiteSpeed Tech        TAILQ_REMOVE(&prq->prq_free_conns, conn, cn_next_pr);
2245392f7a3SLiteSpeed Tech        free(conn);
2255392f7a3SLiteSpeed Tech    }
22692f6e17bSDmitri Tikhonov    lsquic_hash_destroy(prq->prq_reqs_hash);
2275392f7a3SLiteSpeed Tech    lsquic_malo_destroy(prq->prq_reqs_pool);
2285392f7a3SLiteSpeed Tech    free(prq);
2295392f7a3SLiteSpeed Tech}
2305392f7a3SLiteSpeed Tech
2315392f7a3SLiteSpeed Tech
2325392f7a3SLiteSpeed Techstatic struct packet_req *
2335392f7a3SLiteSpeed Techget_req (struct pr_queue *prq)
2345392f7a3SLiteSpeed Tech{
2355392f7a3SLiteSpeed Tech    struct packet_req *req;
2365392f7a3SLiteSpeed Tech    if (prq->prq_nreqs < prq->prq_max_reqs)
2375392f7a3SLiteSpeed Tech    {
2385392f7a3SLiteSpeed Tech        req = lsquic_malo_get(prq->prq_reqs_pool);
2395392f7a3SLiteSpeed Tech        if (req)
2405392f7a3SLiteSpeed Tech            ++prq->prq_nreqs;
2415392f7a3SLiteSpeed Tech        else
2425392f7a3SLiteSpeed Tech            LSQ_WARN("malo_get failed: %s", strerror(errno));
2435392f7a3SLiteSpeed Tech        return req;
2445392f7a3SLiteSpeed Tech    }
2455392f7a3SLiteSpeed Tech    else
2465392f7a3SLiteSpeed Tech        return NULL;
2475392f7a3SLiteSpeed Tech}
2485392f7a3SLiteSpeed Tech
2495392f7a3SLiteSpeed Tech
2505392f7a3SLiteSpeed Techstatic void
2515392f7a3SLiteSpeed Techput_req (struct pr_queue *prq, struct packet_req *req)
2525392f7a3SLiteSpeed Tech{
2535392f7a3SLiteSpeed Tech    lsquic_malo_put(req);
2545392f7a3SLiteSpeed Tech    --prq->prq_nreqs;
2555392f7a3SLiteSpeed Tech}
2565392f7a3SLiteSpeed Tech
2575392f7a3SLiteSpeed Tech
2585392f7a3SLiteSpeed Techint
2595392f7a3SLiteSpeed Techprq_new_req (struct pr_queue *prq, enum packet_req_type type,
2605392f7a3SLiteSpeed Tech         const struct lsquic_packet_in *packet_in, void *peer_ctx,
2615392f7a3SLiteSpeed Tech         const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
2625392f7a3SLiteSpeed Tech{
2635392f7a3SLiteSpeed Tech    struct packet_req *req;
2645392f7a3SLiteSpeed Tech    lsquic_ver_tag_t ver_tag;
26592f6e17bSDmitri Tikhonov    enum lsquic_version version;
26692f6e17bSDmitri Tikhonov    enum pr_flags flags;
26792f6e17bSDmitri Tikhonov    unsigned max, size;
26892f6e17bSDmitri Tikhonov
26992f6e17bSDmitri Tikhonov    if (packet_in->pi_flags & PI_GQUIC)
27092f6e17bSDmitri Tikhonov        flags = PR_GQUIC;
27192f6e17bSDmitri Tikhonov    else
27292f6e17bSDmitri Tikhonov        flags = 0;
27392f6e17bSDmitri Tikhonov
27492f6e17bSDmitri Tikhonov    if (packet_in->pi_quic_ver)
27592f6e17bSDmitri Tikhonov    {
27692f6e17bSDmitri Tikhonov        memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
27792f6e17bSDmitri Tikhonov                                                            sizeof(ver_tag));
27892f6e17bSDmitri Tikhonov        version = lsquic_tag2ver(ver_tag);
27992f6e17bSDmitri Tikhonov    }
28092f6e17bSDmitri Tikhonov    else /* Got to set it to something sensible... */
28192f6e17bSDmitri Tikhonov        version = LSQVER_ID23;
28292f6e17bSDmitri Tikhonov
28392f6e17bSDmitri Tikhonov    if (type == PACKET_REQ_PUBRES && !(flags & PR_GQUIC))
28492f6e17bSDmitri Tikhonov    {
28592f6e17bSDmitri Tikhonov        if (packet_in->pi_data_sz <= IQUIC_MIN_SRST_SIZE)
28692f6e17bSDmitri Tikhonov        {
28792f6e17bSDmitri Tikhonov            LSQ_DEBUGC("not scheduling public reset: incoming packet for CID "
28892f6e17bSDmitri Tikhonov                "%"CID_FMT" too small: %hu bytes",
28992f6e17bSDmitri Tikhonov                CID_BITS(&packet_in->pi_dcid), packet_in->pi_data_sz);
29092f6e17bSDmitri Tikhonov            return -1;
29192f6e17bSDmitri Tikhonov        }
29292f6e17bSDmitri Tikhonov        /* Use a random stateless reset size */
29392f6e17bSDmitri Tikhonov        max = MIN(IQUIC_MAX_SRST_SIZE, packet_in->pi_data_sz - 1u);
29492f6e17bSDmitri Tikhonov        if (max > IQUIC_MIN_SRST_SIZE)
29592f6e17bSDmitri Tikhonov            size = IQUIC_MIN_SRST_SIZE + rand() % (max - IQUIC_MIN_SRST_SIZE);
29692f6e17bSDmitri Tikhonov        else
29792f6e17bSDmitri Tikhonov            size = IQUIC_MIN_SRST_SIZE;
29892f6e17bSDmitri Tikhonov        LSQ_DEBUGC("selected %u-byte reset size for CID %"CID_FMT
29992f6e17bSDmitri Tikhonov            " (range is [%u, %u])", size, CID_BITS(&packet_in->pi_dcid),
30092f6e17bSDmitri Tikhonov            IQUIC_MIN_SRST_SIZE, max);
30192f6e17bSDmitri Tikhonov    }
30292f6e17bSDmitri Tikhonov    else
30392f6e17bSDmitri Tikhonov        size = 0;
3045392f7a3SLiteSpeed Tech
3055392f7a3SLiteSpeed Tech    req = get_req(prq);
3065392f7a3SLiteSpeed Tech    if (!req)
3075392f7a3SLiteSpeed Tech    {
3085392f7a3SLiteSpeed Tech        LSQ_DEBUG("out of reqs: cannot allocated another one");
3095392f7a3SLiteSpeed Tech        return -1;
3105392f7a3SLiteSpeed Tech    }
3115392f7a3SLiteSpeed Tech
3125392f7a3SLiteSpeed Tech    req->pr_type     = type;
3135392f7a3SLiteSpeed Tech    req->pr_dcid     = packet_in->pi_dcid;
31492f6e17bSDmitri Tikhonov    if (lsquic_hash_find(prq->prq_reqs_hash, req, sizeof(req)))
31592f6e17bSDmitri Tikhonov    {
31692f6e17bSDmitri Tikhonov        LSQ_DEBUG("request for this DCID and type already exists");
31792f6e17bSDmitri Tikhonov        put_req(prq, req);
31892f6e17bSDmitri Tikhonov        return -1;
31992f6e17bSDmitri Tikhonov    }
32092f6e17bSDmitri Tikhonov
32192f6e17bSDmitri Tikhonov    req->pr_hash_el.qhe_flags = 0;
32292f6e17bSDmitri Tikhonov    if (!lsquic_hash_insert(prq->prq_reqs_hash, req, sizeof(req),
32392f6e17bSDmitri Tikhonov                                                    req, &req->pr_hash_el))
32492f6e17bSDmitri Tikhonov    {
32592f6e17bSDmitri Tikhonov        LSQ_DEBUG("could not insert req into hash");
32692f6e17bSDmitri Tikhonov        put_req(prq, req);
32792f6e17bSDmitri Tikhonov        return -1;
32892f6e17bSDmitri Tikhonov    }
32992f6e17bSDmitri Tikhonov
33092f6e17bSDmitri Tikhonov    req->pr_flags    = flags;
33192f6e17bSDmitri Tikhonov    req->pr_rst_sz   = size;
33292f6e17bSDmitri Tikhonov    req->pr_version  = version;
33392f6e17bSDmitri Tikhonov    lsquic_scid_from_packet_in(packet_in, &req->pr_scid);
3345392f7a3SLiteSpeed Tech    req->pr_path.np_peer_ctx = peer_ctx;
3355392f7a3SLiteSpeed Tech    memcpy(NP_LOCAL_SA(&req->pr_path), local_addr,
3365392f7a3SLiteSpeed Tech                                            sizeof(req->pr_path.np_local_addr));
3375392f7a3SLiteSpeed Tech    memcpy(NP_PEER_SA(&req->pr_path), peer_addr,
3385392f7a3SLiteSpeed Tech                                            sizeof(req->pr_path.np_peer_addr));
33992f6e17bSDmitri Tikhonov
3405392f7a3SLiteSpeed Tech    LSQ_DEBUGC("scheduled %s packet for connection %"CID_FMT,
3415392f7a3SLiteSpeed Tech                            lsquic_preqt2str[type], CID_BITS(&req->pr_dcid));
3425392f7a3SLiteSpeed Tech    return 0;
3435392f7a3SLiteSpeed Tech}
3445392f7a3SLiteSpeed Tech
3455392f7a3SLiteSpeed Tech
3465392f7a3SLiteSpeed Techstatic size_t
3475392f7a3SLiteSpeed Techmax_bufsz (const struct pr_queue *prq)
3485392f7a3SLiteSpeed Tech{
3495392f7a3SLiteSpeed Tech    return  MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
3505392f7a3SLiteSpeed Tech                        IQUIC_MIN_SRST_SIZE),
3515392f7a3SLiteSpeed Tech                        sizeof(prq->prq_verneg_g_buf)),
3525392f7a3SLiteSpeed Tech                        sizeof(prq->prq_pubres_g_buf));
3535392f7a3SLiteSpeed Tech}
3545392f7a3SLiteSpeed Tech
3555392f7a3SLiteSpeed Tech
3565392f7a3SLiteSpeed Techstatic struct evanescent_conn *
3575392f7a3SLiteSpeed Techget_evconn (struct pr_queue *prq)
3585392f7a3SLiteSpeed Tech{
3595392f7a3SLiteSpeed Tech    struct evanescent_conn *evconn;
3605392f7a3SLiteSpeed Tech    struct lsquic_conn *lconn;
3615392f7a3SLiteSpeed Tech    struct lsquic_packet_out *packet_out;
3625392f7a3SLiteSpeed Tech    size_t bufsz;
3635392f7a3SLiteSpeed Tech
3645392f7a3SLiteSpeed Tech    if (prq->prq_nconns >= prq->prq_max_conns)
3655392f7a3SLiteSpeed Tech    {   /* This deserves a warning */
3665392f7a3SLiteSpeed Tech        LSQ_WARN("tried to get connection past limit of %u", prq->prq_max_conns);
3675392f7a3SLiteSpeed Tech        return NULL;
3685392f7a3SLiteSpeed Tech    }
3695392f7a3SLiteSpeed Tech
3705392f7a3SLiteSpeed Tech    lconn = TAILQ_FIRST(&prq->prq_free_conns);
3715392f7a3SLiteSpeed Tech    if (lconn)
3725392f7a3SLiteSpeed Tech    {
3735392f7a3SLiteSpeed Tech        TAILQ_REMOVE(&prq->prq_free_conns, lconn, cn_next_pr);
3745392f7a3SLiteSpeed Tech        return (struct evanescent_conn *) lconn;
3755392f7a3SLiteSpeed Tech    }
3765392f7a3SLiteSpeed Tech
3775392f7a3SLiteSpeed Tech    bufsz = max_bufsz(prq);
3785392f7a3SLiteSpeed Tech    evconn = calloc(1, sizeof(*evconn) + bufsz);
3795392f7a3SLiteSpeed Tech    if (!evconn)
3805392f7a3SLiteSpeed Tech    {
3815392f7a3SLiteSpeed Tech        LSQ_WARN("calloc failed: %s", strerror(errno));
3825392f7a3SLiteSpeed Tech        return NULL;
3835392f7a3SLiteSpeed Tech    }
3845392f7a3SLiteSpeed Tech
3855392f7a3SLiteSpeed Tech    /* These values stay the same between connection usages: */
3865392f7a3SLiteSpeed Tech    evconn->evc_queue = prq;
3875392f7a3SLiteSpeed Tech    lconn = &evconn->evc_conn;
3885392f7a3SLiteSpeed Tech    lconn->cn_cces = evconn->evc_cces;
3895392f7a3SLiteSpeed Tech    lconn->cn_cces_mask = 1;
3905392f7a3SLiteSpeed Tech    lconn->cn_n_cces = sizeof(evconn->evc_cces) / sizeof(evconn->evc_cces[0]);
3915392f7a3SLiteSpeed Tech    lconn->cn_if = &evanescent_conn_iface;
3925392f7a3SLiteSpeed Tech    lconn->cn_flags = LSCONN_EVANESCENT;
3935392f7a3SLiteSpeed Tech    packet_out = &evconn->evc_packet_out;
3945392f7a3SLiteSpeed Tech    packet_out->po_flags = PO_NOENCRYPT;
3955392f7a3SLiteSpeed Tech    packet_out->po_data = evconn->evc_buf;
3965392f7a3SLiteSpeed Tech
3975392f7a3SLiteSpeed Tech    return evconn;
3985392f7a3SLiteSpeed Tech}
3995392f7a3SLiteSpeed Tech
4005392f7a3SLiteSpeed Tech
4015392f7a3SLiteSpeed Techstruct lsquic_conn *
4025392f7a3SLiteSpeed Techprq_next_conn (struct pr_queue *prq)
4035392f7a3SLiteSpeed Tech{
4045392f7a3SLiteSpeed Tech    struct evanescent_conn *evconn;
4055392f7a3SLiteSpeed Tech    struct lsquic_conn *lconn;
40692f6e17bSDmitri Tikhonov    struct lsquic_hash_elem *el;
4075392f7a3SLiteSpeed Tech    struct packet_req *req;
4085392f7a3SLiteSpeed Tech    struct lsquic_packet_out *packet_out;
4095392f7a3SLiteSpeed Tech    int (*gen_verneg) (unsigned char *, size_t, const lsquic_cid_t *,
4105392f7a3SLiteSpeed Tech                                            const lsquic_cid_t *, unsigned);
4115392f7a3SLiteSpeed Tech    int len;
4125392f7a3SLiteSpeed Tech
4135392f7a3SLiteSpeed Tech    lconn = TAILQ_FIRST(&prq->prq_returned_conns);
4145392f7a3SLiteSpeed Tech    if (lconn)
4155392f7a3SLiteSpeed Tech    {
4165392f7a3SLiteSpeed Tech        TAILQ_REMOVE(&prq->prq_returned_conns, lconn, cn_next_pr);
4175392f7a3SLiteSpeed Tech        return lconn;
4185392f7a3SLiteSpeed Tech    }
4195392f7a3SLiteSpeed Tech
42092f6e17bSDmitri Tikhonov    el = lsquic_hash_first(prq->prq_reqs_hash);
42192f6e17bSDmitri Tikhonov    if (!el)           /* Nothing is queued */
4225392f7a3SLiteSpeed Tech        return NULL;
4235392f7a3SLiteSpeed Tech
4245392f7a3SLiteSpeed Tech    evconn = get_evconn(prq);
4255392f7a3SLiteSpeed Tech    if (!evconn)         /* Reached limit or malloc failed */
4265392f7a3SLiteSpeed Tech        return NULL;
4275392f7a3SLiteSpeed Tech
42892f6e17bSDmitri Tikhonov    req = lsquic_hashelem_getdata(el);
4295392f7a3SLiteSpeed Tech    packet_out = &evconn->evc_packet_out;
4305392f7a3SLiteSpeed Tech    switch ((req->pr_type << 29) | req->pr_flags)
4315392f7a3SLiteSpeed Tech    {
4325392f7a3SLiteSpeed Tech    case (PACKET_REQ_VERNEG << 29) | PR_GQUIC:
4335392f7a3SLiteSpeed Tech        packet_out->po_data_sz = prq->prq_verneg_g_sz;
4345392f7a3SLiteSpeed Tech        packet_out->po_flags |= PO_VERNEG;
4355392f7a3SLiteSpeed Tech        memcpy(packet_out->po_data, prq->prq_verneg_g_buf,
4365392f7a3SLiteSpeed Tech                                                    prq->prq_verneg_g_sz);
4375392f7a3SLiteSpeed Tech        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
4385392f7a3SLiteSpeed Tech        break;
4395392f7a3SLiteSpeed Tech    case (PACKET_REQ_PUBRES << 29) | PR_GQUIC:
4405392f7a3SLiteSpeed Tech        packet_out->po_flags &= ~PO_VERNEG;
4415392f7a3SLiteSpeed Tech        packet_out->po_data_sz = prq->prq_pubres_g_sz;
4425392f7a3SLiteSpeed Tech        memcpy(packet_out->po_data, prq->prq_pubres_g_buf,
4435392f7a3SLiteSpeed Tech                                                    prq->prq_pubres_g_sz);
4445392f7a3SLiteSpeed Tech        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
4455392f7a3SLiteSpeed Tech        break;
4465392f7a3SLiteSpeed Tech    case (PACKET_REQ_VERNEG << 29) | 0:
4475392f7a3SLiteSpeed Tech        packet_out->po_flags |= PO_VERNEG;
4485392f7a3SLiteSpeed Tech        if (req->pr_version == LSQVER_046)
4495392f7a3SLiteSpeed Tech            gen_verneg = lsquic_Q046_gen_ver_nego_pkt;
4505392f7a3SLiteSpeed Tech        else
4515392f7a3SLiteSpeed Tech            gen_verneg = lsquic_ietf_v1_gen_ver_nego_pkt;
4525392f7a3SLiteSpeed Tech        len = gen_verneg(packet_out->po_data, max_bufsz(prq),
4535392f7a3SLiteSpeed Tech                    /* Flip SCID/DCID here: */ &req->pr_dcid, &req->pr_scid,
4545392f7a3SLiteSpeed Tech                    prq->prq_enpub->enp_settings.es_versions);
4555392f7a3SLiteSpeed Tech        if (len > 0)
4565392f7a3SLiteSpeed Tech            packet_out->po_data_sz = len;
4575392f7a3SLiteSpeed Tech        else
4585392f7a3SLiteSpeed Tech            packet_out->po_data_sz = 0;
4595392f7a3SLiteSpeed Tech        break;
4605392f7a3SLiteSpeed Tech    default:
4615392f7a3SLiteSpeed Tech        packet_out->po_flags &= ~PO_VERNEG;
46292f6e17bSDmitri Tikhonov        packet_out->po_data_sz = req->pr_rst_sz;
46392f6e17bSDmitri Tikhonov        RAND_bytes(packet_out->po_data, req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
4645392f7a3SLiteSpeed Tech        packet_out->po_data[0] &= ~0x80;
4655392f7a3SLiteSpeed Tech        packet_out->po_data[0] |=  0x40;
4665392f7a3SLiteSpeed Tech        lsquic_tg_generate_sreset(prq->prq_enpub->enp_tokgen, &req->pr_dcid,
46792f6e17bSDmitri Tikhonov            packet_out->po_data + req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
4685392f7a3SLiteSpeed Tech        break;
4695392f7a3SLiteSpeed Tech    }
4705392f7a3SLiteSpeed Tech
47192f6e17bSDmitri Tikhonov    lsquic_hash_erase(prq->prq_reqs_hash, el);
4725392f7a3SLiteSpeed Tech    evconn->evc_req = req;
4735392f7a3SLiteSpeed Tech
4745392f7a3SLiteSpeed Tech    lconn= &evconn->evc_conn;
4755392f7a3SLiteSpeed Tech    evconn->evc_cces[0].cce_cid = req->pr_dcid;
4765392f7a3SLiteSpeed Tech    packet_out->po_path = &req->pr_path;
4775392f7a3SLiteSpeed Tech
4785392f7a3SLiteSpeed Tech    ++prq->prq_nconns;
4795392f7a3SLiteSpeed Tech    return lconn;
4805392f7a3SLiteSpeed Tech}
4815392f7a3SLiteSpeed Tech
4825392f7a3SLiteSpeed Tech
4835392f7a3SLiteSpeed Techint
4845392f7a3SLiteSpeed Techprq_have_pending (const struct pr_queue *prq)
4855392f7a3SLiteSpeed Tech{
48692f6e17bSDmitri Tikhonov    return lsquic_hash_count(prq->prq_reqs_hash) > 0;
4875392f7a3SLiteSpeed Tech}
4885392f7a3SLiteSpeed Tech
4895392f7a3SLiteSpeed Tech
4905392f7a3SLiteSpeed Techstatic struct lsquic_packet_out *
4915392f7a3SLiteSpeed Techevanescent_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
4925392f7a3SLiteSpeed Tech{
4935392f7a3SLiteSpeed Tech    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
4945392f7a3SLiteSpeed Tech    assert(size == 0);
4955392f7a3SLiteSpeed Tech    return &evconn->evc_packet_out;
4965392f7a3SLiteSpeed Tech}
4975392f7a3SLiteSpeed Tech
4985392f7a3SLiteSpeed Tech
4995392f7a3SLiteSpeed Techstatic void
5005392f7a3SLiteSpeed Techevanescent_conn_ci_packet_sent (struct lsquic_conn *lconn,
5015392f7a3SLiteSpeed Tech                            struct lsquic_packet_out *packet_out)
5025392f7a3SLiteSpeed Tech{
5035392f7a3SLiteSpeed Tech    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
5045392f7a3SLiteSpeed Tech    struct pr_queue *const prq = evconn->evc_queue;
5055392f7a3SLiteSpeed Tech
5065392f7a3SLiteSpeed Tech    assert(packet_out == &evconn->evc_packet_out);
5075392f7a3SLiteSpeed Tech    assert(prq->prq_nconns > 0);
5085392f7a3SLiteSpeed Tech
5095392f7a3SLiteSpeed Tech    LSQ_DEBUGC("sent %s packet for connection %"CID_FMT"; free resources",
5105392f7a3SLiteSpeed Tech        lsquic_preqt2str[ evconn->evc_req->pr_type ],
5115392f7a3SLiteSpeed Tech        CID_BITS(&evconn->evc_req->pr_dcid));
5125392f7a3SLiteSpeed Tech    TAILQ_INSERT_HEAD(&prq->prq_free_conns, lconn, cn_next_pr);
5135392f7a3SLiteSpeed Tech    put_req(prq, evconn->evc_req);
5145392f7a3SLiteSpeed Tech    --prq->prq_nconns;
5155392f7a3SLiteSpeed Tech}
5165392f7a3SLiteSpeed Tech
5175392f7a3SLiteSpeed Tech
5185392f7a3SLiteSpeed Techstatic void
5195392f7a3SLiteSpeed Techevanescent_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
5205392f7a3SLiteSpeed Tech                                struct lsquic_packet_out *packet_out)
5215392f7a3SLiteSpeed Tech{
5225392f7a3SLiteSpeed Tech    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
5235392f7a3SLiteSpeed Tech    struct pr_queue *const prq = evconn->evc_queue;
5245392f7a3SLiteSpeed Tech
5255392f7a3SLiteSpeed Tech    assert(packet_out == &evconn->evc_packet_out);
5265392f7a3SLiteSpeed Tech    assert(prq->prq_nconns > 0);
5275392f7a3SLiteSpeed Tech
5285392f7a3SLiteSpeed Tech    LSQ_DEBUG("packet not sent; put connection onto used list");
5295392f7a3SLiteSpeed Tech    TAILQ_INSERT_HEAD(&prq->prq_returned_conns, lconn, cn_next_pr);
5305392f7a3SLiteSpeed Tech}
5315392f7a3SLiteSpeed Tech
5325392f7a3SLiteSpeed Tech
5335392f7a3SLiteSpeed Techstatic enum tick_st
5345392f7a3SLiteSpeed Techevanescent_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
5355392f7a3SLiteSpeed Tech{
5365392f7a3SLiteSpeed Tech    assert(0);
5375392f7a3SLiteSpeed Tech    return TICK_CLOSE;
5385392f7a3SLiteSpeed Tech}
5395392f7a3SLiteSpeed Tech
5405392f7a3SLiteSpeed Tech
5415392f7a3SLiteSpeed Techstatic void
5425392f7a3SLiteSpeed Techevanescent_conn_ci_destroy (struct lsquic_conn *lconn)
5435392f7a3SLiteSpeed Tech{
5445392f7a3SLiteSpeed Tech    assert(0);
5455392f7a3SLiteSpeed Tech}
5465392f7a3SLiteSpeed Tech
5475392f7a3SLiteSpeed Tech
5485392f7a3SLiteSpeed Techstatic struct lsquic_engine *
5495392f7a3SLiteSpeed Techevanescent_conn_ci_get_engine (struct lsquic_conn *lconn)
5505392f7a3SLiteSpeed Tech{
5515392f7a3SLiteSpeed Tech    assert(0);
5525392f7a3SLiteSpeed Tech    return NULL;
5535392f7a3SLiteSpeed Tech}
5545392f7a3SLiteSpeed Tech
5555392f7a3SLiteSpeed Tech
5565392f7a3SLiteSpeed Techstatic void
5575392f7a3SLiteSpeed Techevanescent_conn_ci_hsk_done (struct lsquic_conn *lconn,
5585392f7a3SLiteSpeed Tech                                                enum lsquic_hsk_status status)
5595392f7a3SLiteSpeed Tech{
5605392f7a3SLiteSpeed Tech    assert(0);
5615392f7a3SLiteSpeed Tech}
5625392f7a3SLiteSpeed Tech
5635392f7a3SLiteSpeed Tech
5645392f7a3SLiteSpeed Techstatic void
5655392f7a3SLiteSpeed Techevanescent_conn_ci_packet_in (struct lsquic_conn *lconn,
5665392f7a3SLiteSpeed Tech                          struct lsquic_packet_in *packet_in)
5675392f7a3SLiteSpeed Tech{
5685392f7a3SLiteSpeed Tech    assert(0);
5695392f7a3SLiteSpeed Tech}
5705392f7a3SLiteSpeed Tech
5715392f7a3SLiteSpeed Tech
5725392f7a3SLiteSpeed Techstatic void
5735392f7a3SLiteSpeed Techevanescent_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
5745392f7a3SLiteSpeed Tech{
5755392f7a3SLiteSpeed Tech    assert(0);
5765392f7a3SLiteSpeed Tech}
5775392f7a3SLiteSpeed Tech
5785392f7a3SLiteSpeed Tech
5795392f7a3SLiteSpeed Techstatic struct network_path *
5805392f7a3SLiteSpeed Techevanescent_conn_ci_get_path (struct lsquic_conn *lconn,
5815392f7a3SLiteSpeed Tech                                                    const struct sockaddr *sa)
5825392f7a3SLiteSpeed Tech{
5835392f7a3SLiteSpeed Tech    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
5845392f7a3SLiteSpeed Tech
5855392f7a3SLiteSpeed Tech    return &evconn->evc_req->pr_path;
5865392f7a3SLiteSpeed Tech}
5875392f7a3SLiteSpeed Tech
5885392f7a3SLiteSpeed Tech
5895392f7a3SLiteSpeed Techstatic unsigned char
5905392f7a3SLiteSpeed Techevanescent_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
5915392f7a3SLiteSpeed Tech            const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
5925392f7a3SLiteSpeed Tech{
5935392f7a3SLiteSpeed Tech    assert(0);
5945392f7a3SLiteSpeed Tech    return 0;
5955392f7a3SLiteSpeed Tech}
5965392f7a3SLiteSpeed Tech
5975392f7a3SLiteSpeed Tech
5985392f7a3SLiteSpeed Techstatic const struct conn_iface evanescent_conn_iface = {
5995392f7a3SLiteSpeed Tech    .ci_client_call_on_new   =  evanescent_conn_ci_client_call_on_new,
6005392f7a3SLiteSpeed Tech    .ci_destroy              =  evanescent_conn_ci_destroy,
6015392f7a3SLiteSpeed Tech    .ci_get_engine           =  evanescent_conn_ci_get_engine,
6025392f7a3SLiteSpeed Tech    .ci_get_path             =  evanescent_conn_ci_get_path,
6035392f7a3SLiteSpeed Tech    .ci_hsk_done             =  evanescent_conn_ci_hsk_done,
6045392f7a3SLiteSpeed Tech    .ci_next_packet_to_send  =  evanescent_conn_ci_next_packet_to_send,
6055392f7a3SLiteSpeed Tech    .ci_packet_in            =  evanescent_conn_ci_packet_in,
6065392f7a3SLiteSpeed Tech    .ci_packet_not_sent      =  evanescent_conn_ci_packet_not_sent,
6075392f7a3SLiteSpeed Tech    .ci_packet_sent          =  evanescent_conn_ci_packet_sent,
6085392f7a3SLiteSpeed Tech    .ci_record_addrs         =  evanescent_conn_ci_record_addrs,
6095392f7a3SLiteSpeed Tech    .ci_tick                 =  evanescent_conn_ci_tick,
6105392f7a3SLiteSpeed Tech};
6115392f7a3SLiteSpeed Tech
6125392f7a3SLiteSpeed Tech
6135392f7a3SLiteSpeed Techconst char *const lsquic_preqt2str[] =
6145392f7a3SLiteSpeed Tech{
6155392f7a3SLiteSpeed Tech    [PACKET_REQ_VERNEG] = "version negotiation",
6165392f7a3SLiteSpeed Tech    [PACKET_REQ_PUBRES] = "stateless reset",
6175392f7a3SLiteSpeed Tech};
618