lsquic_qdec_hdl.c revision fbc6cc04
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_qdec_hdl.c -- QPACK decoder streams handler 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <inttypes.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/queue.h> 12 13#include "lsquic.h" 14#include "lsquic_types.h" 15#include "lsxpack_header.h" 16#include "lsquic_int_types.h" 17#include "lsquic_sfcw.h" 18#include "lsquic_varint.h" 19#include "lsquic_hq.h" 20#include "lsquic_hash.h" 21#include "lsquic_stream.h" 22#include "lsquic_frab_list.h" 23#include "lsqpack.h" 24#include "lsquic_http1x_if.h" 25#include "lsquic_qdec_hdl.h" 26#include "lsquic_mm.h" 27#include "lsquic_engine_public.h" 28#include "lsquic_headers.h" 29#include "lsquic_conn.h" 30#include "lsquic_conn_flow.h" 31#include "lsquic_rtt.h" 32#include "lsquic_conn_public.h" 33#include "lsquic_hq.h" 34#include "lsquic_parse.h" 35 36#define LSQUIC_LOGGER_MODULE LSQLM_QDEC_HDL 37#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qdh->qdh_conn) 38#include "lsquic_logger.h" 39 40static const struct lsqpack_dec_hset_if dhi_if; 41 42 43struct header_ctx 44{ 45 void *hset; 46 struct qpack_dec_hdl *qdh; 47 enum ppc_flags ppc_flags; 48 struct lsquic_ext_http_prio ehp; 49}; 50 51 52/* We need to allocate struct uncompressed_headers anyway when header set 53 * is complete and we give it to the stream using lsquic_stream_uh_in(). 54 * To save a malloc, we reuse context after we're done with it. 55 */ 56union hblock_ctx 57{ 58 struct header_ctx ctx; 59 struct uncompressed_headers uh; 60}; 61 62 63static int 64qdh_write_decoder (struct qpack_dec_hdl *qdh, const unsigned char *buf, 65 size_t sz) 66{ 67 ssize_t nw; 68 69 if (!(qdh->qdh_dec_sm_out && lsquic_frab_list_empty(&qdh->qdh_fral))) 70 { 71 write_to_frab: 72 if (0 == lsquic_frab_list_write(&qdh->qdh_fral, 73 (unsigned char *) buf, sz)) 74 { 75 LSQ_DEBUG("wrote %zu bytes to frab list", sz); 76 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 77 return 0; 78 } 79 else 80 { 81 LSQ_INFO("error writing to frab list"); 82 return -1; 83 } 84 } 85 86 nw = lsquic_stream_write(qdh->qdh_dec_sm_out, buf, sz); 87 if (nw < 0) 88 { 89 LSQ_INFO("error writing to outgoing QPACK decoder stream: %s", 90 strerror(errno)); 91 return -1; 92 } 93 LSQ_DEBUG("wrote %zd bytes to outgoing QPACK decoder stream", nw); 94 95 if ((size_t) nw == sz) 96 return 0; 97 98 buf = buf + nw; 99 sz -= (size_t) nw; 100 goto write_to_frab; 101} 102 103 104static int 105qdh_write_type (struct qpack_dec_hdl *qdh) 106{ 107 int s; 108 109#ifndef NDEBUG 110 const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 111 if (env && atoi(env)) 112 { 113 s = rand() & 3; 114 LSQ_DEBUG("writing %d-byte stream type", 1 << s); 115 } 116 else 117#endif 118 s = 0; 119 120 switch (s) 121 { 122 case 0: 123 return qdh_write_decoder(qdh, 124 (unsigned char []) { HQUST_QPACK_DEC }, 1); 125 case 1: 126 return qdh_write_decoder(qdh, 127 (unsigned char []) { 0x40, HQUST_QPACK_DEC }, 2); 128 case 2: 129 return qdh_write_decoder(qdh, 130 (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_DEC }, 4); 131 default: 132 return qdh_write_decoder(qdh, 133 (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 HQUST_QPACK_DEC }, 8); 135 } 136} 137 138 139static void 140qdh_begin_out (struct qpack_dec_hdl *qdh) 141{ 142 if (0 != qdh_write_type(qdh)) 143 { 144 LSQ_WARN("%s: could not write to decoder", __func__); 145 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 146 "cannot write to decoder stream"); 147 } 148} 149 150 151int 152lsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn, 153 int is_server, const struct lsquic_engine_public *enpub, 154 unsigned dyn_table_size, unsigned max_risked_streams) 155{ 156 enum lsqpack_dec_opts dec_opts; 157 158 dec_opts = 0; 159 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X) 160 dec_opts |= LSQPACK_DEC_OPT_HTTP1X; 161 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME) 162 dec_opts |= LSQPACK_DEC_OPT_HASH_NAME; 163 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL) 164 dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL; 165 166 qdh->qdh_conn = conn; 167 lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL); 168 lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size, 169 max_risked_streams, &dhi_if, dec_opts); 170 qdh->qdh_flags |= QDH_INITIALIZED; 171 qdh->qdh_enpub = enpub; 172 if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 173 { 174 qdh->qdh_h1x_ctor_ctx = (struct http1x_ctor_ctx) { 175 .conn = conn, 176 .max_headers_sz = MAX_HTTP1X_HEADERS_SIZE, 177 .is_server = is_server, 178 }; 179 qdh->qdh_hsi_ctx = &qdh->qdh_h1x_ctor_ctx; 180 } 181 else 182 qdh->qdh_hsi_ctx = qdh->qdh_enpub->enp_hsi_ctx; 183 if (qdh->qdh_dec_sm_out) 184 qdh_begin_out(qdh); 185 if (qdh->qdh_enc_sm_in) 186 lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 187 LSQ_DEBUG("initialized"); 188 return 0; 189} 190 191 192void 193lsquic_qdh_cleanup (struct qpack_dec_hdl *qdh) 194{ 195 if (qdh->qdh_flags & QDH_INITIALIZED) 196 { 197 LSQ_DEBUG("cleanup"); 198 lsqpack_dec_cleanup(&qdh->qdh_decoder); 199 lsquic_frab_list_cleanup(&qdh->qdh_fral); 200 qdh->qdh_flags &= ~QDH_INITIALIZED; 201 } 202} 203 204static lsquic_stream_ctx_t * 205qdh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 206{ 207 struct qpack_dec_hdl *const qdh = stream_if_ctx; 208 qdh->qdh_dec_sm_out = stream; 209 if (qdh->qdh_flags & QDH_INITIALIZED) 210 qdh_begin_out(qdh); 211 LSQ_DEBUG("initialized outgoing decoder stream"); 212 return (void *) qdh; 213} 214 215 216static void 217qdh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 218{ 219 struct qpack_dec_hdl *const qdh = (void *) ctx; 220 struct lsquic_reader reader; 221 ssize_t nw; 222 unsigned char buf[LSQPACK_LONGEST_ICI]; 223 224 if (lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 225 { 226 nw = lsqpack_dec_write_ici(&qdh->qdh_decoder, buf, sizeof(buf)); 227 if (nw > 0) 228 { 229 if (0 == qdh_write_decoder(qdh, buf, nw)) 230 LSQ_DEBUG("wrote %zd-byte TSS instruction", nw); 231 else 232 goto err; 233 } 234 else if (nw < 0) 235 { 236 LSQ_WARN("could not generate TSS instruction"); 237 goto err; 238 } 239 } 240 241 if (lsquic_frab_list_empty(&qdh->qdh_fral)) 242 { 243 LSQ_DEBUG("%s: nothing to write", __func__); 244 lsquic_stream_wantwrite(stream, 0); 245 return; 246 } 247 248 reader = (struct lsquic_reader) { 249 .lsqr_read = lsquic_frab_list_read, 250 .lsqr_size = lsquic_frab_list_size, 251 .lsqr_ctx = &qdh->qdh_fral, 252 }; 253 254 nw = lsquic_stream_writef(stream, &reader); 255 if (nw >= 0) 256 { 257 LSQ_DEBUG("wrote %zd bytes to stream", nw); 258 (void) lsquic_stream_flush(stream); 259 if (lsquic_frab_list_empty(&qdh->qdh_fral)) 260 { 261 lsquic_stream_wantwrite(stream, 0); 262 if (qdh->qdh_on_dec_sent_func) 263 { 264 LSQ_DEBUG("buffered data written: call callback"); 265 qdh->qdh_on_dec_sent_func(qdh->qdh_on_dec_sent_ctx); 266 qdh->qdh_on_dec_sent_func = NULL; 267 qdh->qdh_on_dec_sent_ctx = NULL; 268 } 269 } 270 } 271 else 272 { 273 LSQ_WARN("cannot write to stream: %s", strerror(errno)); 274 err: 275 lsquic_stream_wantwrite(stream, 0); 276 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 277 "cannot write to stream"); 278 } 279} 280 281 282static void 283qdh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 284{ 285 struct qpack_dec_hdl *const qdh = (void *) ctx; 286 qdh->qdh_dec_sm_out = NULL; 287 LSQ_DEBUG("closed outgoing decoder stream"); 288} 289 290 291static void 292qdh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 293{ 294 assert(0); 295} 296 297 298static const struct lsquic_stream_if qdh_dec_sm_out_if = 299{ 300 .on_new_stream = qdh_out_on_new, 301 .on_read = qdh_out_on_read, 302 .on_write = qdh_out_on_write, 303 .on_close = qdh_out_on_close, 304}; 305const struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if = 306 &qdh_dec_sm_out_if; 307 308 309static lsquic_stream_ctx_t * 310qdh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 311{ 312 struct qpack_dec_hdl *const qdh = stream_if_ctx; 313 qdh->qdh_enc_sm_in = stream; 314 if (qdh->qdh_flags & QDH_INITIALIZED) 315 lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 316 LSQ_DEBUG("initialized incoming encoder stream"); 317 return (void *) qdh; 318} 319 320 321static size_t 322qdh_read_encoder_stream (void *ctx, const unsigned char *buf, size_t sz, 323 int fin) 324{ 325 struct qpack_dec_hdl *const qdh = (void *) ctx; 326 const struct lsqpack_dec_err *qerr; 327 int s; 328 329 if (fin) 330 { 331 LSQ_INFO("encoder stream is closed"); 332 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 333 HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK encoder stream"); 334 goto end; 335 } 336 337 s = lsqpack_dec_enc_in(&qdh->qdh_decoder, buf, sz); 338 if (s != 0) 339 { 340 LSQ_INFO("error reading encoder stream"); 341 qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 342 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 343 HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK encoder " 344 "stream; offset %"PRIu64", line %d", qerr->off, qerr->line); 345 goto end; 346 } 347 if (qdh->qdh_dec_sm_out 348 && lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 349 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 350 351 LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz); 352 353 end: 354 return sz; 355} 356 357 358static void 359qdh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 360{ 361 struct qpack_dec_hdl *const qdh = (void *) ctx; 362 ssize_t nread; 363 364 nread = lsquic_stream_readf(stream, qdh_read_encoder_stream, qdh); 365 if (nread <= 0) 366 { 367 if (nread < 0) 368 { 369 LSQ_WARN("cannot read from encoder stream: %s", strerror(errno)); 370 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 371 "cannot read from encoder stream"); 372 } 373 else 374 { 375 LSQ_INFO("encoder stream closed by peer: abort connection"); 376 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 377 HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed"); 378 } 379 lsquic_stream_wantread(stream, 0); 380 } 381} 382 383 384static void 385qdh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 386{ 387 struct qpack_dec_hdl *const qdh = (void *) ctx; 388 LSQ_DEBUG("closed incoming encoder stream"); 389 qdh->qdh_enc_sm_in = NULL; 390} 391 392 393static void 394qdh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 395{ 396 assert(0); 397} 398 399 400static const struct lsquic_stream_if qdh_enc_sm_in_if = 401{ 402 .on_new_stream = qdh_in_on_new, 403 .on_read = qdh_in_on_read, 404 .on_write = qdh_in_on_write, 405 .on_close = qdh_in_on_close, 406}; 407const struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if = 408 &qdh_enc_sm_in_if; 409 410 411static void 412qdh_hblock_unblocked (void *stream_p) 413{ 414 struct lsquic_stream *const stream = stream_p; 415 union hblock_ctx *const u = stream->sm_hblock_ctx; 416 struct qpack_dec_hdl *qdh = u->ctx.qdh; 417 418 LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id); 419 lsquic_stream_qdec_unblocked(stream); 420} 421 422 423struct cont_len 424{ 425 unsigned long long value; 426 int has; /* 1: set, 0: not set, -1: invalid */ 427}; 428 429 430static void 431process_content_length (const struct qpack_dec_hdl *qdh /* for logging */, 432 struct cont_len *cl, const char *val /* not NUL-terminated */, 433 unsigned len) 434{ 435 char *endcl, cont_len_buf[30]; 436 437 if (0 == cl->has) 438 { 439 if (len >= sizeof(cont_len_buf)) 440 { 441 LSQ_DEBUG("content-length has invalid value `%.*s'", 442 (int) len, val); 443 cl->has = -1; 444 return; 445 } 446 memcpy(cont_len_buf, val, len); 447 cont_len_buf[len] = '\0'; 448 cl->value = strtoull(cont_len_buf, &endcl, 10); 449 if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno)) 450 { 451 cl->has = 1; 452 LSQ_DEBUG("content length is %llu", cl->value); 453 } 454 else 455 { 456 cl->has = -1; 457 LSQ_DEBUG("content-length has invalid value `%.*s'", 458 (int) len, val); 459 } 460 } 461 else if (cl->has > 0) 462 { 463 LSQ_DEBUG("header set has two content-length: ambiguous, " 464 "turn off checking"); 465 cl->has = -1; 466 } 467} 468 469 470static int 471is_content_length (const struct lsxpack_header *xhdr) 472{ 473 return ((xhdr->flags & LSXPACK_QPACK_IDX) 474 && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0) 475 || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr), 476 "content-length", 13)) 477 ; 478} 479 480 481static int 482is_priority (const struct lsxpack_header *xhdr) 483{ 484 return xhdr->name_len == 8 485 && 0 == memcmp(lsxpack_header_get_name(xhdr), "priority", 8); 486} 487 488 489static struct lsxpack_header * 490qdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space) 491{ 492 struct lsquic_stream *const stream = stream_p; 493 union hblock_ctx *const u = stream->sm_hblock_ctx; 494 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 495 496 return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode( 497 u->ctx.hset, xhdr, space); 498} 499 500 501static int 502qdh_process_header (void *stream_p, struct lsxpack_header *xhdr) 503{ 504 struct lsquic_stream *const stream = stream_p; 505 union hblock_ctx *const u = stream->sm_hblock_ctx; 506 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 507 struct cont_len cl; 508 509 if (is_content_length(xhdr)) 510 { 511 cl.has = 0; 512 process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr), 513 xhdr->val_len); 514 if (cl.has > 0) 515 (void) lsquic_stream_verify_len(stream, cl.value); 516 } 517 else if ((stream->sm_bflags & (SMBF_HTTP_PRIO|SMBF_HPRIO_SET)) 518 == SMBF_HTTP_PRIO 519 && is_priority(xhdr)) 520 { 521 u->ctx.ppc_flags &= ~(PPC_INC_NAME|PPC_URG_NAME); 522 (void) lsquic_http_parse_pfv(lsxpack_header_get_value(xhdr), 523 xhdr->val_len, &u->ctx.ppc_flags, &u->ctx.ehp, 524 (char *) stream->conn_pub->mm->acki, 525 sizeof(*stream->conn_pub->mm->acki)); 526 } 527 528 return qdh->qdh_enpub->enp_hsi_if->hsi_process_header(u->ctx.hset, xhdr); 529} 530 531 532static const struct lsqpack_dec_hset_if dhi_if = 533{ 534 .dhi_unblocked = qdh_hblock_unblocked, 535 .dhi_prepare_decode = qdh_prepare_decode, 536 .dhi_process_header = qdh_process_header, 537}; 538 539 540static enum lsqpack_read_header_status 541qdh_header_read_results (struct qpack_dec_hdl *qdh, 542 struct lsquic_stream *stream, enum lsqpack_read_header_status rhs, 543 const unsigned char *dec_buf, size_t dec_buf_sz) 544{ 545 const struct lsqpack_dec_err *qerr; 546 struct uncompressed_headers *uh; 547 void *hset; 548 549 if (rhs == LQRHS_DONE) 550 { 551 if (!lsquic_stream_header_is_trailer(stream)) 552 { 553 if (stream->sm_hblock_ctx->ctx.ppc_flags 554 & (PPC_INC_SET|PPC_URG_SET)) 555 { 556 assert(stream->sm_bflags & SMBF_HTTP_PRIO); 557 LSQ_DEBUG("Apply Priority from headers to stream %"PRIu64, 558 stream->id); 559 (void) lsquic_stream_set_http_prio(stream, 560 &stream->sm_hblock_ctx->ctx.ehp); 561 } 562 hset = stream->sm_hblock_ctx->ctx.hset; 563 uh = &stream->sm_hblock_ctx->uh; 564 stream->sm_hblock_ctx = NULL; 565 memset(uh, 0, sizeof(*uh)); 566 uh->uh_stream_id = stream->id; 567 uh->uh_oth_stream_id = 0; 568 uh->uh_weight = 0; 569 uh->uh_exclusive = -1; 570 if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 571 uh->uh_flags |= UH_H1H; 572 if (0 != qdh->qdh_enpub->enp_hsi_if 573 ->hsi_process_header(hset, NULL)) 574 { 575 LSQ_DEBUG("finishing HTTP/1.x hset failed"); 576 free(uh); 577 return LQRHS_ERROR; 578 } 579 uh->uh_hset = hset; 580 if (0 == lsquic_stream_uh_in(stream, uh)) 581 LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id); 582 else 583 { 584 LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id); 585 free(uh); 586 return LQRHS_ERROR; 587 } 588 } 589 else 590 { 591 LSQ_DEBUG("discard trailer header set"); 592 free(stream->sm_hblock_ctx); 593 stream->sm_hblock_ctx = NULL; 594 } 595 if (qdh->qdh_dec_sm_out) 596 { 597 if (dec_buf_sz 598 && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz)) 599 { 600 return LQRHS_ERROR; 601 } 602 if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 603 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 604 } 605 } 606 else if (rhs == LQRHS_ERROR) 607 { 608 qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 609 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 610 HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; " 611 "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id, 612 qerr->off, qerr->line); 613 } 614 615 return rhs; 616} 617 618 619enum lsqpack_read_header_status 620lsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh, 621 struct lsquic_stream *stream, uint64_t header_size, 622 const unsigned char **buf, size_t bufsz) 623{ 624 enum lsqpack_read_header_status rhs; 625 void *hset; 626 int is_pp; 627 size_t dec_buf_sz; 628 union hblock_ctx *u; 629 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 630 631 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 632 633 if (!(qdh->qdh_flags & QDH_INITIALIZED)) 634 { 635 LSQ_WARN("not initialized: cannot process header block"); 636 return LQRHS_ERROR; 637 } 638 639 u = malloc(sizeof(*u)); 640 if (!u) 641 { 642 LSQ_INFO("cannot allocate hblock_ctx"); 643 return LQRHS_ERROR; 644 } 645 646 is_pp = lsquic_stream_header_is_pp(stream); 647 hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set( 648 qdh->qdh_hsi_ctx, stream, is_pp); 649 if (!hset) 650 { 651 free(u); 652 LSQ_DEBUG("hsi_create_header_set failure"); 653 return LQRHS_ERROR; 654 } 655 656 u->ctx.hset = hset; 657 u->ctx.qdh = qdh; 658 u->ctx.ppc_flags = 0; 659 u->ctx.ehp = (struct lsquic_ext_http_prio) { 660 .urgency = LSQUIC_DEF_HTTP_URGENCY, 661 .incremental = LSQUIC_DEF_HTTP_INCREMENTAL, 662 }; 663 stream->sm_hblock_ctx = u; 664 665 dec_buf_sz = sizeof(dec_buf); 666 rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id, 667 header_size, buf, bufsz, dec_buf, &dec_buf_sz); 668 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 669} 670 671 672enum lsqpack_read_header_status 673lsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh, 674 struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz) 675{ 676 enum lsqpack_read_header_status rhs; 677 size_t dec_buf_sz; 678 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 679 680 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 681 682 if (qdh->qdh_flags & QDH_INITIALIZED) 683 { 684 dec_buf_sz = sizeof(dec_buf); 685 rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream, 686 buf, bufsz, dec_buf, &dec_buf_sz); 687 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 688 } 689 else 690 { 691 LSQ_WARN("not initialized: cannot process header block"); 692 return LQRHS_ERROR; 693 } 694} 695 696 697static void 698lsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh, 699 struct lsquic_stream *stream) 700{ 701 if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream)) 702 LSQ_DEBUG("unreffed stream %"PRIu64, stream->id); 703 else 704 LSQ_WARN("cannot unref stream %"PRIu64, stream->id); 705} 706 707 708void 709lsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh, 710 struct lsquic_stream *stream) 711{ 712 ssize_t nw; 713 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 714 715 if (!qdh->qdh_dec_sm_out) 716 return; 717 718 nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf)); 719 if (nw > 0) 720 { 721 if (0 == qdh_write_decoder(qdh, buf, nw)) 722 LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel " 723 "Stream instruction to the decoder stream", stream->id, nw); 724 } 725 else if (nw == 0) 726 LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id); 727 else 728 { 729 LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space " 730 "to encode Cancel Stream instructin", stream->id); 731 lsquic_qdh_unref_stream(qdh, stream); 732 } 733} 734 735 736void 737lsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *qdh, 738 lsquic_stream_id_t stream_id) 739{ 740 ssize_t nw; 741 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 742 743 if (!qdh->qdh_dec_sm_out) 744 return; 745 746 nw = lsqpack_dec_cancel_stream_id(&qdh->qdh_decoder, stream_id, buf, 747 sizeof(buf)); 748 if (nw > 0) 749 { 750 if (0 == qdh_write_decoder(qdh, buf, nw)) 751 LSQ_DEBUG("wrote %zd-byte Cancel Stream instruction for " 752 "stream %"PRIu64" to the decoder stream", nw, stream_id); 753 } 754 else if (nw == 0) 755 LSQ_DEBUG("not generating Cancel Stream instruction for " 756 "stream %"PRIu64, stream_id); 757 else 758 LSQ_WARN("cannot generate Cancel Stream instruction for " 759 "stream %"PRIu64" -- not enough buffer space", stream_id); 760} 761 762 763int 764lsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *), 765 void *ctx) 766{ 767 size_t bytes; 768 769 /* Use size of a single frab list buffer as an arbitrary threshold */ 770 bytes = lsquic_frab_list_size(&qdh->qdh_fral); 771 if (bytes <= qdh->qdh_fral.fl_buf_size) 772 return 0; 773 else 774 { 775 LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set " 776 "up callback", bytes); 777 qdh->qdh_on_dec_sent_func = func; 778 qdh->qdh_on_dec_sent_ctx = ctx; 779 return 1; 780 } 781} 782