lsquic_qenc_hdl.c revision a0e1aeee
15392f7a3SLiteSpeed Tech/* Copyright (c) 2017 - 2019 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
135392f7a3SLiteSpeed Tech#include "lsquic.h"
145392f7a3SLiteSpeed Tech#include "lsquic_types.h"
155392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
165392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h"
175392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
185392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
195392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
205392f7a3SLiteSpeed Tech#include "lsquic_stream.h"
215392f7a3SLiteSpeed Tech#include "lsquic_frab_list.h"
225392f7a3SLiteSpeed Tech#include "lsqpack.h"
235392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
245392f7a3SLiteSpeed Tech#include "lsquic_qenc_hdl.h"
255392f7a3SLiteSpeed Tech
265392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_QENC_HDL
275392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qeh->qeh_conn)
285392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
295392f7a3SLiteSpeed Tech
305392f7a3SLiteSpeed Tech
315392f7a3SLiteSpeed Techstatic int
325392f7a3SLiteSpeed Techqeh_write_type (struct qpack_enc_hdl *qeh)
335392f7a3SLiteSpeed Tech{
345392f7a3SLiteSpeed Tech    int s;
355392f7a3SLiteSpeed Tech
365392f7a3SLiteSpeed Tech#ifndef NDEBUG
375392f7a3SLiteSpeed Tech    const char *env = getenv("LSQUIC_RND_VARINT_LEN");
385392f7a3SLiteSpeed Tech    if (env && atoi(env))
395392f7a3SLiteSpeed Tech    {
405392f7a3SLiteSpeed Tech        s = rand() & 3;
415392f7a3SLiteSpeed Tech        LSQ_DEBUG("writing %d-byte stream type", 1 << s);
425392f7a3SLiteSpeed Tech    }
435392f7a3SLiteSpeed Tech    else
445392f7a3SLiteSpeed Tech#endif
455392f7a3SLiteSpeed Tech        s = 0;
465392f7a3SLiteSpeed Tech
475392f7a3SLiteSpeed Tech    switch (s)
485392f7a3SLiteSpeed Tech    {
495392f7a3SLiteSpeed Tech    case 0:
505392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
515392f7a3SLiteSpeed Tech                                (unsigned char []) { HQUST_QPACK_ENC }, 1);
525392f7a3SLiteSpeed Tech    case 1:
535392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
545392f7a3SLiteSpeed Tech                            (unsigned char []) { 0x40, HQUST_QPACK_ENC }, 2);
555392f7a3SLiteSpeed Tech    case 2:
565392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
575392f7a3SLiteSpeed Tech                (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_ENC }, 4);
585392f7a3SLiteSpeed Tech    default:
595392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
605392f7a3SLiteSpeed Tech                (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615392f7a3SLiteSpeed Tech                                                        HQUST_QPACK_ENC }, 8);
625392f7a3SLiteSpeed Tech    }
635392f7a3SLiteSpeed Tech}
645392f7a3SLiteSpeed Tech
655392f7a3SLiteSpeed Tech
665392f7a3SLiteSpeed Techstatic void
675392f7a3SLiteSpeed Techqeh_begin_out (struct qpack_enc_hdl *qeh)
685392f7a3SLiteSpeed Tech{
695392f7a3SLiteSpeed Tech    if (0 == qeh_write_type(qeh)
705392f7a3SLiteSpeed Tech        && (qeh->qeh_tsu_sz == 0
715392f7a3SLiteSpeed Tech            || 0 == lsquic_frab_list_write(&qeh->qeh_fral, qeh->qeh_tsu_buf,
725392f7a3SLiteSpeed Tech                                                            qeh->qeh_tsu_sz)))
735392f7a3SLiteSpeed Tech    {
745392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zu bytes to frab list", 1 + qeh->qeh_tsu_sz);
755392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(qeh->qeh_enc_sm_out, 1);
765392f7a3SLiteSpeed Tech    }
775392f7a3SLiteSpeed Tech    else
785392f7a3SLiteSpeed Tech    {
795392f7a3SLiteSpeed Tech        LSQ_WARN("could not write to frab list");
805392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
815392f7a3SLiteSpeed Tech                                            "cannot write to frab list");
825392f7a3SLiteSpeed Tech    }
835392f7a3SLiteSpeed Tech}
845392f7a3SLiteSpeed Tech
855392f7a3SLiteSpeed Tech
865392f7a3SLiteSpeed Techvoid
875392f7a3SLiteSpeed Techlsquic_qeh_init (struct qpack_enc_hdl *qeh, struct lsquic_conn *conn)
885392f7a3SLiteSpeed Tech{
895392f7a3SLiteSpeed Tech    assert(!(qeh->qeh_flags & QEH_INITIALIZED));
905392f7a3SLiteSpeed Tech    qeh->qeh_conn = conn;
915392f7a3SLiteSpeed Tech    lsquic_frab_list_init(&qeh->qeh_fral, 0x400, NULL, NULL, NULL);
925392f7a3SLiteSpeed Tech    lsqpack_enc_preinit(&qeh->qeh_encoder, (void *) conn);
935392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_INITIALIZED;
945392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
955392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
965392f7a3SLiteSpeed Tech    if (qeh->qeh_dec_sm_in)
975392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
985392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
995392f7a3SLiteSpeed Tech}
1005392f7a3SLiteSpeed Tech
1015392f7a3SLiteSpeed Tech
1025392f7a3SLiteSpeed Techint
1035392f7a3SLiteSpeed Techlsquic_qeh_settings (struct qpack_enc_hdl *qeh, unsigned max_table_size,
1045392f7a3SLiteSpeed Tech             unsigned dyn_table_size, unsigned max_risked_streams, int server)
1055392f7a3SLiteSpeed Tech{
1065392f7a3SLiteSpeed Tech    enum lsqpack_enc_opts enc_opts;
1075392f7a3SLiteSpeed Tech
1085392f7a3SLiteSpeed Tech    assert(qeh->qeh_flags & QEH_INITIALIZED);
1095392f7a3SLiteSpeed Tech
1105392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
1115392f7a3SLiteSpeed Tech    {
1125392f7a3SLiteSpeed Tech        LSQ_WARN("settings already set");
1135392f7a3SLiteSpeed Tech        return -1;
1145392f7a3SLiteSpeed Tech    }
1155392f7a3SLiteSpeed Tech
1165392f7a3SLiteSpeed Tech    enc_opts = LSQPACK_ENC_OPT_STAGE_2
117a0e1aeeeSDmitri Tikhonov             | (server ? LSQPACK_ENC_OPT_SERVER : 0);
1185392f7a3SLiteSpeed Tech    qeh->qeh_tsu_sz = sizeof(qeh->qeh_tsu_buf);
1195392f7a3SLiteSpeed Tech    if (0 != lsqpack_enc_init(&qeh->qeh_encoder, (void *) qeh->qeh_conn,
1205392f7a3SLiteSpeed Tech                max_table_size, dyn_table_size, max_risked_streams, enc_opts,
1215392f7a3SLiteSpeed Tech                qeh->qeh_tsu_buf, &qeh->qeh_tsu_sz))
1225392f7a3SLiteSpeed Tech    {
1235392f7a3SLiteSpeed Tech        LSQ_INFO("could not initialize QPACK encoder");
1245392f7a3SLiteSpeed Tech        return -1;
1255392f7a3SLiteSpeed Tech    }
1265392f7a3SLiteSpeed Tech    LSQ_DEBUG("%zu-byte post-init TSU", qeh->qeh_tsu_sz);
1275392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_HAVE_SETTINGS;
1285392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1295392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1305392f7a3SLiteSpeed Tech    LSQ_DEBUG("have settings: max table size=%u; dyn table size=%u; max risked "
1315392f7a3SLiteSpeed Tech        "streams=%u", max_table_size, dyn_table_size, max_risked_streams);
1325392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
1335392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1345392f7a3SLiteSpeed Tech    return 0;
1355392f7a3SLiteSpeed Tech}
1365392f7a3SLiteSpeed Tech
1375392f7a3SLiteSpeed Tech
1385392f7a3SLiteSpeed Techvoid
1395392f7a3SLiteSpeed Techlsquic_qeh_cleanup (struct qpack_enc_hdl *qeh)
1405392f7a3SLiteSpeed Tech{
1415392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
1425392f7a3SLiteSpeed Tech    {
1435392f7a3SLiteSpeed Tech        LSQ_DEBUG("cleanup");
1445392f7a3SLiteSpeed Tech        lsqpack_enc_cleanup(&qeh->qeh_encoder);
1455392f7a3SLiteSpeed Tech        lsquic_frab_list_cleanup(&qeh->qeh_fral);
1465392f7a3SLiteSpeed Tech        memset(qeh, 0, sizeof(*qeh));
1475392f7a3SLiteSpeed Tech    }
1485392f7a3SLiteSpeed Tech}
1495392f7a3SLiteSpeed Tech
1505392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
1515392f7a3SLiteSpeed Techqeh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
1525392f7a3SLiteSpeed Tech{
1535392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
1545392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = stream;
1555392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1565392f7a3SLiteSpeed Tech                                    == (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1575392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1585392f7a3SLiteSpeed Tech    else
1595392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
1605392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized outgoing encoder stream");
1615392f7a3SLiteSpeed Tech    return (void *) qeh;
1625392f7a3SLiteSpeed Tech}
1635392f7a3SLiteSpeed Tech
1645392f7a3SLiteSpeed Tech
1655392f7a3SLiteSpeed Techstatic void
1665392f7a3SLiteSpeed Techqeh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1675392f7a3SLiteSpeed Tech{
1685392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1695392f7a3SLiteSpeed Tech    struct lsquic_reader reader = {
1705392f7a3SLiteSpeed Tech        .lsqr_read  = lsquic_frab_list_read,
1715392f7a3SLiteSpeed Tech        .lsqr_size  = lsquic_frab_list_size,
1725392f7a3SLiteSpeed Tech        .lsqr_ctx   = &qeh->qeh_fral,
1735392f7a3SLiteSpeed Tech    };
1745392f7a3SLiteSpeed Tech    ssize_t nw;
1755392f7a3SLiteSpeed Tech
1765392f7a3SLiteSpeed Tech    nw = lsquic_stream_writef(stream, &reader);
1775392f7a3SLiteSpeed Tech    if (nw >= 0)
1785392f7a3SLiteSpeed Tech    {
1795392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zd bytes to stream", nw);
1805392f7a3SLiteSpeed Tech        (void) lsquic_stream_flush(stream);
1815392f7a3SLiteSpeed Tech        if (lsquic_frab_list_empty(&qeh->qeh_fral))
1825392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(stream, 0);
1835392f7a3SLiteSpeed Tech    }
1845392f7a3SLiteSpeed Tech    else
1855392f7a3SLiteSpeed Tech    {
1865392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
1875392f7a3SLiteSpeed Tech                                            "cannot write to stream");
1885392f7a3SLiteSpeed Tech        LSQ_WARN("cannot write to stream: %s", strerror(errno));
1895392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
1905392f7a3SLiteSpeed Tech    }
1915392f7a3SLiteSpeed Tech}
1925392f7a3SLiteSpeed Tech
1935392f7a3SLiteSpeed Tech
1945392f7a3SLiteSpeed Techstatic void
1955392f7a3SLiteSpeed Techqeh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1965392f7a3SLiteSpeed Tech{
1975392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1985392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = NULL;
1995392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed outgoing encoder stream");
2005392f7a3SLiteSpeed Tech}
2015392f7a3SLiteSpeed Tech
2025392f7a3SLiteSpeed Tech
2035392f7a3SLiteSpeed Techstatic void
2045392f7a3SLiteSpeed Techqeh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2055392f7a3SLiteSpeed Tech{
2065392f7a3SLiteSpeed Tech    assert(0);
2075392f7a3SLiteSpeed Tech}
2085392f7a3SLiteSpeed Tech
2095392f7a3SLiteSpeed Tech
2105392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_enc_sm_out_if =
2115392f7a3SLiteSpeed Tech{
2125392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_out_on_new,
2135392f7a3SLiteSpeed Tech    .on_read        = qeh_out_on_read,
2145392f7a3SLiteSpeed Tech    .on_write       = qeh_out_on_write,
2155392f7a3SLiteSpeed Tech    .on_close       = qeh_out_on_close,
2165392f7a3SLiteSpeed Tech};
2175392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_enc_sm_out_if =
2185392f7a3SLiteSpeed Tech                                                    &qeh_enc_sm_out_if;
2195392f7a3SLiteSpeed Tech
2205392f7a3SLiteSpeed Tech
2215392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
2225392f7a3SLiteSpeed Techqeh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
2235392f7a3SLiteSpeed Tech{
2245392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
2255392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = stream;
2265392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
2275392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
2285392f7a3SLiteSpeed Tech    else
2295392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
2305392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized incoming decoder stream");
2315392f7a3SLiteSpeed Tech    return (void *) qeh;
2325392f7a3SLiteSpeed Tech}
2335392f7a3SLiteSpeed Tech
2345392f7a3SLiteSpeed Tech
2355392f7a3SLiteSpeed Techstatic size_t
2365392f7a3SLiteSpeed Techqeh_read_decoder_stream (void *ctx, const unsigned char *buf, size_t sz,
2375392f7a3SLiteSpeed Tech                                                                    int fin)
2385392f7a3SLiteSpeed Tech{
2395392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2405392f7a3SLiteSpeed Tech    uint64_t offset;
2415392f7a3SLiteSpeed Tech    int s;
2425392f7a3SLiteSpeed Tech
2435392f7a3SLiteSpeed Tech    if (fin)
2445392f7a3SLiteSpeed Tech    {
2455392f7a3SLiteSpeed Tech        LSQ_INFO("decoder stream is closed");
2465392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2475392f7a3SLiteSpeed Tech            HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK decoder stream");
2485392f7a3SLiteSpeed Tech        goto end;
2495392f7a3SLiteSpeed Tech    }
2505392f7a3SLiteSpeed Tech
2515392f7a3SLiteSpeed Tech    offset = lsquic_stream_read_offset(qeh->qeh_dec_sm_in);
2525392f7a3SLiteSpeed Tech    s = lsqpack_enc_decoder_in(&qeh->qeh_encoder, buf, sz);
2535392f7a3SLiteSpeed Tech    if (s != 0)
2545392f7a3SLiteSpeed Tech    {
2555392f7a3SLiteSpeed Tech        LSQ_INFO("error reading decoder stream");
2565392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2575392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK decoder "
2585392f7a3SLiteSpeed Tech            "stream at offset %"PRIu64, offset);
2595392f7a3SLiteSpeed Tech        goto end;
2605392f7a3SLiteSpeed Tech    }
2615392f7a3SLiteSpeed Tech    LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz);
2625392f7a3SLiteSpeed Tech
2635392f7a3SLiteSpeed Tech  end:
2645392f7a3SLiteSpeed Tech    return sz;
2655392f7a3SLiteSpeed Tech}
2665392f7a3SLiteSpeed Tech
2675392f7a3SLiteSpeed Tech
2685392f7a3SLiteSpeed Techstatic void
2695392f7a3SLiteSpeed Techqeh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2705392f7a3SLiteSpeed Tech{
2715392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2725392f7a3SLiteSpeed Tech    ssize_t nread;
2735392f7a3SLiteSpeed Tech
2745392f7a3SLiteSpeed Tech    nread = lsquic_stream_readf(stream, qeh_read_decoder_stream, qeh);
2755392f7a3SLiteSpeed Tech    if (nread <= 0)
2765392f7a3SLiteSpeed Tech    {
2775392f7a3SLiteSpeed Tech        if (nread < 0)
2785392f7a3SLiteSpeed Tech        {
2795392f7a3SLiteSpeed Tech            LSQ_WARN("cannot read from encoder stream: %s", strerror(errno));
2805392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
2815392f7a3SLiteSpeed Tech                                        "cannot read from encoder stream");
2825392f7a3SLiteSpeed Tech        }
2835392f7a3SLiteSpeed Tech        else
2845392f7a3SLiteSpeed Tech        {
2855392f7a3SLiteSpeed Tech            LSQ_INFO("encoder stream closed by peer: abort connection");
2865392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2875392f7a3SLiteSpeed Tech                HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed");
2885392f7a3SLiteSpeed Tech        }
2895392f7a3SLiteSpeed Tech        lsquic_stream_wantread(stream, 0);
2905392f7a3SLiteSpeed Tech    }
2915392f7a3SLiteSpeed Tech}
2925392f7a3SLiteSpeed Tech
2935392f7a3SLiteSpeed Tech
2945392f7a3SLiteSpeed Techstatic void
2955392f7a3SLiteSpeed Techqeh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2965392f7a3SLiteSpeed Tech{
2975392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2985392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed incoming decoder stream");
2995392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = NULL;
3005392f7a3SLiteSpeed Tech}
3015392f7a3SLiteSpeed Tech
3025392f7a3SLiteSpeed Tech
3035392f7a3SLiteSpeed Techstatic void
3045392f7a3SLiteSpeed Techqeh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3055392f7a3SLiteSpeed Tech{
3065392f7a3SLiteSpeed Tech    assert(0);
3075392f7a3SLiteSpeed Tech}
3085392f7a3SLiteSpeed Tech
3095392f7a3SLiteSpeed Tech
3105392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_dec_sm_in_if =
3115392f7a3SLiteSpeed Tech{
3125392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_in_on_new,
3135392f7a3SLiteSpeed Tech    .on_read        = qeh_in_on_read,
3145392f7a3SLiteSpeed Tech    .on_write       = qeh_in_on_write,
3155392f7a3SLiteSpeed Tech    .on_close       = qeh_in_on_close,
3165392f7a3SLiteSpeed Tech};
3175392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_dec_sm_in_if =
3185392f7a3SLiteSpeed Tech                                                    &qeh_dec_sm_in_if;
3195392f7a3SLiteSpeed Tech
3205392f7a3SLiteSpeed Tech
3215392f7a3SLiteSpeed Techstatic enum qwh_status
3225392f7a3SLiteSpeed Techqeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
3235392f7a3SLiteSpeed Tech    unsigned seqno, const struct lsquic_http_headers *headers,
3245392f7a3SLiteSpeed Tech    unsigned char *buf, size_t *prefix_sz, size_t *headers_sz,
3254947ba95SDmitri Tikhonov    uint64_t *completion_offset, enum lsqpack_enc_header_flags *hflags)
3265392f7a3SLiteSpeed Tech{
3275392f7a3SLiteSpeed Tech    unsigned char *p = buf;
3285392f7a3SLiteSpeed Tech    unsigned char *const end = buf + *headers_sz;
3295392f7a3SLiteSpeed Tech    const unsigned char *enc_p;
3305392f7a3SLiteSpeed Tech    size_t enc_sz, hea_sz, total_enc_sz;
3315392f7a3SLiteSpeed Tech    ssize_t nw;
3325392f7a3SLiteSpeed Tech    enum lsqpack_enc_status st;
3335392f7a3SLiteSpeed Tech    int i, s, write_to_stream;
3345392f7a3SLiteSpeed Tech    enum lsqpack_enc_flags enc_flags;
3355392f7a3SLiteSpeed Tech    unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ];
3365392f7a3SLiteSpeed Tech
3375392f7a3SLiteSpeed Tech    s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0);
3385392f7a3SLiteSpeed Tech    if (s != 0)
3395392f7a3SLiteSpeed Tech    {
3405392f7a3SLiteSpeed Tech        LSQ_WARN("cannot start header");
3415392f7a3SLiteSpeed Tech        return QWH_ERR;
3425392f7a3SLiteSpeed Tech    }
3435392f7a3SLiteSpeed Tech    LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id);
3445392f7a3SLiteSpeed Tech
3455392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
3465392f7a3SLiteSpeed Tech        enc_flags = 0;
3475392f7a3SLiteSpeed Tech    else
3485392f7a3SLiteSpeed Tech    {
3495392f7a3SLiteSpeed Tech        enc_flags = LQEF_NO_INDEX;
3505392f7a3SLiteSpeed Tech        LSQ_DEBUG("encoder stream is unavailable, won't index headers");
3515392f7a3SLiteSpeed Tech    }
3525392f7a3SLiteSpeed Tech    write_to_stream = qeh->qeh_enc_sm_out
3535392f7a3SLiteSpeed Tech                                && lsquic_frab_list_empty(&qeh->qeh_fral);
3545392f7a3SLiteSpeed Tech    total_enc_sz = 0;
3555392f7a3SLiteSpeed Tech    for (i = 0; i < headers->count; ++i)
3565392f7a3SLiteSpeed Tech    {
3575392f7a3SLiteSpeed Tech        enc_sz = sizeof(enc_buf);
3585392f7a3SLiteSpeed Tech        hea_sz = end - p;
3595392f7a3SLiteSpeed Tech        st = lsqpack_enc_encode(&qeh->qeh_encoder, enc_buf, &enc_sz, p,
3605392f7a3SLiteSpeed Tech                    &hea_sz, headers->headers[i].name.iov_base,
3615392f7a3SLiteSpeed Tech                    headers->headers[i].name.iov_len,
3625392f7a3SLiteSpeed Tech                    headers->headers[i].value.iov_base,
3635392f7a3SLiteSpeed Tech                    headers->headers[i].value.iov_len, enc_flags);
3645392f7a3SLiteSpeed Tech        switch (st)
3655392f7a3SLiteSpeed Tech        {
3665392f7a3SLiteSpeed Tech        case LQES_OK:
3675392f7a3SLiteSpeed Tech            LSQ_DEBUG("encoded `%.*s': `%.*s' -- %zd bytes to header block, "
3685392f7a3SLiteSpeed Tech                "%zd bytes to encoder stream",
3695392f7a3SLiteSpeed Tech                (int) headers->headers[i].name.iov_len,
3705392f7a3SLiteSpeed Tech                                    (char *) headers->headers[i].name.iov_base,
3715392f7a3SLiteSpeed Tech                (int) headers->headers[i].value.iov_len,
3725392f7a3SLiteSpeed Tech                                    (char *) headers->headers[i].value.iov_base,
3735392f7a3SLiteSpeed Tech                hea_sz, enc_sz);
3745392f7a3SLiteSpeed Tech            total_enc_sz += enc_sz;
3755392f7a3SLiteSpeed Tech            p += hea_sz;
3765392f7a3SLiteSpeed Tech            if (enc_sz)
3775392f7a3SLiteSpeed Tech            {
3785392f7a3SLiteSpeed Tech                if (write_to_stream)
3795392f7a3SLiteSpeed Tech                {
3805392f7a3SLiteSpeed Tech                    nw = lsquic_stream_write(qeh->qeh_enc_sm_out, enc_buf, enc_sz);
3815392f7a3SLiteSpeed Tech                    if ((size_t) nw == enc_sz)
3825392f7a3SLiteSpeed Tech                        break;
3835392f7a3SLiteSpeed Tech                    if (nw < 0)
3845392f7a3SLiteSpeed Tech                    {
3855392f7a3SLiteSpeed Tech                        LSQ_INFO("could not write to encoder stream: %s",
3865392f7a3SLiteSpeed Tech                                                                strerror(errno));
3875392f7a3SLiteSpeed Tech                        return QWH_ERR;
3885392f7a3SLiteSpeed Tech                    }
3895392f7a3SLiteSpeed Tech                    write_to_stream = 0;
3905392f7a3SLiteSpeed Tech                    enc_p = enc_buf + (size_t) nw;
3915392f7a3SLiteSpeed Tech                    enc_sz -= (size_t) nw;
3925392f7a3SLiteSpeed Tech                }
3935392f7a3SLiteSpeed Tech                else
3945392f7a3SLiteSpeed Tech                    enc_p = enc_buf;
3955392f7a3SLiteSpeed Tech                if (0 != lsquic_frab_list_write(&qeh->qeh_fral, enc_p, enc_sz))
3965392f7a3SLiteSpeed Tech                {
3975392f7a3SLiteSpeed Tech                    LSQ_INFO("could not write to frab list");
3985392f7a3SLiteSpeed Tech                    return QWH_ERR;
3995392f7a3SLiteSpeed Tech                }
4005392f7a3SLiteSpeed Tech            }
4015392f7a3SLiteSpeed Tech            break;
4025392f7a3SLiteSpeed Tech        case LQES_NOBUF_HEAD:
4035392f7a3SLiteSpeed Tech            return QWH_ENOBUF;
4045392f7a3SLiteSpeed Tech        default:
4055392f7a3SLiteSpeed Tech            assert(0);
4065392f7a3SLiteSpeed Tech            return QWH_ERR;
4075392f7a3SLiteSpeed Tech        case LQES_NOBUF_ENC:
4085392f7a3SLiteSpeed Tech            LSQ_DEBUG("not enough room to write encoder stream data");
4095392f7a3SLiteSpeed Tech            return QWH_ERR;
4105392f7a3SLiteSpeed Tech        }
4115392f7a3SLiteSpeed Tech    }
4125392f7a3SLiteSpeed Tech
4134947ba95SDmitri Tikhonov    nw = lsqpack_enc_end_header(&qeh->qeh_encoder, buf - *prefix_sz,
4144947ba95SDmitri Tikhonov                                                        *prefix_sz, hflags);
4155392f7a3SLiteSpeed Tech    if (nw <= 0)
4165392f7a3SLiteSpeed Tech    {
4175392f7a3SLiteSpeed Tech        LSQ_WARN("could not end header: %zd", nw);
4185392f7a3SLiteSpeed Tech        return QWH_ERR;
4195392f7a3SLiteSpeed Tech    }
4205392f7a3SLiteSpeed Tech
4215392f7a3SLiteSpeed Tech    if ((size_t) nw < *prefix_sz)
4225392f7a3SLiteSpeed Tech    {
4235392f7a3SLiteSpeed Tech        memmove(buf - nw, buf - *prefix_sz, (size_t) nw);
4245392f7a3SLiteSpeed Tech        *prefix_sz = (size_t) nw;
4255392f7a3SLiteSpeed Tech    }
4265392f7a3SLiteSpeed Tech    *headers_sz = p - buf;
4275392f7a3SLiteSpeed Tech    if (lsquic_frab_list_empty(&qeh->qeh_fral))
4285392f7a3SLiteSpeed Tech    {
4295392f7a3SLiteSpeed Tech        LSQ_DEBUG("all %zd bytes of encoder stream written out; header block "
4305392f7a3SLiteSpeed Tech            "is %zd bytes; estimated compression ratio %.3f", total_enc_sz,
4315392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
4325392f7a3SLiteSpeed Tech        return QWH_FULL;
4335392f7a3SLiteSpeed Tech    }
4345392f7a3SLiteSpeed Tech    else
4355392f7a3SLiteSpeed Tech    {
4365392f7a3SLiteSpeed Tech        *completion_offset = lsquic_qeh_enc_off(qeh)
4375392f7a3SLiteSpeed Tech                                    + lsquic_frab_list_size(&qeh->qeh_fral);
4385392f7a3SLiteSpeed Tech        LSQ_DEBUG("not all %zd bytes of encoder stream written out; %zd bytes "
4395392f7a3SLiteSpeed Tech            "buffered; header block is %zd bytes; estimated compression ratio "
4405392f7a3SLiteSpeed Tech            "%.3f", total_enc_sz, lsquic_frab_list_size(&qeh->qeh_fral),
4415392f7a3SLiteSpeed Tech            *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
4425392f7a3SLiteSpeed Tech        return QWH_PARTIAL;
4435392f7a3SLiteSpeed Tech    }
4445392f7a3SLiteSpeed Tech}
4455392f7a3SLiteSpeed Tech
4465392f7a3SLiteSpeed Tech
4475392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
4485392f7a3SLiteSpeed Tech__attribute__((weak))
4495392f7a3SLiteSpeed Tech#endif
4505392f7a3SLiteSpeed Techenum qwh_status
4515392f7a3SLiteSpeed Techlsquic_qeh_write_headers (struct qpack_enc_hdl *qeh,
4525392f7a3SLiteSpeed Tech    lsquic_stream_id_t stream_id, unsigned seqno,
4535392f7a3SLiteSpeed Tech    const struct lsquic_http_headers *headers, unsigned char *buf,
4544947ba95SDmitri Tikhonov    size_t *prefix_sz, size_t *headers_sz, uint64_t *completion_offset,
4554947ba95SDmitri Tikhonov    enum lsqpack_enc_header_flags *hflags)
4565392f7a3SLiteSpeed Tech{
4575392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
4585392f7a3SLiteSpeed Tech        return qeh_write_headers(qeh, stream_id, seqno, headers, buf,
4594947ba95SDmitri Tikhonov                        prefix_sz, headers_sz, completion_offset, hflags);
4605392f7a3SLiteSpeed Tech    else
4615392f7a3SLiteSpeed Tech        return QWH_ERR;
4625392f7a3SLiteSpeed Tech}
4635392f7a3SLiteSpeed Tech
4645392f7a3SLiteSpeed Tech
4655392f7a3SLiteSpeed Tech#if !defined(NDEBUG) && __GNUC__
4665392f7a3SLiteSpeed Tech__attribute__((weak))
4675392f7a3SLiteSpeed Tech#endif
4685392f7a3SLiteSpeed Techuint64_t
4695392f7a3SLiteSpeed Techlsquic_qeh_enc_off (struct qpack_enc_hdl *qeh)
4705392f7a3SLiteSpeed Tech{
4715392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
4725392f7a3SLiteSpeed Tech        return qeh->qeh_enc_sm_out->tosend_off;
4735392f7a3SLiteSpeed Tech    else
4745392f7a3SLiteSpeed Tech        return 0;
4755392f7a3SLiteSpeed Tech}
4765392f7a3SLiteSpeed Tech
4775392f7a3SLiteSpeed Tech
4785392f7a3SLiteSpeed Techsize_t
4795392f7a3SLiteSpeed Techlsquic_qeh_write_avail (struct qpack_enc_hdl *qeh)
4805392f7a3SLiteSpeed Tech{
4815392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & QEH_INITIALIZED) && qeh->qeh_enc_sm_out)
4825392f7a3SLiteSpeed Tech        return lsquic_stream_write_avail(qeh->qeh_enc_sm_out);
4835392f7a3SLiteSpeed Tech    else if (qeh->qeh_flags & QEH_INITIALIZED)
4845392f7a3SLiteSpeed Tech        return ~((size_t) 0);   /* Unlimited write */
4855392f7a3SLiteSpeed Tech    else
4865392f7a3SLiteSpeed Tech        return 0;
4875392f7a3SLiteSpeed Tech}
4885392f7a3SLiteSpeed Tech
4895392f7a3SLiteSpeed Tech
4905392f7a3SLiteSpeed Techsize_t
4915392f7a3SLiteSpeed Techlsquic_qeh_max_prefix_size (const struct qpack_enc_hdl *qeh)
4925392f7a3SLiteSpeed Tech{
4935392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
4945392f7a3SLiteSpeed Tech        return qeh->qeh_max_prefix_size;
4955392f7a3SLiteSpeed Tech    else
4965392f7a3SLiteSpeed Tech        return LSQPACK_UINT64_ENC_SZ * 2;
4975392f7a3SLiteSpeed Tech}
498