lsquic_hcso_writer.c revision 7d09751d
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * lsquic_hcso_writer.c - write to outgoing HTTP Control Stream 45392f7a3SLiteSpeed Tech */ 55392f7a3SLiteSpeed Tech 65392f7a3SLiteSpeed Tech#include <assert.h> 75392f7a3SLiteSpeed Tech#include <errno.h> 85392f7a3SLiteSpeed Tech#include <stdlib.h> 95392f7a3SLiteSpeed Tech#include <string.h> 105392f7a3SLiteSpeed Tech#include <sys/queue.h> 115392f7a3SLiteSpeed Tech 125392f7a3SLiteSpeed Tech#include "lsquic.h" 135392f7a3SLiteSpeed Tech#include "lsquic_types.h" 145392f7a3SLiteSpeed Tech#include "lsquic_int_types.h" 155392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h" 165392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 175392f7a3SLiteSpeed Tech#include "lsquic_hq.h" 185392f7a3SLiteSpeed Tech#include "lsquic_hash.h" 195392f7a3SLiteSpeed Tech#include "lsquic_stream.h" 205392f7a3SLiteSpeed Tech#include "lsquic_frab_list.h" 215392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 225392f7a3SLiteSpeed Tech#include "lsquic_byteswap.h" 235392f7a3SLiteSpeed Tech#include "lsquic_hcso_writer.h" 247d09751dSDmitri Tikhonov#include "lsquic_conn.h" 255392f7a3SLiteSpeed Tech 265392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_HCSO_WRITER 275392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID \ 285392f7a3SLiteSpeed Tech lsquic_conn_log_cid(lsquic_stream_conn(writer->how_stream)) 295392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 305392f7a3SLiteSpeed Tech 315392f7a3SLiteSpeed Tech 325392f7a3SLiteSpeed Techstatic int 335392f7a3SLiteSpeed Techhcso_write_type (struct hcso_writer *writer) 345392f7a3SLiteSpeed Tech{ 355392f7a3SLiteSpeed Tech int s; 365392f7a3SLiteSpeed Tech 375392f7a3SLiteSpeed Tech#ifndef NDEBUG 385392f7a3SLiteSpeed Tech if (writer->how_flags & HOW_RAND_VARINT) 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(&writer->how_fral, 515392f7a3SLiteSpeed Tech (unsigned char []) { HQUST_CONTROL }, 1); 525392f7a3SLiteSpeed Tech case 1: 535392f7a3SLiteSpeed Tech return lsquic_frab_list_write(&writer->how_fral, 545392f7a3SLiteSpeed Tech (unsigned char []) { 0x40, HQUST_CONTROL }, 2); 555392f7a3SLiteSpeed Tech case 2: 565392f7a3SLiteSpeed Tech return lsquic_frab_list_write(&writer->how_fral, 575392f7a3SLiteSpeed Tech (unsigned char []) { 0x80, 0x00, 0x00, HQUST_CONTROL }, 4); 585392f7a3SLiteSpeed Tech default: 595392f7a3SLiteSpeed Tech return lsquic_frab_list_write(&writer->how_fral, 605392f7a3SLiteSpeed Tech (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 615392f7a3SLiteSpeed Tech HQUST_CONTROL }, 8); 625392f7a3SLiteSpeed Tech } 635392f7a3SLiteSpeed Tech} 645392f7a3SLiteSpeed Tech 655392f7a3SLiteSpeed Tech 665392f7a3SLiteSpeed Tech 675392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t * 685392f7a3SLiteSpeed Techhcso_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 695392f7a3SLiteSpeed Tech{ 705392f7a3SLiteSpeed Tech struct hcso_writer *writer = stream_if_ctx; 717d09751dSDmitri Tikhonov struct lsquic_conn *lconn; 727d09751dSDmitri Tikhonov 735392f7a3SLiteSpeed Tech writer->how_stream = stream; 745392f7a3SLiteSpeed Tech lsquic_frab_list_init(&writer->how_fral, 0x100, NULL, NULL, NULL); 755392f7a3SLiteSpeed Tech#ifndef NDEBUG 765392f7a3SLiteSpeed Tech const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 775392f7a3SLiteSpeed Tech if (env && atoi(env)) 785392f7a3SLiteSpeed Tech { 795392f7a3SLiteSpeed Tech writer->how_flags |= HOW_RAND_VARINT; 805392f7a3SLiteSpeed Tech LSQ_INFO("will randomize varints"); 815392f7a3SLiteSpeed Tech if (0 == (rand() & 3)) 825392f7a3SLiteSpeed Tech { 835392f7a3SLiteSpeed Tech writer->how_flags |= HOW_CHOP_STREAM; 845392f7a3SLiteSpeed Tech LSQ_INFO("will chop beginning of stream into tiny STREAM frames"); 855392f7a3SLiteSpeed Tech } 865392f7a3SLiteSpeed Tech } 875392f7a3SLiteSpeed Tech#endif 885392f7a3SLiteSpeed Tech if (0 != hcso_write_type(writer)) 895392f7a3SLiteSpeed Tech { 905392f7a3SLiteSpeed Tech LSQ_INFO("cannot write to frab list"); 917d09751dSDmitri Tikhonov lconn = lsquic_stream_conn(stream); 927d09751dSDmitri Tikhonov lconn->cn_if->ci_internal_error(lconn, "cannot write to frab list"); 935392f7a3SLiteSpeed Tech } 945392f7a3SLiteSpeed Tech LSQ_DEBUG("create HTTP Control Stream Writer"); 955392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 1); 965392f7a3SLiteSpeed Tech return stream_if_ctx; 975392f7a3SLiteSpeed Tech} 985392f7a3SLiteSpeed Tech 995392f7a3SLiteSpeed Tech 1005392f7a3SLiteSpeed Techstatic unsigned 1015392f7a3SLiteSpeed Techhcso_setting_type2bits (struct hcso_writer *writer, unsigned setting) 1025392f7a3SLiteSpeed Tech{ 1035392f7a3SLiteSpeed Tech unsigned bits = vint_val2bits(setting); 1045392f7a3SLiteSpeed Tech 1055392f7a3SLiteSpeed Tech#ifndef NDEBUG 1065392f7a3SLiteSpeed Tech unsigned max_bits; 1075392f7a3SLiteSpeed Tech if (writer->how_flags & HOW_RAND_VARINT) 1085392f7a3SLiteSpeed Tech { 1095392f7a3SLiteSpeed Tech max_bits = rand() & 3; 1105392f7a3SLiteSpeed Tech if (max_bits > bits) 1115392f7a3SLiteSpeed Tech bits = max_bits; 1125392f7a3SLiteSpeed Tech LSQ_DEBUG("writing out HTTP/3 setting %u as %d-byte varint", 1135392f7a3SLiteSpeed Tech setting, 1 << bits); 1145392f7a3SLiteSpeed Tech } 1155392f7a3SLiteSpeed Tech#endif 1165392f7a3SLiteSpeed Tech 1175392f7a3SLiteSpeed Tech return bits; 1185392f7a3SLiteSpeed Tech} 1195392f7a3SLiteSpeed Tech 1205392f7a3SLiteSpeed Tech 1215392f7a3SLiteSpeed Techint 1225392f7a3SLiteSpeed Techlsquic_hcso_write_settings (struct hcso_writer *writer, 1235392f7a3SLiteSpeed Tech const struct lsquic_engine_settings *settings, 1245392f7a3SLiteSpeed Tech int is_server) 1255392f7a3SLiteSpeed Tech{ 1265392f7a3SLiteSpeed Tech unsigned char *p; 1275392f7a3SLiteSpeed Tech unsigned bits; 1285392f7a3SLiteSpeed Tech int was_empty; 1295392f7a3SLiteSpeed Tech#ifdef NDEBUG 1305392f7a3SLiteSpeed Tech const unsigned frame_size_len = 1; 1315392f7a3SLiteSpeed Tech#else 1325392f7a3SLiteSpeed Tech /* Need to use two bytes for frame length, as randomization may require 1335392f7a3SLiteSpeed Tech * more than 63 bytes. 1345392f7a3SLiteSpeed Tech */ 1355392f7a3SLiteSpeed Tech const unsigned frame_size_len = 2; 1365392f7a3SLiteSpeed Tech#endif 1375392f7a3SLiteSpeed Tech unsigned char buf[1 /* Frame type */ + /* Frame size */ frame_size_len 13892f6e17bSDmitri Tikhonov /* There are maximum three settings that need to be written out and 1395392f7a3SLiteSpeed Tech * each value can be encoded in maximum 8 bytes: 1405392f7a3SLiteSpeed Tech */ 14192f6e17bSDmitri Tikhonov + 3 * ( 1425392f7a3SLiteSpeed Tech#ifdef NDEBUG 1435392f7a3SLiteSpeed Tech 1 /* Each setting needs 1-byte varint number, */ 1445392f7a3SLiteSpeed Tech#else 1455392f7a3SLiteSpeed Tech 8 /* but it can be up to 8 bytes when randomized */ 1465392f7a3SLiteSpeed Tech#endif 1475392f7a3SLiteSpeed Tech + 8) ]; 1485392f7a3SLiteSpeed Tech 1495392f7a3SLiteSpeed Tech p = buf; 1505392f7a3SLiteSpeed Tech *p++ = HQFT_SETTINGS; 1515392f7a3SLiteSpeed Tech p += frame_size_len; 1525392f7a3SLiteSpeed Tech 1535392f7a3SLiteSpeed Tech if (settings->es_max_header_list_size != HQ_DF_MAX_HEADER_LIST_SIZE) 1545392f7a3SLiteSpeed Tech { 1555392f7a3SLiteSpeed Tech /* Write out SETTINGS_MAX_HEADER_LIST_SIZE */ 1565392f7a3SLiteSpeed Tech bits = hcso_setting_type2bits(writer, HQSID_MAX_HEADER_LIST_SIZE); 1575392f7a3SLiteSpeed Tech vint_write(p, HQSID_MAX_HEADER_LIST_SIZE, bits, 1 << bits); 1585392f7a3SLiteSpeed Tech p += 1 << bits; 1595392f7a3SLiteSpeed Tech bits = vint_val2bits(settings->es_max_header_list_size); 1605392f7a3SLiteSpeed Tech vint_write(p, settings->es_max_header_list_size, bits, 1 << bits); 1615392f7a3SLiteSpeed Tech p += 1 << bits; 1625392f7a3SLiteSpeed Tech } 1635392f7a3SLiteSpeed Tech 1645392f7a3SLiteSpeed Tech if (settings->es_qpack_dec_max_size != HQ_DF_QPACK_MAX_TABLE_CAPACITY) 1655392f7a3SLiteSpeed Tech { 1665392f7a3SLiteSpeed Tech /* Write out SETTINGS_QPACK_MAX_TABLE_CAPACITY */ 1675392f7a3SLiteSpeed Tech bits = hcso_setting_type2bits(writer, HQSID_QPACK_MAX_TABLE_CAPACITY); 1685392f7a3SLiteSpeed Tech vint_write(p, HQSID_QPACK_MAX_TABLE_CAPACITY, bits, 1 << bits); 1695392f7a3SLiteSpeed Tech p += 1 << bits; 1705392f7a3SLiteSpeed Tech bits = vint_val2bits(settings->es_qpack_dec_max_size); 1715392f7a3SLiteSpeed Tech vint_write(p, settings->es_qpack_dec_max_size, bits, 1 << bits); 1725392f7a3SLiteSpeed Tech p += 1 << bits; 1735392f7a3SLiteSpeed Tech } 1745392f7a3SLiteSpeed Tech 1755392f7a3SLiteSpeed Tech if (settings->es_qpack_dec_max_blocked != HQ_DF_QPACK_BLOCKED_STREAMS) 1765392f7a3SLiteSpeed Tech { 1775392f7a3SLiteSpeed Tech /* Write out SETTINGS_QPACK_BLOCKED_STREAMS */ 1785392f7a3SLiteSpeed Tech bits = hcso_setting_type2bits(writer, HQSID_QPACK_BLOCKED_STREAMS); 1795392f7a3SLiteSpeed Tech vint_write(p, HQSID_QPACK_BLOCKED_STREAMS, bits, 1 << bits); 1805392f7a3SLiteSpeed Tech p += 1 << bits; 1814947ba95SDmitri Tikhonov bits = vint_val2bits(settings->es_qpack_dec_max_blocked); 1825392f7a3SLiteSpeed Tech vint_write(p, settings->es_qpack_dec_max_blocked, bits, 1 << bits); 1835392f7a3SLiteSpeed Tech p += 1 << bits; 1845392f7a3SLiteSpeed Tech } 1855392f7a3SLiteSpeed Tech 1865392f7a3SLiteSpeed Tech#ifdef NDEBUG 1875392f7a3SLiteSpeed Tech buf[1] = p - buf - 2; 1885392f7a3SLiteSpeed Tech#else 1895392f7a3SLiteSpeed Tech vint_write(buf + 1, p - buf - 3, 1, 2); 1905392f7a3SLiteSpeed Tech#endif 1915392f7a3SLiteSpeed Tech 1925392f7a3SLiteSpeed Tech was_empty = lsquic_frab_list_empty(&writer->how_fral); 1935392f7a3SLiteSpeed Tech 1945392f7a3SLiteSpeed Tech if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 1955392f7a3SLiteSpeed Tech { 1965392f7a3SLiteSpeed Tech LSQ_INFO("cannot write SETTINGS frame to frab list"); 1975392f7a3SLiteSpeed Tech return -1; 1985392f7a3SLiteSpeed Tech } 1995392f7a3SLiteSpeed Tech 2005392f7a3SLiteSpeed Tech if (was_empty) 2015392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(writer->how_stream, 1); 2025392f7a3SLiteSpeed Tech 2035392f7a3SLiteSpeed Tech LSQ_DEBUG("generated %u-byte SETTINGS frame", (unsigned) (p - buf)); 2045392f7a3SLiteSpeed Tech return 0; 2055392f7a3SLiteSpeed Tech} 2065392f7a3SLiteSpeed Tech 2075392f7a3SLiteSpeed Tech 2085392f7a3SLiteSpeed Techstatic const char * 2095392f7a3SLiteSpeed Techhqft2str (enum hq_frame_type type) 2105392f7a3SLiteSpeed Tech{ 2115392f7a3SLiteSpeed Tech switch (type) 2125392f7a3SLiteSpeed Tech { 2135392f7a3SLiteSpeed Tech case HQFT_PUSH_PROMISE: return "PUSH_PROMISE"; 2145392f7a3SLiteSpeed Tech case HQFT_MAX_PUSH_ID: return "MAX_PUSH_ID"; 2155392f7a3SLiteSpeed Tech case HQFT_CANCEL_PUSH: return "CANCEL_PUSH"; 2165392f7a3SLiteSpeed Tech case HQFT_GOAWAY: return "GOAWAY"; 2175392f7a3SLiteSpeed Tech default: return "<unknown>"; 2185392f7a3SLiteSpeed Tech } 2195392f7a3SLiteSpeed Tech} 2205392f7a3SLiteSpeed Tech 2215392f7a3SLiteSpeed Tech 2225392f7a3SLiteSpeed Techint 2235392f7a3SLiteSpeed Techhcso_write_number_frame (struct hcso_writer *writer, 2245392f7a3SLiteSpeed Tech enum hq_frame_type type, uint64_t value) 2255392f7a3SLiteSpeed Tech{ 2265392f7a3SLiteSpeed Tech unsigned char *p; 2275392f7a3SLiteSpeed Tech unsigned bits; 2285392f7a3SLiteSpeed Tech int was_empty; 2295392f7a3SLiteSpeed Tech unsigned char buf[1 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ ]; 2305392f7a3SLiteSpeed Tech 2315392f7a3SLiteSpeed Tech p = buf; 2325392f7a3SLiteSpeed Tech *p++ = type; 2335392f7a3SLiteSpeed Tech 2345392f7a3SLiteSpeed Tech bits = vint_val2bits(value); 2355392f7a3SLiteSpeed Tech *p++ = 1 << bits; 2365392f7a3SLiteSpeed Tech 2375392f7a3SLiteSpeed Tech vint_write(p, value, bits, 1 << bits); 2385392f7a3SLiteSpeed Tech p += 1 << bits; 2395392f7a3SLiteSpeed Tech 2405392f7a3SLiteSpeed Tech was_empty = lsquic_frab_list_empty(&writer->how_fral); 2415392f7a3SLiteSpeed Tech 2425392f7a3SLiteSpeed Tech if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 2435392f7a3SLiteSpeed Tech { 2445392f7a3SLiteSpeed Tech LSQ_INFO("cannot write %s frame to frab list", hqft2str(type)); 2455392f7a3SLiteSpeed Tech return -1; 2465392f7a3SLiteSpeed Tech } 2475392f7a3SLiteSpeed Tech 2485392f7a3SLiteSpeed Tech if (was_empty) 2495392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(writer->how_stream, 1); 2505392f7a3SLiteSpeed Tech 2515392f7a3SLiteSpeed Tech LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf), 2525392f7a3SLiteSpeed Tech hqft2str(type)); 2535392f7a3SLiteSpeed Tech return 0; 2545392f7a3SLiteSpeed Tech} 2555392f7a3SLiteSpeed Tech 2565392f7a3SLiteSpeed Tech 2575392f7a3SLiteSpeed Techint 2585392f7a3SLiteSpeed Techlsquic_hcso_write_goaway (struct hcso_writer *writer, 2595392f7a3SLiteSpeed Tech lsquic_stream_id_t stream_id) 2605392f7a3SLiteSpeed Tech{ 2615392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_GOAWAY, stream_id); 2625392f7a3SLiteSpeed Tech} 2635392f7a3SLiteSpeed Tech 2645392f7a3SLiteSpeed Tech 2655392f7a3SLiteSpeed Techint 2665392f7a3SLiteSpeed Techlsquic_hcso_write_max_push_id (struct hcso_writer *writer, uint64_t max_push_id) 2675392f7a3SLiteSpeed Tech{ 2685392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_MAX_PUSH_ID, max_push_id); 2695392f7a3SLiteSpeed Tech} 2705392f7a3SLiteSpeed Tech 2715392f7a3SLiteSpeed Tech 2725392f7a3SLiteSpeed Techint 2735392f7a3SLiteSpeed Techlsquic_hcso_write_cancel_push (struct hcso_writer *writer, uint64_t push_id) 2745392f7a3SLiteSpeed Tech{ 2755392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_CANCEL_PUSH, push_id); 2765392f7a3SLiteSpeed Tech} 2775392f7a3SLiteSpeed Tech 2785392f7a3SLiteSpeed Tech 2795392f7a3SLiteSpeed Tech#ifndef NDEBUG 2805392f7a3SLiteSpeed Tech#define MIN(a, b) ((a) < (b) ? (a) : (b)) 2815392f7a3SLiteSpeed Techstatic size_t 2825392f7a3SLiteSpeed Techone_byte_limit_read (void *ctx, void *buf, size_t bufsz) 2835392f7a3SLiteSpeed Tech{ 2845392f7a3SLiteSpeed Tech return lsquic_frab_list_read(ctx, buf, MIN(bufsz, 1)); 2855392f7a3SLiteSpeed Tech} 2865392f7a3SLiteSpeed Tech 2875392f7a3SLiteSpeed Tech 2885392f7a3SLiteSpeed Techstatic size_t 2895392f7a3SLiteSpeed Techone_byte_limit_size (void *ctx) 2905392f7a3SLiteSpeed Tech{ 2915392f7a3SLiteSpeed Tech size_t size; 2925392f7a3SLiteSpeed Tech 2935392f7a3SLiteSpeed Tech size = lsquic_frab_list_size(ctx); 2945392f7a3SLiteSpeed Tech return MIN(size, 1); 2955392f7a3SLiteSpeed Tech} 2965392f7a3SLiteSpeed Tech#endif 2975392f7a3SLiteSpeed Tech 2985392f7a3SLiteSpeed Techstatic void 2995392f7a3SLiteSpeed Techhcso_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3005392f7a3SLiteSpeed Tech{ 3015392f7a3SLiteSpeed Tech struct hcso_writer *const writer = (void *) ctx; 3025392f7a3SLiteSpeed Tech struct lsquic_reader reader = { 3035392f7a3SLiteSpeed Tech .lsqr_read = lsquic_frab_list_read, 3045392f7a3SLiteSpeed Tech .lsqr_size = lsquic_frab_list_size, 3055392f7a3SLiteSpeed Tech .lsqr_ctx = &writer->how_fral 3065392f7a3SLiteSpeed Tech }; 3075392f7a3SLiteSpeed Tech ssize_t nw; 3087d09751dSDmitri Tikhonov struct lsquic_conn *lconn; 3095392f7a3SLiteSpeed Tech 3105392f7a3SLiteSpeed Tech#ifndef NDEBUG 3115392f7a3SLiteSpeed Tech if (stream->tosend_off < 8 && (writer->how_flags & HOW_CHOP_STREAM)) 3125392f7a3SLiteSpeed Tech { 3135392f7a3SLiteSpeed Tech reader.lsqr_read = one_byte_limit_read; 3145392f7a3SLiteSpeed Tech reader.lsqr_size = one_byte_limit_size; 3155392f7a3SLiteSpeed Tech } 3165392f7a3SLiteSpeed Tech#endif 3175392f7a3SLiteSpeed Tech 3185392f7a3SLiteSpeed Tech nw = lsquic_stream_writef(stream, &reader); 3195392f7a3SLiteSpeed Tech if (nw >= 0) 3205392f7a3SLiteSpeed Tech { 3215392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to stream", nw); 3225392f7a3SLiteSpeed Tech (void) lsquic_stream_flush(stream); 3235392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&writer->how_fral)) 3245392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 3255392f7a3SLiteSpeed Tech } 3265392f7a3SLiteSpeed Tech else 3275392f7a3SLiteSpeed Tech { 3287d09751dSDmitri Tikhonov lconn = lsquic_stream_conn(stream); 3297d09751dSDmitri Tikhonov lconn->cn_if->ci_internal_error(lconn, "cannot write to stream: %s", 3307d09751dSDmitri Tikhonov strerror(errno)); 3315392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 3325392f7a3SLiteSpeed Tech } 3335392f7a3SLiteSpeed Tech} 3345392f7a3SLiteSpeed Tech 3355392f7a3SLiteSpeed Tech 3365392f7a3SLiteSpeed Techstatic void 3375392f7a3SLiteSpeed Techhcso_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3385392f7a3SLiteSpeed Tech{ 3395392f7a3SLiteSpeed Tech struct hcso_writer *writer = (void *) ctx; 3405392f7a3SLiteSpeed Tech LSQ_DEBUG("close HTTP Control Stream Writer"); 3415392f7a3SLiteSpeed Tech lsquic_frab_list_cleanup(&writer->how_fral); 3425392f7a3SLiteSpeed Tech writer->how_stream = NULL; 3435392f7a3SLiteSpeed Tech} 3445392f7a3SLiteSpeed Tech 3455392f7a3SLiteSpeed Tech 3465392f7a3SLiteSpeed Techstatic void 3475392f7a3SLiteSpeed Techhcso_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3485392f7a3SLiteSpeed Tech{ 3495392f7a3SLiteSpeed Tech assert(0); 3505392f7a3SLiteSpeed Tech} 3515392f7a3SLiteSpeed Tech 3525392f7a3SLiteSpeed Tech 3535392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if hcso_if = 3545392f7a3SLiteSpeed Tech{ 3555392f7a3SLiteSpeed Tech .on_new_stream = hcso_on_new, 3565392f7a3SLiteSpeed Tech .on_read = hcso_on_read, 3575392f7a3SLiteSpeed Tech .on_write = hcso_on_write, 3585392f7a3SLiteSpeed Tech .on_close = hcso_on_close, 3595392f7a3SLiteSpeed Tech}; 3605392f7a3SLiteSpeed Tech 3615392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_hcso_writer_if = &hcso_if; 362