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