lsquic_qenc_hdl.c revision 758aff32
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 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
375392f7a3SLiteSpeed Tech
385392f7a3SLiteSpeed Techstatic int
395392f7a3SLiteSpeed Techqeh_write_type (struct qpack_enc_hdl *qeh)
405392f7a3SLiteSpeed Tech{
415392f7a3SLiteSpeed Tech    int s;
425392f7a3SLiteSpeed Tech
435392f7a3SLiteSpeed Tech#ifndef NDEBUG
445392f7a3SLiteSpeed Tech    const char *env = getenv("LSQUIC_RND_VARINT_LEN");
455392f7a3SLiteSpeed Tech    if (env && atoi(env))
465392f7a3SLiteSpeed Tech    {
475392f7a3SLiteSpeed Tech        s = rand() & 3;
485392f7a3SLiteSpeed Tech        LSQ_DEBUG("writing %d-byte stream type", 1 << s);
495392f7a3SLiteSpeed Tech    }
505392f7a3SLiteSpeed Tech    else
515392f7a3SLiteSpeed Tech#endif
525392f7a3SLiteSpeed Tech        s = 0;
535392f7a3SLiteSpeed Tech
545392f7a3SLiteSpeed Tech    switch (s)
555392f7a3SLiteSpeed Tech    {
565392f7a3SLiteSpeed Tech    case 0:
575392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
585392f7a3SLiteSpeed Tech                                (unsigned char []) { HQUST_QPACK_ENC }, 1);
595392f7a3SLiteSpeed Tech    case 1:
605392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
615392f7a3SLiteSpeed Tech                            (unsigned char []) { 0x40, HQUST_QPACK_ENC }, 2);
625392f7a3SLiteSpeed Tech    case 2:
635392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
645392f7a3SLiteSpeed Tech                (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_ENC }, 4);
655392f7a3SLiteSpeed Tech    default:
665392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
675392f7a3SLiteSpeed Tech                (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685392f7a3SLiteSpeed Tech                                                        HQUST_QPACK_ENC }, 8);
695392f7a3SLiteSpeed Tech    }
705392f7a3SLiteSpeed Tech}
715392f7a3SLiteSpeed Tech
725392f7a3SLiteSpeed Tech
735392f7a3SLiteSpeed Techstatic void
745392f7a3SLiteSpeed Techqeh_begin_out (struct qpack_enc_hdl *qeh)
755392f7a3SLiteSpeed Tech{
765392f7a3SLiteSpeed Tech    if (0 == qeh_write_type(qeh)
775392f7a3SLiteSpeed Tech        && (qeh->qeh_tsu_sz == 0
785392f7a3SLiteSpeed Tech            || 0 == lsquic_frab_list_write(&qeh->qeh_fral, qeh->qeh_tsu_buf,
795392f7a3SLiteSpeed Tech                                                            qeh->qeh_tsu_sz)))
805392f7a3SLiteSpeed Tech    {
815392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zu bytes to frab list", 1 + qeh->qeh_tsu_sz);
825392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(qeh->qeh_enc_sm_out, 1);
835392f7a3SLiteSpeed Tech    }
845392f7a3SLiteSpeed Tech    else
855392f7a3SLiteSpeed Tech    {
865392f7a3SLiteSpeed Tech        LSQ_WARN("could not write to frab list");
875392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
885392f7a3SLiteSpeed Tech                                            "cannot write to frab list");
895392f7a3SLiteSpeed Tech    }
905392f7a3SLiteSpeed Tech}
915392f7a3SLiteSpeed Tech
925392f7a3SLiteSpeed Tech
935392f7a3SLiteSpeed Techvoid
945392f7a3SLiteSpeed Techlsquic_qeh_init (struct qpack_enc_hdl *qeh, struct lsquic_conn *conn)
955392f7a3SLiteSpeed Tech{
965392f7a3SLiteSpeed Tech    assert(!(qeh->qeh_flags & QEH_INITIALIZED));
975392f7a3SLiteSpeed Tech    qeh->qeh_conn = conn;
985392f7a3SLiteSpeed Tech    lsquic_frab_list_init(&qeh->qeh_fral, 0x400, NULL, NULL, NULL);
995392f7a3SLiteSpeed Tech    lsqpack_enc_preinit(&qeh->qeh_encoder, (void *) conn);
1005392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_INITIALIZED;
1015392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1025392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1035392f7a3SLiteSpeed Tech    if (qeh->qeh_dec_sm_in)
1045392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
1055392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
1065392f7a3SLiteSpeed Tech}
1075392f7a3SLiteSpeed Tech
1085392f7a3SLiteSpeed Tech
1095392f7a3SLiteSpeed Techint
1105392f7a3SLiteSpeed Techlsquic_qeh_settings (struct qpack_enc_hdl *qeh, unsigned max_table_size,
1115392f7a3SLiteSpeed Tech             unsigned dyn_table_size, unsigned max_risked_streams, int server)
1125392f7a3SLiteSpeed Tech{
1135392f7a3SLiteSpeed Tech    enum lsqpack_enc_opts enc_opts;
1145392f7a3SLiteSpeed Tech
1155392f7a3SLiteSpeed Tech    assert(qeh->qeh_flags & QEH_INITIALIZED);
1165392f7a3SLiteSpeed Tech
1175392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
1185392f7a3SLiteSpeed Tech    {
1195392f7a3SLiteSpeed Tech        LSQ_WARN("settings already set");
1205392f7a3SLiteSpeed Tech        return -1;
1215392f7a3SLiteSpeed Tech    }
1225392f7a3SLiteSpeed Tech
1235392f7a3SLiteSpeed Tech    enc_opts = LSQPACK_ENC_OPT_STAGE_2
124a0e1aeeeSDmitri Tikhonov             | (server ? LSQPACK_ENC_OPT_SERVER : 0);
1255392f7a3SLiteSpeed Tech    qeh->qeh_tsu_sz = sizeof(qeh->qeh_tsu_buf);
1265392f7a3SLiteSpeed Tech    if (0 != lsqpack_enc_init(&qeh->qeh_encoder, (void *) qeh->qeh_conn,
1275392f7a3SLiteSpeed Tech                max_table_size, dyn_table_size, max_risked_streams, enc_opts,
1285392f7a3SLiteSpeed Tech                qeh->qeh_tsu_buf, &qeh->qeh_tsu_sz))
1295392f7a3SLiteSpeed Tech    {
1305392f7a3SLiteSpeed Tech        LSQ_INFO("could not initialize QPACK encoder");
1315392f7a3SLiteSpeed Tech        return -1;
1325392f7a3SLiteSpeed Tech    }
1335392f7a3SLiteSpeed Tech    LSQ_DEBUG("%zu-byte post-init TSU", qeh->qeh_tsu_sz);
1345392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_HAVE_SETTINGS;
1355392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1365392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1375392f7a3SLiteSpeed Tech    LSQ_DEBUG("have settings: max table size=%u; dyn table size=%u; max risked "
1385392f7a3SLiteSpeed Tech        "streams=%u", max_table_size, dyn_table_size, max_risked_streams);
1395392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
1405392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1415392f7a3SLiteSpeed Tech    return 0;
1425392f7a3SLiteSpeed Tech}
1435392f7a3SLiteSpeed Tech
1445392f7a3SLiteSpeed Tech
145758aff32SDmitri Tikhonovstatic void
146758aff32SDmitri Tikhonovqeh_log_and_clean_exp_rec (struct qpack_enc_hdl *qeh)
147758aff32SDmitri Tikhonov{
148758aff32SDmitri Tikhonov    char buf[0x400];
149758aff32SDmitri Tikhonov
150758aff32SDmitri Tikhonov    qeh->qeh_exp_rec->qer_comp_ratio = lsqpack_enc_ratio(&qeh->qeh_encoder);
151758aff32SDmitri Tikhonov    (void) lsquic_qpack_exp_to_xml(qeh->qeh_exp_rec, buf, sizeof(buf));
152758aff32SDmitri Tikhonov    LSQ_NOTICE("%s", buf);
153758aff32SDmitri Tikhonov    lsquic_qpack_exp_destroy(qeh->qeh_exp_rec);
154758aff32SDmitri Tikhonov    qeh->qeh_exp_rec = NULL;
155758aff32SDmitri Tikhonov}
156758aff32SDmitri Tikhonov
157758aff32SDmitri Tikhonov
1585392f7a3SLiteSpeed Techvoid
1595392f7a3SLiteSpeed Techlsquic_qeh_cleanup (struct qpack_enc_hdl *qeh)
1605392f7a3SLiteSpeed Tech{
1615392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
1625392f7a3SLiteSpeed Tech    {
1635392f7a3SLiteSpeed Tech        LSQ_DEBUG("cleanup");
164758aff32SDmitri Tikhonov        if (qeh->qeh_exp_rec)
165758aff32SDmitri Tikhonov            qeh_log_and_clean_exp_rec(qeh);
1665392f7a3SLiteSpeed Tech        lsqpack_enc_cleanup(&qeh->qeh_encoder);
1675392f7a3SLiteSpeed Tech        lsquic_frab_list_cleanup(&qeh->qeh_fral);
1685392f7a3SLiteSpeed Tech        memset(qeh, 0, sizeof(*qeh));
1695392f7a3SLiteSpeed Tech    }
1705392f7a3SLiteSpeed Tech}
1715392f7a3SLiteSpeed Tech
1725392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
1735392f7a3SLiteSpeed Techqeh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
1745392f7a3SLiteSpeed Tech{
1755392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
1765392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = stream;
1775392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1785392f7a3SLiteSpeed Tech                                    == (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1795392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1805392f7a3SLiteSpeed Tech    else
1815392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
1825392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized outgoing encoder stream");
1835392f7a3SLiteSpeed Tech    return (void *) qeh;
1845392f7a3SLiteSpeed Tech}
1855392f7a3SLiteSpeed Tech
1865392f7a3SLiteSpeed Tech
1875392f7a3SLiteSpeed Techstatic void
1885392f7a3SLiteSpeed Techqeh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1895392f7a3SLiteSpeed Tech{
1905392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1915392f7a3SLiteSpeed Tech    struct lsquic_reader reader = {
1925392f7a3SLiteSpeed Tech        .lsqr_read  = lsquic_frab_list_read,
1935392f7a3SLiteSpeed Tech        .lsqr_size  = lsquic_frab_list_size,
1945392f7a3SLiteSpeed Tech        .lsqr_ctx   = &qeh->qeh_fral,
1955392f7a3SLiteSpeed Tech    };
1965392f7a3SLiteSpeed Tech    ssize_t nw;
1975392f7a3SLiteSpeed Tech
1985392f7a3SLiteSpeed Tech    nw = lsquic_stream_writef(stream, &reader);
1995392f7a3SLiteSpeed Tech    if (nw >= 0)
2005392f7a3SLiteSpeed Tech    {
2015392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zd bytes to stream", nw);
2025392f7a3SLiteSpeed Tech        (void) lsquic_stream_flush(stream);
2035392f7a3SLiteSpeed Tech        if (lsquic_frab_list_empty(&qeh->qeh_fral))
2045392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(stream, 0);
2055392f7a3SLiteSpeed Tech    }
2065392f7a3SLiteSpeed Tech    else
2075392f7a3SLiteSpeed Tech    {
2085392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
2095392f7a3SLiteSpeed Tech                                            "cannot write to stream");
2105392f7a3SLiteSpeed Tech        LSQ_WARN("cannot write to stream: %s", strerror(errno));
2115392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
2125392f7a3SLiteSpeed Tech    }
2135392f7a3SLiteSpeed Tech}
2145392f7a3SLiteSpeed Tech
2155392f7a3SLiteSpeed Tech
2165392f7a3SLiteSpeed Techstatic void
2175392f7a3SLiteSpeed Techqeh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2185392f7a3SLiteSpeed Tech{
2195392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2205392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = NULL;
2215392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed outgoing encoder stream");
2225392f7a3SLiteSpeed Tech}
2235392f7a3SLiteSpeed Tech
2245392f7a3SLiteSpeed Tech
2255392f7a3SLiteSpeed Techstatic void
2265392f7a3SLiteSpeed Techqeh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2275392f7a3SLiteSpeed Tech{
2285392f7a3SLiteSpeed Tech    assert(0);
2295392f7a3SLiteSpeed Tech}
2305392f7a3SLiteSpeed Tech
2315392f7a3SLiteSpeed Tech
2325392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_enc_sm_out_if =
2335392f7a3SLiteSpeed Tech{
2345392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_out_on_new,
2355392f7a3SLiteSpeed Tech    .on_read        = qeh_out_on_read,
2365392f7a3SLiteSpeed Tech    .on_write       = qeh_out_on_write,
2375392f7a3SLiteSpeed Tech    .on_close       = qeh_out_on_close,
2385392f7a3SLiteSpeed Tech};
2395392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_enc_sm_out_if =
2405392f7a3SLiteSpeed Tech                                                    &qeh_enc_sm_out_if;
2415392f7a3SLiteSpeed Tech
2425392f7a3SLiteSpeed Tech
2435392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
2445392f7a3SLiteSpeed Techqeh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
2455392f7a3SLiteSpeed Tech{
2465392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
2475392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = stream;
2485392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
2495392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
2505392f7a3SLiteSpeed Tech    else
2515392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
2525392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized incoming decoder stream");
2535392f7a3SLiteSpeed Tech    return (void *) qeh;
2545392f7a3SLiteSpeed Tech}
2555392f7a3SLiteSpeed Tech
2565392f7a3SLiteSpeed Tech
2575392f7a3SLiteSpeed Techstatic size_t
2585392f7a3SLiteSpeed Techqeh_read_decoder_stream (void *ctx, const unsigned char *buf, size_t sz,
2595392f7a3SLiteSpeed Tech                                                                    int fin)
2605392f7a3SLiteSpeed Tech{
2615392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2625392f7a3SLiteSpeed Tech    uint64_t offset;
2635392f7a3SLiteSpeed Tech    int s;
2645392f7a3SLiteSpeed Tech
2655392f7a3SLiteSpeed Tech    if (fin)
2665392f7a3SLiteSpeed Tech    {
2675392f7a3SLiteSpeed Tech        LSQ_INFO("decoder stream is closed");
2685392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2695392f7a3SLiteSpeed Tech            HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK decoder stream");
2705392f7a3SLiteSpeed Tech        goto end;
2715392f7a3SLiteSpeed Tech    }
2725392f7a3SLiteSpeed Tech
2735392f7a3SLiteSpeed Tech    offset = lsquic_stream_read_offset(qeh->qeh_dec_sm_in);
2745392f7a3SLiteSpeed Tech    s = lsqpack_enc_decoder_in(&qeh->qeh_encoder, buf, sz);
2755392f7a3SLiteSpeed Tech    if (s != 0)
2765392f7a3SLiteSpeed Tech    {
2775392f7a3SLiteSpeed Tech        LSQ_INFO("error reading decoder stream");
2785392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2795392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK decoder "
2805392f7a3SLiteSpeed Tech            "stream at offset %"PRIu64, offset);
2815392f7a3SLiteSpeed Tech        goto end;
2825392f7a3SLiteSpeed Tech    }
2835392f7a3SLiteSpeed Tech    LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz);
2845392f7a3SLiteSpeed Tech
2855392f7a3SLiteSpeed Tech  end:
2865392f7a3SLiteSpeed Tech    return sz;
2875392f7a3SLiteSpeed Tech}
2885392f7a3SLiteSpeed Tech
2895392f7a3SLiteSpeed Tech
2905392f7a3SLiteSpeed Techstatic void
2915392f7a3SLiteSpeed Techqeh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2925392f7a3SLiteSpeed Tech{
2935392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2945392f7a3SLiteSpeed Tech    ssize_t nread;
2955392f7a3SLiteSpeed Tech
2965392f7a3SLiteSpeed Tech    nread = lsquic_stream_readf(stream, qeh_read_decoder_stream, qeh);
2975392f7a3SLiteSpeed Tech    if (nread <= 0)
2985392f7a3SLiteSpeed Tech    {
2995392f7a3SLiteSpeed Tech        if (nread < 0)
3005392f7a3SLiteSpeed Tech        {
3015392f7a3SLiteSpeed Tech            LSQ_WARN("cannot read from encoder stream: %s", strerror(errno));
3025392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
3035392f7a3SLiteSpeed Tech                                        "cannot read from encoder stream");
3045392f7a3SLiteSpeed Tech        }
3055392f7a3SLiteSpeed Tech        else
3065392f7a3SLiteSpeed Tech        {
3075392f7a3SLiteSpeed Tech            LSQ_INFO("encoder stream closed by peer: abort connection");
3085392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
3095392f7a3SLiteSpeed Tech                HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed");
3105392f7a3SLiteSpeed Tech        }
3115392f7a3SLiteSpeed Tech        lsquic_stream_wantread(stream, 0);
3125392f7a3SLiteSpeed Tech    }
3135392f7a3SLiteSpeed Tech}
3145392f7a3SLiteSpeed Tech
3155392f7a3SLiteSpeed Tech
3165392f7a3SLiteSpeed Techstatic void
3175392f7a3SLiteSpeed Techqeh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3185392f7a3SLiteSpeed Tech{
3195392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
3205392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed incoming decoder stream");
3215392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = NULL;
3225392f7a3SLiteSpeed Tech}
3235392f7a3SLiteSpeed Tech
3245392f7a3SLiteSpeed Tech
3255392f7a3SLiteSpeed Techstatic void
3265392f7a3SLiteSpeed Techqeh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3275392f7a3SLiteSpeed Tech{
3285392f7a3SLiteSpeed Tech    assert(0);
3295392f7a3SLiteSpeed Tech}
3305392f7a3SLiteSpeed Tech
3315392f7a3SLiteSpeed Tech
3325392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_dec_sm_in_if =
3335392f7a3SLiteSpeed Tech{
3345392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_in_on_new,
3355392f7a3SLiteSpeed Tech    .on_read        = qeh_in_on_read,
3365392f7a3SLiteSpeed Tech    .on_write       = qeh_in_on_write,
3375392f7a3SLiteSpeed Tech    .on_close       = qeh_in_on_close,
3385392f7a3SLiteSpeed Tech};
3395392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_dec_sm_in_if =
3405392f7a3SLiteSpeed Tech                                                    &qeh_dec_sm_in_if;
3415392f7a3SLiteSpeed Tech
3425392f7a3SLiteSpeed Tech
343758aff32SDmitri Tikhonovstatic void
344758aff32SDmitri Tikhonovqeh_maybe_set_user_agent (struct qpack_enc_hdl *qeh,
345758aff32SDmitri Tikhonov                                    const struct lsquic_http_headers *headers)
346758aff32SDmitri Tikhonov{
347758aff32SDmitri Tikhonov    const char *const name = qeh->qeh_exp_rec->qer_flags & QER_SERVER ?
348758aff32SDmitri Tikhonov                                    "server" : "user-agent";
349758aff32SDmitri Tikhonov    const size_t len = qeh->qeh_exp_rec->qer_flags & QER_SERVER ? 6 : 10;
350758aff32SDmitri Tikhonov    int i;
351758aff32SDmitri Tikhonov
352758aff32SDmitri Tikhonov    for (i = 0; i < headers->count; ++i)
353758aff32SDmitri Tikhonov        if (len == headers->headers[i].name_len
354758aff32SDmitri Tikhonov                && 0 == memcmp(name,
355758aff32SDmitri Tikhonov                        lsxpack_header_get_name(&headers->headers[i]), len))
356758aff32SDmitri Tikhonov        {
357758aff32SDmitri Tikhonov            qeh->qeh_exp_rec->qer_user_agent = strndup(
358758aff32SDmitri Tikhonov                            lsxpack_header_get_value(&headers->headers[i]),
359758aff32SDmitri Tikhonov                            headers->headers[i].val_len);
360758aff32SDmitri Tikhonov            break;
361758aff32SDmitri Tikhonov        }
362758aff32SDmitri Tikhonov}
363758aff32SDmitri Tikhonov
364758aff32SDmitri Tikhonov
3655392f7a3SLiteSpeed Techstatic enum qwh_status
3665392f7a3SLiteSpeed Techqeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
3675392f7a3SLiteSpeed Tech    unsigned seqno, const struct lsquic_http_headers *headers,
3685392f7a3SLiteSpeed Tech    unsigned char *buf, size_t *prefix_sz, size_t *headers_sz,
3694947ba95SDmitri Tikhonov    uint64_t *completion_offset, enum lsqpack_enc_header_flags *hflags)
3705392f7a3SLiteSpeed Tech{
3715392f7a3SLiteSpeed Tech    unsigned char *p = buf;
3725392f7a3SLiteSpeed Tech    unsigned char *const end = buf + *headers_sz;
3735392f7a3SLiteSpeed Tech    const unsigned char *enc_p;
3745392f7a3SLiteSpeed Tech    size_t enc_sz, hea_sz, total_enc_sz;
3755392f7a3SLiteSpeed Tech    ssize_t nw;
3765392f7a3SLiteSpeed Tech    enum lsqpack_enc_status st;
3775392f7a3SLiteSpeed Tech    int i, s, write_to_stream;
3785392f7a3SLiteSpeed Tech    enum lsqpack_enc_flags enc_flags;
379fb3e20e0SDmitri Tikhonov    enum qwh_status retval;
380fb3e20e0SDmitri Tikhonov#ifndef WIN32
3815392f7a3SLiteSpeed Tech    unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ];
382fb3e20e0SDmitri Tikhonov#else
383fb3e20e0SDmitri Tikhonov    unsigned char *enc_buf;
384fb3e20e0SDmitri Tikhonov    enc_buf = _malloca(qeh->qeh_encoder.qpe_cur_max_capacity * 2);
385fb3e20e0SDmitri Tikhonov    if (!enc_buf)
386fb3e20e0SDmitri Tikhonov        return QWH_ERR;
387fb3e20e0SDmitri Tikhonov#endif
3885392f7a3SLiteSpeed Tech
389758aff32SDmitri Tikhonov    if (qeh->qeh_exp_rec)
390758aff32SDmitri Tikhonov    {
391758aff32SDmitri Tikhonov        const lsquic_time_t now = lsquic_time_now();
392758aff32SDmitri Tikhonov        if (qeh->qeh_exp_rec->qer_hblock_count == 0)
393758aff32SDmitri Tikhonov            qeh->qeh_exp_rec->qer_first_req = now;
394758aff32SDmitri Tikhonov        qeh->qeh_exp_rec->qer_last_req = now;
395758aff32SDmitri Tikhonov        ++qeh->qeh_exp_rec->qer_hblock_count;
396758aff32SDmitri Tikhonov        if (!qeh->qeh_exp_rec->qer_user_agent)
397758aff32SDmitri Tikhonov            qeh_maybe_set_user_agent(qeh, headers);
398758aff32SDmitri Tikhonov    }
399758aff32SDmitri Tikhonov
4005392f7a3SLiteSpeed Tech    s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0);
4015392f7a3SLiteSpeed Tech    if (s != 0)
4025392f7a3SLiteSpeed Tech    {
4035392f7a3SLiteSpeed Tech        LSQ_WARN("cannot start header");
404fb3e20e0SDmitri Tikhonov        retval = QWH_ERR;
405fb3e20e0SDmitri Tikhonov        goto end;
4065392f7a3SLiteSpeed Tech    }
4075392f7a3SLiteSpeed Tech    LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id);
4085392f7a3SLiteSpeed Tech
4095392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
4105392f7a3SLiteSpeed Tech        enc_flags = 0;
4115392f7a3SLiteSpeed Tech    else
4125392f7a3SLiteSpeed Tech    {
4135392f7a3SLiteSpeed Tech        enc_flags = LQEF_NO_INDEX;
4145392f7a3SLiteSpeed Tech        LSQ_DEBUG("encoder stream is unavailable, won't index headers");
4155392f7a3SLiteSpeed Tech    }
4165392f7a3SLiteSpeed Tech    write_to_stream = qeh->qeh_enc_sm_out
4175392f7a3SLiteSpeed Tech                                && lsquic_frab_list_empty(&qeh->qeh_fral);
4185392f7a3SLiteSpeed Tech    total_enc_sz = 0;
4195392f7a3SLiteSpeed Tech    for (i = 0; i < headers->count; ++i)
4205392f7a3SLiteSpeed Tech    {
42155613f44SDmitri Tikhonov        if (headers->headers[i].buf == NULL)
42255613f44SDmitri Tikhonov            continue;
4235392f7a3SLiteSpeed Tech        enc_sz = sizeof(enc_buf);
4245392f7a3SLiteSpeed Tech        hea_sz = end - p;
4255392f7a3SLiteSpeed Tech        st = lsqpack_enc_encode(&qeh->qeh_encoder, enc_buf, &enc_sz, p,
42655613f44SDmitri Tikhonov                                &hea_sz, &headers->headers[i], enc_flags);
4275392f7a3SLiteSpeed Tech        switch (st)
4285392f7a3SLiteSpeed Tech        {
4295392f7a3SLiteSpeed Tech        case LQES_OK:
4305392f7a3SLiteSpeed Tech            LSQ_DEBUG("encoded `%.*s': `%.*s' -- %zd bytes to header block, "
4315392f7a3SLiteSpeed Tech                "%zd bytes to encoder stream",
43255613f44SDmitri Tikhonov                (int) headers->headers[i].name_len,
43355613f44SDmitri Tikhonov                    lsxpack_header_get_name(&headers->headers[i]),
43455613f44SDmitri Tikhonov                (int) headers->headers[i].val_len,
43555613f44SDmitri Tikhonov                    lsxpack_header_get_value(&headers->headers[i]),
4365392f7a3SLiteSpeed Tech                hea_sz, enc_sz);
4375392f7a3SLiteSpeed Tech            total_enc_sz += enc_sz;
4385392f7a3SLiteSpeed Tech            p += hea_sz;
4395392f7a3SLiteSpeed Tech            if (enc_sz)
4405392f7a3SLiteSpeed Tech            {
4415392f7a3SLiteSpeed Tech                if (write_to_stream)
4425392f7a3SLiteSpeed Tech                {
4435392f7a3SLiteSpeed Tech                    nw = lsquic_stream_write(qeh->qeh_enc_sm_out, enc_buf, enc_sz);
4445392f7a3SLiteSpeed Tech                    if ((size_t) nw == enc_sz)
4455392f7a3SLiteSpeed Tech                        break;
4465392f7a3SLiteSpeed Tech                    if (nw < 0)
4475392f7a3SLiteSpeed Tech                    {
4485392f7a3SLiteSpeed Tech                        LSQ_INFO("could not write to encoder stream: %s",
4495392f7a3SLiteSpeed Tech                                                                strerror(errno));
450fb3e20e0SDmitri Tikhonov                        retval = QWH_ERR;
451fb3e20e0SDmitri Tikhonov                        goto end;
4525392f7a3SLiteSpeed Tech                    }
4535392f7a3SLiteSpeed Tech                    write_to_stream = 0;
4545392f7a3SLiteSpeed Tech                    enc_p = enc_buf + (size_t) nw;
4555392f7a3SLiteSpeed Tech                    enc_sz -= (size_t) nw;
4565392f7a3SLiteSpeed Tech                }
4575392f7a3SLiteSpeed Tech                else
4585392f7a3SLiteSpeed Tech                    enc_p = enc_buf;
4595392f7a3SLiteSpeed Tech                if (0 != lsquic_frab_list_write(&qeh->qeh_fral, enc_p, enc_sz))
4605392f7a3SLiteSpeed Tech                {
4615392f7a3SLiteSpeed Tech                    LSQ_INFO("could not write to frab list");
462fb3e20e0SDmitri Tikhonov                    retval = QWH_ERR;
463fb3e20e0SDmitri Tikhonov                    goto end;
4645392f7a3SLiteSpeed Tech                }
4655392f7a3SLiteSpeed Tech            }
4665392f7a3SLiteSpeed Tech            break;
4675392f7a3SLiteSpeed Tech        case LQES_NOBUF_HEAD:
468fb3e20e0SDmitri Tikhonov            retval = QWH_ENOBUF;
469fb3e20e0SDmitri Tikhonov            goto end;
4705392f7a3SLiteSpeed Tech        default:
4715392f7a3SLiteSpeed Tech            assert(0);
472fb3e20e0SDmitri Tikhonov            retval = QWH_ERR;
473fb3e20e0SDmitri Tikhonov            goto end;
4745392f7a3SLiteSpeed Tech        case LQES_NOBUF_ENC:
4755392f7a3SLiteSpeed Tech            LSQ_DEBUG("not enough room to write encoder stream data");
476fb3e20e0SDmitri Tikhonov            retval = QWH_ERR;
477fb3e20e0SDmitri Tikhonov            goto end;
4785392f7a3SLiteSpeed Tech        }
4795392f7a3SLiteSpeed Tech    }
4805392f7a3SLiteSpeed Tech
4814947ba95SDmitri Tikhonov    nw = lsqpack_enc_end_header(&qeh->qeh_encoder, buf - *prefix_sz,
4824947ba95SDmitri Tikhonov                                                        *prefix_sz, hflags);
4835392f7a3SLiteSpeed Tech    if (nw <= 0)
4845392f7a3SLiteSpeed Tech    {
4855392f7a3SLiteSpeed Tech        LSQ_WARN("could not end header: %zd", nw);
486fb3e20e0SDmitri Tikhonov        retval = QWH_ERR;
487fb3e20e0SDmitri Tikhonov        goto end;
4885392f7a3SLiteSpeed Tech    }
4895392f7a3SLiteSpeed Tech
4905392f7a3SLiteSpeed Tech    if ((size_t) nw < *prefix_sz)
4915392f7a3SLiteSpeed Tech    {
4925392f7a3SLiteSpeed Tech        memmove(buf - nw, buf - *prefix_sz, (size_t) nw);
4935392f7a3SLiteSpeed Tech        *prefix_sz = (size_t) nw;
4945392f7a3SLiteSpeed Tech    }
4955392f7a3SLiteSpeed Tech    *headers_sz = p - buf;
496758aff32SDmitri Tikhonov    if (qeh->qeh_exp_rec)
497758aff32SDmitri Tikhonov        qeh->qeh_exp_rec->qer_hblock_size += p - buf;
4985392f7a3SLiteSpeed Tech    if (lsquic_frab_list_empty(&qeh->qeh_fral))
4995392f7a3SLiteSpeed Tech    {
5005392f7a3SLiteSpeed Tech        LSQ_DEBUG("all %zd bytes of encoder stream written out; header block "
5015392f7a3SLiteSpeed Tech            "is %zd bytes; estimated compression ratio %.3f", total_enc_sz,
5025392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
503fb3e20e0SDmitri Tikhonov        retval = QWH_FULL;
504fb3e20e0SDmitri Tikhonov        goto end;
5055392f7a3SLiteSpeed Tech    }
5065392f7a3SLiteSpeed Tech    else
5075392f7a3SLiteSpeed Tech    {
5085392f7a3SLiteSpeed Tech        *completion_offset = lsquic_qeh_enc_off(qeh)
5095392f7a3SLiteSpeed Tech                                    + lsquic_frab_list_size(&qeh->qeh_fral);
5105392f7a3SLiteSpeed Tech        LSQ_DEBUG("not all %zd bytes of encoder stream written out; %zd bytes "
5115392f7a3SLiteSpeed Tech            "buffered; header block is %zd bytes; estimated compression ratio "
5125392f7a3SLiteSpeed Tech            "%.3f", total_enc_sz, lsquic_frab_list_size(&qeh->qeh_fral),
5135392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
514fb3e20e0SDmitri Tikhonov        retval = QWH_PARTIAL;
515fb3e20e0SDmitri Tikhonov        goto end;
5165392f7a3SLiteSpeed Tech    }
517fb3e20e0SDmitri Tikhonov
518fb3e20e0SDmitri Tikhonov  end:
519fb3e20e0SDmitri Tikhonov#ifdef WIN32
520fb3e20e0SDmitri Tikhonov    _freea(enc_buf);
521fb3e20e0SDmitri Tikhonov#endif
522fb3e20e0SDmitri Tikhonov    return retval;
5235392f7a3SLiteSpeed Tech}
5245392f7a3SLiteSpeed Tech
5255392f7a3SLiteSpeed Tech
5265392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
5275392f7a3SLiteSpeed Tech__attribute__((weak))
5285392f7a3SLiteSpeed Tech#endif
5295392f7a3SLiteSpeed Techenum qwh_status
5305392f7a3SLiteSpeed Techlsquic_qeh_write_headers (struct qpack_enc_hdl *qeh,
5315392f7a3SLiteSpeed Tech    lsquic_stream_id_t stream_id, unsigned seqno,
5325392f7a3SLiteSpeed Tech    const struct lsquic_http_headers *headers, unsigned char *buf,
5334947ba95SDmitri Tikhonov    size_t *prefix_sz, size_t *headers_sz, uint64_t *completion_offset,
5344947ba95SDmitri Tikhonov    enum lsqpack_enc_header_flags *hflags)
5355392f7a3SLiteSpeed Tech{
5365392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
5375392f7a3SLiteSpeed Tech        return qeh_write_headers(qeh, stream_id, seqno, headers, buf,
5384947ba95SDmitri Tikhonov                        prefix_sz, headers_sz, completion_offset, hflags);
5395392f7a3SLiteSpeed Tech    else
5405392f7a3SLiteSpeed Tech        return QWH_ERR;
5415392f7a3SLiteSpeed Tech}
5425392f7a3SLiteSpeed Tech
5435392f7a3SLiteSpeed Tech
5445392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
5455392f7a3SLiteSpeed Tech__attribute__((weak))
5465392f7a3SLiteSpeed Tech#endif
5475392f7a3SLiteSpeed Techuint64_t
5485392f7a3SLiteSpeed Techlsquic_qeh_enc_off (struct qpack_enc_hdl *qeh)
5495392f7a3SLiteSpeed Tech{
5505392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
5515392f7a3SLiteSpeed Tech        return qeh->qeh_enc_sm_out->tosend_off;
5525392f7a3SLiteSpeed Tech    else
5535392f7a3SLiteSpeed Tech        return 0;
5545392f7a3SLiteSpeed Tech}
5555392f7a3SLiteSpeed Tech
5565392f7a3SLiteSpeed Tech
5575392f7a3SLiteSpeed Techsize_t
5585392f7a3SLiteSpeed Techlsquic_qeh_write_avail (struct qpack_enc_hdl *qeh)
5595392f7a3SLiteSpeed Tech{
5605392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & QEH_INITIALIZED) && qeh->qeh_enc_sm_out)
5615392f7a3SLiteSpeed Tech        return lsquic_stream_write_avail(qeh->qeh_enc_sm_out);
5625392f7a3SLiteSpeed Tech    else if (qeh->qeh_flags & QEH_INITIALIZED)
5635392f7a3SLiteSpeed Tech        return ~((size_t) 0);   /* Unlimited write */
5645392f7a3SLiteSpeed Tech    else
5655392f7a3SLiteSpeed Tech        return 0;
5665392f7a3SLiteSpeed Tech}
5675392f7a3SLiteSpeed Tech
5685392f7a3SLiteSpeed Tech
5695392f7a3SLiteSpeed Techsize_t
5705392f7a3SLiteSpeed Techlsquic_qeh_max_prefix_size (const struct qpack_enc_hdl *qeh)
5715392f7a3SLiteSpeed Tech{
5725392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
5735392f7a3SLiteSpeed Tech        return qeh->qeh_max_prefix_size;
5745392f7a3SLiteSpeed Tech    else
5755392f7a3SLiteSpeed Tech        return LSQPACK_UINT64_ENC_SZ * 2;
5765392f7a3SLiteSpeed Tech}
577