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