lsquic_qdec_hdl.c revision 55613f44
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * lsquic_qdec_hdl.c -- QPACK decoder streams handler 45392f7a3SLiteSpeed Tech */ 55392f7a3SLiteSpeed Tech 65392f7a3SLiteSpeed Tech#include <assert.h> 75392f7a3SLiteSpeed Tech#include <errno.h> 85392f7a3SLiteSpeed Tech#include <inttypes.h> 95392f7a3SLiteSpeed Tech#include <stdlib.h> 105392f7a3SLiteSpeed Tech#include <string.h> 115392f7a3SLiteSpeed Tech#include <sys/queue.h> 125392f7a3SLiteSpeed Tech 135392f7a3SLiteSpeed Tech#include "lsquic.h" 145392f7a3SLiteSpeed Tech#include "lsquic_types.h" 15a5fa05f9SDmitri Tikhonov#include "lsxpack_header.h" 165392f7a3SLiteSpeed Tech#include "lsquic_int_types.h" 175392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h" 185392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 195392f7a3SLiteSpeed Tech#include "lsquic_hq.h" 205392f7a3SLiteSpeed Tech#include "lsquic_hash.h" 215392f7a3SLiteSpeed Tech#include "lsquic_stream.h" 225392f7a3SLiteSpeed Tech#include "lsquic_frab_list.h" 235392f7a3SLiteSpeed Tech#include "lsqpack.h" 245392f7a3SLiteSpeed Tech#include "lsquic_http1x_if.h" 255392f7a3SLiteSpeed Tech#include "lsquic_qdec_hdl.h" 265392f7a3SLiteSpeed Tech#include "lsquic_mm.h" 275392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h" 285392f7a3SLiteSpeed Tech#include "lsquic_headers.h" 295392f7a3SLiteSpeed Tech#include "lsquic_conn.h" 305392f7a3SLiteSpeed Tech 315392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_QDEC_HDL 325392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qdh->qdh_conn) 335392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 345392f7a3SLiteSpeed Tech 3555613f44SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if dhi_if; 3655613f44SDmitri Tikhonov 3755613f44SDmitri Tikhonov 3855613f44SDmitri Tikhonovstruct header_ctx 3955613f44SDmitri Tikhonov{ 4055613f44SDmitri Tikhonov void *hset; 4155613f44SDmitri Tikhonov struct qpack_dec_hdl *qdh; 4255613f44SDmitri Tikhonov}; 4355613f44SDmitri Tikhonov 4455613f44SDmitri Tikhonov 4555613f44SDmitri Tikhonov/* We need to allocate struct uncompressed_headers anyway when header set 4655613f44SDmitri Tikhonov * is complete and we give it to the stream using lsquic_stream_uh_in(). 4755613f44SDmitri Tikhonov * To save a malloc, we reuse context after we're done with it. 4855613f44SDmitri Tikhonov */ 4955613f44SDmitri Tikhonovunion hblock_ctx 5055613f44SDmitri Tikhonov{ 5155613f44SDmitri Tikhonov struct header_ctx ctx; 5255613f44SDmitri Tikhonov struct uncompressed_headers uh; 5355613f44SDmitri Tikhonov}; 545392f7a3SLiteSpeed Tech 555392f7a3SLiteSpeed Tech 565392f7a3SLiteSpeed Techstatic int 575392f7a3SLiteSpeed Techqdh_write_decoder (struct qpack_dec_hdl *qdh, const unsigned char *buf, 585392f7a3SLiteSpeed Tech size_t sz) 595392f7a3SLiteSpeed Tech{ 605392f7a3SLiteSpeed Tech ssize_t nw; 615392f7a3SLiteSpeed Tech 625392f7a3SLiteSpeed Tech if (!(qdh->qdh_dec_sm_out && lsquic_frab_list_empty(&qdh->qdh_fral))) 635392f7a3SLiteSpeed Tech { 645392f7a3SLiteSpeed Tech write_to_frab: 655392f7a3SLiteSpeed Tech if (0 == lsquic_frab_list_write(&qdh->qdh_fral, 665392f7a3SLiteSpeed Tech (unsigned char *) buf, sz)) 675392f7a3SLiteSpeed Tech { 685392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zu bytes to frab list", sz); 695392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 705392f7a3SLiteSpeed Tech return 0; 715392f7a3SLiteSpeed Tech } 725392f7a3SLiteSpeed Tech else 735392f7a3SLiteSpeed Tech { 745392f7a3SLiteSpeed Tech LSQ_INFO("error writing to frab list"); 755392f7a3SLiteSpeed Tech return -1; 765392f7a3SLiteSpeed Tech } 775392f7a3SLiteSpeed Tech } 785392f7a3SLiteSpeed Tech 795392f7a3SLiteSpeed Tech nw = lsquic_stream_write(qdh->qdh_dec_sm_out, buf, sz); 805392f7a3SLiteSpeed Tech if (nw < 0) 815392f7a3SLiteSpeed Tech { 825392f7a3SLiteSpeed Tech LSQ_INFO("error writing to outgoing QPACK decoder stream: %s", 835392f7a3SLiteSpeed Tech strerror(errno)); 845392f7a3SLiteSpeed Tech return -1; 855392f7a3SLiteSpeed Tech } 865392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to outgoing QPACK decoder stream", nw); 875392f7a3SLiteSpeed Tech 885392f7a3SLiteSpeed Tech if ((size_t) nw == sz) 895392f7a3SLiteSpeed Tech return 0; 905392f7a3SLiteSpeed Tech 915392f7a3SLiteSpeed Tech buf = buf + nw; 925392f7a3SLiteSpeed Tech sz -= (size_t) nw; 935392f7a3SLiteSpeed Tech goto write_to_frab; 945392f7a3SLiteSpeed Tech} 955392f7a3SLiteSpeed Tech 965392f7a3SLiteSpeed Tech 975392f7a3SLiteSpeed Techstatic int 985392f7a3SLiteSpeed Techqdh_write_type (struct qpack_dec_hdl *qdh) 995392f7a3SLiteSpeed Tech{ 1005392f7a3SLiteSpeed Tech int s; 1015392f7a3SLiteSpeed Tech 1025392f7a3SLiteSpeed Tech#ifndef NDEBUG 1035392f7a3SLiteSpeed Tech const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 1045392f7a3SLiteSpeed Tech if (env && atoi(env)) 1055392f7a3SLiteSpeed Tech { 1065392f7a3SLiteSpeed Tech s = rand() & 3; 1075392f7a3SLiteSpeed Tech LSQ_DEBUG("writing %d-byte stream type", 1 << s); 1085392f7a3SLiteSpeed Tech } 1095392f7a3SLiteSpeed Tech else 1105392f7a3SLiteSpeed Tech#endif 1115392f7a3SLiteSpeed Tech s = 0; 1125392f7a3SLiteSpeed Tech 1135392f7a3SLiteSpeed Tech switch (s) 1145392f7a3SLiteSpeed Tech { 1155392f7a3SLiteSpeed Tech case 0: 1165392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1175392f7a3SLiteSpeed Tech (unsigned char []) { HQUST_QPACK_DEC }, 1); 1185392f7a3SLiteSpeed Tech case 1: 1195392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1205392f7a3SLiteSpeed Tech (unsigned char []) { 0x40, HQUST_QPACK_DEC }, 2); 1215392f7a3SLiteSpeed Tech case 2: 1225392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1235392f7a3SLiteSpeed Tech (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_DEC }, 4); 1245392f7a3SLiteSpeed Tech default: 1255392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1265392f7a3SLiteSpeed Tech (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1275392f7a3SLiteSpeed Tech HQUST_QPACK_DEC }, 8); 1285392f7a3SLiteSpeed Tech } 1295392f7a3SLiteSpeed Tech} 1305392f7a3SLiteSpeed Tech 1315392f7a3SLiteSpeed Tech 1325392f7a3SLiteSpeed Techstatic void 1335392f7a3SLiteSpeed Techqdh_begin_out (struct qpack_dec_hdl *qdh) 1345392f7a3SLiteSpeed Tech{ 1355392f7a3SLiteSpeed Tech if (0 != qdh_write_type(qdh)) 1365392f7a3SLiteSpeed Tech { 1375392f7a3SLiteSpeed Tech LSQ_WARN("%s: could not write to decoder", __func__); 1385392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 1395392f7a3SLiteSpeed Tech "cannot write to decoder stream"); 1405392f7a3SLiteSpeed Tech } 1415392f7a3SLiteSpeed Tech} 1425392f7a3SLiteSpeed Tech 1435392f7a3SLiteSpeed Tech 1445392f7a3SLiteSpeed Techint 1455392f7a3SLiteSpeed Techlsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn, 1465392f7a3SLiteSpeed Tech int is_server, const struct lsquic_engine_public *enpub, 1475392f7a3SLiteSpeed Tech unsigned dyn_table_size, unsigned max_risked_streams) 1485392f7a3SLiteSpeed Tech{ 14955613f44SDmitri Tikhonov enum lsqpack_dec_opts dec_opts; 15055613f44SDmitri Tikhonov 15155613f44SDmitri Tikhonov dec_opts = 0; 15255613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X) 15355613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HTTP1X; 15455613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME) 15555613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HASH_NAME; 15655613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL) 15755613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL; 15855613f44SDmitri Tikhonov 1595392f7a3SLiteSpeed Tech qdh->qdh_conn = conn; 1605392f7a3SLiteSpeed Tech lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL); 1615392f7a3SLiteSpeed Tech lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size, 16255613f44SDmitri Tikhonov max_risked_streams, &dhi_if, dec_opts); 1635392f7a3SLiteSpeed Tech qdh->qdh_flags |= QDH_INITIALIZED; 1645392f7a3SLiteSpeed Tech qdh->qdh_enpub = enpub; 1655392f7a3SLiteSpeed Tech if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 1665392f7a3SLiteSpeed Tech { 1675392f7a3SLiteSpeed Tech qdh->qdh_h1x_ctor_ctx = (struct http1x_ctor_ctx) { 1685392f7a3SLiteSpeed Tech .conn = conn, 169a4f5dac3SDmitri Tikhonov .max_headers_sz = MAX_HTTP1X_HEADERS_SIZE, 1705392f7a3SLiteSpeed Tech .is_server = is_server, 1715392f7a3SLiteSpeed Tech }; 1725392f7a3SLiteSpeed Tech qdh->qdh_hsi_ctx = &qdh->qdh_h1x_ctor_ctx; 1735392f7a3SLiteSpeed Tech } 1745392f7a3SLiteSpeed Tech else 1755392f7a3SLiteSpeed Tech qdh->qdh_hsi_ctx = qdh->qdh_enpub->enp_hsi_ctx; 1765392f7a3SLiteSpeed Tech if (qdh->qdh_dec_sm_out) 1775392f7a3SLiteSpeed Tech qdh_begin_out(qdh); 1785392f7a3SLiteSpeed Tech if (qdh->qdh_enc_sm_in) 1795392f7a3SLiteSpeed Tech lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 1805392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized"); 1815392f7a3SLiteSpeed Tech return 0; 1825392f7a3SLiteSpeed Tech} 1835392f7a3SLiteSpeed Tech 1845392f7a3SLiteSpeed Tech 1855392f7a3SLiteSpeed Techvoid 1865392f7a3SLiteSpeed Techlsquic_qdh_cleanup (struct qpack_dec_hdl *qdh) 1875392f7a3SLiteSpeed Tech{ 1885392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 1895392f7a3SLiteSpeed Tech { 1905392f7a3SLiteSpeed Tech LSQ_DEBUG("cleanup"); 1915392f7a3SLiteSpeed Tech lsqpack_dec_cleanup(&qdh->qdh_decoder); 1925392f7a3SLiteSpeed Tech lsquic_frab_list_cleanup(&qdh->qdh_fral); 1935392f7a3SLiteSpeed Tech qdh->qdh_flags &= ~QDH_INITIALIZED; 1945392f7a3SLiteSpeed Tech } 1955392f7a3SLiteSpeed Tech} 1965392f7a3SLiteSpeed Tech 1975392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t * 1985392f7a3SLiteSpeed Techqdh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 1995392f7a3SLiteSpeed Tech{ 2005392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = stream_if_ctx; 2015392f7a3SLiteSpeed Tech qdh->qdh_dec_sm_out = stream; 2025392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 2035392f7a3SLiteSpeed Tech qdh_begin_out(qdh); 2045392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized outgoing decoder stream"); 2055392f7a3SLiteSpeed Tech return (void *) qdh; 2065392f7a3SLiteSpeed Tech} 2075392f7a3SLiteSpeed Tech 2085392f7a3SLiteSpeed Tech 2095392f7a3SLiteSpeed Techstatic void 2105392f7a3SLiteSpeed Techqdh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 2115392f7a3SLiteSpeed Tech{ 2125392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 2135392f7a3SLiteSpeed Tech struct lsquic_reader reader; 2145392f7a3SLiteSpeed Tech ssize_t nw; 2155392f7a3SLiteSpeed Tech unsigned char buf[LSQPACK_LONGEST_ICI]; 2165392f7a3SLiteSpeed Tech 2175392f7a3SLiteSpeed Tech if (lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 2185392f7a3SLiteSpeed Tech { 2195392f7a3SLiteSpeed Tech nw = lsqpack_dec_write_ici(&qdh->qdh_decoder, buf, sizeof(buf)); 2205392f7a3SLiteSpeed Tech if (nw > 0) 2215392f7a3SLiteSpeed Tech { 2225392f7a3SLiteSpeed Tech if (0 == qdh_write_decoder(qdh, buf, nw)) 2235392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd-byte TSS instruction", nw); 2245392f7a3SLiteSpeed Tech else 2255392f7a3SLiteSpeed Tech goto err; 2265392f7a3SLiteSpeed Tech } 2275392f7a3SLiteSpeed Tech else if (nw < 0) 2285392f7a3SLiteSpeed Tech { 2295392f7a3SLiteSpeed Tech LSQ_WARN("could not generate TSS instruction"); 2305392f7a3SLiteSpeed Tech goto err; 2315392f7a3SLiteSpeed Tech } 2325392f7a3SLiteSpeed Tech } 2335392f7a3SLiteSpeed Tech 2345392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&qdh->qdh_fral)) 2355392f7a3SLiteSpeed Tech { 2365392f7a3SLiteSpeed Tech LSQ_DEBUG("%s: nothing to write", __func__); 2375392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 2385392f7a3SLiteSpeed Tech return; 2395392f7a3SLiteSpeed Tech } 2405392f7a3SLiteSpeed Tech 2415392f7a3SLiteSpeed Tech reader = (struct lsquic_reader) { 2425392f7a3SLiteSpeed Tech .lsqr_read = lsquic_frab_list_read, 2435392f7a3SLiteSpeed Tech .lsqr_size = lsquic_frab_list_size, 2445392f7a3SLiteSpeed Tech .lsqr_ctx = &qdh->qdh_fral, 2455392f7a3SLiteSpeed Tech }; 2465392f7a3SLiteSpeed Tech 2475392f7a3SLiteSpeed Tech nw = lsquic_stream_writef(stream, &reader); 2485392f7a3SLiteSpeed Tech if (nw >= 0) 2495392f7a3SLiteSpeed Tech { 2505392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to stream", nw); 2515392f7a3SLiteSpeed Tech (void) lsquic_stream_flush(stream); 2525392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&qdh->qdh_fral)) 253747be414SDmitri Tikhonov { 2545392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 255747be414SDmitri Tikhonov if (qdh->qdh_on_dec_sent_func) 256747be414SDmitri Tikhonov { 257747be414SDmitri Tikhonov LSQ_DEBUG("buffered data written: call callback"); 258747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func(qdh->qdh_on_dec_sent_ctx); 259747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func = NULL; 260747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_ctx = NULL; 261747be414SDmitri Tikhonov } 262747be414SDmitri Tikhonov } 2635392f7a3SLiteSpeed Tech } 2645392f7a3SLiteSpeed Tech else 2655392f7a3SLiteSpeed Tech { 2665392f7a3SLiteSpeed Tech LSQ_WARN("cannot write to stream: %s", strerror(errno)); 2675392f7a3SLiteSpeed Tech err: 2685392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 2695392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 2705392f7a3SLiteSpeed Tech "cannot write to stream"); 2715392f7a3SLiteSpeed Tech } 2725392f7a3SLiteSpeed Tech} 2735392f7a3SLiteSpeed Tech 2745392f7a3SLiteSpeed Tech 2755392f7a3SLiteSpeed Techstatic void 2765392f7a3SLiteSpeed Techqdh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 2775392f7a3SLiteSpeed Tech{ 2785392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 2795392f7a3SLiteSpeed Tech qdh->qdh_dec_sm_out = NULL; 2805392f7a3SLiteSpeed Tech LSQ_DEBUG("closed outgoing decoder stream"); 2815392f7a3SLiteSpeed Tech} 2825392f7a3SLiteSpeed Tech 2835392f7a3SLiteSpeed Tech 2845392f7a3SLiteSpeed Techstatic void 2855392f7a3SLiteSpeed Techqdh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 2865392f7a3SLiteSpeed Tech{ 2875392f7a3SLiteSpeed Tech assert(0); 2885392f7a3SLiteSpeed Tech} 2895392f7a3SLiteSpeed Tech 2905392f7a3SLiteSpeed Tech 2915392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_dec_sm_out_if = 2925392f7a3SLiteSpeed Tech{ 2935392f7a3SLiteSpeed Tech .on_new_stream = qdh_out_on_new, 2945392f7a3SLiteSpeed Tech .on_read = qdh_out_on_read, 2955392f7a3SLiteSpeed Tech .on_write = qdh_out_on_write, 2965392f7a3SLiteSpeed Tech .on_close = qdh_out_on_close, 2975392f7a3SLiteSpeed Tech}; 2985392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if = 2995392f7a3SLiteSpeed Tech &qdh_dec_sm_out_if; 3005392f7a3SLiteSpeed Tech 3015392f7a3SLiteSpeed Tech 3025392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t * 3035392f7a3SLiteSpeed Techqdh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 3045392f7a3SLiteSpeed Tech{ 3055392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = stream_if_ctx; 3065392f7a3SLiteSpeed Tech qdh->qdh_enc_sm_in = stream; 3075392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 3085392f7a3SLiteSpeed Tech lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 3095392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized incoming encoder stream"); 3105392f7a3SLiteSpeed Tech return (void *) qdh; 3115392f7a3SLiteSpeed Tech} 3125392f7a3SLiteSpeed Tech 3135392f7a3SLiteSpeed Tech 3145392f7a3SLiteSpeed Techstatic size_t 3155392f7a3SLiteSpeed Techqdh_read_encoder_stream (void *ctx, const unsigned char *buf, size_t sz, 3165392f7a3SLiteSpeed Tech int fin) 3175392f7a3SLiteSpeed Tech{ 3185392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 3195392f7a3SLiteSpeed Tech const struct lsqpack_dec_err *qerr; 3205392f7a3SLiteSpeed Tech int s; 3215392f7a3SLiteSpeed Tech 3225392f7a3SLiteSpeed Tech if (fin) 3235392f7a3SLiteSpeed Tech { 3245392f7a3SLiteSpeed Tech LSQ_INFO("encoder stream is closed"); 3255392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 3265392f7a3SLiteSpeed Tech HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK encoder stream"); 3275392f7a3SLiteSpeed Tech goto end; 3285392f7a3SLiteSpeed Tech } 3295392f7a3SLiteSpeed Tech 3305392f7a3SLiteSpeed Tech s = lsqpack_dec_enc_in(&qdh->qdh_decoder, buf, sz); 3315392f7a3SLiteSpeed Tech if (s != 0) 3325392f7a3SLiteSpeed Tech { 333747be414SDmitri Tikhonov LSQ_INFO("error reading encoder stream"); 3345392f7a3SLiteSpeed Tech qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 3355392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 3365392f7a3SLiteSpeed Tech HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK encoder " 3375392f7a3SLiteSpeed Tech "stream; offset %"PRIu64", line %d", qerr->off, qerr->line); 3385392f7a3SLiteSpeed Tech goto end; 3395392f7a3SLiteSpeed Tech } 3405392f7a3SLiteSpeed Tech if (qdh->qdh_dec_sm_out 3415392f7a3SLiteSpeed Tech && lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 3425392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 3435392f7a3SLiteSpeed Tech 3445392f7a3SLiteSpeed Tech LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz); 3455392f7a3SLiteSpeed Tech 3465392f7a3SLiteSpeed Tech end: 3475392f7a3SLiteSpeed Tech return sz; 3485392f7a3SLiteSpeed Tech} 3495392f7a3SLiteSpeed Tech 3505392f7a3SLiteSpeed Tech 3515392f7a3SLiteSpeed Techstatic void 3525392f7a3SLiteSpeed Techqdh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3535392f7a3SLiteSpeed Tech{ 3545392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 3555392f7a3SLiteSpeed Tech ssize_t nread; 3565392f7a3SLiteSpeed Tech 3575392f7a3SLiteSpeed Tech nread = lsquic_stream_readf(stream, qdh_read_encoder_stream, qdh); 3585392f7a3SLiteSpeed Tech if (nread <= 0) 3595392f7a3SLiteSpeed Tech { 3605392f7a3SLiteSpeed Tech if (nread < 0) 3615392f7a3SLiteSpeed Tech { 3625392f7a3SLiteSpeed Tech LSQ_WARN("cannot read from encoder stream: %s", strerror(errno)); 3635392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 3645392f7a3SLiteSpeed Tech "cannot read from encoder stream"); 3655392f7a3SLiteSpeed Tech } 3665392f7a3SLiteSpeed Tech else 3675392f7a3SLiteSpeed Tech { 3685392f7a3SLiteSpeed Tech LSQ_INFO("encoder stream closed by peer: abort connection"); 3695392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 3705392f7a3SLiteSpeed Tech HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed"); 3715392f7a3SLiteSpeed Tech } 3725392f7a3SLiteSpeed Tech lsquic_stream_wantread(stream, 0); 3735392f7a3SLiteSpeed Tech } 3745392f7a3SLiteSpeed Tech} 3755392f7a3SLiteSpeed Tech 3765392f7a3SLiteSpeed Tech 3775392f7a3SLiteSpeed Techstatic void 3785392f7a3SLiteSpeed Techqdh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3795392f7a3SLiteSpeed Tech{ 3805392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 3815392f7a3SLiteSpeed Tech LSQ_DEBUG("closed incoming encoder stream"); 3825392f7a3SLiteSpeed Tech qdh->qdh_enc_sm_in = NULL; 3835392f7a3SLiteSpeed Tech} 3845392f7a3SLiteSpeed Tech 3855392f7a3SLiteSpeed Tech 3865392f7a3SLiteSpeed Techstatic void 3875392f7a3SLiteSpeed Techqdh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3885392f7a3SLiteSpeed Tech{ 3895392f7a3SLiteSpeed Tech assert(0); 3905392f7a3SLiteSpeed Tech} 3915392f7a3SLiteSpeed Tech 3925392f7a3SLiteSpeed Tech 3935392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_enc_sm_in_if = 3945392f7a3SLiteSpeed Tech{ 3955392f7a3SLiteSpeed Tech .on_new_stream = qdh_in_on_new, 3965392f7a3SLiteSpeed Tech .on_read = qdh_in_on_read, 3975392f7a3SLiteSpeed Tech .on_write = qdh_in_on_write, 3985392f7a3SLiteSpeed Tech .on_close = qdh_in_on_close, 3995392f7a3SLiteSpeed Tech}; 4005392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if = 4015392f7a3SLiteSpeed Tech &qdh_enc_sm_in_if; 4025392f7a3SLiteSpeed Tech 4035392f7a3SLiteSpeed Tech 4045392f7a3SLiteSpeed Techstatic void 4055392f7a3SLiteSpeed Techqdh_hblock_unblocked (void *stream_p) 4065392f7a3SLiteSpeed Tech{ 4075392f7a3SLiteSpeed Tech struct lsquic_stream *const stream = stream_p; 40855613f44SDmitri Tikhonov union hblock_ctx *const u = stream->sm_hblock_ctx; 40955613f44SDmitri Tikhonov struct qpack_dec_hdl *qdh = u->ctx.qdh; 4105392f7a3SLiteSpeed Tech 4115392f7a3SLiteSpeed Tech LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id); 4125392f7a3SLiteSpeed Tech lsquic_stream_qdec_unblocked(stream); 4135392f7a3SLiteSpeed Tech} 4145392f7a3SLiteSpeed Tech 4155392f7a3SLiteSpeed Tech 416747be414SDmitri Tikhonovstruct cont_len 417747be414SDmitri Tikhonov{ 418747be414SDmitri Tikhonov unsigned long long value; 419747be414SDmitri Tikhonov int has; /* 1: set, 0: not set, -1: invalid */ 420747be414SDmitri Tikhonov}; 421747be414SDmitri Tikhonov 422747be414SDmitri Tikhonov 423747be414SDmitri Tikhonovstatic void 424747be414SDmitri Tikhonovprocess_content_length (const struct qpack_dec_hdl *qdh /* for logging */, 425747be414SDmitri Tikhonov struct cont_len *cl, const char *val /* not NUL-terminated */, 426747be414SDmitri Tikhonov unsigned len) 427747be414SDmitri Tikhonov{ 428747be414SDmitri Tikhonov char *endcl, cont_len_buf[30]; 429747be414SDmitri Tikhonov 430747be414SDmitri Tikhonov if (0 == cl->has) 431747be414SDmitri Tikhonov { 432747be414SDmitri Tikhonov if (len >= sizeof(cont_len_buf)) 433747be414SDmitri Tikhonov { 434747be414SDmitri Tikhonov LSQ_DEBUG("content-length has invalid value `%.*s'", 435747be414SDmitri Tikhonov (int) len, val); 436747be414SDmitri Tikhonov cl->has = -1; 437747be414SDmitri Tikhonov return; 438747be414SDmitri Tikhonov } 439747be414SDmitri Tikhonov memcpy(cont_len_buf, val, len); 440747be414SDmitri Tikhonov cont_len_buf[len] = '\0'; 441747be414SDmitri Tikhonov cl->value = strtoull(cont_len_buf, &endcl, 10); 442747be414SDmitri Tikhonov if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno)) 443747be414SDmitri Tikhonov { 444747be414SDmitri Tikhonov cl->has = 1; 445747be414SDmitri Tikhonov LSQ_DEBUG("content length is %llu", cl->value); 446747be414SDmitri Tikhonov } 447747be414SDmitri Tikhonov else 448747be414SDmitri Tikhonov { 449747be414SDmitri Tikhonov cl->has = -1; 450747be414SDmitri Tikhonov LSQ_DEBUG("content-length has invalid value `%.*s'", 451747be414SDmitri Tikhonov (int) len, val); 452747be414SDmitri Tikhonov } 453747be414SDmitri Tikhonov } 454747be414SDmitri Tikhonov else if (cl->has > 0) 455747be414SDmitri Tikhonov { 456747be414SDmitri Tikhonov LSQ_DEBUG("header set has two content-length: ambiguous, " 457747be414SDmitri Tikhonov "turn off checking"); 458747be414SDmitri Tikhonov cl->has = -1; 459747be414SDmitri Tikhonov } 460747be414SDmitri Tikhonov} 461747be414SDmitri Tikhonov 462747be414SDmitri Tikhonov 463747be414SDmitri Tikhonovstatic int 46455613f44SDmitri Tikhonovis_content_length (const struct lsxpack_header *xhdr) 465747be414SDmitri Tikhonov{ 46655613f44SDmitri Tikhonov return ((xhdr->flags & LSXPACK_QPACK_IDX) 46755613f44SDmitri Tikhonov && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0) 46855613f44SDmitri Tikhonov || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr), 46955613f44SDmitri Tikhonov "content-length", 13)) 470747be414SDmitri Tikhonov ; 471747be414SDmitri Tikhonov} 472747be414SDmitri Tikhonov 473747be414SDmitri Tikhonov 47455613f44SDmitri Tikhonovstatic struct lsxpack_header * 47555613f44SDmitri Tikhonovqdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space) 4765392f7a3SLiteSpeed Tech{ 47755613f44SDmitri Tikhonov struct lsquic_stream *const stream = stream_p; 47855613f44SDmitri Tikhonov union hblock_ctx *const u = stream->sm_hblock_ctx; 47955613f44SDmitri Tikhonov struct qpack_dec_hdl *const qdh = u->ctx.qdh; 48055613f44SDmitri Tikhonov 48155613f44SDmitri Tikhonov return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode( 48255613f44SDmitri Tikhonov u->ctx.hset, xhdr, space); 48355613f44SDmitri Tikhonov} 4845392f7a3SLiteSpeed Tech 4855392f7a3SLiteSpeed Tech 48655613f44SDmitri Tikhonovstatic int 48755613f44SDmitri Tikhonovqdh_process_header (void *stream_p, struct lsxpack_header *xhdr) 48855613f44SDmitri Tikhonov{ 48955613f44SDmitri Tikhonov struct lsquic_stream *const stream = stream_p; 49055613f44SDmitri Tikhonov union hblock_ctx *const u = stream->sm_hblock_ctx; 49155613f44SDmitri Tikhonov struct qpack_dec_hdl *const qdh = u->ctx.qdh; 49255613f44SDmitri Tikhonov struct cont_len cl; 4935392f7a3SLiteSpeed Tech 49455613f44SDmitri Tikhonov if (is_content_length(xhdr)) 4955392f7a3SLiteSpeed Tech { 49655613f44SDmitri Tikhonov cl.has = 0; 49755613f44SDmitri Tikhonov process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr), 49855613f44SDmitri Tikhonov xhdr->val_len); 49955613f44SDmitri Tikhonov if (cl.has > 0) 50055613f44SDmitri Tikhonov (void) lsquic_stream_verify_len(stream, cl.value); 5015392f7a3SLiteSpeed Tech } 5025392f7a3SLiteSpeed Tech 50355613f44SDmitri Tikhonov return qdh->qdh_enpub->enp_hsi_if->hsi_process_header(u->ctx.hset, xhdr); 5045392f7a3SLiteSpeed Tech} 5055392f7a3SLiteSpeed Tech 5065392f7a3SLiteSpeed Tech 50755613f44SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if dhi_if = 50802b6086dSDmitri Tikhonov{ 50955613f44SDmitri Tikhonov .dhi_unblocked = qdh_hblock_unblocked, 51055613f44SDmitri Tikhonov .dhi_prepare_decode = qdh_prepare_decode, 51155613f44SDmitri Tikhonov .dhi_process_header = qdh_process_header, 51255613f44SDmitri Tikhonov}; 51302b6086dSDmitri Tikhonov 51402b6086dSDmitri Tikhonov 5155392f7a3SLiteSpeed Techstatic enum lsqpack_read_header_status 5165392f7a3SLiteSpeed Techqdh_header_read_results (struct qpack_dec_hdl *qdh, 5175392f7a3SLiteSpeed Tech struct lsquic_stream *stream, enum lsqpack_read_header_status rhs, 51855613f44SDmitri Tikhonov const unsigned char *dec_buf, size_t dec_buf_sz) 5195392f7a3SLiteSpeed Tech{ 5205392f7a3SLiteSpeed Tech const struct lsqpack_dec_err *qerr; 52155613f44SDmitri Tikhonov struct uncompressed_headers *uh; 52255613f44SDmitri Tikhonov void *hset; 5235392f7a3SLiteSpeed Tech 5245392f7a3SLiteSpeed Tech if (rhs == LQRHS_DONE) 5255392f7a3SLiteSpeed Tech { 52655613f44SDmitri Tikhonov if (!lsquic_stream_header_is_trailer(stream)) 5275392f7a3SLiteSpeed Tech { 52855613f44SDmitri Tikhonov hset = stream->sm_hblock_ctx->ctx.hset; 52955613f44SDmitri Tikhonov uh = &stream->sm_hblock_ctx->uh; 53055613f44SDmitri Tikhonov stream->sm_hblock_ctx = NULL; 53155613f44SDmitri Tikhonov memset(uh, 0, sizeof(*uh)); 53255613f44SDmitri Tikhonov uh->uh_stream_id = stream->id; 53355613f44SDmitri Tikhonov uh->uh_oth_stream_id = 0; 53455613f44SDmitri Tikhonov uh->uh_weight = 0; 53555613f44SDmitri Tikhonov uh->uh_exclusive = -1; 53655613f44SDmitri Tikhonov if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 53755613f44SDmitri Tikhonov uh->uh_flags |= UH_H1H; 53855613f44SDmitri Tikhonov if (0 != qdh->qdh_enpub->enp_hsi_if 53955613f44SDmitri Tikhonov ->hsi_process_header(hset, NULL)) 54055613f44SDmitri Tikhonov { 54155613f44SDmitri Tikhonov LSQ_DEBUG("finishing HTTP/1.x hset failed"); 54255613f44SDmitri Tikhonov free(uh); 5435392f7a3SLiteSpeed Tech return LQRHS_ERROR; 54455613f44SDmitri Tikhonov } 54555613f44SDmitri Tikhonov uh->uh_hset = hset; 54655613f44SDmitri Tikhonov if (0 == lsquic_stream_uh_in(stream, uh)) 54755613f44SDmitri Tikhonov LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id); 54855613f44SDmitri Tikhonov else 5495392f7a3SLiteSpeed Tech { 55055613f44SDmitri Tikhonov LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id); 55155613f44SDmitri Tikhonov free(uh); 55255613f44SDmitri Tikhonov return LQRHS_ERROR; 5535392f7a3SLiteSpeed Tech } 5545392f7a3SLiteSpeed Tech } 5555392f7a3SLiteSpeed Tech else 5565392f7a3SLiteSpeed Tech { 55755613f44SDmitri Tikhonov LSQ_DEBUG("discard trailer header set"); 55855613f44SDmitri Tikhonov free(stream->sm_hblock_ctx); 55955613f44SDmitri Tikhonov stream->sm_hblock_ctx = NULL; 56055613f44SDmitri Tikhonov } 56155613f44SDmitri Tikhonov if (qdh->qdh_dec_sm_out) 56255613f44SDmitri Tikhonov { 56355613f44SDmitri Tikhonov if (dec_buf_sz 56455613f44SDmitri Tikhonov && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz)) 56555613f44SDmitri Tikhonov { 56655613f44SDmitri Tikhonov return LQRHS_ERROR; 56755613f44SDmitri Tikhonov } 56855613f44SDmitri Tikhonov if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 56955613f44SDmitri Tikhonov lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 5705392f7a3SLiteSpeed Tech } 5715392f7a3SLiteSpeed Tech } 5725392f7a3SLiteSpeed Tech else if (rhs == LQRHS_ERROR) 5735392f7a3SLiteSpeed Tech { 5745392f7a3SLiteSpeed Tech qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 5755392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 5765392f7a3SLiteSpeed Tech HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; " 5775392f7a3SLiteSpeed Tech "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id, 5785392f7a3SLiteSpeed Tech qerr->off, qerr->line); 5795392f7a3SLiteSpeed Tech } 5805392f7a3SLiteSpeed Tech 5815392f7a3SLiteSpeed Tech return rhs; 5825392f7a3SLiteSpeed Tech} 5835392f7a3SLiteSpeed Tech 5845392f7a3SLiteSpeed Tech 5855392f7a3SLiteSpeed Techenum lsqpack_read_header_status 5865392f7a3SLiteSpeed Techlsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh, 5875392f7a3SLiteSpeed Tech struct lsquic_stream *stream, uint64_t header_size, 5885392f7a3SLiteSpeed Tech const unsigned char **buf, size_t bufsz) 5895392f7a3SLiteSpeed Tech{ 5905392f7a3SLiteSpeed Tech enum lsqpack_read_header_status rhs; 59155613f44SDmitri Tikhonov void *hset; 59255613f44SDmitri Tikhonov int is_pp; 5935392f7a3SLiteSpeed Tech size_t dec_buf_sz; 59455613f44SDmitri Tikhonov union hblock_ctx *u; 5955392f7a3SLiteSpeed Tech unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 5965392f7a3SLiteSpeed Tech 59755613f44SDmitri Tikhonov if (!(qdh->qdh_flags & QDH_INITIALIZED)) 5985392f7a3SLiteSpeed Tech { 59955613f44SDmitri Tikhonov LSQ_WARN("not initialized: cannot process header block"); 60055613f44SDmitri Tikhonov return LQRHS_ERROR; 6015392f7a3SLiteSpeed Tech } 60255613f44SDmitri Tikhonov 60355613f44SDmitri Tikhonov u = malloc(sizeof(*u)); 60455613f44SDmitri Tikhonov if (!u) 6055392f7a3SLiteSpeed Tech { 60655613f44SDmitri Tikhonov LSQ_INFO("cannot allocate hblock_ctx"); 60755613f44SDmitri Tikhonov return LQRHS_ERROR; 60855613f44SDmitri Tikhonov } 60955613f44SDmitri Tikhonov 61055613f44SDmitri Tikhonov is_pp = lsquic_stream_header_is_pp(stream); 61155613f44SDmitri Tikhonov hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set( 61255613f44SDmitri Tikhonov qdh->qdh_hsi_ctx, stream, is_pp); 61355613f44SDmitri Tikhonov if (!hset) 61455613f44SDmitri Tikhonov { 61555613f44SDmitri Tikhonov free(u); 61655613f44SDmitri Tikhonov LSQ_DEBUG("hsi_create_header_set failure"); 6175392f7a3SLiteSpeed Tech return LQRHS_ERROR; 6185392f7a3SLiteSpeed Tech } 6195392f7a3SLiteSpeed Tech 62055613f44SDmitri Tikhonov u->ctx.hset = hset; 62155613f44SDmitri Tikhonov u->ctx.qdh = qdh; 62255613f44SDmitri Tikhonov stream->sm_hblock_ctx = u; 62355613f44SDmitri Tikhonov 62455613f44SDmitri Tikhonov dec_buf_sz = sizeof(dec_buf); 62555613f44SDmitri Tikhonov rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id, 62655613f44SDmitri Tikhonov header_size, buf, bufsz, dec_buf, &dec_buf_sz); 62755613f44SDmitri Tikhonov return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 6285392f7a3SLiteSpeed Tech} 6295392f7a3SLiteSpeed Tech 6305392f7a3SLiteSpeed Tech 6315392f7a3SLiteSpeed Techenum lsqpack_read_header_status 6325392f7a3SLiteSpeed Techlsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh, 6335392f7a3SLiteSpeed Tech struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz) 6345392f7a3SLiteSpeed Tech{ 6355392f7a3SLiteSpeed Tech enum lsqpack_read_header_status rhs; 6365392f7a3SLiteSpeed Tech size_t dec_buf_sz; 6375392f7a3SLiteSpeed Tech unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 6385392f7a3SLiteSpeed Tech 6395392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 6405392f7a3SLiteSpeed Tech { 6415392f7a3SLiteSpeed Tech dec_buf_sz = sizeof(dec_buf); 6425392f7a3SLiteSpeed Tech rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream, 64355613f44SDmitri Tikhonov buf, bufsz, dec_buf, &dec_buf_sz); 64455613f44SDmitri Tikhonov return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 6455392f7a3SLiteSpeed Tech } 6465392f7a3SLiteSpeed Tech else 6475392f7a3SLiteSpeed Tech { 6485392f7a3SLiteSpeed Tech LSQ_WARN("not initialized: cannot process header block"); 6495392f7a3SLiteSpeed Tech return LQRHS_ERROR; 6505392f7a3SLiteSpeed Tech } 6515392f7a3SLiteSpeed Tech} 6525392f7a3SLiteSpeed Tech 6535392f7a3SLiteSpeed Tech 6545392f7a3SLiteSpeed Techvoid 6555392f7a3SLiteSpeed Techlsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh, 6565392f7a3SLiteSpeed Tech struct lsquic_stream *stream) 6575392f7a3SLiteSpeed Tech{ 6585392f7a3SLiteSpeed Tech if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream)) 6595392f7a3SLiteSpeed Tech LSQ_DEBUG("unreffed stream %"PRIu64, stream->id); 6605392f7a3SLiteSpeed Tech else 6615392f7a3SLiteSpeed Tech LSQ_WARN("cannot unref stream %"PRIu64, stream->id); 6625392f7a3SLiteSpeed Tech} 6635392f7a3SLiteSpeed Tech 6645392f7a3SLiteSpeed Tech 6655392f7a3SLiteSpeed Techvoid 6665392f7a3SLiteSpeed Techlsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh, 6675392f7a3SLiteSpeed Tech struct lsquic_stream *stream) 6685392f7a3SLiteSpeed Tech{ 6695392f7a3SLiteSpeed Tech ssize_t nw; 6705392f7a3SLiteSpeed Tech unsigned char buf[LSQPACK_LONGEST_CANCEL]; 6715392f7a3SLiteSpeed Tech 6725392f7a3SLiteSpeed Tech nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf)); 6735392f7a3SLiteSpeed Tech if (nw > 0) 6745392f7a3SLiteSpeed Tech { 6755392f7a3SLiteSpeed Tech if (0 == qdh_write_decoder(qdh, buf, nw)) 6765392f7a3SLiteSpeed Tech LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel " 6775392f7a3SLiteSpeed Tech "Stream instruction to the decoder stream", stream->id, nw); 6785392f7a3SLiteSpeed Tech } 6795392f7a3SLiteSpeed Tech else if (nw == 0) 6805392f7a3SLiteSpeed Tech LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id); 6815392f7a3SLiteSpeed Tech else 6825392f7a3SLiteSpeed Tech { 6835392f7a3SLiteSpeed Tech LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space " 6845392f7a3SLiteSpeed Tech "to encode Cancel Stream instructin", stream->id); 6855392f7a3SLiteSpeed Tech lsquic_qdh_unref_stream(qdh, stream); 6865392f7a3SLiteSpeed Tech } 6875392f7a3SLiteSpeed Tech} 688747be414SDmitri Tikhonov 689747be414SDmitri Tikhonov 690747be414SDmitri Tikhonovint 691747be414SDmitri Tikhonovlsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *), 692747be414SDmitri Tikhonov void *ctx) 693747be414SDmitri Tikhonov{ 694747be414SDmitri Tikhonov size_t bytes; 695747be414SDmitri Tikhonov 696747be414SDmitri Tikhonov /* Use size of a single frab list buffer as an arbitrary threshold */ 697747be414SDmitri Tikhonov bytes = lsquic_frab_list_size(&qdh->qdh_fral); 698747be414SDmitri Tikhonov if (bytes <= qdh->qdh_fral.fl_buf_size) 699747be414SDmitri Tikhonov return 0; 700747be414SDmitri Tikhonov else 701747be414SDmitri Tikhonov { 702747be414SDmitri Tikhonov LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set " 703747be414SDmitri Tikhonov "up callback", bytes); 704747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func = func; 705747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_ctx = ctx; 706747be414SDmitri Tikhonov return 1; 707747be414SDmitri Tikhonov } 708747be414SDmitri Tikhonov} 709