694 lines
20 KiB
C
694 lines
20 KiB
C
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
|
|
/*
|
|
* lsquic_pr_queue.c -- packet request queue.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/queue.h>
|
|
|
|
#ifndef WIN32
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
#include <openssl/aead.h>
|
|
#include <openssl/rand.h>
|
|
|
|
#include "lsquic.h"
|
|
#include "lsquic_types.h"
|
|
#include "lsquic_int_types.h"
|
|
#include "lsquic_packet_common.h"
|
|
#include "lsquic_packet_gquic.h"
|
|
#include "lsquic_packet_out.h"
|
|
#include "lsquic_packet_in.h"
|
|
#include "lsquic_hash.h"
|
|
#include "lsquic_conn.h"
|
|
#include "lsquic_parse.h"
|
|
#include "lsquic_malo.h"
|
|
#include "lsquic_pr_queue.h"
|
|
#include "lsquic_parse_common.h"
|
|
#include "lsquic_tokgen.h"
|
|
#include "lsquic_version.h"
|
|
#include "lsquic_mm.h"
|
|
#include "lsquic_engine_public.h"
|
|
#include "lsquic_sizes.h"
|
|
#include "lsquic_handshake.h"
|
|
#include "lsquic_xxhash.h"
|
|
#include "lsquic_crand.h"
|
|
|
|
#define LSQUIC_LOGGER_MODULE LSQLM_PRQ
|
|
#include "lsquic_logger.h"
|
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
|
|
static const struct conn_iface evanescent_conn_iface;
|
|
|
|
|
|
struct packet_req
|
|
{
|
|
struct lsquic_hash_elem pr_hash_el;
|
|
lsquic_cid_t pr_scid;
|
|
lsquic_cid_t pr_dcid;
|
|
enum packet_req_type pr_type;
|
|
enum pr_flags {
|
|
PR_GQUIC = 1 << 0,
|
|
} pr_flags;
|
|
enum lsquic_version pr_version;
|
|
unsigned pr_rst_sz;
|
|
struct network_path pr_path;
|
|
};
|
|
|
|
|
|
struct evanescent_conn
|
|
{
|
|
struct lsquic_conn evc_conn;
|
|
struct packet_req *evc_req;
|
|
struct pr_queue *evc_queue;
|
|
struct lsquic_packet_out evc_packet_out;
|
|
struct conn_cid_elem evc_cces[1];
|
|
enum {
|
|
EVC_DROP = 1 << 0,
|
|
} evc_flags;
|
|
unsigned char evc_buf[0];
|
|
};
|
|
|
|
|
|
/* [draft-ietf-quic-transport-22], Section 17.2.1 */
|
|
#define IQUIC_VERNEG_SIZE (1 /* Type */ + 4 /* Version (zero tag) */ \
|
|
+ 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
|
|
4 * N_LSQVER)
|
|
|
|
/* [draft-ietf-quic-transport-22], Section 17.2.5 */
|
|
#define IQUIC_RETRY_SIZE (1 /* Type */ + 4 /* Version */ + \
|
|
+ 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
|
|
+ 1 /* ODCIL */ + MAX_CID_LEN + MAX_RETRY_TOKEN_LEN)
|
|
|
|
/* GQUIC retry is dynamically size, this is a reasonable high bound */
|
|
#define GQUIC_RETRY_SIZE 512
|
|
|
|
struct pr_queue
|
|
{
|
|
TAILQ_HEAD(, lsquic_conn) prq_free_conns,
|
|
prq_returned_conns;
|
|
struct malo *prq_reqs_pool;
|
|
const struct lsquic_engine_public
|
|
*prq_enpub;
|
|
struct lsquic_hash *prq_reqs_hash;
|
|
unsigned prq_max_reqs;
|
|
unsigned prq_nreqs;
|
|
unsigned prq_max_conns;
|
|
unsigned prq_nconns;
|
|
unsigned prq_verneg_g_sz; /* Size of prq_verneg_g_buf */
|
|
unsigned prq_pubres_g_sz; /* Size of prq_pubres_g_buf */
|
|
|
|
/* GQUIC version negotiation and stateless reset packets are generated
|
|
* once, when the Packet Request Queue is created. For each request,
|
|
* these buffers are simply copied and the connection ID is replaced.
|
|
*
|
|
* Since IETF QUIC uses variable-length connections IDs, we have to
|
|
* generate packets every time.
|
|
*/
|
|
unsigned char prq_pubres_g_buf[GQUIC_RESET_SZ];
|
|
unsigned char prq_verneg_g_buf[1 + GQUIC_CID_LEN
|
|
+ N_LSQVER * 4];
|
|
};
|
|
|
|
|
|
static int
|
|
comp_reqs (const void *s1, const void *s2, size_t n)
|
|
{
|
|
const struct packet_req *a, *b;
|
|
|
|
a = s1;
|
|
b = s2;
|
|
if (a->pr_type == b->pr_type && LSQUIC_CIDS_EQ(&a->pr_dcid, &b->pr_dcid))
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
static unsigned
|
|
hash_req (const void *p, size_t len, unsigned seed)
|
|
{
|
|
const struct packet_req *req;
|
|
|
|
req = p;
|
|
return XXH32(req->pr_dcid.idbuf, req->pr_dcid.len, seed);
|
|
}
|
|
|
|
|
|
struct pr_queue *
|
|
lsquic_prq_create (unsigned max_elems, unsigned max_conns,
|
|
const struct lsquic_engine_public *enpub)
|
|
{
|
|
const struct parse_funcs *pf;
|
|
struct pr_queue *prq;
|
|
struct malo *malo;
|
|
struct lsquic_hash *hash;
|
|
unsigned verneg_g_sz;
|
|
ssize_t prst_g_sz;
|
|
int len;
|
|
|
|
malo = lsquic_malo_create(sizeof(struct packet_req));
|
|
if (!malo)
|
|
{
|
|
LSQ_WARN("malo_create failed: %s", strerror(errno));
|
|
goto err0;
|
|
}
|
|
|
|
|
|
hash = lsquic_hash_create_ext(comp_reqs, hash_req);
|
|
if (!hash)
|
|
{
|
|
LSQ_WARN("cannot create hash");
|
|
goto err1;
|
|
}
|
|
|
|
prq = malloc(sizeof(*prq));
|
|
if (!prq)
|
|
{
|
|
LSQ_WARN("malloc failed: %s", strerror(errno));
|
|
goto err2;
|
|
}
|
|
|
|
const lsquic_cid_t cid = { .len = 8, };
|
|
pf = select_pf_by_ver(LSQVER_043);
|
|
len = lsquic_gquic_gen_ver_nego_pkt(prq->prq_verneg_g_buf,
|
|
sizeof(prq->prq_verneg_g_buf), &cid,
|
|
enpub->enp_settings.es_versions);
|
|
assert(len > 0);
|
|
if (len <= 0)
|
|
{
|
|
LSQ_ERROR("cannot generate version negotiation packet");
|
|
goto err3;
|
|
}
|
|
verneg_g_sz = (unsigned) len;
|
|
|
|
prst_g_sz = pf->pf_generate_simple_prst(0 /* This is just placeholder */,
|
|
prq->prq_pubres_g_buf, sizeof(prq->prq_pubres_g_buf));
|
|
if (prst_g_sz < 0)
|
|
{
|
|
LSQ_ERROR("cannot generate public reset packet");
|
|
goto err3;
|
|
}
|
|
|
|
TAILQ_INIT(&prq->prq_free_conns);
|
|
TAILQ_INIT(&prq->prq_returned_conns);
|
|
prq->prq_reqs_hash = hash;
|
|
prq->prq_reqs_pool = malo;
|
|
prq->prq_max_reqs = max_elems;
|
|
prq->prq_nreqs = 0;
|
|
prq->prq_max_conns = max_conns;
|
|
prq->prq_nconns = 0;
|
|
prq->prq_verneg_g_sz = verneg_g_sz;
|
|
prq->prq_pubres_g_sz = (unsigned) prst_g_sz;
|
|
prq->prq_enpub = enpub;
|
|
|
|
LSQ_INFO("initialized queue of size %d", max_elems);
|
|
|
|
return prq;
|
|
|
|
err3:
|
|
free(prq);
|
|
err2:
|
|
lsquic_hash_destroy(hash);
|
|
err1:
|
|
lsquic_malo_destroy(malo);
|
|
err0:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void
|
|
lsquic_prq_destroy (struct pr_queue *prq)
|
|
{
|
|
struct lsquic_conn *conn;
|
|
|
|
LSQ_INFO("destroy");
|
|
while ((conn = TAILQ_FIRST(&prq->prq_free_conns)))
|
|
{
|
|
TAILQ_REMOVE(&prq->prq_free_conns, conn, cn_next_pr);
|
|
free(conn);
|
|
}
|
|
lsquic_hash_destroy(prq->prq_reqs_hash);
|
|
lsquic_malo_destroy(prq->prq_reqs_pool);
|
|
free(prq);
|
|
}
|
|
|
|
|
|
static struct packet_req *
|
|
get_req (struct pr_queue *prq)
|
|
{
|
|
struct packet_req *req;
|
|
if (prq->prq_nreqs < prq->prq_max_reqs)
|
|
{
|
|
req = lsquic_malo_get(prq->prq_reqs_pool);
|
|
if (req)
|
|
++prq->prq_nreqs;
|
|
else
|
|
LSQ_WARN("malo_get failed: %s", strerror(errno));
|
|
return req;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
put_req (struct pr_queue *prq, struct packet_req *req)
|
|
{
|
|
lsquic_malo_put(req);
|
|
--prq->prq_nreqs;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_prq_new_req_ext (struct pr_queue *prq, enum packet_req_type type,
|
|
unsigned flags, enum lsquic_version version, unsigned short data_sz,
|
|
const lsquic_cid_t *dcid, const lsquic_cid_t *scid, void *peer_ctx,
|
|
const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
|
|
{
|
|
struct packet_req *req;
|
|
unsigned max, size, rand;
|
|
|
|
if (type == PACKET_REQ_PUBRES && !(flags & PR_GQUIC))
|
|
{
|
|
if (data_sz <= IQUIC_MIN_SRST_SIZE)
|
|
{
|
|
LSQ_DEBUGC("not scheduling public reset: incoming packet for CID "
|
|
"%"CID_FMT" too small: %hu bytes", CID_BITS(dcid), data_sz);
|
|
return -1;
|
|
}
|
|
/* Use a random stateless reset size */
|
|
max = MIN(IQUIC_MAX_SRST_SIZE, data_sz - 1u);
|
|
if (max > IQUIC_MIN_SRST_SIZE)
|
|
{
|
|
rand = lsquic_crand_get_byte(prq->prq_enpub->enp_crand);
|
|
size = IQUIC_MIN_SRST_SIZE + rand % (max - IQUIC_MIN_SRST_SIZE);
|
|
}
|
|
else
|
|
size = IQUIC_MIN_SRST_SIZE;
|
|
LSQ_DEBUGC("selected %u-byte reset size for CID %"CID_FMT
|
|
" (range is [%u, %u])", size, CID_BITS(dcid),
|
|
IQUIC_MIN_SRST_SIZE, max);
|
|
}
|
|
else
|
|
size = 0;
|
|
|
|
req = get_req(prq);
|
|
if (!req)
|
|
{
|
|
LSQ_DEBUG("out of reqs: cannot allocated another one");
|
|
return -1;
|
|
}
|
|
|
|
req->pr_type = type;
|
|
req->pr_dcid = *dcid;
|
|
if (lsquic_hash_find(prq->prq_reqs_hash, req, sizeof(*req)))
|
|
{
|
|
LSQ_DEBUG("request for this DCID and type already exists");
|
|
put_req(prq, req);
|
|
return -1;
|
|
}
|
|
|
|
req->pr_hash_el.qhe_flags = 0;
|
|
if (!lsquic_hash_insert(prq->prq_reqs_hash, req, sizeof(*req),
|
|
req, &req->pr_hash_el))
|
|
{
|
|
LSQ_DEBUG("could not insert req into hash");
|
|
put_req(prq, req);
|
|
return -1;
|
|
}
|
|
|
|
req->pr_flags = flags;
|
|
req->pr_rst_sz = size;
|
|
req->pr_version = version;
|
|
req->pr_scid = *scid;
|
|
req->pr_path.np_peer_ctx = peer_ctx;
|
|
memcpy(req->pr_path.np_local_addr, local_addr,
|
|
sizeof(req->pr_path.np_local_addr));
|
|
memcpy(NP_PEER_SA(&req->pr_path), peer_addr,
|
|
sizeof(req->pr_path.np_peer_addr));
|
|
|
|
LSQ_DEBUGC("scheduled %s packet for connection %"CID_FMT,
|
|
lsquic_preqt2str[type], CID_BITS(&req->pr_dcid));
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
|
|
const struct lsquic_packet_in *packet_in, void *peer_ctx,
|
|
const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
|
|
{
|
|
lsquic_ver_tag_t ver_tag;
|
|
enum lsquic_version version;
|
|
enum pr_flags flags;
|
|
lsquic_cid_t scid;
|
|
|
|
if (packet_in->pi_flags & PI_GQUIC)
|
|
flags = PR_GQUIC;
|
|
else
|
|
flags = 0;
|
|
|
|
if (packet_in->pi_quic_ver)
|
|
{
|
|
memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
|
|
sizeof(ver_tag));
|
|
version = lsquic_tag2ver(ver_tag);
|
|
}
|
|
else /* Got to set it to something sensible... */
|
|
version = LSQVER_ID27;
|
|
|
|
lsquic_scid_from_packet_in(packet_in, &scid);
|
|
return lsquic_prq_new_req_ext(prq, type, flags, version,
|
|
packet_in->pi_data_sz, &packet_in->pi_dcid, &scid,
|
|
peer_ctx, local_addr, peer_addr);
|
|
}
|
|
|
|
|
|
static size_t
|
|
max_bufsz (const struct pr_queue *prq)
|
|
{
|
|
return MAX(MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
|
|
IQUIC_RETRY_SIZE),
|
|
IQUIC_MAX_SRST_SIZE),
|
|
sizeof(prq->prq_verneg_g_buf)),
|
|
sizeof(prq->prq_pubres_g_buf));
|
|
}
|
|
|
|
|
|
static struct evanescent_conn *
|
|
get_evconn (struct pr_queue *prq)
|
|
{
|
|
struct evanescent_conn *evconn;
|
|
struct lsquic_conn *lconn;
|
|
struct lsquic_packet_out *packet_out;
|
|
size_t bufsz;
|
|
|
|
if (prq->prq_nconns >= prq->prq_max_conns)
|
|
{ /* This deserves a warning */
|
|
LSQ_WARN("tried to get connection past limit of %u", prq->prq_max_conns);
|
|
return NULL;
|
|
}
|
|
|
|
lconn = TAILQ_FIRST(&prq->prq_free_conns);
|
|
if (lconn)
|
|
{
|
|
TAILQ_REMOVE(&prq->prq_free_conns, lconn, cn_next_pr);
|
|
evconn = (struct evanescent_conn *) lconn;
|
|
evconn->evc_flags = 0;
|
|
return evconn;
|
|
}
|
|
|
|
bufsz = max_bufsz(prq);
|
|
evconn = calloc(1, sizeof(*evconn) + bufsz);
|
|
if (!evconn)
|
|
{
|
|
LSQ_WARN("calloc failed: %s", strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
/* These values stay the same between connection usages: */
|
|
evconn->evc_queue = prq;
|
|
lconn = &evconn->evc_conn;
|
|
lconn->cn_cces = evconn->evc_cces;
|
|
lconn->cn_cces_mask = 1;
|
|
lconn->cn_n_cces = sizeof(evconn->evc_cces) / sizeof(evconn->evc_cces[0]);
|
|
lconn->cn_if = &evanescent_conn_iface;
|
|
lconn->cn_flags = LSCONN_EVANESCENT;
|
|
packet_out = &evconn->evc_packet_out;
|
|
packet_out->po_flags = PO_NOENCRYPT;
|
|
packet_out->po_data = evconn->evc_buf;
|
|
|
|
return evconn;
|
|
}
|
|
|
|
|
|
struct lsquic_conn *
|
|
lsquic_prq_next_conn (struct pr_queue *prq)
|
|
{
|
|
struct evanescent_conn *evconn;
|
|
struct lsquic_conn *lconn;
|
|
struct lsquic_hash_elem *el;
|
|
struct packet_req *req;
|
|
struct lsquic_packet_out *packet_out;
|
|
int (*gen_verneg) (unsigned char *, size_t, const lsquic_cid_t *,
|
|
const lsquic_cid_t *, unsigned, uint8_t);
|
|
int len;
|
|
|
|
lconn = TAILQ_FIRST(&prq->prq_returned_conns);
|
|
if (lconn)
|
|
{
|
|
TAILQ_REMOVE(&prq->prq_returned_conns, lconn, cn_next_pr);
|
|
return lconn;
|
|
}
|
|
|
|
el = lsquic_hash_first(prq->prq_reqs_hash);
|
|
if (!el) /* Nothing is queued */
|
|
return NULL;
|
|
|
|
evconn = get_evconn(prq);
|
|
if (!evconn) /* Reached limit or malloc failed */
|
|
return NULL;
|
|
|
|
req = lsquic_hashelem_getdata(el);
|
|
packet_out = &evconn->evc_packet_out;
|
|
switch ((req->pr_type << 29) | req->pr_flags)
|
|
{
|
|
case (PACKET_REQ_VERNEG << 29) | PR_GQUIC:
|
|
packet_out->po_data_sz = prq->prq_verneg_g_sz;
|
|
packet_out->po_flags |= PO_VERNEG;
|
|
memcpy(packet_out->po_data, prq->prq_verneg_g_buf,
|
|
prq->prq_verneg_g_sz);
|
|
memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
|
|
break;
|
|
case (PACKET_REQ_PUBRES << 29) | PR_GQUIC:
|
|
packet_out->po_flags &= ~PO_VERNEG;
|
|
packet_out->po_data_sz = prq->prq_pubres_g_sz;
|
|
memcpy(packet_out->po_data, prq->prq_pubres_g_buf,
|
|
prq->prq_pubres_g_sz);
|
|
memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
|
|
break;
|
|
case (PACKET_REQ_VERNEG << 29) | 0:
|
|
packet_out->po_flags |= PO_VERNEG;
|
|
if (req->pr_version == LSQVER_046)
|
|
gen_verneg = lsquic_Q046_gen_ver_nego_pkt;
|
|
else
|
|
gen_verneg = lsquic_ietf_v1_gen_ver_nego_pkt;
|
|
len = gen_verneg(packet_out->po_data, max_bufsz(prq),
|
|
/* Flip SCID/DCID here: */ &req->pr_dcid, &req->pr_scid,
|
|
prq->prq_enpub->enp_settings.es_versions,
|
|
lsquic_crand_get_byte(prq->prq_enpub->enp_crand));
|
|
if (len > 0)
|
|
packet_out->po_data_sz = len;
|
|
else
|
|
packet_out->po_data_sz = 0;
|
|
break;
|
|
case (PACKET_REQ_RETRY << 29) | 0:
|
|
packet_out->po_flags |= PO_RETRY;
|
|
len = lsquic_iquic_gen_retry_pkt(packet_out->po_data, max_bufsz(prq),
|
|
prq->prq_enpub, &req->pr_scid, &req->pr_dcid,
|
|
req->pr_version, NP_PEER_SA(&req->pr_path),
|
|
lsquic_crand_get_nybble(prq->prq_enpub->enp_crand));
|
|
if (len > 0)
|
|
packet_out->po_data_sz = len;
|
|
else
|
|
packet_out->po_data_sz = 0;
|
|
break;
|
|
default:
|
|
packet_out->po_flags &= ~PO_VERNEG;
|
|
packet_out->po_data_sz = req->pr_rst_sz;
|
|
RAND_bytes(packet_out->po_data, req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
|
|
packet_out->po_data[0] &= ~0x80;
|
|
packet_out->po_data[0] |= 0x40;
|
|
lsquic_tg_generate_sreset(prq->prq_enpub->enp_tokgen, &req->pr_dcid,
|
|
packet_out->po_data + req->pr_rst_sz - IQUIC_SRESET_TOKEN_SZ);
|
|
break;
|
|
}
|
|
|
|
lsquic_hash_erase(prq->prq_reqs_hash, el);
|
|
evconn->evc_req = req;
|
|
|
|
lconn= &evconn->evc_conn;
|
|
evconn->evc_cces[0].cce_cid = req->pr_dcid;
|
|
packet_out->po_path = &req->pr_path;
|
|
|
|
++prq->prq_nconns;
|
|
return lconn;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_prq_have_pending (const struct pr_queue *prq)
|
|
{
|
|
return lsquic_hash_count(prq->prq_reqs_hash) > 0;
|
|
}
|
|
|
|
|
|
static struct lsquic_packet_out *
|
|
evanescent_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
|
const struct to_coal *to_coal_UNUSED)
|
|
{
|
|
struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
|
|
assert(!to_coal_UNUSED);
|
|
return &evconn->evc_packet_out;
|
|
}
|
|
|
|
|
|
static void
|
|
prq_free_conn (struct pr_queue *prq, struct lsquic_conn *lconn)
|
|
{
|
|
struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
|
|
|
|
TAILQ_INSERT_HEAD(&prq->prq_free_conns, lconn, cn_next_pr);
|
|
put_req(prq, evconn->evc_req);
|
|
--prq->prq_nconns;
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_packet_sent (struct lsquic_conn *lconn,
|
|
struct lsquic_packet_out *packet_out)
|
|
{
|
|
struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
|
|
struct pr_queue *const prq = evconn->evc_queue;
|
|
|
|
assert(packet_out == &evconn->evc_packet_out);
|
|
assert(prq->prq_nconns > 0);
|
|
|
|
LSQ_DEBUGC("sent %s packet for connection %"CID_FMT"; free resources",
|
|
lsquic_preqt2str[ evconn->evc_req->pr_type ],
|
|
CID_BITS(&evconn->evc_req->pr_dcid));
|
|
prq_free_conn(prq, lconn);
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
|
|
struct lsquic_packet_out *packet_out)
|
|
{
|
|
struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
|
|
struct pr_queue *const prq = evconn->evc_queue;
|
|
|
|
assert(packet_out == &evconn->evc_packet_out);
|
|
assert(prq->prq_nconns > 0);
|
|
|
|
if (evconn->evc_flags & EVC_DROP)
|
|
{
|
|
LSQ_DEBUGC("packet not sent; drop connection %"CID_FMT,
|
|
CID_BITS(&evconn->evc_req->pr_dcid));
|
|
prq_free_conn(prq, lconn);
|
|
}
|
|
else
|
|
{
|
|
LSQ_DEBUG("packet not sent; put connection onto used list");
|
|
TAILQ_INSERT_HEAD(&prq->prq_returned_conns, lconn, cn_next_pr);
|
|
}
|
|
}
|
|
|
|
|
|
static enum tick_st
|
|
evanescent_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|
|
{
|
|
assert(0);
|
|
return TICK_CLOSE;
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_destroy (struct lsquic_conn *lconn)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
static struct lsquic_engine *
|
|
evanescent_conn_ci_get_engine (struct lsquic_conn *lconn)
|
|
{
|
|
assert(0);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_hsk_done (struct lsquic_conn *lconn,
|
|
enum lsquic_hsk_status status)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_packet_in (struct lsquic_conn *lconn,
|
|
struct lsquic_packet_in *packet_in)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
static void
|
|
evanescent_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
static struct network_path *
|
|
evanescent_conn_ci_get_path (struct lsquic_conn *lconn,
|
|
const struct sockaddr *sa)
|
|
{
|
|
struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
|
|
|
|
return &evconn->evc_req->pr_path;
|
|
}
|
|
|
|
|
|
static unsigned char
|
|
evanescent_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
|
|
const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
|
|
{
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static const struct conn_iface evanescent_conn_iface = {
|
|
.ci_client_call_on_new = evanescent_conn_ci_client_call_on_new,
|
|
.ci_destroy = evanescent_conn_ci_destroy,
|
|
.ci_get_engine = evanescent_conn_ci_get_engine,
|
|
.ci_get_path = evanescent_conn_ci_get_path,
|
|
.ci_hsk_done = evanescent_conn_ci_hsk_done,
|
|
.ci_next_packet_to_send = evanescent_conn_ci_next_packet_to_send,
|
|
.ci_packet_in = evanescent_conn_ci_packet_in,
|
|
.ci_packet_not_sent = evanescent_conn_ci_packet_not_sent,
|
|
.ci_packet_sent = evanescent_conn_ci_packet_sent,
|
|
.ci_record_addrs = evanescent_conn_ci_record_addrs,
|
|
.ci_tick = evanescent_conn_ci_tick,
|
|
};
|
|
|
|
|
|
const char *const lsquic_preqt2str[] =
|
|
{
|
|
[PACKET_REQ_VERNEG] = "version negotiation",
|
|
[PACKET_REQ_PUBRES] = "stateless reset",
|
|
};
|
|
|
|
|
|
void
|
|
lsquic_prq_drop (struct lsquic_conn *lconn)
|
|
{
|
|
struct evanescent_conn *const evconn = (void *) lconn;
|
|
|
|
evconn->evc_flags |= EVC_DROP;
|
|
LSQ_DEBUGC("mark for connection %"CID_FMT" for dropping",
|
|
CID_BITS(&evconn->evc_req->pr_dcid));
|
|
}
|