lsquic_qenc_hdl.c revision 55613f44
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
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"
2355613f44SDmitri Tikhonov#include "lsxpack_header.h"
245392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
255392f7a3SLiteSpeed Tech#include "lsquic_qenc_hdl.h"
265392f7a3SLiteSpeed Tech
275392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_QENC_HDL
285392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qeh->qeh_conn)
295392f7a3SLiteSpeed Tech#include "lsquic_logger.h"
305392f7a3SLiteSpeed Tech
315392f7a3SLiteSpeed Tech
325392f7a3SLiteSpeed Techstatic int
335392f7a3SLiteSpeed Techqeh_write_type (struct qpack_enc_hdl *qeh)
345392f7a3SLiteSpeed Tech{
355392f7a3SLiteSpeed Tech    int s;
365392f7a3SLiteSpeed Tech
375392f7a3SLiteSpeed Tech#ifndef NDEBUG
385392f7a3SLiteSpeed Tech    const char *env = getenv("LSQUIC_RND_VARINT_LEN");
395392f7a3SLiteSpeed Tech    if (env && atoi(env))
405392f7a3SLiteSpeed Tech    {
415392f7a3SLiteSpeed Tech        s = rand() & 3;
425392f7a3SLiteSpeed Tech        LSQ_DEBUG("writing %d-byte stream type", 1 << s);
435392f7a3SLiteSpeed Tech    }
445392f7a3SLiteSpeed Tech    else
455392f7a3SLiteSpeed Tech#endif
465392f7a3SLiteSpeed Tech        s = 0;
475392f7a3SLiteSpeed Tech
485392f7a3SLiteSpeed Tech    switch (s)
495392f7a3SLiteSpeed Tech    {
505392f7a3SLiteSpeed Tech    case 0:
515392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
525392f7a3SLiteSpeed Tech                                (unsigned char []) { HQUST_QPACK_ENC }, 1);
535392f7a3SLiteSpeed Tech    case 1:
545392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
555392f7a3SLiteSpeed Tech                            (unsigned char []) { 0x40, HQUST_QPACK_ENC }, 2);
565392f7a3SLiteSpeed Tech    case 2:
575392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
585392f7a3SLiteSpeed Tech                (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_ENC }, 4);
595392f7a3SLiteSpeed Tech    default:
605392f7a3SLiteSpeed Tech        return lsquic_frab_list_write(&qeh->qeh_fral,
615392f7a3SLiteSpeed Tech                (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625392f7a3SLiteSpeed Tech                                                        HQUST_QPACK_ENC }, 8);
635392f7a3SLiteSpeed Tech    }
645392f7a3SLiteSpeed Tech}
655392f7a3SLiteSpeed Tech
665392f7a3SLiteSpeed Tech
675392f7a3SLiteSpeed Techstatic void
685392f7a3SLiteSpeed Techqeh_begin_out (struct qpack_enc_hdl *qeh)
695392f7a3SLiteSpeed Tech{
705392f7a3SLiteSpeed Tech    if (0 == qeh_write_type(qeh)
715392f7a3SLiteSpeed Tech        && (qeh->qeh_tsu_sz == 0
725392f7a3SLiteSpeed Tech            || 0 == lsquic_frab_list_write(&qeh->qeh_fral, qeh->qeh_tsu_buf,
735392f7a3SLiteSpeed Tech                                                            qeh->qeh_tsu_sz)))
745392f7a3SLiteSpeed Tech    {
755392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zu bytes to frab list", 1 + qeh->qeh_tsu_sz);
765392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(qeh->qeh_enc_sm_out, 1);
775392f7a3SLiteSpeed Tech    }
785392f7a3SLiteSpeed Tech    else
795392f7a3SLiteSpeed Tech    {
805392f7a3SLiteSpeed Tech        LSQ_WARN("could not write to frab list");
815392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
825392f7a3SLiteSpeed Tech                                            "cannot write to frab list");
835392f7a3SLiteSpeed Tech    }
845392f7a3SLiteSpeed Tech}
855392f7a3SLiteSpeed Tech
865392f7a3SLiteSpeed Tech
875392f7a3SLiteSpeed Techvoid
885392f7a3SLiteSpeed Techlsquic_qeh_init (struct qpack_enc_hdl *qeh, struct lsquic_conn *conn)
895392f7a3SLiteSpeed Tech{
905392f7a3SLiteSpeed Tech    assert(!(qeh->qeh_flags & QEH_INITIALIZED));
915392f7a3SLiteSpeed Tech    qeh->qeh_conn = conn;
925392f7a3SLiteSpeed Tech    lsquic_frab_list_init(&qeh->qeh_fral, 0x400, NULL, NULL, NULL);
935392f7a3SLiteSpeed Tech    lsqpack_enc_preinit(&qeh->qeh_encoder, (void *) conn);
945392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_INITIALIZED;
955392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
965392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
975392f7a3SLiteSpeed Tech    if (qeh->qeh_dec_sm_in)
985392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
995392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized");
1005392f7a3SLiteSpeed Tech}
1015392f7a3SLiteSpeed Tech
1025392f7a3SLiteSpeed Tech
1035392f7a3SLiteSpeed Techint
1045392f7a3SLiteSpeed Techlsquic_qeh_settings (struct qpack_enc_hdl *qeh, unsigned max_table_size,
1055392f7a3SLiteSpeed Tech             unsigned dyn_table_size, unsigned max_risked_streams, int server)
1065392f7a3SLiteSpeed Tech{
1075392f7a3SLiteSpeed Tech    enum lsqpack_enc_opts enc_opts;
1085392f7a3SLiteSpeed Tech
1095392f7a3SLiteSpeed Tech    assert(qeh->qeh_flags & QEH_INITIALIZED);
1105392f7a3SLiteSpeed Tech
1115392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_HAVE_SETTINGS)
1125392f7a3SLiteSpeed Tech    {
1135392f7a3SLiteSpeed Tech        LSQ_WARN("settings already set");
1145392f7a3SLiteSpeed Tech        return -1;
1155392f7a3SLiteSpeed Tech    }
1165392f7a3SLiteSpeed Tech
1175392f7a3SLiteSpeed Tech    enc_opts = LSQPACK_ENC_OPT_STAGE_2
118a0e1aeeeSDmitri Tikhonov             | (server ? LSQPACK_ENC_OPT_SERVER : 0);
1195392f7a3SLiteSpeed Tech    qeh->qeh_tsu_sz = sizeof(qeh->qeh_tsu_buf);
1205392f7a3SLiteSpeed Tech    if (0 != lsqpack_enc_init(&qeh->qeh_encoder, (void *) qeh->qeh_conn,
1215392f7a3SLiteSpeed Tech                max_table_size, dyn_table_size, max_risked_streams, enc_opts,
1225392f7a3SLiteSpeed Tech                qeh->qeh_tsu_buf, &qeh->qeh_tsu_sz))
1235392f7a3SLiteSpeed Tech    {
1245392f7a3SLiteSpeed Tech        LSQ_INFO("could not initialize QPACK encoder");
1255392f7a3SLiteSpeed Tech        return -1;
1265392f7a3SLiteSpeed Tech    }
1275392f7a3SLiteSpeed Tech    LSQ_DEBUG("%zu-byte post-init TSU", qeh->qeh_tsu_sz);
1285392f7a3SLiteSpeed Tech    qeh->qeh_flags |= QEH_HAVE_SETTINGS;
1295392f7a3SLiteSpeed Tech    qeh->qeh_max_prefix_size =
1305392f7a3SLiteSpeed Tech                        lsqpack_enc_header_block_prefix_size(&qeh->qeh_encoder);
1315392f7a3SLiteSpeed Tech    LSQ_DEBUG("have settings: max table size=%u; dyn table size=%u; max risked "
1325392f7a3SLiteSpeed Tech        "streams=%u", max_table_size, dyn_table_size, max_risked_streams);
1335392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
1345392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1355392f7a3SLiteSpeed Tech    return 0;
1365392f7a3SLiteSpeed Tech}
1375392f7a3SLiteSpeed Tech
1385392f7a3SLiteSpeed Tech
1395392f7a3SLiteSpeed Techvoid
1405392f7a3SLiteSpeed Techlsquic_qeh_cleanup (struct qpack_enc_hdl *qeh)
1415392f7a3SLiteSpeed Tech{
1425392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
1435392f7a3SLiteSpeed Tech    {
1445392f7a3SLiteSpeed Tech        LSQ_DEBUG("cleanup");
1455392f7a3SLiteSpeed Tech        lsqpack_enc_cleanup(&qeh->qeh_encoder);
1465392f7a3SLiteSpeed Tech        lsquic_frab_list_cleanup(&qeh->qeh_fral);
1475392f7a3SLiteSpeed Tech        memset(qeh, 0, sizeof(*qeh));
1485392f7a3SLiteSpeed Tech    }
1495392f7a3SLiteSpeed Tech}
1505392f7a3SLiteSpeed Tech
1515392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
1525392f7a3SLiteSpeed Techqeh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
1535392f7a3SLiteSpeed Tech{
1545392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
1555392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = stream;
1565392f7a3SLiteSpeed Tech    if ((qeh->qeh_flags & (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1575392f7a3SLiteSpeed Tech                                    == (QEH_INITIALIZED|QEH_HAVE_SETTINGS))
1585392f7a3SLiteSpeed Tech        qeh_begin_out(qeh);
1595392f7a3SLiteSpeed Tech    else
1605392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
1615392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized outgoing encoder stream");
1625392f7a3SLiteSpeed Tech    return (void *) qeh;
1635392f7a3SLiteSpeed Tech}
1645392f7a3SLiteSpeed Tech
1655392f7a3SLiteSpeed Tech
1665392f7a3SLiteSpeed Techstatic void
1675392f7a3SLiteSpeed Techqeh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1685392f7a3SLiteSpeed Tech{
1695392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1705392f7a3SLiteSpeed Tech    struct lsquic_reader reader = {
1715392f7a3SLiteSpeed Tech        .lsqr_read  = lsquic_frab_list_read,
1725392f7a3SLiteSpeed Tech        .lsqr_size  = lsquic_frab_list_size,
1735392f7a3SLiteSpeed Tech        .lsqr_ctx   = &qeh->qeh_fral,
1745392f7a3SLiteSpeed Tech    };
1755392f7a3SLiteSpeed Tech    ssize_t nw;
1765392f7a3SLiteSpeed Tech
1775392f7a3SLiteSpeed Tech    nw = lsquic_stream_writef(stream, &reader);
1785392f7a3SLiteSpeed Tech    if (nw >= 0)
1795392f7a3SLiteSpeed Tech    {
1805392f7a3SLiteSpeed Tech        LSQ_DEBUG("wrote %zd bytes to stream", nw);
1815392f7a3SLiteSpeed Tech        (void) lsquic_stream_flush(stream);
1825392f7a3SLiteSpeed Tech        if (lsquic_frab_list_empty(&qeh->qeh_fral))
1835392f7a3SLiteSpeed Tech            lsquic_stream_wantwrite(stream, 0);
1845392f7a3SLiteSpeed Tech    }
1855392f7a3SLiteSpeed Tech    else
1865392f7a3SLiteSpeed Tech    {
1875392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
1885392f7a3SLiteSpeed Tech                                            "cannot write to stream");
1895392f7a3SLiteSpeed Tech        LSQ_WARN("cannot write to stream: %s", strerror(errno));
1905392f7a3SLiteSpeed Tech        lsquic_stream_wantwrite(stream, 0);
1915392f7a3SLiteSpeed Tech    }
1925392f7a3SLiteSpeed Tech}
1935392f7a3SLiteSpeed Tech
1945392f7a3SLiteSpeed Tech
1955392f7a3SLiteSpeed Techstatic void
1965392f7a3SLiteSpeed Techqeh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
1975392f7a3SLiteSpeed Tech{
1985392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
1995392f7a3SLiteSpeed Tech    qeh->qeh_enc_sm_out = NULL;
2005392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed outgoing encoder stream");
2015392f7a3SLiteSpeed Tech}
2025392f7a3SLiteSpeed Tech
2035392f7a3SLiteSpeed Tech
2045392f7a3SLiteSpeed Techstatic void
2055392f7a3SLiteSpeed Techqeh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2065392f7a3SLiteSpeed Tech{
2075392f7a3SLiteSpeed Tech    assert(0);
2085392f7a3SLiteSpeed Tech}
2095392f7a3SLiteSpeed Tech
2105392f7a3SLiteSpeed Tech
2115392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_enc_sm_out_if =
2125392f7a3SLiteSpeed Tech{
2135392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_out_on_new,
2145392f7a3SLiteSpeed Tech    .on_read        = qeh_out_on_read,
2155392f7a3SLiteSpeed Tech    .on_write       = qeh_out_on_write,
2165392f7a3SLiteSpeed Tech    .on_close       = qeh_out_on_close,
2175392f7a3SLiteSpeed Tech};
2185392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_enc_sm_out_if =
2195392f7a3SLiteSpeed Tech                                                    &qeh_enc_sm_out_if;
2205392f7a3SLiteSpeed Tech
2215392f7a3SLiteSpeed Tech
2225392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t *
2235392f7a3SLiteSpeed Techqeh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
2245392f7a3SLiteSpeed Tech{
2255392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = stream_if_ctx;
2265392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = stream;
2275392f7a3SLiteSpeed Tech    if (qeh->qeh_flags & QEH_INITIALIZED)
2285392f7a3SLiteSpeed Tech        lsquic_stream_wantread(qeh->qeh_dec_sm_in, 1);
2295392f7a3SLiteSpeed Tech    else
2305392f7a3SLiteSpeed Tech        qeh->qeh_conn = lsquic_stream_conn(stream);   /* Or NULL deref in log */
2315392f7a3SLiteSpeed Tech    LSQ_DEBUG("initialized incoming decoder stream");
2325392f7a3SLiteSpeed Tech    return (void *) qeh;
2335392f7a3SLiteSpeed Tech}
2345392f7a3SLiteSpeed Tech
2355392f7a3SLiteSpeed Tech
2365392f7a3SLiteSpeed Techstatic size_t
2375392f7a3SLiteSpeed Techqeh_read_decoder_stream (void *ctx, const unsigned char *buf, size_t sz,
2385392f7a3SLiteSpeed Tech                                                                    int fin)
2395392f7a3SLiteSpeed Tech{
2405392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2415392f7a3SLiteSpeed Tech    uint64_t offset;
2425392f7a3SLiteSpeed Tech    int s;
2435392f7a3SLiteSpeed Tech
2445392f7a3SLiteSpeed Tech    if (fin)
2455392f7a3SLiteSpeed Tech    {
2465392f7a3SLiteSpeed Tech        LSQ_INFO("decoder stream is closed");
2475392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2485392f7a3SLiteSpeed Tech            HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK decoder stream");
2495392f7a3SLiteSpeed Tech        goto end;
2505392f7a3SLiteSpeed Tech    }
2515392f7a3SLiteSpeed Tech
2525392f7a3SLiteSpeed Tech    offset = lsquic_stream_read_offset(qeh->qeh_dec_sm_in);
2535392f7a3SLiteSpeed Tech    s = lsqpack_enc_decoder_in(&qeh->qeh_encoder, buf, sz);
2545392f7a3SLiteSpeed Tech    if (s != 0)
2555392f7a3SLiteSpeed Tech    {
2565392f7a3SLiteSpeed Tech        LSQ_INFO("error reading decoder stream");
2575392f7a3SLiteSpeed Tech        qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2585392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_STREAM_ERROR, "Error interpreting QPACK decoder "
2595392f7a3SLiteSpeed Tech            "stream at offset %"PRIu64, offset);
2605392f7a3SLiteSpeed Tech        goto end;
2615392f7a3SLiteSpeed Tech    }
2625392f7a3SLiteSpeed Tech    LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz);
2635392f7a3SLiteSpeed Tech
2645392f7a3SLiteSpeed Tech  end:
2655392f7a3SLiteSpeed Tech    return sz;
2665392f7a3SLiteSpeed Tech}
2675392f7a3SLiteSpeed Tech
2685392f7a3SLiteSpeed Tech
2695392f7a3SLiteSpeed Techstatic void
2705392f7a3SLiteSpeed Techqeh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2715392f7a3SLiteSpeed Tech{
2725392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2735392f7a3SLiteSpeed Tech    ssize_t nread;
2745392f7a3SLiteSpeed Tech
2755392f7a3SLiteSpeed Tech    nread = lsquic_stream_readf(stream, qeh_read_decoder_stream, qeh);
2765392f7a3SLiteSpeed Tech    if (nread <= 0)
2775392f7a3SLiteSpeed Tech    {
2785392f7a3SLiteSpeed Tech        if (nread < 0)
2795392f7a3SLiteSpeed Tech        {
2805392f7a3SLiteSpeed Tech            LSQ_WARN("cannot read from encoder stream: %s", strerror(errno));
2815392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_internal_error(qeh->qeh_conn,
2825392f7a3SLiteSpeed Tech                                        "cannot read from encoder stream");
2835392f7a3SLiteSpeed Tech        }
2845392f7a3SLiteSpeed Tech        else
2855392f7a3SLiteSpeed Tech        {
2865392f7a3SLiteSpeed Tech            LSQ_INFO("encoder stream closed by peer: abort connection");
2875392f7a3SLiteSpeed Tech            qeh->qeh_conn->cn_if->ci_abort_error(qeh->qeh_conn, 1,
2885392f7a3SLiteSpeed Tech                HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed");
2895392f7a3SLiteSpeed Tech        }
2905392f7a3SLiteSpeed Tech        lsquic_stream_wantread(stream, 0);
2915392f7a3SLiteSpeed Tech    }
2925392f7a3SLiteSpeed Tech}
2935392f7a3SLiteSpeed Tech
2945392f7a3SLiteSpeed Tech
2955392f7a3SLiteSpeed Techstatic void
2965392f7a3SLiteSpeed Techqeh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
2975392f7a3SLiteSpeed Tech{
2985392f7a3SLiteSpeed Tech    struct qpack_enc_hdl *const qeh = (void *) ctx;
2995392f7a3SLiteSpeed Tech    LSQ_DEBUG("closed incoming decoder stream");
3005392f7a3SLiteSpeed Tech    qeh->qeh_dec_sm_in = NULL;
3015392f7a3SLiteSpeed Tech}
3025392f7a3SLiteSpeed Tech
3035392f7a3SLiteSpeed Tech
3045392f7a3SLiteSpeed Techstatic void
3055392f7a3SLiteSpeed Techqeh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
3065392f7a3SLiteSpeed Tech{
3075392f7a3SLiteSpeed Tech    assert(0);
3085392f7a3SLiteSpeed Tech}
3095392f7a3SLiteSpeed Tech
3105392f7a3SLiteSpeed Tech
3115392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qeh_dec_sm_in_if =
3125392f7a3SLiteSpeed Tech{
3135392f7a3SLiteSpeed Tech    .on_new_stream  = qeh_in_on_new,
3145392f7a3SLiteSpeed Tech    .on_read        = qeh_in_on_read,
3155392f7a3SLiteSpeed Tech    .on_write       = qeh_in_on_write,
3165392f7a3SLiteSpeed Tech    .on_close       = qeh_in_on_close,
3175392f7a3SLiteSpeed Tech};
3185392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qeh_dec_sm_in_if =
3195392f7a3SLiteSpeed Tech                                                    &qeh_dec_sm_in_if;
3205392f7a3SLiteSpeed Tech
3215392f7a3SLiteSpeed Tech
3225392f7a3SLiteSpeed Techstatic enum qwh_status
3235392f7a3SLiteSpeed Techqeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
3245392f7a3SLiteSpeed Tech    unsigned seqno, const struct lsquic_http_headers *headers,
3255392f7a3SLiteSpeed Tech    unsigned char *buf, size_t *prefix_sz, size_t *headers_sz,
3264947ba95SDmitri Tikhonov    uint64_t *completion_offset, enum lsqpack_enc_header_flags *hflags)
3275392f7a3SLiteSpeed Tech{
3285392f7a3SLiteSpeed Tech    unsigned char *p = buf;
3295392f7a3SLiteSpeed Tech    unsigned char *const end = buf + *headers_sz;
3305392f7a3SLiteSpeed Tech    const unsigned char *enc_p;
3315392f7a3SLiteSpeed Tech    size_t enc_sz, hea_sz, total_enc_sz;
3325392f7a3SLiteSpeed Tech    ssize_t nw;
3335392f7a3SLiteSpeed Tech    enum lsqpack_enc_status st;
3345392f7a3SLiteSpeed Tech    int i, s, write_to_stream;
3355392f7a3SLiteSpeed Tech    enum lsqpack_enc_flags enc_flags;
3365392f7a3SLiteSpeed Tech    unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ];
3375392f7a3SLiteSpeed Tech
3385392f7a3SLiteSpeed Tech    s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0);
3395392f7a3SLiteSpeed Tech    if (s != 0)
3405392f7a3SLiteSpeed Tech    {
3415392f7a3SLiteSpeed Tech        LSQ_WARN("cannot start header");
3425392f7a3SLiteSpeed Tech        return QWH_ERR;
3435392f7a3SLiteSpeed Tech    }
3445392f7a3SLiteSpeed Tech    LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id);
3455392f7a3SLiteSpeed Tech
3465392f7a3SLiteSpeed Tech    if (qeh->qeh_enc_sm_out)
3475392f7a3SLiteSpeed Tech        enc_flags = 0;
3485392f7a3SLiteSpeed Tech    else
3495392f7a3SLiteSpeed Tech    {
3505392f7a3SLiteSpeed Tech        enc_flags = LQEF_NO_INDEX;
3515392f7a3SLiteSpeed Tech        LSQ_DEBUG("encoder stream is unavailable, won't index headers");
3525392f7a3SLiteSpeed Tech    }
3535392f7a3SLiteSpeed Tech    write_to_stream = qeh->qeh_enc_sm_out
3545392f7a3SLiteSpeed Tech                                && lsquic_frab_list_empty(&qeh->qeh_fral);
3555392f7a3SLiteSpeed Tech    total_enc_sz = 0;
3565392f7a3SLiteSpeed Tech    for (i = 0; i < headers->count; ++i)
3575392f7a3SLiteSpeed Tech    {
35855613f44SDmitri Tikhonov        if (headers->headers[i].buf == NULL)
35955613f44SDmitri Tikhonov            continue;
3605392f7a3SLiteSpeed Tech        enc_sz = sizeof(enc_buf);
3615392f7a3SLiteSpeed Tech        hea_sz = end - p;
3625392f7a3SLiteSpeed Tech        st = lsqpack_enc_encode(&qeh->qeh_encoder, enc_buf, &enc_sz, p,
36355613f44SDmitri Tikhonov                                &hea_sz, &headers->headers[i], 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",
36955613f44SDmitri Tikhonov                (int) headers->headers[i].name_len,
37055613f44SDmitri Tikhonov                    lsxpack_header_get_name(&headers->headers[i]),
37155613f44SDmitri Tikhonov                (int) headers->headers[i].val_len,
37255613f44SDmitri Tikhonov                    lsxpack_header_get_value(&headers->headers[i]),
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