lsquic_engine.c revision 9626cfc2
1/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_engine.c - QUIC engine 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <inttypes.h> 9#include <stdint.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <sys/queue.h> 14#include <time.h> 15#ifndef WIN32 16#include <sys/time.h> 17#include <netinet/in.h> 18#include <sys/types.h> 19#include <sys/stat.h> 20#include <fcntl.h> 21#include <unistd.h> 22#include <netdb.h> 23#endif 24 25 26 27#include "lsquic.h" 28#include "lsquic_types.h" 29#include "lsquic_alarmset.h" 30#include "lsquic_parse_common.h" 31#include "lsquic_parse.h" 32#include "lsquic_packet_in.h" 33#include "lsquic_packet_out.h" 34#include "lsquic_senhist.h" 35#include "lsquic_rtt.h" 36#include "lsquic_cubic.h" 37#include "lsquic_pacer.h" 38#include "lsquic_send_ctl.h" 39#include "lsquic_set.h" 40#include "lsquic_conn_flow.h" 41#include "lsquic_sfcw.h" 42#include "lsquic_stream.h" 43#include "lsquic_conn.h" 44#include "lsquic_full_conn.h" 45#include "lsquic_util.h" 46#include "lsquic_qtags.h" 47#include "lsquic_str.h" 48#include "lsquic_handshake.h" 49#include "lsquic_mm.h" 50#include "lsquic_conn_hash.h" 51#include "lsquic_engine_public.h" 52#include "lsquic_eng_hist.h" 53#include "lsquic_ev_log.h" 54#include "lsquic_version.h" 55#include "lsquic_hash.h" 56#include "lsquic_attq.h" 57#include "lsquic_min_heap.h" 58 59#define LSQUIC_LOGGER_MODULE LSQLM_ENGINE 60#include "lsquic_logger.h" 61 62 63/* The batch of outgoing packets grows and shrinks dynamically */ 64#define MAX_OUT_BATCH_SIZE 1024 65#define MIN_OUT_BATCH_SIZE 256 66#define INITIAL_OUT_BATCH_SIZE 512 67 68struct out_batch 69{ 70 lsquic_conn_t *conns [MAX_OUT_BATCH_SIZE]; 71 lsquic_packet_out_t *packets[MAX_OUT_BATCH_SIZE]; 72 struct lsquic_out_spec outs [MAX_OUT_BATCH_SIZE]; 73}; 74 75typedef struct lsquic_conn * (*conn_iter_f)(struct lsquic_engine *); 76 77static void 78process_connections (struct lsquic_engine *engine, conn_iter_f iter, 79 lsquic_time_t now); 80 81static void 82engine_incref_conn (lsquic_conn_t *conn, enum lsquic_conn_flags flag); 83 84static lsquic_conn_t * 85engine_decref_conn (lsquic_engine_t *engine, lsquic_conn_t *conn, 86 enum lsquic_conn_flags flag); 87 88static void 89force_close_conn (lsquic_engine_t *engine, lsquic_conn_t *conn); 90 91/* Nested calls to LSQUIC are not supported */ 92#define ENGINE_IN(e) do { \ 93 assert(!((e)->pub.enp_flags & ENPUB_PROC)); \ 94 (e)->pub.enp_flags |= ENPUB_PROC; \ 95} while (0) 96 97#define ENGINE_OUT(e) do { \ 98 assert((e)->pub.enp_flags & ENPUB_PROC); \ 99 (e)->pub.enp_flags &= ~ENPUB_PROC; \ 100} while (0) 101 102/* A connection can be referenced from one of six places: 103 * 104 * 1. Connection hash: a connection starts its life in one of those. 105 * 106 * 2. Outgoing queue. 107 * 108 * 3. Tickable queue 109 * 110 * 4. Advisory Tick Time queue. 111 * 112 * 5. Closing connections queue. This is a transient queue -- it only 113 * exists for the duration of process_connections() function call. 114 * 115 * 6. Ticked connections queue. Another transient queue, similar to (5). 116 * 117 * The idea is to destroy the connection when it is no longer referenced. 118 * For example, a connection tick may return TICK_SEND|TICK_CLOSE. In 119 * that case, the connection is referenced from two places: (2) and (5). 120 * After its packets are sent, it is only referenced in (5), and at the 121 * end of the function call, when it is removed from (5), reference count 122 * goes to zero and the connection is destroyed. If not all packets can 123 * be sent, at the end of the function call, the connection is referenced 124 * by (2) and will only be removed once all outgoing packets have been 125 * sent. 126 */ 127#define CONN_REF_FLAGS (LSCONN_HASHED \ 128 |LSCONN_HAS_OUTGOING \ 129 |LSCONN_TICKABLE \ 130 |LSCONN_TICKED \ 131 |LSCONN_CLOSING \ 132 |LSCONN_ATTQ) 133 134 135 136 137struct lsquic_engine 138{ 139 struct lsquic_engine_public pub; 140 enum { 141 ENG_SERVER = LSENG_SERVER, 142 ENG_HTTP = LSENG_HTTP, 143 ENG_COOLDOWN = (1 << 7), /* Cooldown: no new connections */ 144 ENG_PAST_DEADLINE 145 = (1 << 8), /* Previous call to a processing 146 * function went past time threshold. 147 */ 148#ifndef NDEBUG 149 ENG_DTOR = (1 << 26), /* Engine destructor */ 150#endif 151 } flags; 152 const struct lsquic_stream_if *stream_if; 153 void *stream_if_ctx; 154 lsquic_packets_out_f packets_out; 155 void *packets_out_ctx; 156 void *bad_handshake_ctx; 157 struct conn_hash conns_hash; 158 struct min_heap conns_tickable; 159 struct min_heap conns_out; 160 struct eng_hist history; 161 unsigned batch_size; 162 struct attq *attq; 163 /* Track time last time a packet was sent to give new connections 164 * priority lower than that of existing connections. 165 */ 166 lsquic_time_t last_sent; 167 unsigned n_conns; 168 lsquic_time_t deadline; 169 struct out_batch out_batch; 170}; 171 172 173void 174lsquic_engine_init_settings (struct lsquic_engine_settings *settings, 175 unsigned flags) 176{ 177 memset(settings, 0, sizeof(*settings)); 178 settings->es_versions = LSQUIC_DF_VERSIONS; 179 if (flags & ENG_SERVER) 180 { 181 settings->es_cfcw = LSQUIC_DF_CFCW_SERVER; 182 settings->es_sfcw = LSQUIC_DF_SFCW_SERVER; 183 settings->es_support_srej= LSQUIC_DF_SUPPORT_SREJ_SERVER; 184 } 185 else 186 { 187 settings->es_cfcw = LSQUIC_DF_CFCW_CLIENT; 188 settings->es_sfcw = LSQUIC_DF_SFCW_CLIENT; 189 settings->es_support_srej= LSQUIC_DF_SUPPORT_SREJ_CLIENT; 190 } 191 settings->es_max_streams_in = LSQUIC_DF_MAX_STREAMS_IN; 192 settings->es_idle_conn_to = LSQUIC_DF_IDLE_CONN_TO; 193 settings->es_handshake_to = LSQUIC_DF_HANDSHAKE_TO; 194 settings->es_silent_close = LSQUIC_DF_SILENT_CLOSE; 195 settings->es_max_header_list_size 196 = LSQUIC_DF_MAX_HEADER_LIST_SIZE; 197 settings->es_ua = LSQUIC_DF_UA; 198 199 settings->es_pdmd = QTAG_X509; 200 settings->es_aead = QTAG_AESG; 201 settings->es_kexs = QTAG_C255; 202 settings->es_support_push = LSQUIC_DF_SUPPORT_PUSH; 203 settings->es_support_tcid0 = LSQUIC_DF_SUPPORT_TCID0; 204 settings->es_support_nstp = LSQUIC_DF_SUPPORT_NSTP; 205 settings->es_honor_prst = LSQUIC_DF_HONOR_PRST; 206 settings->es_progress_check = LSQUIC_DF_PROGRESS_CHECK; 207 settings->es_rw_once = LSQUIC_DF_RW_ONCE; 208 settings->es_proc_time_thresh= LSQUIC_DF_PROC_TIME_THRESH; 209 settings->es_pace_packets = LSQUIC_DF_PACE_PACKETS; 210} 211 212 213/* Note: if returning an error, err_buf must be valid if non-NULL */ 214int 215lsquic_engine_check_settings (const struct lsquic_engine_settings *settings, 216 unsigned flags, 217 char *err_buf, size_t err_buf_sz) 218{ 219 if (settings->es_cfcw < LSQUIC_MIN_FCW || 220 settings->es_sfcw < LSQUIC_MIN_FCW) 221 { 222 if (err_buf) 223 snprintf(err_buf, err_buf_sz, "%s", 224 "flow control window set too low"); 225 return -1; 226 } 227 if (0 == (settings->es_versions & LSQUIC_SUPPORTED_VERSIONS)) 228 { 229 if (err_buf) 230 snprintf(err_buf, err_buf_sz, "%s", 231 "No supported QUIC versions specified"); 232 return -1; 233 } 234 if (settings->es_versions & ~LSQUIC_SUPPORTED_VERSIONS) 235 { 236 if (err_buf) 237 snprintf(err_buf, err_buf_sz, "%s", 238 "one or more unsupported QUIC version is specified"); 239 return -1; 240 } 241 return 0; 242} 243 244 245static void 246free_packet (void *ctx, unsigned char *packet_data) 247{ 248 free(packet_data); 249} 250 251 252static void * 253malloc_buf (void *ctx, size_t size) 254{ 255 return malloc(size); 256} 257 258 259static const struct lsquic_packout_mem_if stock_pmi = 260{ 261 malloc_buf, (void(*)(void *, void *)) free_packet, 262}; 263 264 265static int 266hash_conns_by_addr (const struct lsquic_engine *engine) 267{ 268 if (engine->pub.enp_settings.es_versions & LSQUIC_FORCED_TCID0_VERSIONS) 269 return 1; 270 if ((engine->pub.enp_settings.es_versions & LSQUIC_GQUIC_HEADER_VERSIONS) 271 && engine->pub.enp_settings.es_support_tcid0) 272 return 1; 273 return 0; 274} 275 276 277lsquic_engine_t * 278lsquic_engine_new (unsigned flags, 279 const struct lsquic_engine_api *api) 280{ 281 lsquic_engine_t *engine; 282 int tag_buf_len; 283 char err_buf[100]; 284 285 if (!api->ea_packets_out) 286 { 287 LSQ_ERROR("packets_out callback is not specified"); 288 return NULL; 289 } 290 291 if (api->ea_settings && 292 0 != lsquic_engine_check_settings(api->ea_settings, flags, 293 err_buf, sizeof(err_buf))) 294 { 295 LSQ_ERROR("cannot create engine: %s", err_buf); 296 return NULL; 297 } 298 299 engine = calloc(1, sizeof(*engine)); 300 if (!engine) 301 return NULL; 302 if (0 != lsquic_mm_init(&engine->pub.enp_mm)) 303 { 304 free(engine); 305 return NULL; 306 } 307 if (api->ea_settings) 308 engine->pub.enp_settings = *api->ea_settings; 309 else 310 lsquic_engine_init_settings(&engine->pub.enp_settings, flags); 311 tag_buf_len = lsquic_gen_ver_tags(engine->pub.enp_ver_tags_buf, 312 sizeof(engine->pub.enp_ver_tags_buf), 313 engine->pub.enp_settings.es_versions); 314 if (tag_buf_len <= 0) 315 { 316 LSQ_ERROR("cannot generate version tags buffer"); 317 free(engine); 318 return NULL; 319 } 320 engine->pub.enp_ver_tags_len = tag_buf_len; 321 engine->pub.enp_flags = ENPUB_CAN_SEND; 322 323 engine->flags = flags; 324 engine->stream_if = api->ea_stream_if; 325 engine->stream_if_ctx = api->ea_stream_if_ctx; 326 engine->packets_out = api->ea_packets_out; 327 engine->packets_out_ctx = api->ea_packets_out_ctx; 328 if (api->ea_pmi) 329 { 330 engine->pub.enp_pmi = api->ea_pmi; 331 engine->pub.enp_pmi_ctx = api->ea_pmi_ctx; 332 } 333 else 334 { 335 engine->pub.enp_pmi = &stock_pmi; 336 engine->pub.enp_pmi_ctx = NULL; 337 } 338 engine->pub.enp_engine = engine; 339 conn_hash_init(&engine->conns_hash, 340 hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0); 341 engine->attq = attq_create(); 342 eng_hist_init(&engine->history); 343 engine->batch_size = INITIAL_OUT_BATCH_SIZE; 344 345 346 LSQ_INFO("instantiated engine"); 347 return engine; 348} 349 350 351static void 352grow_batch_size (struct lsquic_engine *engine) 353{ 354 engine->batch_size <<= engine->batch_size < MAX_OUT_BATCH_SIZE; 355} 356 357 358static void 359shrink_batch_size (struct lsquic_engine *engine) 360{ 361 engine->batch_size >>= engine->batch_size > MIN_OUT_BATCH_SIZE; 362} 363 364 365/* Wrapper to make sure important things occur before the connection is 366 * really destroyed. 367 */ 368static void 369destroy_conn (struct lsquic_engine *engine, lsquic_conn_t *conn) 370{ 371 --engine->n_conns; 372 conn->cn_flags |= LSCONN_NEVER_TICKABLE; 373 conn->cn_if->ci_destroy(conn); 374} 375 376 377static int 378maybe_grow_conn_heaps (struct lsquic_engine *engine) 379{ 380 struct min_heap_elem *els; 381 unsigned count; 382 383 if (engine->n_conns < lsquic_mh_nalloc(&engine->conns_tickable)) 384 return 0; /* Nothing to do */ 385 386 if (lsquic_mh_nalloc(&engine->conns_tickable)) 387 count = lsquic_mh_nalloc(&engine->conns_tickable) * 2 * 2; 388 else 389 count = 8; 390 391 els = malloc(sizeof(els[0]) * count); 392 if (!els) 393 { 394 LSQ_ERROR("%s: malloc failed", __func__); 395 return -1; 396 } 397 398 LSQ_DEBUG("grew heaps to %u elements", count / 2); 399 memcpy(&els[0], engine->conns_tickable.mh_elems, 400 sizeof(els[0]) * lsquic_mh_count(&engine->conns_tickable)); 401 memcpy(&els[count / 2], engine->conns_out.mh_elems, 402 sizeof(els[0]) * lsquic_mh_count(&engine->conns_out)); 403 free(engine->conns_tickable.mh_elems); 404 engine->conns_tickable.mh_elems = els; 405 engine->conns_out.mh_elems = &els[count / 2]; 406 engine->conns_tickable.mh_nalloc = count / 2; 407 engine->conns_out.mh_nalloc = count / 2; 408 return 0; 409} 410 411 412static lsquic_conn_t * 413new_full_conn_client (lsquic_engine_t *engine, const char *hostname, 414 unsigned short max_packet_size) 415{ 416 lsquic_conn_t *conn; 417 unsigned flags; 418 if (0 != maybe_grow_conn_heaps(engine)) 419 return NULL; 420 flags = engine->flags & (ENG_SERVER|ENG_HTTP); 421 conn = full_conn_client_new(&engine->pub, engine->stream_if, 422 engine->stream_if_ctx, flags, hostname, max_packet_size); 423 if (!conn) 424 return NULL; 425 ++engine->n_conns; 426 return conn; 427} 428 429 430static lsquic_conn_t * 431find_conn (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in, 432 struct packin_parse_state *ppstate, const struct sockaddr *sa_local) 433{ 434 lsquic_conn_t *conn; 435 436 if (conn_hash_using_addr(&engine->conns_hash)) 437 conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local); 438 else if (packet_in->pi_flags & PI_CONN_ID) 439 conn = conn_hash_find_by_cid(&engine->conns_hash, 440 packet_in->pi_conn_id); 441 else 442 { 443 LSQ_DEBUG("packet header does not have connection ID: discarding"); 444 return NULL; 445 } 446 447 if (!conn) 448 return NULL; 449 450 conn->cn_pf->pf_parse_packet_in_finish(packet_in, ppstate); 451 if ((packet_in->pi_flags & PI_CONN_ID) 452 && conn->cn_cid != packet_in->pi_conn_id) 453 { 454 LSQ_DEBUG("connection IDs do not match"); 455 return NULL; 456 } 457 458 return conn; 459} 460 461 462#if !defined(NDEBUG) && __GNUC__ 463__attribute__((weak)) 464#endif 465void 466lsquic_engine_add_conn_to_tickable (struct lsquic_engine_public *enpub, 467 lsquic_conn_t *conn) 468{ 469 if (0 == (enpub->enp_flags & ENPUB_PROC) && 470 0 == (conn->cn_flags & (LSCONN_TICKABLE|LSCONN_NEVER_TICKABLE))) 471 { 472 lsquic_engine_t *engine = (lsquic_engine_t *) enpub; 473 lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked); 474 engine_incref_conn(conn, LSCONN_TICKABLE); 475 } 476} 477 478 479void 480lsquic_engine_add_conn_to_attq (struct lsquic_engine_public *enpub, 481 lsquic_conn_t *conn, lsquic_time_t tick_time) 482{ 483 lsquic_engine_t *const engine = (lsquic_engine_t *) enpub; 484 if (conn->cn_flags & LSCONN_TICKABLE) 485 { 486 /* Optimization: no need to add the connection to the Advisory Tick 487 * Time Queue: it is about to be ticked, after which it its next tick 488 * time may be queried again. 489 */; 490 } 491 else if (conn->cn_flags & LSCONN_ATTQ) 492 { 493 if (lsquic_conn_adv_time(conn) != tick_time) 494 { 495 attq_remove(engine->attq, conn); 496 if (0 != attq_add(engine->attq, conn, tick_time)) 497 engine_decref_conn(engine, conn, LSCONN_ATTQ); 498 } 499 } 500 else if (0 == attq_add(engine->attq, conn, tick_time)) 501 engine_incref_conn(conn, LSCONN_ATTQ); 502} 503 504 505/* Return 0 if packet is being processed by a connections, otherwise return 1 */ 506static int 507process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in, 508 struct packin_parse_state *ppstate, const struct sockaddr *sa_local, 509 const struct sockaddr *sa_peer, void *peer_ctx) 510{ 511 lsquic_conn_t *conn; 512 513 if (lsquic_packet_in_is_gquic_prst(packet_in) 514 && !engine->pub.enp_settings.es_honor_prst) 515 { 516 lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in); 517 LSQ_DEBUG("public reset packet: discarding"); 518 return 1; 519 } 520 521 conn = find_conn(engine, packet_in, ppstate, sa_local); 522 523 if (!conn) 524 { 525 lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in); 526 return 1; 527 } 528 529 if (0 == (conn->cn_flags & LSCONN_TICKABLE)) 530 { 531 lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked); 532 engine_incref_conn(conn, LSCONN_TICKABLE); 533 } 534 lsquic_conn_record_sockaddr(conn, sa_local, sa_peer); 535 lsquic_packet_in_upref(packet_in); 536 conn->cn_peer_ctx = peer_ctx; 537 conn->cn_if->ci_packet_in(conn, packet_in); 538 lsquic_packet_in_put(&engine->pub.enp_mm, packet_in); 539 return 0; 540} 541 542 543void 544lsquic_engine_destroy (lsquic_engine_t *engine) 545{ 546 lsquic_conn_t *conn; 547 548 LSQ_DEBUG("destroying engine"); 549#ifndef NDEBUG 550 engine->flags |= ENG_DTOR; 551#endif 552 553 while ((conn = lsquic_mh_pop(&engine->conns_out))) 554 { 555 assert(conn->cn_flags & LSCONN_HAS_OUTGOING); 556 (void) engine_decref_conn(engine, conn, LSCONN_HAS_OUTGOING); 557 } 558 559 while ((conn = lsquic_mh_pop(&engine->conns_tickable))) 560 { 561 assert(conn->cn_flags & LSCONN_TICKABLE); 562 (void) engine_decref_conn(engine, conn, LSCONN_TICKABLE); 563 } 564 565 for (conn = conn_hash_first(&engine->conns_hash); conn; 566 conn = conn_hash_next(&engine->conns_hash)) 567 force_close_conn(engine, conn); 568 conn_hash_cleanup(&engine->conns_hash); 569 570 assert(0 == engine->n_conns); 571 attq_destroy(engine->attq); 572 573 assert(0 == lsquic_mh_count(&engine->conns_out)); 574 assert(0 == lsquic_mh_count(&engine->conns_tickable)); 575 free(engine->conns_tickable.mh_elems); 576 free(engine); 577} 578 579 580lsquic_conn_t * 581lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *local_sa, 582 const struct sockaddr *peer_sa, 583 void *peer_ctx, lsquic_conn_ctx_t *conn_ctx, 584 const char *hostname, unsigned short max_packet_size) 585{ 586 lsquic_conn_t *conn; 587 ENGINE_IN(engine); 588 589 if (engine->flags & ENG_SERVER) 590 { 591 LSQ_ERROR("`%s' must only be called in client mode", __func__); 592 goto err; 593 } 594 595 if (conn_hash_using_addr(&engine->conns_hash) 596 && conn_hash_find_by_addr(&engine->conns_hash, local_sa)) 597 { 598 LSQ_ERROR("cannot have more than one connection on the same port"); 599 goto err; 600 } 601 602 if (0 == max_packet_size) 603 { 604 switch (peer_sa->sa_family) 605 { 606 case AF_INET: 607 max_packet_size = QUIC_MAX_IPv4_PACKET_SZ; 608 break; 609 default: 610 max_packet_size = QUIC_MAX_IPv6_PACKET_SZ; 611 break; 612 } 613 } 614 615 conn = new_full_conn_client(engine, hostname, max_packet_size); 616 if (!conn) 617 goto err; 618 lsquic_conn_record_sockaddr(conn, local_sa, peer_sa); 619 if (0 != conn_hash_add(&engine->conns_hash, conn)) 620 { 621 LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy", 622 conn->cn_cid); 623 destroy_conn(engine, conn); 624 goto err; 625 } 626 assert(!(conn->cn_flags & 627 (CONN_REF_FLAGS 628 & ~LSCONN_TICKABLE /* This flag may be set as effect of user 629 callbacks */ 630 ))); 631 conn->cn_flags |= LSCONN_HASHED; 632 lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked); 633 engine_incref_conn(conn, LSCONN_TICKABLE); 634 conn->cn_peer_ctx = peer_ctx; 635 lsquic_conn_set_ctx(conn, conn_ctx); 636 full_conn_client_call_on_new(conn); 637 end: 638 ENGINE_OUT(engine); 639 return conn; 640 err: 641 conn = NULL; 642 goto end; 643} 644 645 646static void 647remove_conn_from_hash (lsquic_engine_t *engine, lsquic_conn_t *conn) 648{ 649 conn_hash_remove(&engine->conns_hash, conn); 650 (void) engine_decref_conn(engine, conn, LSCONN_HASHED); 651} 652 653 654static void 655refflags2str (enum lsquic_conn_flags flags, char s[6]) 656{ 657 *s = 'C'; s += !!(flags & LSCONN_CLOSING); 658 *s = 'H'; s += !!(flags & LSCONN_HASHED); 659 *s = 'O'; s += !!(flags & LSCONN_HAS_OUTGOING); 660 *s = 'T'; s += !!(flags & LSCONN_TICKABLE); 661 *s = 'A'; s += !!(flags & LSCONN_ATTQ); 662 *s = 'K'; s += !!(flags & LSCONN_TICKED); 663 *s = '\0'; 664} 665 666 667static void 668engine_incref_conn (lsquic_conn_t *conn, enum lsquic_conn_flags flag) 669{ 670 char str[2][7]; 671 assert(flag & CONN_REF_FLAGS); 672 assert(!(conn->cn_flags & flag)); 673 conn->cn_flags |= flag; 674 LSQ_DEBUG("incref conn %"PRIu64", '%s' -> '%s'", conn->cn_cid, 675 (refflags2str(conn->cn_flags & ~flag, str[0]), str[0]), 676 (refflags2str(conn->cn_flags, str[1]), str[1])); 677} 678 679 680static lsquic_conn_t * 681engine_decref_conn (lsquic_engine_t *engine, lsquic_conn_t *conn, 682 enum lsquic_conn_flags flags) 683{ 684 char str[2][7]; 685 assert(flags & CONN_REF_FLAGS); 686 assert(conn->cn_flags & flags); 687#ifndef NDEBUG 688 if (flags & LSCONN_CLOSING) 689 assert(0 == (conn->cn_flags & LSCONN_HASHED)); 690#endif 691 conn->cn_flags &= ~flags; 692 LSQ_DEBUG("decref conn %"PRIu64", '%s' -> '%s'", conn->cn_cid, 693 (refflags2str(conn->cn_flags | flags, str[0]), str[0]), 694 (refflags2str(conn->cn_flags, str[1]), str[1])); 695 if (0 == (conn->cn_flags & CONN_REF_FLAGS)) 696 { 697 eng_hist_inc(&engine->history, 0, sl_del_full_conns); 698 destroy_conn(engine, conn); 699 return NULL; 700 } 701 else 702 return conn; 703} 704 705 706/* This is not a general-purpose function. Only call from engine dtor. */ 707static void 708force_close_conn (lsquic_engine_t *engine, lsquic_conn_t *conn) 709{ 710 assert(engine->flags & ENG_DTOR); 711 const enum lsquic_conn_flags flags = conn->cn_flags; 712 assert(conn->cn_flags & CONN_REF_FLAGS); 713 assert(!(flags & LSCONN_HAS_OUTGOING)); /* Should be removed already */ 714 assert(!(flags & LSCONN_TICKABLE)); /* Should be removed already */ 715 assert(!(flags & LSCONN_CLOSING)); /* It is in transient queue? */ 716 if (flags & LSCONN_ATTQ) 717 { 718 attq_remove(engine->attq, conn); 719 (void) engine_decref_conn(engine, conn, LSCONN_ATTQ); 720 } 721 if (flags & LSCONN_HASHED) 722 remove_conn_from_hash(engine, conn); 723} 724 725 726/* Iterator for tickable connections (those on the Tickable Queue). Before 727 * a connection is returned, it is removed from the Advisory Tick Time queue 728 * if necessary. 729 */ 730static lsquic_conn_t * 731conn_iter_next_tickable (struct lsquic_engine *engine) 732{ 733 lsquic_conn_t *conn; 734 735 conn = lsquic_mh_pop(&engine->conns_tickable); 736 737 if (conn) 738 conn = engine_decref_conn(engine, conn, LSCONN_TICKABLE); 739 if (conn && (conn->cn_flags & LSCONN_ATTQ)) 740 { 741 attq_remove(engine->attq, conn); 742 conn = engine_decref_conn(engine, conn, LSCONN_ATTQ); 743 } 744 745 return conn; 746} 747 748 749void 750lsquic_engine_process_conns (lsquic_engine_t *engine) 751{ 752 lsquic_conn_t *conn; 753 lsquic_time_t now; 754 755 ENGINE_IN(engine); 756 757 now = lsquic_time_now(); 758 while ((conn = attq_pop(engine->attq, now))) 759 { 760 conn = engine_decref_conn(engine, conn, LSCONN_ATTQ); 761 if (conn && !(conn->cn_flags & LSCONN_TICKABLE)) 762 { 763 lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked); 764 engine_incref_conn(conn, LSCONN_TICKABLE); 765 } 766 } 767 768 process_connections(engine, conn_iter_next_tickable, now); 769 ENGINE_OUT(engine); 770} 771 772 773static ssize_t 774really_encrypt_packet (const lsquic_conn_t *conn, 775 struct lsquic_packet_out *packet_out, 776 unsigned char *buf, size_t bufsz) 777{ 778 int header_sz, is_hello_packet; 779 enum enc_level enc_level; 780 size_t packet_sz; 781 unsigned char header_buf[QUIC_MAX_PUBHDR_SZ]; 782 783 header_sz = conn->cn_pf->pf_gen_reg_pkt_header(conn, packet_out, 784 header_buf, sizeof(header_buf)); 785 if (header_sz < 0) 786 return -1; 787 788 is_hello_packet = !!(packet_out->po_flags & PO_HELLO); 789 enc_level = conn->cn_esf->esf_encrypt(conn->cn_enc_session, 790 conn->cn_version, 0, 791 packet_out->po_packno, header_buf, header_sz, 792 packet_out->po_data, packet_out->po_data_sz, 793 buf, bufsz, &packet_sz, is_hello_packet); 794 if ((int) enc_level >= 0) 795 { 796 lsquic_packet_out_set_enc_level(packet_out, enc_level); 797 LSQ_DEBUG("encrypted packet %"PRIu64"; plaintext is %zu bytes, " 798 "ciphertext is %zd bytes", 799 packet_out->po_packno, 800 conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) + 801 packet_out->po_data_sz, 802 packet_sz); 803 return packet_sz; 804 } 805 else 806 return -1; 807} 808 809 810static enum { ENCPA_OK, ENCPA_NOMEM, ENCPA_BADCRYPT, } 811encrypt_packet (lsquic_engine_t *engine, const lsquic_conn_t *conn, 812 lsquic_packet_out_t *packet_out) 813{ 814 ssize_t enc_sz; 815 size_t bufsz; 816 unsigned sent_sz; 817 unsigned char *buf; 818 819 bufsz = conn->cn_pf->pf_packout_header_size(conn, packet_out->po_flags) + 820 packet_out->po_data_sz + QUIC_PACKET_HASH_SZ; 821 buf = engine->pub.enp_pmi->pmi_allocate(engine->pub.enp_pmi_ctx, bufsz); 822 if (!buf) 823 { 824 LSQ_DEBUG("could not allocate memory for outgoing packet of size %zd", 825 bufsz); 826 return ENCPA_NOMEM; 827 } 828 829 { 830 enc_sz = really_encrypt_packet(conn, packet_out, buf, bufsz); 831 sent_sz = enc_sz; 832 } 833 834 if (enc_sz < 0) 835 { 836 engine->pub.enp_pmi->pmi_release(engine->pub.enp_pmi_ctx, buf); 837 return ENCPA_BADCRYPT; 838 } 839 840 packet_out->po_enc_data = buf; 841 packet_out->po_enc_data_sz = enc_sz; 842 packet_out->po_sent_sz = sent_sz; 843 packet_out->po_flags |= PO_ENCRYPTED|PO_SENT_SZ; 844 845 return ENCPA_OK; 846} 847 848 849STAILQ_HEAD(conns_stailq, lsquic_conn); 850TAILQ_HEAD(conns_tailq, lsquic_conn); 851 852 853struct conns_out_iter 854{ 855 struct min_heap *coi_heap; 856 TAILQ_HEAD(, lsquic_conn) coi_active_list, 857 coi_inactive_list; 858 lsquic_conn_t *coi_next; 859#ifndef NDEBUG 860 lsquic_time_t coi_last_sent; 861#endif 862}; 863 864 865static void 866coi_init (struct conns_out_iter *iter, struct lsquic_engine *engine) 867{ 868 iter->coi_heap = &engine->conns_out; 869 iter->coi_next = NULL; 870 TAILQ_INIT(&iter->coi_active_list); 871 TAILQ_INIT(&iter->coi_inactive_list); 872#ifndef NDEBUG 873 iter->coi_last_sent = 0; 874#endif 875} 876 877 878static lsquic_conn_t * 879coi_next (struct conns_out_iter *iter) 880{ 881 lsquic_conn_t *conn; 882 883 if (lsquic_mh_count(iter->coi_heap) > 0) 884 { 885 conn = lsquic_mh_pop(iter->coi_heap); 886 TAILQ_INSERT_TAIL(&iter->coi_active_list, conn, cn_next_out); 887 conn->cn_flags |= LSCONN_COI_ACTIVE; 888#ifndef NDEBUG 889 if (iter->coi_last_sent) 890 assert(iter->coi_last_sent <= conn->cn_last_sent); 891 iter->coi_last_sent = conn->cn_last_sent; 892#endif 893 return conn; 894 } 895 else if (!TAILQ_EMPTY(&iter->coi_active_list)) 896 { 897 conn = iter->coi_next; 898 if (!conn) 899 conn = TAILQ_FIRST(&iter->coi_active_list); 900 if (conn) 901 iter->coi_next = TAILQ_NEXT(conn, cn_next_out); 902 return conn; 903 } 904 else 905 return NULL; 906} 907 908 909static void 910coi_deactivate (struct conns_out_iter *iter, lsquic_conn_t *conn) 911{ 912 if (!(conn->cn_flags & LSCONN_EVANESCENT)) 913 { 914 assert(!TAILQ_EMPTY(&iter->coi_active_list)); 915 TAILQ_REMOVE(&iter->coi_active_list, conn, cn_next_out); 916 conn->cn_flags &= ~LSCONN_COI_ACTIVE; 917 TAILQ_INSERT_TAIL(&iter->coi_inactive_list, conn, cn_next_out); 918 conn->cn_flags |= LSCONN_COI_INACTIVE; 919 } 920} 921 922 923static void 924coi_reactivate (struct conns_out_iter *iter, lsquic_conn_t *conn) 925{ 926 assert(conn->cn_flags & LSCONN_COI_INACTIVE); 927 TAILQ_REMOVE(&iter->coi_inactive_list, conn, cn_next_out); 928 conn->cn_flags &= ~LSCONN_COI_INACTIVE; 929 TAILQ_INSERT_TAIL(&iter->coi_active_list, conn, cn_next_out); 930 conn->cn_flags |= LSCONN_COI_ACTIVE; 931} 932 933 934static void 935coi_reheap (struct conns_out_iter *iter, lsquic_engine_t *engine) 936{ 937 lsquic_conn_t *conn; 938 while ((conn = TAILQ_FIRST(&iter->coi_active_list))) 939 { 940 TAILQ_REMOVE(&iter->coi_active_list, conn, cn_next_out); 941 conn->cn_flags &= ~LSCONN_COI_ACTIVE; 942 lsquic_mh_insert(iter->coi_heap, conn, conn->cn_last_sent); 943 } 944 while ((conn = TAILQ_FIRST(&iter->coi_inactive_list))) 945 { 946 TAILQ_REMOVE(&iter->coi_inactive_list, conn, cn_next_out); 947 conn->cn_flags &= ~LSCONN_COI_INACTIVE; 948 (void) engine_decref_conn(engine, conn, LSCONN_HAS_OUTGOING); 949 } 950} 951 952 953static unsigned 954send_batch (lsquic_engine_t *engine, struct conns_out_iter *conns_iter, 955 struct out_batch *batch, unsigned n_to_send) 956{ 957 int n_sent, i; 958 lsquic_time_t now; 959 960 /* Set sent time before the write to avoid underestimating RTT */ 961 now = lsquic_time_now(); 962 for (i = 0; i < (int) n_to_send; ++i) 963 batch->packets[i]->po_sent = now; 964 n_sent = engine->packets_out(engine->packets_out_ctx, batch->outs, 965 n_to_send); 966 if (n_sent >= 0) 967 LSQ_DEBUG("packets out returned %d (out of %u)", n_sent, n_to_send); 968 else 969 { 970 engine->pub.enp_flags &= ~ENPUB_CAN_SEND; 971 LSQ_DEBUG("packets out returned an error: %s", strerror(errno)); 972 EV_LOG_GENERIC_EVENT("cannot send packets"); 973 n_sent = 0; 974 } 975 if (n_sent > 0) 976 engine->last_sent = now + n_sent; 977 for (i = 0; i < n_sent; ++i) 978 { 979 eng_hist_inc(&engine->history, now, sl_packets_out); 980 EV_LOG_PACKET_SENT(batch->conns[i]->cn_cid, batch->packets[i]); 981 batch->conns[i]->cn_if->ci_packet_sent(batch->conns[i], 982 batch->packets[i]); 983 /* `i' is added to maintain relative order */ 984 batch->conns[i]->cn_last_sent = now + i; 985 /* Release packet out buffer as soon as the packet is sent 986 * successfully. If not successfully sent, we hold on to 987 * this buffer until the packet sending is attempted again 988 * or until it times out and regenerated. 989 */ 990 if (batch->packets[i]->po_flags & PO_ENCRYPTED) 991 { 992 batch->packets[i]->po_flags &= ~PO_ENCRYPTED; 993 engine->pub.enp_pmi->pmi_release(engine->pub.enp_pmi_ctx, 994 batch->packets[i]->po_enc_data); 995 batch->packets[i]->po_enc_data = NULL; /* JIC */ 996 } 997 } 998 if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) 999 for ( ; i < (int) n_to_send; ++i) 1000 EV_LOG_PACKET_NOT_SENT(batch->conns[i]->cn_cid, batch->packets[i]); 1001 /* Return packets to the connection in reverse order so that the packet 1002 * ordering is maintained. 1003 */ 1004 for (i = (int) n_to_send - 1; i >= n_sent; --i) 1005 { 1006 batch->conns[i]->cn_if->ci_packet_not_sent(batch->conns[i], 1007 batch->packets[i]); 1008 if (!(batch->conns[i]->cn_flags & (LSCONN_COI_ACTIVE|LSCONN_EVANESCENT))) 1009 coi_reactivate(conns_iter, batch->conns[i]); 1010 } 1011 return n_sent; 1012} 1013 1014 1015/* Return 1 if went past deadline, 0 otherwise */ 1016static int 1017check_deadline (lsquic_engine_t *engine) 1018{ 1019 if (engine->pub.enp_settings.es_proc_time_thresh && 1020 lsquic_time_now() > engine->deadline) 1021 { 1022 LSQ_INFO("went past threshold of %u usec, stop sending", 1023 engine->pub.enp_settings.es_proc_time_thresh); 1024 engine->flags |= ENG_PAST_DEADLINE; 1025 return 1; 1026 } 1027 else 1028 return 0; 1029} 1030 1031 1032static void 1033send_packets_out (struct lsquic_engine *engine, 1034 struct conns_tailq *ticked_conns, 1035 struct conns_stailq *closed_conns) 1036{ 1037 unsigned n, w, n_sent, n_batches_sent; 1038 lsquic_packet_out_t *packet_out; 1039 lsquic_conn_t *conn; 1040 struct out_batch *const batch = &engine->out_batch; 1041 struct conns_out_iter conns_iter; 1042 int shrink, deadline_exceeded; 1043 1044 coi_init(&conns_iter, engine); 1045 n_batches_sent = 0; 1046 n_sent = 0, n = 0; 1047 shrink = 0; 1048 deadline_exceeded = 0; 1049 1050 while ((conn = coi_next(&conns_iter))) 1051 { 1052 packet_out = conn->cn_if->ci_next_packet_to_send(conn); 1053 if (!packet_out) { 1054 LSQ_DEBUG("batched all outgoing packets for conn %"PRIu64, 1055 conn->cn_cid); 1056 coi_deactivate(&conns_iter, conn); 1057 continue; 1058 } 1059 if (!(packet_out->po_flags & (PO_ENCRYPTED|PO_NOENCRYPT))) 1060 { 1061 switch (encrypt_packet(engine, conn, packet_out)) 1062 { 1063 case ENCPA_NOMEM: 1064 /* Send what we have and wait for a more opportune moment */ 1065 conn->cn_if->ci_packet_not_sent(conn, packet_out); 1066 goto end_for; 1067 case ENCPA_BADCRYPT: 1068 /* This is pretty bad: close connection immediately */ 1069 conn->cn_if->ci_packet_not_sent(conn, packet_out); 1070 LSQ_INFO("conn %"PRIu64" has unsendable packets", conn->cn_cid); 1071 if (!(conn->cn_flags & LSCONN_EVANESCENT)) 1072 { 1073 if (!(conn->cn_flags & LSCONN_CLOSING)) 1074 { 1075 STAILQ_INSERT_TAIL(closed_conns, conn, cn_next_closed_conn); 1076 engine_incref_conn(conn, LSCONN_CLOSING); 1077 if (conn->cn_flags & LSCONN_HASHED) 1078 remove_conn_from_hash(engine, conn); 1079 } 1080 coi_deactivate(&conns_iter, conn); 1081 if (conn->cn_flags & LSCONN_TICKED) 1082 { 1083 TAILQ_REMOVE(ticked_conns, conn, cn_next_ticked); 1084 engine_decref_conn(engine, conn, LSCONN_TICKED); 1085 } 1086 } 1087 continue; 1088 case ENCPA_OK: 1089 break; 1090 } 1091 } 1092 LSQ_DEBUG("batched packet %"PRIu64" for connection %"PRIu64, 1093 packet_out->po_packno, conn->cn_cid); 1094 assert(conn->cn_flags & LSCONN_HAS_PEER_SA); 1095 if (packet_out->po_flags & PO_ENCRYPTED) 1096 { 1097 batch->outs[n].buf = packet_out->po_enc_data; 1098 batch->outs[n].sz = packet_out->po_enc_data_sz; 1099 } 1100 else 1101 { 1102 batch->outs[n].buf = packet_out->po_data; 1103 batch->outs[n].sz = packet_out->po_data_sz; 1104 } 1105 batch->outs [n].peer_ctx = conn->cn_peer_ctx; 1106 batch->outs [n].local_sa = (struct sockaddr *) conn->cn_local_addr; 1107 batch->outs [n].dest_sa = (struct sockaddr *) conn->cn_peer_addr; 1108 batch->conns [n] = conn; 1109 batch->packets[n] = packet_out; 1110 ++n; 1111 if (n == engine->batch_size) 1112 { 1113 n = 0; 1114 w = send_batch(engine, &conns_iter, batch, engine->batch_size); 1115 ++n_batches_sent; 1116 n_sent += w; 1117 if (w < engine->batch_size) 1118 { 1119 shrink = 1; 1120 break; 1121 } 1122 deadline_exceeded = check_deadline(engine); 1123 if (deadline_exceeded) 1124 break; 1125 grow_batch_size(engine); 1126 } 1127 } 1128 end_for: 1129 1130 if (n > 0) { 1131 w = send_batch(engine, &conns_iter, batch, n); 1132 n_sent += w; 1133 shrink = w < n; 1134 ++n_batches_sent; 1135 deadline_exceeded = check_deadline(engine); 1136 } 1137 1138 if (shrink) 1139 shrink_batch_size(engine); 1140 else if (n_batches_sent > 1 && !deadline_exceeded) 1141 grow_batch_size(engine); 1142 1143 coi_reheap(&conns_iter, engine); 1144 1145 LSQ_DEBUG("%s: sent %u packet%.*s", __func__, n_sent, n_sent != 1, "s"); 1146} 1147 1148 1149int 1150lsquic_engine_has_unsent_packets (lsquic_engine_t *engine) 1151{ 1152 return lsquic_mh_count(&engine->conns_out) > 0 1153 ; 1154} 1155 1156 1157static void 1158reset_deadline (lsquic_engine_t *engine, lsquic_time_t now) 1159{ 1160 engine->deadline = now + engine->pub.enp_settings.es_proc_time_thresh; 1161 engine->flags &= ~ENG_PAST_DEADLINE; 1162} 1163 1164 1165/* TODO: this is a user-facing function, account for load */ 1166void 1167lsquic_engine_send_unsent_packets (lsquic_engine_t *engine) 1168{ 1169 lsquic_conn_t *conn; 1170 struct conns_stailq closed_conns; 1171 struct conns_tailq ticked_conns = TAILQ_HEAD_INITIALIZER(ticked_conns); 1172 1173 STAILQ_INIT(&closed_conns); 1174 reset_deadline(engine, lsquic_time_now()); 1175 if (!(engine->pub.enp_flags & ENPUB_CAN_SEND)) 1176 { 1177 LSQ_DEBUG("can send again"); 1178 EV_LOG_GENERIC_EVENT("can send again"); 1179 engine->pub.enp_flags |= ENPUB_CAN_SEND; 1180 } 1181 1182 send_packets_out(engine, &ticked_conns, &closed_conns); 1183 1184 while ((conn = STAILQ_FIRST(&closed_conns))) { 1185 STAILQ_REMOVE_HEAD(&closed_conns, cn_next_closed_conn); 1186 (void) engine_decref_conn(engine, conn, LSCONN_CLOSING); 1187 } 1188 1189} 1190 1191 1192static void 1193process_connections (lsquic_engine_t *engine, conn_iter_f next_conn, 1194 lsquic_time_t now) 1195{ 1196 lsquic_conn_t *conn; 1197 enum tick_st tick_st; 1198 unsigned i; 1199 lsquic_time_t next_tick_time; 1200 struct conns_stailq closed_conns; 1201 struct conns_tailq ticked_conns; 1202 1203 eng_hist_tick(&engine->history, now); 1204 1205 STAILQ_INIT(&closed_conns); 1206 TAILQ_INIT(&ticked_conns); 1207 reset_deadline(engine, now); 1208 1209 i = 0; 1210 while ((conn = next_conn(engine)) 1211 ) 1212 { 1213 tick_st = conn->cn_if->ci_tick(conn, now); 1214 conn->cn_last_ticked = now + i /* Maintain relative order */ ++; 1215 if (tick_st & TICK_SEND) 1216 { 1217 if (!(conn->cn_flags & LSCONN_HAS_OUTGOING)) 1218 { 1219 lsquic_mh_insert(&engine->conns_out, conn, conn->cn_last_sent); 1220 engine_incref_conn(conn, LSCONN_HAS_OUTGOING); 1221 } 1222 } 1223 if (tick_st & TICK_CLOSE) 1224 { 1225 STAILQ_INSERT_TAIL(&closed_conns, conn, cn_next_closed_conn); 1226 engine_incref_conn(conn, LSCONN_CLOSING); 1227 if (conn->cn_flags & LSCONN_HASHED) 1228 remove_conn_from_hash(engine, conn); 1229 } 1230 else 1231 { 1232 TAILQ_INSERT_TAIL(&ticked_conns, conn, cn_next_ticked); 1233 engine_incref_conn(conn, LSCONN_TICKED); 1234 } 1235 } 1236 1237 if ((engine->pub.enp_flags & ENPUB_CAN_SEND) 1238 && lsquic_engine_has_unsent_packets(engine)) 1239 send_packets_out(engine, &ticked_conns, &closed_conns); 1240 1241 while ((conn = STAILQ_FIRST(&closed_conns))) { 1242 STAILQ_REMOVE_HEAD(&closed_conns, cn_next_closed_conn); 1243 (void) engine_decref_conn(engine, conn, LSCONN_CLOSING); 1244 } 1245 1246 /* TODO Heapification can be optimized by switching to the Floyd method: 1247 * https://en.wikipedia.org/wiki/Binary_heap#Building_a_heap 1248 */ 1249 while ((conn = TAILQ_FIRST(&ticked_conns))) 1250 { 1251 TAILQ_REMOVE(&ticked_conns, conn, cn_next_ticked); 1252 engine_decref_conn(engine, conn, LSCONN_TICKED); 1253 if (!(conn->cn_flags & LSCONN_TICKABLE) 1254 && conn->cn_if->ci_is_tickable(conn)) 1255 { 1256 lsquic_mh_insert(&engine->conns_tickable, conn, conn->cn_last_ticked); 1257 engine_incref_conn(conn, LSCONN_TICKABLE); 1258 } 1259 else if (!(conn->cn_flags & LSCONN_ATTQ)) 1260 { 1261 next_tick_time = conn->cn_if->ci_next_tick_time(conn); 1262 if (next_tick_time) 1263 { 1264 if (0 == attq_add(engine->attq, conn, next_tick_time)) 1265 engine_incref_conn(conn, LSCONN_ATTQ); 1266 } 1267 else 1268 assert(0); 1269 } 1270 } 1271 1272} 1273 1274 1275/* Return 0 if packet is being processed by a real connection, 1 if the 1276 * packet was processed, but not by a connection, and -1 on error. 1277 */ 1278int 1279lsquic_engine_packet_in (lsquic_engine_t *engine, 1280 const unsigned char *packet_in_data, size_t packet_in_size, 1281 const struct sockaddr *sa_local, const struct sockaddr *sa_peer, 1282 void *peer_ctx) 1283{ 1284 struct packin_parse_state ppstate; 1285 lsquic_packet_in_t *packet_in; 1286 int (*parse_packet_in_begin) (struct lsquic_packet_in *, size_t length, 1287 int is_server, struct packin_parse_state *); 1288 1289 if (packet_in_size > QUIC_MAX_PACKET_SZ) 1290 { 1291 LSQ_DEBUG("Cannot handle packet_in_size(%zd) > %d packet incoming " 1292 "packet's header", packet_in_size, QUIC_MAX_PACKET_SZ); 1293 errno = E2BIG; 1294 return -1; 1295 } 1296 1297 if (conn_hash_using_addr(&engine->conns_hash)) 1298 { 1299 const struct lsquic_conn *conn; 1300 conn = conn_hash_find_by_addr(&engine->conns_hash, sa_local); 1301 if (!conn) 1302 return -1; 1303 if ((1 << conn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS) 1304 parse_packet_in_begin = lsquic_gquic_parse_packet_in_begin; 1305 else 1306 parse_packet_in_begin = lsquic_iquic_parse_packet_in_begin; 1307 } 1308 else 1309 parse_packet_in_begin = lsquic_parse_packet_in_begin; 1310 1311 packet_in = lsquic_mm_get_packet_in(&engine->pub.enp_mm); 1312 if (!packet_in) 1313 return -1; 1314 1315 /* Library does not modify packet_in_data, it is not referenced after 1316 * this function returns and subsequent release of pi_data is guarded 1317 * by PI_OWN_DATA flag. 1318 */ 1319 packet_in->pi_data = (unsigned char *) packet_in_data; 1320 if (0 != parse_packet_in_begin(packet_in, packet_in_size, 1321 engine->flags & ENG_SERVER, &ppstate)) 1322 { 1323 LSQ_DEBUG("Cannot parse incoming packet's header"); 1324 lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in); 1325 errno = EINVAL; 1326 return -1; 1327 } 1328 1329 packet_in->pi_received = lsquic_time_now(); 1330 eng_hist_inc(&engine->history, packet_in->pi_received, sl_packets_in); 1331 return process_packet_in(engine, packet_in, &ppstate, sa_local, sa_peer, 1332 peer_ctx); 1333} 1334 1335 1336#if __GNUC__ && !defined(NDEBUG) 1337__attribute__((weak)) 1338#endif 1339unsigned 1340lsquic_engine_quic_versions (const lsquic_engine_t *engine) 1341{ 1342 return engine->pub.enp_settings.es_versions; 1343} 1344 1345 1346int 1347lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff) 1348{ 1349 const lsquic_time_t *next_time; 1350 lsquic_time_t now; 1351 1352 if (((engine->flags & ENG_PAST_DEADLINE) 1353 && lsquic_mh_count(&engine->conns_out)) 1354 || lsquic_mh_count(&engine->conns_tickable)) 1355 { 1356 *diff = 0; 1357 return 1; 1358 } 1359 1360 next_time = attq_next_time(engine->attq); 1361 if (!next_time) 1362 return 0; 1363 1364 now = lsquic_time_now(); 1365 *diff = (int) ((int64_t) *next_time - (int64_t) now); 1366 return 1; 1367} 1368 1369 1370unsigned 1371lsquic_engine_count_attq (lsquic_engine_t *engine, int from_now) 1372{ 1373 lsquic_time_t now; 1374 now = lsquic_time_now(); 1375 if (from_now < 0) 1376 now -= from_now; 1377 else 1378 now += from_now; 1379 return attq_count_before(engine->attq, now); 1380} 1381