lsquic_pr_queue.c revision 5392f7a3
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_pr_queue.c -- packet request queue.
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <netinet/in.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/queue.h>
13#include <sys/socket.h>
14
15#include <openssl/aead.h>
16#include <openssl/rand.h>
17
18#include "lsquic.h"
19#include "lsquic_types.h"
20#include "lsquic_int_types.h"
21#include "lsquic_packet_common.h"
22#include "lsquic_packet_gquic.h"
23#include "lsquic_packet_out.h"
24#include "lsquic_packet_in.h"
25#include "lsquic_hash.h"
26#include "lsquic_conn.h"
27#include "lsquic_parse.h"
28#include "lsquic_malo.h"
29#include "lsquic_pr_queue.h"
30#include "lsquic_parse_common.h"
31#include "lsquic_tokgen.h"
32#include "lsquic_version.h"
33#include "lsquic_mm.h"
34#include "lsquic_engine_public.h"
35#include "lsquic_sizes.h"
36#include "lsquic_handshake.h"
37
38#define LSQUIC_LOGGER_MODULE LSQLM_PRQ
39#include "lsquic_logger.h"
40
41#define MAX(a, b) ((a) > (b) ? (a) : (b))
42
43
44static const struct conn_iface evanescent_conn_iface;
45
46
47struct packet_req
48{
49    STAILQ_ENTRY(packet_req)    pr_next;
50    lsquic_cid_t                pr_scid;
51    lsquic_cid_t                pr_dcid;
52    enum packet_req_type        pr_type;
53    enum {
54        PR_GQUIC    = 1 << 0,
55    }                           pr_flags;
56    enum lsquic_version         pr_version;
57    struct network_path         pr_path;
58};
59
60
61struct evanescent_conn
62{
63    struct lsquic_conn          evc_conn;
64    struct packet_req          *evc_req;
65    struct pr_queue            *evc_queue;
66    struct lsquic_packet_out    evc_packet_out;
67    struct conn_cid_elem        evc_cces[1];
68    unsigned char               evc_buf[0];
69};
70
71
72/* [draft-ietf-quic-transport-22], Section 17.2.1 */
73#define IQUIC_VERNEG_SIZE (1 /* Type */ + 4 /* Version (zero tag) */ \
74                + 1 /* DCIL */ + MAX_CID_LEN + 1 /* SCIL */ + MAX_CID_LEN + \
75                4 * N_LSQVER)
76
77
78struct pr_queue
79{
80    TAILQ_HEAD(, lsquic_conn)   prq_free_conns,
81                                prq_returned_conns;
82    STAILQ_HEAD(, packet_req)   prq_reqs_queue;
83    struct malo                *prq_reqs_pool;
84    const struct lsquic_engine_public
85                               *prq_enpub;
86    unsigned                    prq_max_reqs;
87    unsigned                    prq_nreqs;
88    unsigned                    prq_max_conns;
89    unsigned                    prq_nconns;
90    unsigned                    prq_verneg_g_sz;  /* Size of prq_verneg_g_buf */
91    unsigned                    prq_pubres_g_sz;  /* Size of prq_pubres_g_buf */
92
93    /* GQUIC version negotiation and stateless reset packets are generated
94     * once, when the Packet Request Queue is created.  For each request,
95     * these buffers are simply copied and the connection ID is replaced.
96     *
97     * Since IETF QUIC uses variable-length connections IDs, we have to
98     * generate packets every time.
99     */
100    unsigned char               prq_pubres_g_buf[GQUIC_RESET_SZ];
101    unsigned char               prq_verneg_g_buf[1 + GQUIC_CID_LEN
102                                                                + N_LSQVER * 4];
103};
104
105
106struct pr_queue *
107prq_create (unsigned max_elems, unsigned max_conns,
108                        const struct lsquic_engine_public *enpub)
109{
110    const struct parse_funcs *pf;
111    struct pr_queue *prq;
112    struct malo *malo;
113    unsigned verneg_g_sz;
114    ssize_t prst_g_sz;
115    int len;
116
117    malo = lsquic_malo_create(sizeof(struct packet_req));
118    if (!malo)
119    {
120        LSQ_WARN("malo_create failed: %s", strerror(errno));
121        goto err0;
122    }
123
124    prq = malloc(sizeof(*prq));
125    if (!prq)
126    {
127        LSQ_WARN("malloc failed: %s", strerror(errno));
128        goto err1;
129    }
130
131    const lsquic_cid_t cid = { .len = 8, };
132    pf = select_pf_by_ver(LSQVER_039);
133    len = lsquic_gquic_gen_ver_nego_pkt(prq->prq_verneg_g_buf,
134                    sizeof(prq->prq_verneg_g_buf), &cid,
135                    enpub->enp_settings.es_versions);
136    assert(len > 0);
137    if (len <= 0)
138    {
139        LSQ_ERROR("cannot generate version negotiation packet");
140        goto err2;
141    }
142    verneg_g_sz = (unsigned) len;
143
144    prst_g_sz = pf->pf_generate_simple_prst(0 /* This is just placeholder */,
145                                prq->prq_pubres_g_buf, sizeof(prq->prq_pubres_g_buf));
146    if (prst_g_sz < 0)
147    {
148        LSQ_ERROR("cannot generate public reset packet");
149        goto err2;
150    }
151
152    TAILQ_INIT(&prq->prq_free_conns);
153    TAILQ_INIT(&prq->prq_returned_conns);
154    STAILQ_INIT(&prq->prq_reqs_queue);
155    prq->prq_reqs_pool = malo;
156    prq->prq_max_reqs = max_elems;
157    prq->prq_nreqs = 0;
158    prq->prq_max_conns = max_conns;
159    prq->prq_nconns = 0;
160    prq->prq_verneg_g_sz = verneg_g_sz;
161    prq->prq_pubres_g_sz = (unsigned) prst_g_sz;
162    prq->prq_enpub       = enpub;
163
164    LSQ_INFO("initialized queue of size %d", max_elems);
165
166    return prq;
167
168  err2:
169    free(prq);
170  err1:
171    lsquic_malo_destroy(malo);
172  err0:
173    return NULL;
174}
175
176
177void
178prq_destroy (struct pr_queue *prq)
179{
180    struct lsquic_conn *conn;
181
182    LSQ_INFO("destroy");
183    while ((conn = TAILQ_FIRST(&prq->prq_free_conns)))
184    {
185        TAILQ_REMOVE(&prq->prq_free_conns, conn, cn_next_pr);
186        free(conn);
187    }
188    lsquic_malo_destroy(prq->prq_reqs_pool);
189    free(prq);
190}
191
192
193static struct packet_req *
194get_req (struct pr_queue *prq)
195{
196    struct packet_req *req;
197    if (prq->prq_nreqs < prq->prq_max_reqs)
198    {
199        req = lsquic_malo_get(prq->prq_reqs_pool);
200        if (req)
201            ++prq->prq_nreqs;
202        else
203            LSQ_WARN("malo_get failed: %s", strerror(errno));
204        return req;
205    }
206    else
207        return NULL;
208}
209
210
211static void
212put_req (struct pr_queue *prq, struct packet_req *req)
213{
214    lsquic_malo_put(req);
215    --prq->prq_nreqs;
216}
217
218
219int
220prq_new_req (struct pr_queue *prq, enum packet_req_type type,
221         const struct lsquic_packet_in *packet_in, void *peer_ctx,
222         const struct sockaddr *local_addr, const struct sockaddr *peer_addr)
223{
224    struct packet_req *req;
225    lsquic_ver_tag_t ver_tag;
226
227    req = get_req(prq);
228    if (!req)
229    {
230        LSQ_DEBUG("out of reqs: cannot allocated another one");
231        return -1;
232    }
233
234    STAILQ_INSERT_TAIL(&prq->prq_reqs_queue, req, pr_next);
235
236    req->pr_type     = type;
237    req->pr_flags    = packet_in->pi_flags & PI_GQUIC ? PR_GQUIC : 0;
238    lsquic_scid_from_packet_in(packet_in, &req->pr_scid);
239    req->pr_dcid     = packet_in->pi_dcid;
240    req->pr_path.np_peer_ctx = peer_ctx;
241    memcpy(NP_LOCAL_SA(&req->pr_path), local_addr,
242                                            sizeof(req->pr_path.np_local_addr));
243    memcpy(NP_PEER_SA(&req->pr_path), peer_addr,
244                                            sizeof(req->pr_path.np_peer_addr));
245    if (packet_in->pi_quic_ver)
246    {
247        memcpy(&ver_tag, packet_in->pi_data + packet_in->pi_quic_ver,
248                                                            sizeof(ver_tag));
249        req->pr_version = lsquic_tag2ver(ver_tag);
250    }
251    else /* Got to set it to something sensible... */
252        req->pr_version = LSQVER_ID22;
253    LSQ_DEBUGC("scheduled %s packet for connection %"CID_FMT,
254                            lsquic_preqt2str[type], CID_BITS(&req->pr_dcid));
255    return 0;
256}
257
258
259static size_t
260max_bufsz (const struct pr_queue *prq)
261{
262    return  MAX(MAX(MAX(IQUIC_VERNEG_SIZE,
263                        IQUIC_MIN_SRST_SIZE),
264                        sizeof(prq->prq_verneg_g_buf)),
265                        sizeof(prq->prq_pubres_g_buf));
266}
267
268
269static struct evanescent_conn *
270get_evconn (struct pr_queue *prq)
271{
272    struct evanescent_conn *evconn;
273    struct lsquic_conn *lconn;
274    struct lsquic_packet_out *packet_out;
275    size_t bufsz;
276
277    if (prq->prq_nconns >= prq->prq_max_conns)
278    {   /* This deserves a warning */
279        LSQ_WARN("tried to get connection past limit of %u", prq->prq_max_conns);
280        return NULL;
281    }
282
283    lconn = TAILQ_FIRST(&prq->prq_free_conns);
284    if (lconn)
285    {
286        TAILQ_REMOVE(&prq->prq_free_conns, lconn, cn_next_pr);
287        return (struct evanescent_conn *) lconn;
288    }
289
290    bufsz = max_bufsz(prq);
291    evconn = calloc(1, sizeof(*evconn) + bufsz);
292    if (!evconn)
293    {
294        LSQ_WARN("calloc failed: %s", strerror(errno));
295        return NULL;
296    }
297
298    /* These values stay the same between connection usages: */
299    evconn->evc_queue = prq;
300    lconn = &evconn->evc_conn;
301    lconn->cn_cces = evconn->evc_cces;
302    lconn->cn_cces_mask = 1;
303    lconn->cn_n_cces = sizeof(evconn->evc_cces) / sizeof(evconn->evc_cces[0]);
304    lconn->cn_if = &evanescent_conn_iface;
305    lconn->cn_flags = LSCONN_EVANESCENT;
306    packet_out = &evconn->evc_packet_out;
307    packet_out->po_flags = PO_NOENCRYPT;
308    packet_out->po_data = evconn->evc_buf;
309
310    return evconn;
311}
312
313
314struct lsquic_conn *
315prq_next_conn (struct pr_queue *prq)
316{
317    struct evanescent_conn *evconn;
318    struct lsquic_conn *lconn;
319    struct packet_req *req;
320    struct lsquic_packet_out *packet_out;
321    int (*gen_verneg) (unsigned char *, size_t, const lsquic_cid_t *,
322                                            const lsquic_cid_t *, unsigned);
323    int len;
324
325    lconn = TAILQ_FIRST(&prq->prq_returned_conns);
326    if (lconn)
327    {
328        TAILQ_REMOVE(&prq->prq_returned_conns, lconn, cn_next_pr);
329        return lconn;
330    }
331
332    req = STAILQ_FIRST(&prq->prq_reqs_queue);
333    if (!req)           /* Nothing is queued */
334        return NULL;
335
336    evconn = get_evconn(prq);
337    if (!evconn)         /* Reached limit or malloc failed */
338        return NULL;
339
340    packet_out = &evconn->evc_packet_out;
341    switch ((req->pr_type << 29) | req->pr_flags)
342    {
343    case (PACKET_REQ_VERNEG << 29) | PR_GQUIC:
344        packet_out->po_data_sz = prq->prq_verneg_g_sz;
345        packet_out->po_flags |= PO_VERNEG;
346        memcpy(packet_out->po_data, prq->prq_verneg_g_buf,
347                                                    prq->prq_verneg_g_sz);
348        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
349        break;
350    case (PACKET_REQ_PUBRES << 29) | PR_GQUIC:
351        packet_out->po_flags &= ~PO_VERNEG;
352        packet_out->po_data_sz = prq->prq_pubres_g_sz;
353        memcpy(packet_out->po_data, prq->prq_pubres_g_buf,
354                                                    prq->prq_pubres_g_sz);
355        memcpy(packet_out->po_data + 1, req->pr_dcid.idbuf, GQUIC_CID_LEN);
356        break;
357    case (PACKET_REQ_VERNEG << 29) | 0:
358        packet_out->po_flags |= PO_VERNEG;
359        if (req->pr_version == LSQVER_046)
360            gen_verneg = lsquic_Q046_gen_ver_nego_pkt;
361        else
362            gen_verneg = lsquic_ietf_v1_gen_ver_nego_pkt;
363        len = gen_verneg(packet_out->po_data, max_bufsz(prq),
364                    /* Flip SCID/DCID here: */ &req->pr_dcid, &req->pr_scid,
365                    prq->prq_enpub->enp_settings.es_versions);
366        if (len > 0)
367            packet_out->po_data_sz = len;
368        else
369            packet_out->po_data_sz = 0;
370        break;
371    default:
372        packet_out->po_flags &= ~PO_VERNEG;
373        packet_out->po_data_sz = IQUIC_MIN_SRST_SIZE;
374        RAND_bytes(packet_out->po_data, IQUIC_MIN_SRST_RANDOM_BYTES);
375        packet_out->po_data[0] &= ~0x80;
376        packet_out->po_data[0] |=  0x40;
377        lsquic_tg_generate_sreset(prq->prq_enpub->enp_tokgen, &req->pr_dcid,
378            packet_out->po_data + IQUIC_MIN_SRST_RANDOM_BYTES);
379        break;
380    }
381
382    STAILQ_REMOVE_HEAD(&prq->prq_reqs_queue, pr_next);
383    evconn->evc_req = req;
384
385    lconn= &evconn->evc_conn;
386    evconn->evc_cces[0].cce_cid = req->pr_dcid;
387    packet_out->po_path = &req->pr_path;
388
389    ++prq->prq_nconns;
390    return lconn;
391}
392
393
394int
395prq_have_pending (const struct pr_queue *prq)
396{
397    return !STAILQ_EMPTY(&prq->prq_reqs_queue);
398}
399
400
401static struct lsquic_packet_out *
402evanescent_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
403{
404    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
405    assert(size == 0);
406    return &evconn->evc_packet_out;
407}
408
409
410static void
411evanescent_conn_ci_packet_sent (struct lsquic_conn *lconn,
412                            struct lsquic_packet_out *packet_out)
413{
414    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
415    struct pr_queue *const prq = evconn->evc_queue;
416
417    assert(packet_out == &evconn->evc_packet_out);
418    assert(prq->prq_nconns > 0);
419
420    LSQ_DEBUGC("sent %s packet for connection %"CID_FMT"; free resources",
421        lsquic_preqt2str[ evconn->evc_req->pr_type ],
422        CID_BITS(&evconn->evc_req->pr_dcid));
423    TAILQ_INSERT_HEAD(&prq->prq_free_conns, lconn, cn_next_pr);
424    put_req(prq, evconn->evc_req);
425    --prq->prq_nconns;
426}
427
428
429static void
430evanescent_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
431                                struct lsquic_packet_out *packet_out)
432{
433    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
434    struct pr_queue *const prq = evconn->evc_queue;
435
436    assert(packet_out == &evconn->evc_packet_out);
437    assert(prq->prq_nconns > 0);
438
439    LSQ_DEBUG("packet not sent; put connection onto used list");
440    TAILQ_INSERT_HEAD(&prq->prq_returned_conns, lconn, cn_next_pr);
441}
442
443
444static enum tick_st
445evanescent_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
446{
447    assert(0);
448    return TICK_CLOSE;
449}
450
451
452static void
453evanescent_conn_ci_destroy (struct lsquic_conn *lconn)
454{
455    assert(0);
456}
457
458
459static struct lsquic_engine *
460evanescent_conn_ci_get_engine (struct lsquic_conn *lconn)
461{
462    assert(0);
463    return NULL;
464}
465
466
467static void
468evanescent_conn_ci_hsk_done (struct lsquic_conn *lconn,
469                                                enum lsquic_hsk_status status)
470{
471    assert(0);
472}
473
474
475static void
476evanescent_conn_ci_packet_in (struct lsquic_conn *lconn,
477                          struct lsquic_packet_in *packet_in)
478{
479    assert(0);
480}
481
482
483static void
484evanescent_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
485{
486    assert(0);
487}
488
489
490static struct network_path *
491evanescent_conn_ci_get_path (struct lsquic_conn *lconn,
492                                                    const struct sockaddr *sa)
493{
494    struct evanescent_conn *const evconn = (struct evanescent_conn *) lconn;
495
496    return &evconn->evc_req->pr_path;
497}
498
499
500static unsigned char
501evanescent_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
502            const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
503{
504    assert(0);
505    return 0;
506}
507
508
509static const struct conn_iface evanescent_conn_iface = {
510    .ci_client_call_on_new   =  evanescent_conn_ci_client_call_on_new,
511    .ci_destroy              =  evanescent_conn_ci_destroy,
512    .ci_get_engine           =  evanescent_conn_ci_get_engine,
513    .ci_get_path             =  evanescent_conn_ci_get_path,
514    .ci_hsk_done             =  evanescent_conn_ci_hsk_done,
515    .ci_next_packet_to_send  =  evanescent_conn_ci_next_packet_to_send,
516    .ci_packet_in            =  evanescent_conn_ci_packet_in,
517    .ci_packet_not_sent      =  evanescent_conn_ci_packet_not_sent,
518    .ci_packet_sent          =  evanescent_conn_ci_packet_sent,
519    .ci_record_addrs         =  evanescent_conn_ci_record_addrs,
520    .ci_tick                 =  evanescent_conn_ci_tick,
521};
522
523
524const char *const lsquic_preqt2str[] =
525{
526    [PACKET_REQ_VERNEG] = "version negotiation",
527    [PACKET_REQ_PUBRES] = "stateless reset",
528};
529