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