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