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