1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech/*
35392f7a3SLiteSpeed Tech * lsquic_qenc_hdl.c -- QPACK encoder 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
13fb3e20e0SDmitri Tikhonov#ifdef WIN32
14fb3e20e0SDmitri Tikhonov#include <malloc.h>
15fb3e20e0SDmitri Tikhonov#endif
16fb3e20e0SDmitri Tikhonov
175392f7a3SLiteSpeed Tech#include "lsquic.h"
185392f7a3SLiteSpeed Tech#include "lsquic_types.h"
195392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
205392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h"
215392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
225392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
235392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
245392f7a3SLiteSpeed Tech#include "lsquic_stream.h"
255392f7a3SLiteSpeed Tech#include "lsquic_frab_list.h"
265392f7a3SLiteSpeed Tech#include "lsqpack.h"
2755613f44SDmitri Tikhonov#include "lsxpack_header.h"
285392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
29758aff32SDmitri Tikhonov#include "lsquic_qpack_exp.h"
30758aff32SDmitri Tikhonov#include "lsquic_util.h"
315392f7a3SLiteSpeed Tech#include "lsquic_qenc_hdl.h"
325392f7a3SLiteSpeed Tech
335392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_QENC_HDL
345392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qeh->qeh_conn)
355392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
365392f7a3SLiteSpeed Tech
37a74702c6SGeorge Wang#define QENC_MIN_DYN_TABLE_SIZE 32u
385392f7a3SLiteSpeed Tech
395392f7a3SLiteSpeed Techstatic int
405392f7a3SLiteSpeed Techqeh_write_type (struct qpack_enc_hdl *qeh)
415392f7a3SLiteSpeed Tech{
425392f7a3SLiteSpeed Tech    int s;
435392f7a3SLiteSpeed Tech
445392f7a3SLiteSpeed Tech#ifndef NDEBUG
455392f7a3SLiteSpeed Tech    const char *env = getenv("LSQUIC_RND_VARINT_LEN");
465392f7a3SLiteSpeed Tech    if (env && atoi(env))
475392f7a3SLiteSpeed Tech    {
485392f7a3SLiteSpeed Tech        s = rand() & 3;
495392f7a3SLiteSpeed Tech        LSQ_DEBUG("writing %d-byte stream type", 1 << s);
505392f7a3SLiteSpeed Tech    }
515392f7a3SLiteSpeed Tech    else
525392f7a3SLiteSpeed Tech#endif
535392f7a3SLiteSpeed Tech        s = 0;
545392f7a3SLiteSpeed Tech
555392f7a3SLiteSpeed Tech    switch (s)
565392f7a3SLiteSpeed Tech    {
575392f7a3SLiteSpeed Tech    case 0:
585392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
595392f7a3SLiteSpeed Tech                                (unsigned char []) { HQUST_QPACK_ENC }, 1);
605392f7a3SLiteSpeed Tech    case 1:
615392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
625392f7a3SLiteSpeed Tech                            (unsigned char []) { 0x40, HQUST_QPACK_ENC }, 2);
635392f7a3SLiteSpeed Tech    case 2:
645392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
655392f7a3SLiteSpeed Tech                (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_ENC }, 4);
665392f7a3SLiteSpeed Tech    default:
675392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
685392f7a3SLiteSpeed Tech                (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695392f7a3SLiteSpeed Tech                                                        HQUST_QPACK_ENC }, 8);
705392f7a3SLiteSpeed Tech    }
715392f7a3SLiteSpeed Tech}
725392f7a3SLiteSpeed Tech
735392f7a3SLiteSpeed Tech
745392f7a3SLiteSpeed Techstatic void
755392f7a3SLiteSpeed Techqeh_begin_out (struct qpack_enc_hdl *qeh)
765392f7a3SLiteSpeed Tech{
775392f7a3SLiteSpeed Tech    if (0 == qeh_write_type(qeh)
785392f7a3SLiteSpeed Tech        && (qeh->qeh_tsu_sz == 0
795392f7a3SLiteSpeed Tech            || 0 == lsquic_frab_list_write(&qeh->qeh_fral, qeh->qeh_tsu_buf,
805392f7a3SLiteSpeed Tech                                                            qeh->qeh_tsu_sz)))
815392f7a3SLiteSpeed Tech    {
825392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zu bytes to frab list", 1 + qeh->qeh_tsu_sz);
835392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(qeh->qeh_enc_sm_out, 1);
845392f7a3SLiteSpeed Tech    }
855392f7a3SLiteSpeed Tech    else
865392f7a3SLiteSpeed Tech    {
875392f7a3SLiteSpeed Tech        LSQ_WARN("could not write to frab list");
885392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
895392f7a3SLiteSpeed Tech                                            "cannot write to frab list");
905392f7a3SLiteSpeed Tech    }
915392f7a3SLiteSpeed Tech}
925392f7a3SLiteSpeed Tech
935392f7a3SLiteSpeed Tech
945392f7a3SLiteSpeed Techvoid
955392f7a3SLiteSpeed Techlsquic_qeh_init (struct qpack_enc_hdl *qeh, struct lsquic_conn *conn)
965392f7a3SLiteSpeed Tech{
975392f7a3SLiteSpeed Tech    assert(!(qeh->qeh_flags & QEH_INITIALIZED));
985392f7a3SLiteSpeed Tech    qeh->qeh_conn = conn;
995392f7a3SLiteSpeed Tech    lsquic_frab_list_init(&qeh->qeh_fral, 0x400, NULL, NULL, NULL);
1005392f7a3SLiteSpeed Tech    lsqpack_enc_preinit(&qeh->qeh_encoder, (void *) conn);
1015392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_INITIALIZED;
1025392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1035392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1045392f7a3SLiteSpeed Tech    if (qeh->qeh_dec_sm_in)
1055392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
1065392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
1075392f7a3SLiteSpeed Tech}
1085392f7a3SLiteSpeed Tech
1095392f7a3SLiteSpeed Tech
1105392f7a3SLiteSpeed Techint
1115392f7a3SLiteSpeed Techlsquic_qeh_settings (struct qpack_enc_hdl *qeh, unsigned max_table_size,
1125392f7a3SLiteSpeed Tech             unsigned dyn_table_size, unsigned max_risked_streams, int server)
1135392f7a3SLiteSpeed Tech{
1145392f7a3SLiteSpeed Tech    enum lsqpack_enc_opts enc_opts;
1155392f7a3SLiteSpeed Tech
1165392f7a3SLiteSpeed Tech    assert(qeh->qeh_flags & QEH_INITIALIZED);
1175392f7a3SLiteSpeed Tech
1185392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
1195392f7a3SLiteSpeed Tech    {
1205392f7a3SLiteSpeed Tech        LSQ_WARN("settings already set");
1215392f7a3SLiteSpeed Tech        return -1;
1225392f7a3SLiteSpeed Tech    }
1235392f7a3SLiteSpeed Tech
1245392f7a3SLiteSpeed Tech    enc_opts = LSQPACK_ENC_OPT_STAGE_2
125a0e1aeeeSDmitri Tikhonov             | (server ? LSQPACK_ENC_OPT_SERVER : 0);
1265392f7a3SLiteSpeed Tech    qeh->qeh_tsu_sz = sizeof(qeh->qeh_tsu_buf);
127a74702c6SGeorge Wang    if (QENC_MIN_DYN_TABLE_SIZE > dyn_table_size)
128a74702c6SGeorge Wang        dyn_table_size = 0;
1295392f7a3SLiteSpeed Tech    if (0 != lsqpack_enc_init(&qeh->qeh_encoder, (void *) qeh->qeh_conn,
1305392f7a3SLiteSpeed Tech                max_table_size, dyn_table_size, max_risked_streams, enc_opts,
1315392f7a3SLiteSpeed Tech                qeh->qeh_tsu_buf, &qeh->qeh_tsu_sz))
1325392f7a3SLiteSpeed Tech    {
1335392f7a3SLiteSpeed Tech        LSQ_INFO("could not initialize QPACK encoder");
1345392f7a3SLiteSpeed Tech        return -1;
1355392f7a3SLiteSpeed Tech    }
1365392f7a3SLiteSpeed Tech    LSQ_DEBUG("%zu-byte post-init TSU", qeh->qeh_tsu_sz);
1375392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_HAVE_SETTINGS;
1385392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1395392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1405392f7a3SLiteSpeed Tech    LSQ_DEBUG("have settings: max table size=%u; dyn table size=%u; max risked "
1415392f7a3SLiteSpeed Tech        "streams=%u", max_table_size, dyn_table_size, max_risked_streams);
1425392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
1435392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1445392f7a3SLiteSpeed Tech    return 0;
1455392f7a3SLiteSpeed Tech}
1465392f7a3SLiteSpeed Tech
1475392f7a3SLiteSpeed Tech
148758aff32SDmitri Tikhonovstatic void
149758aff32SDmitri Tikhonovqeh_log_and_clean_exp_rec (struct qpack_enc_hdl *qeh)
150758aff32SDmitri Tikhonov{
151758aff32SDmitri Tikhonov    char buf[0x400];
152758aff32SDmitri Tikhonov
153758aff32SDmitri Tikhonov    qeh->qeh_exp_rec->qer_comp_ratio = lsqpack_enc_ratio(&qeh->qeh_encoder);
154758aff32SDmitri Tikhonov    (void) lsquic_qpack_exp_to_xml(qeh->qeh_exp_rec, buf, sizeof(buf));
155758aff32SDmitri Tikhonov    LSQ_NOTICE("%s", buf);
156758aff32SDmitri Tikhonov    lsquic_qpack_exp_destroy(qeh->qeh_exp_rec);
157758aff32SDmitri Tikhonov    qeh->qeh_exp_rec = NULL;
158758aff32SDmitri Tikhonov}
159758aff32SDmitri Tikhonov
160758aff32SDmitri Tikhonov
1615392f7a3SLiteSpeed Techvoid
1625392f7a3SLiteSpeed Techlsquic_qeh_cleanup (struct qpack_enc_hdl *qeh)
1635392f7a3SLiteSpeed Tech{
1645392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
1655392f7a3SLiteSpeed Tech    {
1665392f7a3SLiteSpeed Tech        LSQ_DEBUG("cleanup");
167758aff32SDmitri Tikhonov        if (qeh->qeh_exp_rec)
168758aff32SDmitri Tikhonov            qeh_log_and_clean_exp_rec(qeh);
1695392f7a3SLiteSpeed Tech        lsqpack_enc_cleanup(&qeh->qeh_encoder);
1705392f7a3SLiteSpeed Tech        lsquic_frab_list_cleanup(&qeh->qeh_fral);
1715392f7a3SLiteSpeed Tech        memset(qeh, 0, sizeof(*qeh));
1725392f7a3SLiteSpeed Tech    }
1735392f7a3SLiteSpeed Tech}
1745392f7a3SLiteSpeed Tech
1755392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
1765392f7a3SLiteSpeed Techqeh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
1775392f7a3SLiteSpeed Tech{
1785392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
1795392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = stream;
1805392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1815392f7a3SLiteSpeed Tech                                    == (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1825392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1835392f7a3SLiteSpeed Tech    else
1845392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
1855392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized outgoing encoder stream");
1865392f7a3SLiteSpeed Tech    return (void *) qeh;
1875392f7a3SLiteSpeed Tech}
1885392f7a3SLiteSpeed Tech
1895392f7a3SLiteSpeed Tech
1905392f7a3SLiteSpeed Techstatic void
1915392f7a3SLiteSpeed Techqeh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1925392f7a3SLiteSpeed Tech{
1935392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1945392f7a3SLiteSpeed Tech    struct lsquic_reader reader = {
1955392f7a3SLiteSpeed Tech        .lsqr_read  = lsquic_frab_list_read,
1965392f7a3SLiteSpeed Tech        .lsqr_size  = lsquic_frab_list_size,
1975392f7a3SLiteSpeed Tech        .lsqr_ctx   = &qeh->qeh_fral,
1985392f7a3SLiteSpeed Tech    };
1995392f7a3SLiteSpeed Tech    ssize_t nw;
2005392f7a3SLiteSpeed Tech
2015392f7a3SLiteSpeed Tech    nw = lsquic_stream_writef(stream, &reader);
2025392f7a3SLiteSpeed Tech    if (nw >= 0)
2035392f7a3SLiteSpeed Tech    {
2045392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zd bytes to stream", nw);
2055392f7a3SLiteSpeed Tech        (void) lsquic_stream_flush(stream);
2065392f7a3SLiteSpeed Tech        if (lsquic_frab_list_empty(&qeh->qeh_fral))
2075392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(stream, 0);
2085392f7a3SLiteSpeed Tech    }
2095392f7a3SLiteSpeed Tech    else
2105392f7a3SLiteSpeed Tech    {
2115392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
2125392f7a3SLiteSpeed Tech                                            "cannot write to stream");
2135392f7a3SLiteSpeed Tech        LSQ_WARN("cannot write to stream: %s", strerror(errno));
2145392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
2155392f7a3SLiteSpeed Tech    }
2165392f7a3SLiteSpeed Tech}
2175392f7a3SLiteSpeed Tech
2185392f7a3SLiteSpeed Tech
2195392f7a3SLiteSpeed Techstatic void
2205392f7a3SLiteSpeed Techqeh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2215392f7a3SLiteSpeed Tech{
2225392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2235392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = NULL;
2245392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed outgoing encoder stream");
2255392f7a3SLiteSpeed Tech}
2265392f7a3SLiteSpeed Tech
2275392f7a3SLiteSpeed Tech
2285392f7a3SLiteSpeed Techstatic void
2295392f7a3SLiteSpeed Techqeh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2305392f7a3SLiteSpeed Tech{
2315392f7a3SLiteSpeed Tech    assert(0);
2325392f7a3SLiteSpeed Tech}
2335392f7a3SLiteSpeed Tech
2345392f7a3SLiteSpeed Tech
2355392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_enc_sm_out_if =
2365392f7a3SLiteSpeed Tech{
2375392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_out_on_new,
2385392f7a3SLiteSpeed Tech    .on_read        = qeh_out_on_read,
2395392f7a3SLiteSpeed Tech    .on_write       = qeh_out_on_write,
2405392f7a3SLiteSpeed Tech    .on_close       = qeh_out_on_close,
2415392f7a3SLiteSpeed Tech};
2425392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_enc_sm_out_if =
2435392f7a3SLiteSpeed Tech                                                    &qeh_enc_sm_out_if;
2445392f7a3SLiteSpeed Tech
2455392f7a3SLiteSpeed Tech
2465392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
2475392f7a3SLiteSpeed Techqeh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
2485392f7a3SLiteSpeed Tech{
2495392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
2505392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = stream;
2515392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
2525392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
2535392f7a3SLiteSpeed Tech    else
2545392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
2555392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized incoming decoder stream");
2565392f7a3SLiteSpeed Tech    return (void *) qeh;
2575392f7a3SLiteSpeed Tech}
2585392f7a3SLiteSpeed Tech
2595392f7a3SLiteSpeed Tech
2605392f7a3SLiteSpeed Techstatic size_t
2615392f7a3SLiteSpeed Techqeh_read_decoder_stream (void *ctx, const unsigned char *buf, size_t sz,
2625392f7a3SLiteSpeed Tech                                                                    int fin)
2635392f7a3SLiteSpeed Tech{
2645392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2655392f7a3SLiteSpeed Tech    uint64_t offset;
2665392f7a3SLiteSpeed Tech    int s;
2675392f7a3SLiteSpeed Tech
2685392f7a3SLiteSpeed Tech    if (fin)
2695392f7a3SLiteSpeed Tech    {
2705392f7a3SLiteSpeed Tech        LSQ_INFO("decoder stream is closed");
2715392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2725392f7a3SLiteSpeed Tech            HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK decoder stream");
2735392f7a3SLiteSpeed Tech        goto end;
2745392f7a3SLiteSpeed Tech    }
2755392f7a3SLiteSpeed Tech
2765392f7a3SLiteSpeed Tech    offset = lsquic_stream_read_offset(qeh->qeh_dec_sm_in);
2775392f7a3SLiteSpeed Tech    s = lsqpack_enc_decoder_in(&qeh->qeh_encoder, buf, sz);
2785392f7a3SLiteSpeed Tech    if (s != 0)
2795392f7a3SLiteSpeed Tech    {
2805392f7a3SLiteSpeed Tech        LSQ_INFO("error reading decoder stream");
2815392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2825392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK decoder "
2835392f7a3SLiteSpeed Tech            "stream at offset %"PRIu64, offset);
2845392f7a3SLiteSpeed Tech        goto end;
2855392f7a3SLiteSpeed Tech    }
2865392f7a3SLiteSpeed Tech    LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz);
2875392f7a3SLiteSpeed Tech
2885392f7a3SLiteSpeed Tech  end:
2895392f7a3SLiteSpeed Tech    return sz;
2905392f7a3SLiteSpeed Tech}
2915392f7a3SLiteSpeed Tech
2925392f7a3SLiteSpeed Tech
2935392f7a3SLiteSpeed Techstatic void
2945392f7a3SLiteSpeed Techqeh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2955392f7a3SLiteSpeed Tech{
2965392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2975392f7a3SLiteSpeed Tech    ssize_t nread;
2985392f7a3SLiteSpeed Tech
2995392f7a3SLiteSpeed Tech    nread = lsquic_stream_readf(stream, qeh_read_decoder_stream, qeh);
3005392f7a3SLiteSpeed Tech    if (nread <= 0)
3015392f7a3SLiteSpeed Tech    {
3025392f7a3SLiteSpeed Tech        if (nread < 0)
3035392f7a3SLiteSpeed Tech        {
3045392f7a3SLiteSpeed Tech            LSQ_WARN("cannot read from encoder stream: %s", strerror(errno));
3055392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
3065392f7a3SLiteSpeed Tech                                        "cannot read from encoder stream");
3075392f7a3SLiteSpeed Tech        }
3085392f7a3SLiteSpeed Tech        else
3095392f7a3SLiteSpeed Tech        {
3105392f7a3SLiteSpeed Tech            LSQ_INFO("encoder stream closed by peer: abort connection");
3115392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
3125392f7a3SLiteSpeed Tech                HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed");
3135392f7a3SLiteSpeed Tech        }
3145392f7a3SLiteSpeed Tech        lsquic_stream_wantread(stream, 0);
3155392f7a3SLiteSpeed Tech    }
3165392f7a3SLiteSpeed Tech}
3175392f7a3SLiteSpeed Tech
3185392f7a3SLiteSpeed Tech
3195392f7a3SLiteSpeed Techstatic void
3205392f7a3SLiteSpeed Techqeh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3215392f7a3SLiteSpeed Tech{
3225392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
3235392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed incoming decoder stream");
3245392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = NULL;
3255392f7a3SLiteSpeed Tech}
3265392f7a3SLiteSpeed Tech
3275392f7a3SLiteSpeed Tech
3285392f7a3SLiteSpeed Techstatic void
3295392f7a3SLiteSpeed Techqeh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3305392f7a3SLiteSpeed Tech{
3315392f7a3SLiteSpeed Tech    assert(0);
3325392f7a3SLiteSpeed Tech}
3335392f7a3SLiteSpeed Tech
3345392f7a3SLiteSpeed Tech
3355392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_dec_sm_in_if =
3365392f7a3SLiteSpeed Tech{
3375392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_in_on_new,
3385392f7a3SLiteSpeed Tech    .on_read        = qeh_in_on_read,
3395392f7a3SLiteSpeed Tech    .on_write       = qeh_in_on_write,
3405392f7a3SLiteSpeed Tech    .on_close       = qeh_in_on_close,
3415392f7a3SLiteSpeed Tech};
3425392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_dec_sm_in_if =
3435392f7a3SLiteSpeed Tech                                                    &qeh_dec_sm_in_if;
3445392f7a3SLiteSpeed Tech
3455392f7a3SLiteSpeed Tech
346758aff32SDmitri Tikhonovstatic void
347758aff32SDmitri Tikhonovqeh_maybe_set_user_agent (struct qpack_enc_hdl *qeh,
348758aff32SDmitri Tikhonov                                    const struct lsquic_http_headers *headers)
349758aff32SDmitri Tikhonov{
350758aff32SDmitri Tikhonov    const char *const name = qeh->qeh_exp_rec->qer_flags & QER_SERVER ?
351758aff32SDmitri Tikhonov                                    "server" : "user-agent";
352758aff32SDmitri Tikhonov    const size_t len = qeh->qeh_exp_rec->qer_flags & QER_SERVER ? 6 : 10;
353758aff32SDmitri Tikhonov    int i;
354758aff32SDmitri Tikhonov
355758aff32SDmitri Tikhonov    for (i = 0; i < headers->count; ++i)
356758aff32SDmitri Tikhonov        if (len == headers->headers[i].name_len
357758aff32SDmitri Tikhonov                && 0 == memcmp(name,
358758aff32SDmitri Tikhonov                        lsxpack_header_get_name(&headers->headers[i]), len))
359758aff32SDmitri Tikhonov        {
360758aff32SDmitri Tikhonov            qeh->qeh_exp_rec->qer_user_agent = strndup(
361758aff32SDmitri Tikhonov                            lsxpack_header_get_value(&headers->headers[i]),
362758aff32SDmitri Tikhonov                            headers->headers[i].val_len);
363758aff32SDmitri Tikhonov            break;
364758aff32SDmitri Tikhonov        }
365758aff32SDmitri Tikhonov}
366758aff32SDmitri Tikhonov
367758aff32SDmitri Tikhonov
3685392f7a3SLiteSpeed Techstatic enum qwh_status
3695392f7a3SLiteSpeed Techqeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
3705392f7a3SLiteSpeed Tech    unsigned seqno, const struct lsquic_http_headers *headers,
3715392f7a3SLiteSpeed Tech    unsigned char *buf, size_t *prefix_sz, size_t *headers_sz,
3724947ba95SDmitri Tikhonov    uint64_t *completion_offset, enum lsqpack_enc_header_flags *hflags)
3735392f7a3SLiteSpeed Tech{
3745392f7a3SLiteSpeed Tech    unsigned char *p = buf;
3755392f7a3SLiteSpeed Tech    unsigned char *const end = buf + *headers_sz;
3765392f7a3SLiteSpeed Tech    const unsigned char *enc_p;
3775392f7a3SLiteSpeed Tech    size_t enc_sz, hea_sz, total_enc_sz;
3785392f7a3SLiteSpeed Tech    ssize_t nw;
3795392f7a3SLiteSpeed Tech    enum lsqpack_enc_status st;
3805392f7a3SLiteSpeed Tech    int i, s, write_to_stream;
3815392f7a3SLiteSpeed Tech    enum lsqpack_enc_flags enc_flags;
382fb3e20e0SDmitri Tikhonov    enum qwh_status retval;
383fb3e20e0SDmitri Tikhonov#ifndef WIN32
3845392f7a3SLiteSpeed Tech    unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ];
385fb3e20e0SDmitri Tikhonov#else
386fb3e20e0SDmitri Tikhonov    unsigned char *enc_buf;
387fb3e20e0SDmitri Tikhonov    enc_buf = _malloca(qeh->qeh_encoder.qpe_cur_max_capacity * 2);
388fb3e20e0SDmitri Tikhonov    if (!enc_buf)
389fb3e20e0SDmitri Tikhonov        return QWH_ERR;
390fb3e20e0SDmitri Tikhonov#endif
3915392f7a3SLiteSpeed Tech
392758aff32SDmitri Tikhonov    if (qeh->qeh_exp_rec)
393758aff32SDmitri Tikhonov    {
394758aff32SDmitri Tikhonov        const lsquic_time_t now = lsquic_time_now();
395758aff32SDmitri Tikhonov        if (qeh->qeh_exp_rec->qer_hblock_count == 0)
396758aff32SDmitri Tikhonov            qeh->qeh_exp_rec->qer_first_req = now;
397758aff32SDmitri Tikhonov        qeh->qeh_exp_rec->qer_last_req = now;
398758aff32SDmitri Tikhonov        ++qeh->qeh_exp_rec->qer_hblock_count;
399758aff32SDmitri Tikhonov        if (!qeh->qeh_exp_rec->qer_user_agent)
400758aff32SDmitri Tikhonov            qeh_maybe_set_user_agent(qeh, headers);
401758aff32SDmitri Tikhonov    }
402758aff32SDmitri Tikhonov
4035392f7a3SLiteSpeed Tech    s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0);
4045392f7a3SLiteSpeed Tech    if (s != 0)
4055392f7a3SLiteSpeed Tech    {
4065392f7a3SLiteSpeed Tech        LSQ_WARN("cannot start header");
407fb3e20e0SDmitri Tikhonov        retval = QWH_ERR;
408fb3e20e0SDmitri Tikhonov        goto end;
4095392f7a3SLiteSpeed Tech    }
4105392f7a3SLiteSpeed Tech    LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id);
4115392f7a3SLiteSpeed Tech
4125392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
4135392f7a3SLiteSpeed Tech        enc_flags = 0;
4145392f7a3SLiteSpeed Tech    else
4155392f7a3SLiteSpeed Tech    {
4165392f7a3SLiteSpeed Tech        enc_flags = LQEF_NO_INDEX;
4175392f7a3SLiteSpeed Tech        LSQ_DEBUG("encoder stream is unavailable, won't index headers");
4185392f7a3SLiteSpeed Tech    }
4195392f7a3SLiteSpeed Tech    write_to_stream = qeh->qeh_enc_sm_out
4205392f7a3SLiteSpeed Tech                                && lsquic_frab_list_empty(&qeh->qeh_fral);
4215392f7a3SLiteSpeed Tech    total_enc_sz = 0;
4225392f7a3SLiteSpeed Tech    for (i = 0; i < headers->count; ++i)
4235392f7a3SLiteSpeed Tech    {
42455613f44SDmitri Tikhonov        if (headers->headers[i].buf == NULL)
42555613f44SDmitri Tikhonov            continue;
4265392f7a3SLiteSpeed Tech        enc_sz = sizeof(enc_buf);
4275392f7a3SLiteSpeed Tech        hea_sz = end - p;
4285392f7a3SLiteSpeed Tech        st = lsqpack_enc_encode(&qeh->qeh_encoder, enc_buf, &enc_sz, p,
42955613f44SDmitri Tikhonov                                &hea_sz, &headers->headers[i], enc_flags);
4305392f7a3SLiteSpeed Tech        switch (st)
4315392f7a3SLiteSpeed Tech        {
4325392f7a3SLiteSpeed Tech        case LQES_OK:
4335392f7a3SLiteSpeed Tech            LSQ_DEBUG("encoded `%.*s': `%.*s' -- %zd bytes to header block, "
4345392f7a3SLiteSpeed Tech                "%zd bytes to encoder stream",
43555613f44SDmitri Tikhonov                (int) headers->headers[i].name_len,
43655613f44SDmitri Tikhonov                    lsxpack_header_get_name(&headers->headers[i]),
43755613f44SDmitri Tikhonov                (int) headers->headers[i].val_len,
43855613f44SDmitri Tikhonov                    lsxpack_header_get_value(&headers->headers[i]),
4395392f7a3SLiteSpeed Tech                hea_sz, enc_sz);
4405392f7a3SLiteSpeed Tech            total_enc_sz += enc_sz;
4415392f7a3SLiteSpeed Tech            p += hea_sz;
4425392f7a3SLiteSpeed Tech            if (enc_sz)
4435392f7a3SLiteSpeed Tech            {
4445392f7a3SLiteSpeed Tech                if (write_to_stream)
4455392f7a3SLiteSpeed Tech                {
4465392f7a3SLiteSpeed Tech                    nw = lsquic_stream_write(qeh->qeh_enc_sm_out, enc_buf, enc_sz);
4475392f7a3SLiteSpeed Tech                    if ((size_t) nw == enc_sz)
4485392f7a3SLiteSpeed Tech                        break;
4495392f7a3SLiteSpeed Tech                    if (nw < 0)
4505392f7a3SLiteSpeed Tech                    {
4515392f7a3SLiteSpeed Tech                        LSQ_INFO("could not write to encoder stream: %s",
4525392f7a3SLiteSpeed Tech                                                                strerror(errno));
453fb3e20e0SDmitri Tikhonov                        retval = QWH_ERR;
454fb3e20e0SDmitri Tikhonov                        goto end;
4555392f7a3SLiteSpeed Tech                    }
4565392f7a3SLiteSpeed Tech                    write_to_stream = 0;
4575392f7a3SLiteSpeed Tech                    enc_p = enc_buf + (size_t) nw;
4585392f7a3SLiteSpeed Tech                    enc_sz -= (size_t) nw;
4595392f7a3SLiteSpeed Tech                }
4605392f7a3SLiteSpeed Tech                else
4615392f7a3SLiteSpeed Tech                    enc_p = enc_buf;
4625392f7a3SLiteSpeed Tech                if (0 != lsquic_frab_list_write(&qeh->qeh_fral, enc_p, enc_sz))
4635392f7a3SLiteSpeed Tech                {
4645392f7a3SLiteSpeed Tech                    LSQ_INFO("could not write to frab list");
465fb3e20e0SDmitri Tikhonov                    retval = QWH_ERR;
466fb3e20e0SDmitri Tikhonov                    goto end;
4675392f7a3SLiteSpeed Tech                }
4685392f7a3SLiteSpeed Tech            }
4695392f7a3SLiteSpeed Tech            break;
4705392f7a3SLiteSpeed Tech        case LQES_NOBUF_HEAD:
471fb3e20e0SDmitri Tikhonov            retval = QWH_ENOBUF;
472fb3e20e0SDmitri Tikhonov            goto end;
4735392f7a3SLiteSpeed Tech        default:
4745392f7a3SLiteSpeed Tech            assert(0);
475fb3e20e0SDmitri Tikhonov            retval = QWH_ERR;
476fb3e20e0SDmitri Tikhonov            goto end;
4775392f7a3SLiteSpeed Tech        case LQES_NOBUF_ENC:
4785392f7a3SLiteSpeed Tech            LSQ_DEBUG("not enough room to write encoder stream data");
479fb3e20e0SDmitri Tikhonov            retval = QWH_ERR;
480fb3e20e0SDmitri Tikhonov            goto end;
4815392f7a3SLiteSpeed Tech        }
4825392f7a3SLiteSpeed Tech    }
4835392f7a3SLiteSpeed Tech
4844947ba95SDmitri Tikhonov    nw = lsqpack_enc_end_header(&qeh->qeh_encoder, buf - *prefix_sz,
4854947ba95SDmitri Tikhonov                                                        *prefix_sz, hflags);
4865392f7a3SLiteSpeed Tech    if (nw <= 0)
4875392f7a3SLiteSpeed Tech    {
4885392f7a3SLiteSpeed Tech        LSQ_WARN("could not end header: %zd", nw);
489fb3e20e0SDmitri Tikhonov        retval = QWH_ERR;
490fb3e20e0SDmitri Tikhonov        goto end;
4915392f7a3SLiteSpeed Tech    }
4925392f7a3SLiteSpeed Tech
4935392f7a3SLiteSpeed Tech    if ((size_t) nw < *prefix_sz)
4945392f7a3SLiteSpeed Tech    {
4955392f7a3SLiteSpeed Tech        memmove(buf - nw, buf - *prefix_sz, (size_t) nw);
4965392f7a3SLiteSpeed Tech        *prefix_sz = (size_t) nw;
4975392f7a3SLiteSpeed Tech    }
4985392f7a3SLiteSpeed Tech    *headers_sz = p - buf;
499758aff32SDmitri Tikhonov    if (qeh->qeh_exp_rec)
500758aff32SDmitri Tikhonov        qeh->qeh_exp_rec->qer_hblock_size += p - buf;
5015392f7a3SLiteSpeed Tech    if (lsquic_frab_list_empty(&qeh->qeh_fral))
5025392f7a3SLiteSpeed Tech    {
5035392f7a3SLiteSpeed Tech        LSQ_DEBUG("all %zd bytes of encoder stream written out; header block "
5045392f7a3SLiteSpeed Tech            "is %zd bytes; estimated compression ratio %.3f", total_enc_sz,
5055392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
506fb3e20e0SDmitri Tikhonov        retval = QWH_FULL;
507fb3e20e0SDmitri Tikhonov        goto end;
5085392f7a3SLiteSpeed Tech    }
5095392f7a3SLiteSpeed Tech    else
5105392f7a3SLiteSpeed Tech    {
5115392f7a3SLiteSpeed Tech        *completion_offset = lsquic_qeh_enc_off(qeh)
5125392f7a3SLiteSpeed Tech                                    + lsquic_frab_list_size(&qeh->qeh_fral);
5135392f7a3SLiteSpeed Tech        LSQ_DEBUG("not all %zd bytes of encoder stream written out; %zd bytes "
5145392f7a3SLiteSpeed Tech            "buffered; header block is %zd bytes; estimated compression ratio "
5155392f7a3SLiteSpeed Tech            "%.3f", total_enc_sz, lsquic_frab_list_size(&qeh->qeh_fral),
5165392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
517fb3e20e0SDmitri Tikhonov        retval = QWH_PARTIAL;
518fb3e20e0SDmitri Tikhonov        goto end;
5195392f7a3SLiteSpeed Tech    }
520fb3e20e0SDmitri Tikhonov
521fb3e20e0SDmitri Tikhonov  end:
522fb3e20e0SDmitri Tikhonov#ifdef WIN32
523fb3e20e0SDmitri Tikhonov    _freea(enc_buf);
524fb3e20e0SDmitri Tikhonov#endif
525fb3e20e0SDmitri Tikhonov    return retval;
5265392f7a3SLiteSpeed Tech}
5275392f7a3SLiteSpeed Tech
5285392f7a3SLiteSpeed Tech
5295392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
5305392f7a3SLiteSpeed Tech__attribute__((weak))
5315392f7a3SLiteSpeed Tech#endif
5325392f7a3SLiteSpeed Techenum qwh_status
5335392f7a3SLiteSpeed Techlsquic_qeh_write_headers (struct qpack_enc_hdl *qeh,
5345392f7a3SLiteSpeed Tech    lsquic_stream_id_t stream_id, unsigned seqno,
5355392f7a3SLiteSpeed Tech    const struct lsquic_http_headers *headers, unsigned char *buf,
5364947ba95SDmitri Tikhonov    size_t *prefix_sz, size_t *headers_sz, uint64_t *completion_offset,
5374947ba95SDmitri Tikhonov    enum lsqpack_enc_header_flags *hflags)
5385392f7a3SLiteSpeed Tech{
5395392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
5405392f7a3SLiteSpeed Tech        return qeh_write_headers(qeh, stream_id, seqno, headers, buf,
5414947ba95SDmitri Tikhonov                        prefix_sz, headers_sz, completion_offset, hflags);
5425392f7a3SLiteSpeed Tech    else
5435392f7a3SLiteSpeed Tech        return QWH_ERR;
5445392f7a3SLiteSpeed Tech}
5455392f7a3SLiteSpeed Tech
5465392f7a3SLiteSpeed Tech
5475392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
5485392f7a3SLiteSpeed Tech__attribute__((weak))
5495392f7a3SLiteSpeed Tech#endif
5505392f7a3SLiteSpeed Techuint64_t
5515392f7a3SLiteSpeed Techlsquic_qeh_enc_off (struct qpack_enc_hdl *qeh)
5525392f7a3SLiteSpeed Tech{
5535392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
5545392f7a3SLiteSpeed Tech        return qeh->qeh_enc_sm_out->tosend_off;
5555392f7a3SLiteSpeed Tech    else
5565392f7a3SLiteSpeed Tech        return 0;
5575392f7a3SLiteSpeed Tech}
5585392f7a3SLiteSpeed Tech
5595392f7a3SLiteSpeed Tech
5605392f7a3SLiteSpeed Techsize_t
5615392f7a3SLiteSpeed Techlsquic_qeh_write_avail (struct qpack_enc_hdl *qeh)
5625392f7a3SLiteSpeed Tech{
5635392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & QEH_INITIALIZED) && qeh->qeh_enc_sm_out)
5645392f7a3SLiteSpeed Tech        return lsquic_stream_write_avail(qeh->qeh_enc_sm_out);
5655392f7a3SLiteSpeed Tech    else if (qeh->qeh_flags & QEH_INITIALIZED)
5665392f7a3SLiteSpeed Tech        return ~((size_t) 0);   /* Unlimited write */
5675392f7a3SLiteSpeed Tech    else
5685392f7a3SLiteSpeed Tech        return 0;
5695392f7a3SLiteSpeed Tech}
5705392f7a3SLiteSpeed Tech
5715392f7a3SLiteSpeed Tech
5725392f7a3SLiteSpeed Techsize_t
5735392f7a3SLiteSpeed Techlsquic_qeh_max_prefix_size (const struct qpack_enc_hdl *qeh)
5745392f7a3SLiteSpeed Tech{
5755392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
5765392f7a3SLiteSpeed Tech        return qeh->qeh_max_prefix_size;
5775392f7a3SLiteSpeed Tech    else
5785392f7a3SLiteSpeed Tech        return LSQPACK_UINT64_ENC_SZ * 2;
5795392f7a3SLiteSpeed Tech}
580