lsquic_qdec_hdl.c revision a5fa05f9
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
355392f7a3SLiteSpeed Techstatic void
365392f7a3SLiteSpeed Techqdh_hblock_unblocked (void *);
375392f7a3SLiteSpeed Tech
385392f7a3SLiteSpeed Tech
395392f7a3SLiteSpeed Techstatic int
405392f7a3SLiteSpeed Techqdh_write_decoder (struct qpack_dec_hdl *qdh, const unsigned char *buf,
415392f7a3SLiteSpeed Tech                                                                size_t sz)
425392f7a3SLiteSpeed Tech{
435392f7a3SLiteSpeed Tech    ssize_t nw;
445392f7a3SLiteSpeed Tech
455392f7a3SLiteSpeed Tech    if (!(qdh->qdh_dec_sm_out && lsquic_frab_list_empty(&qdh->qdh_fral)))
465392f7a3SLiteSpeed Tech    {
475392f7a3SLiteSpeed Tech  write_to_frab:
485392f7a3SLiteSpeed Tech        if (0 == lsquic_frab_list_write(&qdh->qdh_fral,
495392f7a3SLiteSpeed Tech                                                (unsigned char *) buf, sz))
505392f7a3SLiteSpeed Tech        {
515392f7a3SLiteSpeed Tech            LSQ_DEBUG("wrote %zu bytes to frab list", sz);
525392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
535392f7a3SLiteSpeed Tech            return 0;
545392f7a3SLiteSpeed Tech        }
555392f7a3SLiteSpeed Tech        else
565392f7a3SLiteSpeed Tech        {
575392f7a3SLiteSpeed Tech            LSQ_INFO("error writing to frab list");
585392f7a3SLiteSpeed Tech            return -1;
595392f7a3SLiteSpeed Tech        }
605392f7a3SLiteSpeed Tech    }
615392f7a3SLiteSpeed Tech
625392f7a3SLiteSpeed Tech    nw = lsquic_stream_write(qdh->qdh_dec_sm_out, buf, sz);
635392f7a3SLiteSpeed Tech    if (nw < 0)
645392f7a3SLiteSpeed Tech    {
655392f7a3SLiteSpeed Tech        LSQ_INFO("error writing to outgoing QPACK decoder stream: %s",
665392f7a3SLiteSpeed Tech                                                        strerror(errno));
675392f7a3SLiteSpeed Tech        return -1;
685392f7a3SLiteSpeed Tech    }
695392f7a3SLiteSpeed Tech    LSQ_DEBUG("wrote %zd bytes to outgoing QPACK decoder stream", nw);
705392f7a3SLiteSpeed Tech
715392f7a3SLiteSpeed Tech    if ((size_t) nw == sz)
725392f7a3SLiteSpeed Tech        return 0;
735392f7a3SLiteSpeed Tech
745392f7a3SLiteSpeed Tech    buf = buf + nw;
755392f7a3SLiteSpeed Tech    sz -= (size_t) nw;
765392f7a3SLiteSpeed Tech    goto write_to_frab;
775392f7a3SLiteSpeed Tech}
785392f7a3SLiteSpeed Tech
795392f7a3SLiteSpeed Tech
805392f7a3SLiteSpeed Techstatic int
815392f7a3SLiteSpeed Techqdh_write_type (struct qpack_dec_hdl *qdh)
825392f7a3SLiteSpeed Tech{
835392f7a3SLiteSpeed Tech    int s;
845392f7a3SLiteSpeed Tech
855392f7a3SLiteSpeed Tech#ifndef NDEBUG
865392f7a3SLiteSpeed Tech    const char *env = getenv("LSQUIC_RND_VARINT_LEN");
875392f7a3SLiteSpeed Tech    if (env && atoi(env))
885392f7a3SLiteSpeed Tech    {
895392f7a3SLiteSpeed Tech        s = rand() & 3;
905392f7a3SLiteSpeed Tech        LSQ_DEBUG("writing %d-byte stream type", 1 << s);
915392f7a3SLiteSpeed Tech    }
925392f7a3SLiteSpeed Tech    else
935392f7a3SLiteSpeed Tech#endif
945392f7a3SLiteSpeed Tech        s = 0;
955392f7a3SLiteSpeed Tech
965392f7a3SLiteSpeed Tech    switch (s)
975392f7a3SLiteSpeed Tech    {
985392f7a3SLiteSpeed Tech    case 0:
995392f7a3SLiteSpeed Tech        return qdh_write_decoder(qdh,
1005392f7a3SLiteSpeed Tech                                (unsigned char []) { HQUST_QPACK_DEC }, 1);
1015392f7a3SLiteSpeed Tech    case 1:
1025392f7a3SLiteSpeed Tech        return qdh_write_decoder(qdh,
1035392f7a3SLiteSpeed Tech                            (unsigned char []) { 0x40, HQUST_QPACK_DEC }, 2);
1045392f7a3SLiteSpeed Tech    case 2:
1055392f7a3SLiteSpeed Tech        return qdh_write_decoder(qdh,
1065392f7a3SLiteSpeed Tech                (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_DEC }, 4);
1075392f7a3SLiteSpeed Tech    default:
1085392f7a3SLiteSpeed Tech        return qdh_write_decoder(qdh,
1095392f7a3SLiteSpeed Tech                (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1105392f7a3SLiteSpeed Tech                                                        HQUST_QPACK_DEC }, 8);
1115392f7a3SLiteSpeed Tech    }
1125392f7a3SLiteSpeed Tech}
1135392f7a3SLiteSpeed Tech
1145392f7a3SLiteSpeed Tech
1155392f7a3SLiteSpeed Techstatic void
1165392f7a3SLiteSpeed Techqdh_begin_out (struct qpack_dec_hdl *qdh)
1175392f7a3SLiteSpeed Tech{
1185392f7a3SLiteSpeed Tech    if (0 != qdh_write_type(qdh))
1195392f7a3SLiteSpeed Tech    {
1205392f7a3SLiteSpeed Tech        LSQ_WARN("%s: could not write to decoder", __func__);
1215392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn,
1225392f7a3SLiteSpeed Tech                                        "cannot write to decoder stream");
1235392f7a3SLiteSpeed Tech    }
1245392f7a3SLiteSpeed Tech}
1255392f7a3SLiteSpeed Tech
1265392f7a3SLiteSpeed Tech
1275392f7a3SLiteSpeed Techint
1285392f7a3SLiteSpeed Techlsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn,
1295392f7a3SLiteSpeed Tech                    int is_server, const struct lsquic_engine_public *enpub,
1305392f7a3SLiteSpeed Tech                    unsigned dyn_table_size, unsigned max_risked_streams)
1315392f7a3SLiteSpeed Tech{
1325392f7a3SLiteSpeed Tech    qdh->qdh_conn = conn;
1335392f7a3SLiteSpeed Tech    lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL);
1345392f7a3SLiteSpeed Tech    lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size,
1355392f7a3SLiteSpeed Tech                        max_risked_streams, qdh_hblock_unblocked);
1365392f7a3SLiteSpeed Tech    qdh->qdh_flags |= QDH_INITIALIZED;
1375392f7a3SLiteSpeed Tech    qdh->qdh_enpub = enpub;
1385392f7a3SLiteSpeed Tech    if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if)
1395392f7a3SLiteSpeed Tech    {
1405392f7a3SLiteSpeed Tech        qdh->qdh_h1x_ctor_ctx = (struct http1x_ctor_ctx) {
1415392f7a3SLiteSpeed Tech            .conn           = conn,
142a4f5dac3SDmitri Tikhonov            .max_headers_sz = MAX_HTTP1X_HEADERS_SIZE,
1435392f7a3SLiteSpeed Tech            .is_server      = is_server,
1445392f7a3SLiteSpeed Tech        };
1455392f7a3SLiteSpeed Tech        qdh->qdh_hsi_ctx = &qdh->qdh_h1x_ctor_ctx;
1465392f7a3SLiteSpeed Tech    }
1475392f7a3SLiteSpeed Tech    else
1485392f7a3SLiteSpeed Tech        qdh->qdh_hsi_ctx = qdh->qdh_enpub->enp_hsi_ctx;
1495392f7a3SLiteSpeed Tech    if (qdh->qdh_dec_sm_out)
1505392f7a3SLiteSpeed Tech        qdh_begin_out(qdh);
1515392f7a3SLiteSpeed Tech    if (qdh->qdh_enc_sm_in)
1525392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1);
1535392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
1545392f7a3SLiteSpeed Tech    return 0;
1555392f7a3SLiteSpeed Tech}
1565392f7a3SLiteSpeed Tech
1575392f7a3SLiteSpeed Tech
1585392f7a3SLiteSpeed Techvoid
1595392f7a3SLiteSpeed Techlsquic_qdh_cleanup (struct qpack_dec_hdl *qdh)
1605392f7a3SLiteSpeed Tech{
1615392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
1625392f7a3SLiteSpeed Tech    {
1635392f7a3SLiteSpeed Tech        LSQ_DEBUG("cleanup");
1645392f7a3SLiteSpeed Tech        lsqpack_dec_cleanup(&qdh->qdh_decoder);
1655392f7a3SLiteSpeed Tech        lsquic_frab_list_cleanup(&qdh->qdh_fral);
1665392f7a3SLiteSpeed Tech        qdh->qdh_flags &= ~QDH_INITIALIZED;
1675392f7a3SLiteSpeed Tech    }
1685392f7a3SLiteSpeed Tech}
1695392f7a3SLiteSpeed Tech
1705392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
1715392f7a3SLiteSpeed Techqdh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
1725392f7a3SLiteSpeed Tech{
1735392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = stream_if_ctx;
1745392f7a3SLiteSpeed Tech    qdh->qdh_dec_sm_out = stream;
1755392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
1765392f7a3SLiteSpeed Tech        qdh_begin_out(qdh);
1775392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized outgoing decoder stream");
1785392f7a3SLiteSpeed Tech    return (void *) qdh;
1795392f7a3SLiteSpeed Tech}
1805392f7a3SLiteSpeed Tech
1815392f7a3SLiteSpeed Tech
1825392f7a3SLiteSpeed Techstatic void
1835392f7a3SLiteSpeed Techqdh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1845392f7a3SLiteSpeed Tech{
1855392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = (void *) ctx;
1865392f7a3SLiteSpeed Tech    struct lsquic_reader reader;
1875392f7a3SLiteSpeed Tech    ssize_t nw;
1885392f7a3SLiteSpeed Tech    unsigned char buf[LSQPACK_LONGEST_ICI];
1895392f7a3SLiteSpeed Tech
1905392f7a3SLiteSpeed Tech    if (lsqpack_dec_ici_pending(&qdh->qdh_decoder))
1915392f7a3SLiteSpeed Tech    {
1925392f7a3SLiteSpeed Tech        nw = lsqpack_dec_write_ici(&qdh->qdh_decoder, buf, sizeof(buf));
1935392f7a3SLiteSpeed Tech        if (nw > 0)
1945392f7a3SLiteSpeed Tech        {
1955392f7a3SLiteSpeed Tech            if (0 == qdh_write_decoder(qdh, buf, nw))
1965392f7a3SLiteSpeed Tech                LSQ_DEBUG("wrote %zd-byte TSS instruction", nw);
1975392f7a3SLiteSpeed Tech            else
1985392f7a3SLiteSpeed Tech                goto err;
1995392f7a3SLiteSpeed Tech        }
2005392f7a3SLiteSpeed Tech        else if (nw < 0)
2015392f7a3SLiteSpeed Tech        {
2025392f7a3SLiteSpeed Tech            LSQ_WARN("could not generate TSS instruction");
2035392f7a3SLiteSpeed Tech            goto err;
2045392f7a3SLiteSpeed Tech        }
2055392f7a3SLiteSpeed Tech    }
2065392f7a3SLiteSpeed Tech
2075392f7a3SLiteSpeed Tech    if (lsquic_frab_list_empty(&qdh->qdh_fral))
2085392f7a3SLiteSpeed Tech    {
2095392f7a3SLiteSpeed Tech        LSQ_DEBUG("%s: nothing to write", __func__);
2105392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
2115392f7a3SLiteSpeed Tech        return;
2125392f7a3SLiteSpeed Tech    }
2135392f7a3SLiteSpeed Tech
2145392f7a3SLiteSpeed Tech    reader = (struct lsquic_reader) {
2155392f7a3SLiteSpeed Tech        .lsqr_read  = lsquic_frab_list_read,
2165392f7a3SLiteSpeed Tech        .lsqr_size  = lsquic_frab_list_size,
2175392f7a3SLiteSpeed Tech        .lsqr_ctx   = &qdh->qdh_fral,
2185392f7a3SLiteSpeed Tech    };
2195392f7a3SLiteSpeed Tech
2205392f7a3SLiteSpeed Tech    nw = lsquic_stream_writef(stream, &reader);
2215392f7a3SLiteSpeed Tech    if (nw >= 0)
2225392f7a3SLiteSpeed Tech    {
2235392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zd bytes to stream", nw);
2245392f7a3SLiteSpeed Tech        (void) lsquic_stream_flush(stream);
2255392f7a3SLiteSpeed Tech        if (lsquic_frab_list_empty(&qdh->qdh_fral))
226747be414SDmitri Tikhonov        {
2275392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(stream, 0);
228747be414SDmitri Tikhonov            if (qdh->qdh_on_dec_sent_func)
229747be414SDmitri Tikhonov            {
230747be414SDmitri Tikhonov                LSQ_DEBUG("buffered data written: call callback");
231747be414SDmitri Tikhonov                qdh->qdh_on_dec_sent_func(qdh->qdh_on_dec_sent_ctx);
232747be414SDmitri Tikhonov                qdh->qdh_on_dec_sent_func = NULL;
233747be414SDmitri Tikhonov                qdh->qdh_on_dec_sent_ctx = NULL;
234747be414SDmitri Tikhonov            }
235747be414SDmitri Tikhonov        }
2365392f7a3SLiteSpeed Tech    }
2375392f7a3SLiteSpeed Tech    else
2385392f7a3SLiteSpeed Tech    {
2395392f7a3SLiteSpeed Tech        LSQ_WARN("cannot write to stream: %s", strerror(errno));
2405392f7a3SLiteSpeed Tech  err:
2415392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
2425392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn,
2435392f7a3SLiteSpeed Tech                                        "cannot write to stream");
2445392f7a3SLiteSpeed Tech    }
2455392f7a3SLiteSpeed Tech}
2465392f7a3SLiteSpeed Tech
2475392f7a3SLiteSpeed Tech
2485392f7a3SLiteSpeed Techstatic void
2495392f7a3SLiteSpeed Techqdh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2505392f7a3SLiteSpeed Tech{
2515392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = (void *) ctx;
2525392f7a3SLiteSpeed Tech    qdh->qdh_dec_sm_out = NULL;
2535392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed outgoing decoder stream");
2545392f7a3SLiteSpeed Tech}
2555392f7a3SLiteSpeed Tech
2565392f7a3SLiteSpeed Tech
2575392f7a3SLiteSpeed Techstatic void
2585392f7a3SLiteSpeed Techqdh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2595392f7a3SLiteSpeed Tech{
2605392f7a3SLiteSpeed Tech    assert(0);
2615392f7a3SLiteSpeed Tech}
2625392f7a3SLiteSpeed Tech
2635392f7a3SLiteSpeed Tech
2645392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_dec_sm_out_if =
2655392f7a3SLiteSpeed Tech{
2665392f7a3SLiteSpeed Tech    .on_new_stream  = qdh_out_on_new,
2675392f7a3SLiteSpeed Tech    .on_read        = qdh_out_on_read,
2685392f7a3SLiteSpeed Tech    .on_write       = qdh_out_on_write,
2695392f7a3SLiteSpeed Tech    .on_close       = qdh_out_on_close,
2705392f7a3SLiteSpeed Tech};
2715392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if =
2725392f7a3SLiteSpeed Tech                                                    &qdh_dec_sm_out_if;
2735392f7a3SLiteSpeed Tech
2745392f7a3SLiteSpeed Tech
2755392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
2765392f7a3SLiteSpeed Techqdh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
2775392f7a3SLiteSpeed Tech{
2785392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = stream_if_ctx;
2795392f7a3SLiteSpeed Tech    qdh->qdh_enc_sm_in = stream;
2805392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
2815392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1);
2825392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized incoming encoder stream");
2835392f7a3SLiteSpeed Tech    return (void *) qdh;
2845392f7a3SLiteSpeed Tech}
2855392f7a3SLiteSpeed Tech
2865392f7a3SLiteSpeed Tech
2875392f7a3SLiteSpeed Techstatic size_t
2885392f7a3SLiteSpeed Techqdh_read_encoder_stream (void *ctx, const unsigned char *buf, size_t sz,
2895392f7a3SLiteSpeed Tech                                                                    int fin)
2905392f7a3SLiteSpeed Tech{
2915392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = (void *) ctx;
2925392f7a3SLiteSpeed Tech    const struct lsqpack_dec_err *qerr;
2935392f7a3SLiteSpeed Tech    int s;
2945392f7a3SLiteSpeed Tech
2955392f7a3SLiteSpeed Tech    if (fin)
2965392f7a3SLiteSpeed Tech    {
2975392f7a3SLiteSpeed Tech        LSQ_INFO("encoder stream is closed");
2985392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1,
2995392f7a3SLiteSpeed Tech            HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK encoder stream");
3005392f7a3SLiteSpeed Tech        goto end;
3015392f7a3SLiteSpeed Tech    }
3025392f7a3SLiteSpeed Tech
3035392f7a3SLiteSpeed Tech    s = lsqpack_dec_enc_in(&qdh->qdh_decoder, buf, sz);
3045392f7a3SLiteSpeed Tech    if (s != 0)
3055392f7a3SLiteSpeed Tech    {
306747be414SDmitri Tikhonov        LSQ_INFO("error reading encoder stream");
3075392f7a3SLiteSpeed Tech        qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder);
3085392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1,
3095392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK encoder "
3105392f7a3SLiteSpeed Tech            "stream; offset %"PRIu64", line %d", qerr->off, qerr->line);
3115392f7a3SLiteSpeed Tech        goto end;
3125392f7a3SLiteSpeed Tech    }
3135392f7a3SLiteSpeed Tech    if (qdh->qdh_dec_sm_out
3145392f7a3SLiteSpeed Tech                    && lsqpack_dec_ici_pending(&qdh->qdh_decoder))
3155392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
3165392f7a3SLiteSpeed Tech
3175392f7a3SLiteSpeed Tech    LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz);
3185392f7a3SLiteSpeed Tech
3195392f7a3SLiteSpeed Tech  end:
3205392f7a3SLiteSpeed Tech    return sz;
3215392f7a3SLiteSpeed Tech}
3225392f7a3SLiteSpeed Tech
3235392f7a3SLiteSpeed Tech
3245392f7a3SLiteSpeed Techstatic void
3255392f7a3SLiteSpeed Techqdh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3265392f7a3SLiteSpeed Tech{
3275392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = (void *) ctx;
3285392f7a3SLiteSpeed Tech    ssize_t nread;
3295392f7a3SLiteSpeed Tech
3305392f7a3SLiteSpeed Tech    nread = lsquic_stream_readf(stream, qdh_read_encoder_stream, qdh);
3315392f7a3SLiteSpeed Tech    if (nread <= 0)
3325392f7a3SLiteSpeed Tech    {
3335392f7a3SLiteSpeed Tech        if (nread < 0)
3345392f7a3SLiteSpeed Tech        {
3355392f7a3SLiteSpeed Tech            LSQ_WARN("cannot read from encoder stream: %s", strerror(errno));
3365392f7a3SLiteSpeed Tech            qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn,
3375392f7a3SLiteSpeed Tech                                        "cannot read from encoder stream");
3385392f7a3SLiteSpeed Tech        }
3395392f7a3SLiteSpeed Tech        else
3405392f7a3SLiteSpeed Tech        {
3415392f7a3SLiteSpeed Tech            LSQ_INFO("encoder stream closed by peer: abort connection");
3425392f7a3SLiteSpeed Tech            qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1,
3435392f7a3SLiteSpeed Tech                HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed");
3445392f7a3SLiteSpeed Tech        }
3455392f7a3SLiteSpeed Tech        lsquic_stream_wantread(stream, 0);
3465392f7a3SLiteSpeed Tech    }
3475392f7a3SLiteSpeed Tech}
3485392f7a3SLiteSpeed Tech
3495392f7a3SLiteSpeed Tech
3505392f7a3SLiteSpeed Techstatic void
3515392f7a3SLiteSpeed Techqdh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3525392f7a3SLiteSpeed Tech{
3535392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = (void *) ctx;
3545392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed incoming encoder stream");
3555392f7a3SLiteSpeed Tech    qdh->qdh_enc_sm_in = NULL;
3565392f7a3SLiteSpeed Tech}
3575392f7a3SLiteSpeed Tech
3585392f7a3SLiteSpeed Tech
3595392f7a3SLiteSpeed Techstatic void
3605392f7a3SLiteSpeed Techqdh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3615392f7a3SLiteSpeed Tech{
3625392f7a3SLiteSpeed Tech    assert(0);
3635392f7a3SLiteSpeed Tech}
3645392f7a3SLiteSpeed Tech
3655392f7a3SLiteSpeed Tech
3665392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_enc_sm_in_if =
3675392f7a3SLiteSpeed Tech{
3685392f7a3SLiteSpeed Tech    .on_new_stream  = qdh_in_on_new,
3695392f7a3SLiteSpeed Tech    .on_read        = qdh_in_on_read,
3705392f7a3SLiteSpeed Tech    .on_write       = qdh_in_on_write,
3715392f7a3SLiteSpeed Tech    .on_close       = qdh_in_on_close,
3725392f7a3SLiteSpeed Tech};
3735392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if =
3745392f7a3SLiteSpeed Tech                                                    &qdh_enc_sm_in_if;
3755392f7a3SLiteSpeed Tech
3765392f7a3SLiteSpeed Tech
3775392f7a3SLiteSpeed Techstatic void
3785392f7a3SLiteSpeed Techqdh_hblock_unblocked (void *stream_p)
3795392f7a3SLiteSpeed Tech{
3805392f7a3SLiteSpeed Tech    struct lsquic_stream *const stream = stream_p;
3815392f7a3SLiteSpeed Tech    struct qpack_dec_hdl *const qdh = lsquic_stream_get_qdh(stream);
3825392f7a3SLiteSpeed Tech
3835392f7a3SLiteSpeed Tech    LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id);
3845392f7a3SLiteSpeed Tech    lsquic_stream_qdec_unblocked(stream);
3855392f7a3SLiteSpeed Tech}
3865392f7a3SLiteSpeed Tech
3875392f7a3SLiteSpeed Tech
388747be414SDmitri Tikhonovstruct cont_len
389747be414SDmitri Tikhonov{
390747be414SDmitri Tikhonov    unsigned long long      value;
391747be414SDmitri Tikhonov    int                     has;    /* 1: set, 0: not set, -1: invalid */
392747be414SDmitri Tikhonov};
393747be414SDmitri Tikhonov
394747be414SDmitri Tikhonov
395747be414SDmitri Tikhonovstatic void
396747be414SDmitri Tikhonovprocess_content_length (const struct qpack_dec_hdl *qdh /* for logging */,
397747be414SDmitri Tikhonov            struct cont_len *cl, const char *val /* not NUL-terminated */,
398747be414SDmitri Tikhonov                                                                unsigned len)
399747be414SDmitri Tikhonov{
400747be414SDmitri Tikhonov    char *endcl, cont_len_buf[30];
401747be414SDmitri Tikhonov
402747be414SDmitri Tikhonov    if (0 == cl->has)
403747be414SDmitri Tikhonov    {
404747be414SDmitri Tikhonov        if (len >= sizeof(cont_len_buf))
405747be414SDmitri Tikhonov        {
406747be414SDmitri Tikhonov            LSQ_DEBUG("content-length has invalid value `%.*s'",
407747be414SDmitri Tikhonov                                                            (int) len, val);
408747be414SDmitri Tikhonov            cl->has = -1;
409747be414SDmitri Tikhonov            return;
410747be414SDmitri Tikhonov        }
411747be414SDmitri Tikhonov        memcpy(cont_len_buf, val, len);
412747be414SDmitri Tikhonov        cont_len_buf[len] = '\0';
413747be414SDmitri Tikhonov        cl->value = strtoull(cont_len_buf, &endcl, 10);
414747be414SDmitri Tikhonov        if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno))
415747be414SDmitri Tikhonov        {
416747be414SDmitri Tikhonov            cl->has = 1;
417747be414SDmitri Tikhonov            LSQ_DEBUG("content length is %llu", cl->value);
418747be414SDmitri Tikhonov        }
419747be414SDmitri Tikhonov        else
420747be414SDmitri Tikhonov        {
421747be414SDmitri Tikhonov            cl->has = -1;
422747be414SDmitri Tikhonov            LSQ_DEBUG("content-length has invalid value `%.*s'",
423747be414SDmitri Tikhonov                (int) len, val);
424747be414SDmitri Tikhonov        }
425747be414SDmitri Tikhonov    }
426747be414SDmitri Tikhonov    else if (cl->has > 0)
427747be414SDmitri Tikhonov    {
428747be414SDmitri Tikhonov        LSQ_DEBUG("header set has two content-length: ambiguous, "
429747be414SDmitri Tikhonov            "turn off checking");
430747be414SDmitri Tikhonov        cl->has = -1;
431747be414SDmitri Tikhonov    }
432747be414SDmitri Tikhonov}
433747be414SDmitri Tikhonov
434747be414SDmitri Tikhonov
435747be414SDmitri Tikhonovstatic int
436747be414SDmitri Tikhonovis_content_length (const struct lsqpack_header *header)
437747be414SDmitri Tikhonov{
438747be414SDmitri Tikhonov    return ((header->qh_flags & QH_ID_SET) && header->qh_static_id == 4)
439747be414SDmitri Tikhonov        || (header->qh_name_len == 14 && header->qh_name[0] == 'c'
440747be414SDmitri Tikhonov                    && 0 == memcmp(header->qh_name + 1, "ontent-length", 13))
441747be414SDmitri Tikhonov        ;
442747be414SDmitri Tikhonov}
443747be414SDmitri Tikhonov
444747be414SDmitri Tikhonov
4455392f7a3SLiteSpeed Techstatic int
4465392f7a3SLiteSpeed Techqdh_supply_hset_to_stream (struct qpack_dec_hdl *qdh,
4475392f7a3SLiteSpeed Tech            struct lsquic_stream *stream, struct lsqpack_header_list *qlist)
4485392f7a3SLiteSpeed Tech{
4495392f7a3SLiteSpeed Tech    const struct lsquic_hset_if *const hset_if = qdh->qdh_enpub->enp_hsi_if;
4505392f7a3SLiteSpeed Tech    struct uncompressed_headers *uh = NULL;
4515392f7a3SLiteSpeed Tech    const struct lsqpack_header *header;
452a5fa05f9SDmitri Tikhonov    int st;
45302b6086dSDmitri Tikhonov    int push_promise;
4545392f7a3SLiteSpeed Tech    unsigned i;
4555392f7a3SLiteSpeed Tech    void *hset;
456747be414SDmitri Tikhonov    struct cont_len cl;
457a5fa05f9SDmitri Tikhonov    struct lsxpack_header *xhdr;
458a5fa05f9SDmitri Tikhonov    size_t extra;
4595392f7a3SLiteSpeed Tech
46002b6086dSDmitri Tikhonov    push_promise = lsquic_stream_header_is_pp(stream);
46102b6086dSDmitri Tikhonov    hset = hset_if->hsi_create_header_set(qdh->qdh_hsi_ctx, push_promise);
4625392f7a3SLiteSpeed Tech    if (!hset)
4635392f7a3SLiteSpeed Tech    {
4645392f7a3SLiteSpeed Tech        LSQ_INFO("call to hsi_create_header_set failed");
4655392f7a3SLiteSpeed Tech        return -1;
4665392f7a3SLiteSpeed Tech    }
4675392f7a3SLiteSpeed Tech
4685392f7a3SLiteSpeed Tech    LSQ_DEBUG("got header set for stream %"PRIu64, stream->id);
4695392f7a3SLiteSpeed Tech
470747be414SDmitri Tikhonov    cl.has = 0;
4715392f7a3SLiteSpeed Tech    for (i = 0; i < qlist->qhl_count; ++i)
4725392f7a3SLiteSpeed Tech    {
4735392f7a3SLiteSpeed Tech        header = qlist->qhl_headers[i];
4745392f7a3SLiteSpeed Tech        LSQ_DEBUG("%.*s: %.*s", header->qh_name_len, header->qh_name,
4755392f7a3SLiteSpeed Tech                                        header->qh_value_len, header->qh_value);
476a5fa05f9SDmitri Tikhonov        extra = header->qh_name_len + header->qh_value_len + 4;
477a5fa05f9SDmitri Tikhonov        xhdr = hset_if->hsi_prepare_decode(hset, NULL, extra);
478a5fa05f9SDmitri Tikhonov        if (!xhdr)
479a137764bSDmitri Tikhonov        {
480a5fa05f9SDmitri Tikhonov            LSQ_DEBUG("prepare_decode(%zd) failed", extra);
481a5fa05f9SDmitri Tikhonov            goto err;
482a5fa05f9SDmitri Tikhonov        }
483a5fa05f9SDmitri Tikhonov        memcpy(xhdr->buf + xhdr->name_offset, header->qh_name,
484a5fa05f9SDmitri Tikhonov                                                    header->qh_name_len);
485a5fa05f9SDmitri Tikhonov        xhdr->name_len = header->qh_name_len;
486a5fa05f9SDmitri Tikhonov        memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len, ": ", 2);
487a5fa05f9SDmitri Tikhonov        xhdr->val_offset = xhdr->name_offset + xhdr->name_len + 2;
488a5fa05f9SDmitri Tikhonov        memcpy(xhdr->buf + xhdr->val_offset,
489a5fa05f9SDmitri Tikhonov                                    header->qh_value, header->qh_value_len);
490a5fa05f9SDmitri Tikhonov        xhdr->val_len = header->qh_value_len;
491a5fa05f9SDmitri Tikhonov        memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len + 2
492a5fa05f9SDmitri Tikhonov                    + xhdr->val_len, "\r\n", 2);
493a5fa05f9SDmitri Tikhonov        xhdr->dec_overhead = 4;
494a5fa05f9SDmitri Tikhonov        if (header->qh_flags & QH_ID_SET)
495a5fa05f9SDmitri Tikhonov        {
496a5fa05f9SDmitri Tikhonov            xhdr->flags |= LSXPACK_QPACK_IDX;
497a5fa05f9SDmitri Tikhonov            xhdr->qpack_index = header->qh_static_id;
498a5fa05f9SDmitri Tikhonov        }
499a5fa05f9SDmitri Tikhonov        st = hset_if->hsi_process_header(hset, xhdr);
500a5fa05f9SDmitri Tikhonov        if (st != 0)
501a5fa05f9SDmitri Tikhonov        {
502a5fa05f9SDmitri Tikhonov            LSQ_INFO("header process returned non-OK code %d", st);
5035392f7a3SLiteSpeed Tech            goto err;
504a137764bSDmitri Tikhonov        }
505747be414SDmitri Tikhonov        if (is_content_length(header))
506747be414SDmitri Tikhonov            process_content_length(qdh, &cl, header->qh_value,
507747be414SDmitri Tikhonov                                                        header->qh_value_len);
5085392f7a3SLiteSpeed Tech    }
5095392f7a3SLiteSpeed Tech
5105392f7a3SLiteSpeed Tech    lsqpack_dec_destroy_header_list(qlist);
511a0e1aeeeSDmitri Tikhonov    qlist = NULL;
512a5fa05f9SDmitri Tikhonov    st = hset_if->hsi_process_header(hset, NULL);
513a5fa05f9SDmitri Tikhonov    if (st != 0)
5145392f7a3SLiteSpeed Tech        goto err;
5155392f7a3SLiteSpeed Tech
5165392f7a3SLiteSpeed Tech    uh = calloc(1, sizeof(*uh));
5175392f7a3SLiteSpeed Tech    if (!uh)
5185392f7a3SLiteSpeed Tech        goto err;
5195392f7a3SLiteSpeed Tech    uh->uh_stream_id = stream->id;
5205392f7a3SLiteSpeed Tech    uh->uh_oth_stream_id = 0;
5215392f7a3SLiteSpeed Tech    uh->uh_weight = 0;
5225392f7a3SLiteSpeed Tech    uh->uh_exclusive = -1;
5235392f7a3SLiteSpeed Tech    if (hset_if == lsquic_http1x_if)
5245392f7a3SLiteSpeed Tech        uh->uh_flags    |= UH_H1H;
5255392f7a3SLiteSpeed Tech    uh->uh_hset = hset;
5265392f7a3SLiteSpeed Tech    if (0 != lsquic_stream_uh_in(stream, uh))
5275392f7a3SLiteSpeed Tech        goto err;
5285392f7a3SLiteSpeed Tech    LSQ_DEBUG("converted qlist to hset and gave it to stream %"PRIu64,
5295392f7a3SLiteSpeed Tech                                                                stream->id);
530747be414SDmitri Tikhonov    if (cl.has > 0)
531747be414SDmitri Tikhonov        (void) lsquic_stream_verify_len(stream, cl.value);
5325392f7a3SLiteSpeed Tech    return 0;
5335392f7a3SLiteSpeed Tech
5345392f7a3SLiteSpeed Tech  err:
535a0e1aeeeSDmitri Tikhonov    if (qlist)
536a0e1aeeeSDmitri Tikhonov        lsqpack_dec_destroy_header_list(qlist);
5375392f7a3SLiteSpeed Tech    hset_if->hsi_discard_header_set(hset);
5385392f7a3SLiteSpeed Tech    free(uh);
5395392f7a3SLiteSpeed Tech    return -1;
5405392f7a3SLiteSpeed Tech}
5415392f7a3SLiteSpeed Tech
5425392f7a3SLiteSpeed Tech
54310c41073SDmitri Tikhonov/* Releases qlist */
54402b6086dSDmitri Tikhonovstatic int
54502b6086dSDmitri Tikhonovqdh_process_qlist (struct qpack_dec_hdl *qdh,
54602b6086dSDmitri Tikhonov            struct lsquic_stream *stream, struct lsqpack_header_list *qlist)
54702b6086dSDmitri Tikhonov{
54802b6086dSDmitri Tikhonov    if (!lsquic_stream_header_is_trailer(stream))
54902b6086dSDmitri Tikhonov        return qdh_supply_hset_to_stream(qdh, stream, qlist);
55002b6086dSDmitri Tikhonov    else
55102b6086dSDmitri Tikhonov    {
55202b6086dSDmitri Tikhonov        LSQ_DEBUG("discard trailer header set");
55302b6086dSDmitri Tikhonov        lsqpack_dec_destroy_header_list(qlist);
55402b6086dSDmitri Tikhonov        return 0;
55502b6086dSDmitri Tikhonov    }
55602b6086dSDmitri Tikhonov}
55702b6086dSDmitri Tikhonov
55802b6086dSDmitri Tikhonov
5595392f7a3SLiteSpeed Techstatic enum lsqpack_read_header_status
5605392f7a3SLiteSpeed Techqdh_header_read_results (struct qpack_dec_hdl *qdh,
5615392f7a3SLiteSpeed Tech        struct lsquic_stream *stream, enum lsqpack_read_header_status rhs,
5625392f7a3SLiteSpeed Tech        struct lsqpack_header_list *qlist, const unsigned char *dec_buf,
5635392f7a3SLiteSpeed Tech        size_t dec_buf_sz)
5645392f7a3SLiteSpeed Tech{
5655392f7a3SLiteSpeed Tech    const struct lsqpack_dec_err *qerr;
5665392f7a3SLiteSpeed Tech
5675392f7a3SLiteSpeed Tech    if (rhs == LQRHS_DONE)
5685392f7a3SLiteSpeed Tech    {
5695392f7a3SLiteSpeed Tech        if (qlist)
5705392f7a3SLiteSpeed Tech        {
57102b6086dSDmitri Tikhonov            if (0 != qdh_process_qlist(qdh, stream, qlist))
5725392f7a3SLiteSpeed Tech                return LQRHS_ERROR;
5735392f7a3SLiteSpeed Tech            if (qdh->qdh_dec_sm_out)
5745392f7a3SLiteSpeed Tech            {
5755392f7a3SLiteSpeed Tech                if (dec_buf_sz
5765392f7a3SLiteSpeed Tech                    && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz))
5775392f7a3SLiteSpeed Tech                {
5785392f7a3SLiteSpeed Tech                    return LQRHS_ERROR;
5795392f7a3SLiteSpeed Tech                }
5805392f7a3SLiteSpeed Tech                if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder))
5815392f7a3SLiteSpeed Tech                    lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
5825392f7a3SLiteSpeed Tech            }
5835392f7a3SLiteSpeed Tech        }
5845392f7a3SLiteSpeed Tech        else
5855392f7a3SLiteSpeed Tech        {
58610c41073SDmitri Tikhonov            LSQ_WARN("read header status is DONE but header list is not set");
58710c41073SDmitri Tikhonov            assert(0);
5885392f7a3SLiteSpeed Tech            return LQRHS_ERROR;
5895392f7a3SLiteSpeed Tech        }
5905392f7a3SLiteSpeed Tech    }
5915392f7a3SLiteSpeed Tech    else if (rhs == LQRHS_ERROR)
5925392f7a3SLiteSpeed Tech    {
5935392f7a3SLiteSpeed Tech        qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder);
5945392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1,
5955392f7a3SLiteSpeed Tech            HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; "
5965392f7a3SLiteSpeed Tech            "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id,
5975392f7a3SLiteSpeed Tech            qerr->off, qerr->line);
5985392f7a3SLiteSpeed Tech    }
5995392f7a3SLiteSpeed Tech
6005392f7a3SLiteSpeed Tech    return rhs;
6015392f7a3SLiteSpeed Tech}
6025392f7a3SLiteSpeed Tech
6035392f7a3SLiteSpeed Tech
6045392f7a3SLiteSpeed Techenum lsqpack_read_header_status
6055392f7a3SLiteSpeed Techlsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh,
6065392f7a3SLiteSpeed Tech                        struct lsquic_stream *stream, uint64_t header_size,
6075392f7a3SLiteSpeed Tech                        const unsigned char **buf, size_t bufsz)
6085392f7a3SLiteSpeed Tech{
6095392f7a3SLiteSpeed Tech    enum lsqpack_read_header_status rhs;
6105392f7a3SLiteSpeed Tech    struct lsqpack_header_list *qlist;
6115392f7a3SLiteSpeed Tech    size_t dec_buf_sz;
6125392f7a3SLiteSpeed Tech    unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
6135392f7a3SLiteSpeed Tech
6145392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
6155392f7a3SLiteSpeed Tech    {
6165392f7a3SLiteSpeed Tech        dec_buf_sz = sizeof(dec_buf);
6175392f7a3SLiteSpeed Tech        rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id,
6185392f7a3SLiteSpeed Tech                        header_size, buf, bufsz, &qlist, dec_buf, &dec_buf_sz);
6195392f7a3SLiteSpeed Tech        return qdh_header_read_results(qdh, stream, rhs, qlist, dec_buf,
6205392f7a3SLiteSpeed Tech                                                                dec_buf_sz);
6215392f7a3SLiteSpeed Tech    }
6225392f7a3SLiteSpeed Tech    else
6235392f7a3SLiteSpeed Tech    {
6245392f7a3SLiteSpeed Tech        LSQ_WARN("not initialized: cannot process header block");
6255392f7a3SLiteSpeed Tech        return LQRHS_ERROR;
6265392f7a3SLiteSpeed Tech    }
6275392f7a3SLiteSpeed Tech
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    struct lsqpack_header_list *qlist;
6375392f7a3SLiteSpeed Tech    size_t dec_buf_sz;
6385392f7a3SLiteSpeed Tech    unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
6395392f7a3SLiteSpeed Tech
6405392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
6415392f7a3SLiteSpeed Tech    {
6425392f7a3SLiteSpeed Tech        dec_buf_sz = sizeof(dec_buf);
6435392f7a3SLiteSpeed Tech        rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream,
6445392f7a3SLiteSpeed Tech                                    buf, bufsz, &qlist, dec_buf, &dec_buf_sz);
6455392f7a3SLiteSpeed Tech        return qdh_header_read_results(qdh, stream, rhs, qlist, dec_buf,
6465392f7a3SLiteSpeed Tech                                                                dec_buf_sz);
6475392f7a3SLiteSpeed Tech    }
6485392f7a3SLiteSpeed Tech    else
6495392f7a3SLiteSpeed Tech    {
6505392f7a3SLiteSpeed Tech        LSQ_WARN("not initialized: cannot process header block");
6515392f7a3SLiteSpeed Tech        return LQRHS_ERROR;
6525392f7a3SLiteSpeed Tech    }
6535392f7a3SLiteSpeed Tech}
6545392f7a3SLiteSpeed Tech
6555392f7a3SLiteSpeed Tech
6565392f7a3SLiteSpeed Techvoid
6575392f7a3SLiteSpeed Techlsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh,
6585392f7a3SLiteSpeed Tech                                                struct lsquic_stream *stream)
6595392f7a3SLiteSpeed Tech{
6605392f7a3SLiteSpeed Tech    if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream))
6615392f7a3SLiteSpeed Tech        LSQ_DEBUG("unreffed stream %"PRIu64, stream->id);
6625392f7a3SLiteSpeed Tech    else
6635392f7a3SLiteSpeed Tech        LSQ_WARN("cannot unref stream %"PRIu64, stream->id);
6645392f7a3SLiteSpeed Tech}
6655392f7a3SLiteSpeed Tech
6665392f7a3SLiteSpeed Tech
6675392f7a3SLiteSpeed Techvoid
6685392f7a3SLiteSpeed Techlsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh,
6695392f7a3SLiteSpeed Tech                                                struct lsquic_stream *stream)
6705392f7a3SLiteSpeed Tech{
6715392f7a3SLiteSpeed Tech    ssize_t nw;
6725392f7a3SLiteSpeed Tech    unsigned char buf[LSQPACK_LONGEST_CANCEL];
6735392f7a3SLiteSpeed Tech
6745392f7a3SLiteSpeed Tech    nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf));
6755392f7a3SLiteSpeed Tech    if (nw > 0)
6765392f7a3SLiteSpeed Tech    {
6775392f7a3SLiteSpeed Tech        if (0 == qdh_write_decoder(qdh, buf, nw))
6785392f7a3SLiteSpeed Tech            LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel "
6795392f7a3SLiteSpeed Tech                "Stream instruction to the decoder stream", stream->id, nw);
6805392f7a3SLiteSpeed Tech    }
6815392f7a3SLiteSpeed Tech    else if (nw == 0)
6825392f7a3SLiteSpeed Tech        LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id);
6835392f7a3SLiteSpeed Tech    else
6845392f7a3SLiteSpeed Tech    {
6855392f7a3SLiteSpeed Tech        LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space "
6865392f7a3SLiteSpeed Tech            "to encode Cancel Stream instructin", stream->id);
6875392f7a3SLiteSpeed Tech        lsquic_qdh_unref_stream(qdh, stream);
6885392f7a3SLiteSpeed Tech    }
6895392f7a3SLiteSpeed Tech}
690747be414SDmitri Tikhonov
691747be414SDmitri Tikhonov
692747be414SDmitri Tikhonovint
693747be414SDmitri Tikhonovlsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *),
694747be414SDmitri Tikhonov                                                                    void *ctx)
695747be414SDmitri Tikhonov{
696747be414SDmitri Tikhonov    size_t bytes;
697747be414SDmitri Tikhonov
698747be414SDmitri Tikhonov    /* Use size of a single frab list buffer as an arbitrary threshold */
699747be414SDmitri Tikhonov    bytes = lsquic_frab_list_size(&qdh->qdh_fral);
700747be414SDmitri Tikhonov    if (bytes <= qdh->qdh_fral.fl_buf_size)
701747be414SDmitri Tikhonov        return 0;
702747be414SDmitri Tikhonov    else
703747be414SDmitri Tikhonov    {
704747be414SDmitri Tikhonov        LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set "
705747be414SDmitri Tikhonov            "up callback", bytes);
706747be414SDmitri Tikhonov        qdh->qdh_on_dec_sent_func = func;
707747be414SDmitri Tikhonov        qdh->qdh_on_dec_sent_ctx  = ctx;
708747be414SDmitri Tikhonov        return 1;
709747be414SDmitri Tikhonov    }
710747be414SDmitri Tikhonov}
711