1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 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_byteswap.h" 225392f7a3SLiteSpeed Tech#include "lsquic_hcso_writer.h" 237d09751dSDmitri Tikhonov#include "lsquic_conn.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; 707d09751dSDmitri Tikhonov struct lsquic_conn *lconn; 717d09751dSDmitri Tikhonov 725392f7a3SLiteSpeed Tech writer->how_stream = stream; 735392f7a3SLiteSpeed Tech lsquic_frab_list_init(&writer->how_fral, 0x100, NULL, NULL, NULL); 745392f7a3SLiteSpeed Tech#ifndef NDEBUG 755392f7a3SLiteSpeed Tech const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 765392f7a3SLiteSpeed Tech if (env && atoi(env)) 775392f7a3SLiteSpeed Tech { 785392f7a3SLiteSpeed Tech writer->how_flags |= HOW_RAND_VARINT; 795392f7a3SLiteSpeed Tech LSQ_INFO("will randomize varints"); 805392f7a3SLiteSpeed Tech if (0 == (rand() & 3)) 815392f7a3SLiteSpeed Tech { 825392f7a3SLiteSpeed Tech writer->how_flags |= HOW_CHOP_STREAM; 835392f7a3SLiteSpeed Tech LSQ_INFO("will chop beginning of stream into tiny STREAM frames"); 845392f7a3SLiteSpeed Tech } 855392f7a3SLiteSpeed Tech } 865392f7a3SLiteSpeed Tech#endif 875392f7a3SLiteSpeed Tech if (0 != hcso_write_type(writer)) 885392f7a3SLiteSpeed Tech { 895392f7a3SLiteSpeed Tech LSQ_INFO("cannot write to frab list"); 907d09751dSDmitri Tikhonov lconn = lsquic_stream_conn(stream); 917d09751dSDmitri Tikhonov lconn->cn_if->ci_internal_error(lconn, "cannot write to frab list"); 925392f7a3SLiteSpeed Tech } 935392f7a3SLiteSpeed Tech LSQ_DEBUG("create HTTP Control Stream Writer"); 945392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 1); 955392f7a3SLiteSpeed Tech return stream_if_ctx; 965392f7a3SLiteSpeed Tech} 975392f7a3SLiteSpeed Tech 985392f7a3SLiteSpeed Tech 995392f7a3SLiteSpeed Techstatic unsigned 1005392f7a3SLiteSpeed Techhcso_setting_type2bits (struct hcso_writer *writer, unsigned setting) 1015392f7a3SLiteSpeed Tech{ 1025392f7a3SLiteSpeed Tech unsigned bits = vint_val2bits(setting); 1035392f7a3SLiteSpeed Tech 1045392f7a3SLiteSpeed Tech#ifndef NDEBUG 1055392f7a3SLiteSpeed Tech unsigned max_bits; 1065392f7a3SLiteSpeed Tech if (writer->how_flags & HOW_RAND_VARINT) 1075392f7a3SLiteSpeed Tech { 1085392f7a3SLiteSpeed Tech max_bits = rand() & 3; 1095392f7a3SLiteSpeed Tech if (max_bits > bits) 1105392f7a3SLiteSpeed Tech bits = max_bits; 1115392f7a3SLiteSpeed Tech LSQ_DEBUG("writing out HTTP/3 setting %u as %d-byte varint", 1125392f7a3SLiteSpeed Tech setting, 1 << bits); 1135392f7a3SLiteSpeed Tech } 1145392f7a3SLiteSpeed Tech#endif 1155392f7a3SLiteSpeed Tech 1165392f7a3SLiteSpeed Tech return bits; 1175392f7a3SLiteSpeed Tech} 1185392f7a3SLiteSpeed Tech 1195392f7a3SLiteSpeed Tech 1205392f7a3SLiteSpeed Techint 1215392f7a3SLiteSpeed Techlsquic_hcso_write_settings (struct hcso_writer *writer, 122758aff32SDmitri Tikhonov unsigned max_header_list_size, 123758aff32SDmitri Tikhonov unsigned dyn_table_size, unsigned max_risked_streams, 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 130fb3e20e0SDmitri Tikhonov# define 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 */ 135fb3e20e0SDmitri Tikhonov# define 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 153758aff32SDmitri Tikhonov if (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; 159758aff32SDmitri Tikhonov bits = vint_val2bits(max_header_list_size); 160758aff32SDmitri Tikhonov vint_write(p, max_header_list_size, bits, 1 << bits); 1615392f7a3SLiteSpeed Tech p += 1 << bits; 1625392f7a3SLiteSpeed Tech } 1635392f7a3SLiteSpeed Tech 164758aff32SDmitri Tikhonov if (dyn_table_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; 170758aff32SDmitri Tikhonov bits = vint_val2bits(dyn_table_size); 171758aff32SDmitri Tikhonov vint_write(p, dyn_table_size, bits, 1 << bits); 1725392f7a3SLiteSpeed Tech p += 1 << bits; 1735392f7a3SLiteSpeed Tech } 1745392f7a3SLiteSpeed Tech 175758aff32SDmitri Tikhonov if (max_risked_streams != 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; 181758aff32SDmitri Tikhonov bits = vint_val2bits(max_risked_streams); 182758aff32SDmitri Tikhonov vint_write(p, max_risked_streams, 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"; 217fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_PUSH:return "PRIORITY_UPDATE (push)"; 218fbc6cc04SDmitri Tikhonov case HQFT_PRIORITY_UPDATE_STREAM:return "PRIORITY_UPDATE (stream)"; 2195392f7a3SLiteSpeed Tech default: return "<unknown>"; 2205392f7a3SLiteSpeed Tech } 2215392f7a3SLiteSpeed Tech} 2225392f7a3SLiteSpeed Tech 2235392f7a3SLiteSpeed Tech 224a5fa05f9SDmitri Tikhonovstatic int 2255392f7a3SLiteSpeed Techhcso_write_number_frame (struct hcso_writer *writer, 2265392f7a3SLiteSpeed Tech enum hq_frame_type type, uint64_t value) 2275392f7a3SLiteSpeed Tech{ 2285392f7a3SLiteSpeed Tech unsigned char *p; 2295392f7a3SLiteSpeed Tech unsigned bits; 2305392f7a3SLiteSpeed Tech int was_empty; 2315392f7a3SLiteSpeed Tech unsigned char buf[1 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ ]; 2325392f7a3SLiteSpeed Tech 2335392f7a3SLiteSpeed Tech p = buf; 2345392f7a3SLiteSpeed Tech *p++ = type; 2355392f7a3SLiteSpeed Tech 2365392f7a3SLiteSpeed Tech bits = vint_val2bits(value); 2375392f7a3SLiteSpeed Tech *p++ = 1 << bits; 2385392f7a3SLiteSpeed Tech 2395392f7a3SLiteSpeed Tech vint_write(p, value, bits, 1 << bits); 2405392f7a3SLiteSpeed Tech p += 1 << bits; 2415392f7a3SLiteSpeed Tech 2425392f7a3SLiteSpeed Tech was_empty = lsquic_frab_list_empty(&writer->how_fral); 2435392f7a3SLiteSpeed Tech 2445392f7a3SLiteSpeed Tech if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 2455392f7a3SLiteSpeed Tech { 2465392f7a3SLiteSpeed Tech LSQ_INFO("cannot write %s frame to frab list", hqft2str(type)); 2475392f7a3SLiteSpeed Tech return -1; 2485392f7a3SLiteSpeed Tech } 2495392f7a3SLiteSpeed Tech 2505392f7a3SLiteSpeed Tech if (was_empty) 2515392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(writer->how_stream, 1); 2525392f7a3SLiteSpeed Tech 2535392f7a3SLiteSpeed Tech LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf), 2545392f7a3SLiteSpeed Tech hqft2str(type)); 2555392f7a3SLiteSpeed Tech return 0; 2565392f7a3SLiteSpeed Tech} 2575392f7a3SLiteSpeed Tech 2585392f7a3SLiteSpeed Tech 2595392f7a3SLiteSpeed Techint 2605392f7a3SLiteSpeed Techlsquic_hcso_write_goaway (struct hcso_writer *writer, 2615392f7a3SLiteSpeed Tech lsquic_stream_id_t stream_id) 2625392f7a3SLiteSpeed Tech{ 2635392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_GOAWAY, stream_id); 2645392f7a3SLiteSpeed Tech} 2655392f7a3SLiteSpeed Tech 2665392f7a3SLiteSpeed Tech 2675392f7a3SLiteSpeed Techint 2685392f7a3SLiteSpeed Techlsquic_hcso_write_max_push_id (struct hcso_writer *writer, uint64_t max_push_id) 2695392f7a3SLiteSpeed Tech{ 2705392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_MAX_PUSH_ID, max_push_id); 2715392f7a3SLiteSpeed Tech} 2725392f7a3SLiteSpeed Tech 2735392f7a3SLiteSpeed Tech 2745392f7a3SLiteSpeed Techint 2755392f7a3SLiteSpeed Techlsquic_hcso_write_cancel_push (struct hcso_writer *writer, uint64_t push_id) 2765392f7a3SLiteSpeed Tech{ 2775392f7a3SLiteSpeed Tech return hcso_write_number_frame(writer, HQFT_CANCEL_PUSH, push_id); 2785392f7a3SLiteSpeed Tech} 2795392f7a3SLiteSpeed Tech 2805392f7a3SLiteSpeed Tech 281fbc6cc04SDmitri Tikhonovint 282fbc6cc04SDmitri Tikhonovlsquic_hcso_write_priority_update (struct hcso_writer *writer, 283fbc6cc04SDmitri Tikhonov enum hq_frame_type type, uint64_t stream_or_push_id, 284fbc6cc04SDmitri Tikhonov const struct lsquic_ext_http_prio *ehp) 285fbc6cc04SDmitri Tikhonov{ 286fbc6cc04SDmitri Tikhonov unsigned char *p, *len; 287fbc6cc04SDmitri Tikhonov unsigned bits; 288fbc6cc04SDmitri Tikhonov int was_empty; 289fbc6cc04SDmitri Tikhonov unsigned char buf[8 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ 290fbc6cc04SDmitri Tikhonov + 5 /* PFV: "u=.,i" or "u=." */]; 291fbc6cc04SDmitri Tikhonov 292fbc6cc04SDmitri Tikhonov p = buf; 293fbc6cc04SDmitri Tikhonov bits = vint_val2bits(type); 294fbc6cc04SDmitri Tikhonov vint_write(p, type, bits, 1 << bits); 295fbc6cc04SDmitri Tikhonov p += 1 << bits; 296fbc6cc04SDmitri Tikhonov 297fbc6cc04SDmitri Tikhonov bits = vint_val2bits(stream_or_push_id); 298fbc6cc04SDmitri Tikhonov len = p; 299fbc6cc04SDmitri Tikhonov ++p; 300fbc6cc04SDmitri Tikhonov 301fbc6cc04SDmitri Tikhonov vint_write(p, stream_or_push_id, bits, 1 << bits); 302fbc6cc04SDmitri Tikhonov p += 1 << bits; 303fbc6cc04SDmitri Tikhonov if (!(ehp->urgency == LSQUIC_DEF_HTTP_URGENCY 304fbc6cc04SDmitri Tikhonov && ehp->incremental == LSQUIC_DEF_HTTP_INCREMENTAL)) 305fbc6cc04SDmitri Tikhonov { 306fbc6cc04SDmitri Tikhonov *p++ = 'u'; 307fbc6cc04SDmitri Tikhonov *p++ = '='; 308fbc6cc04SDmitri Tikhonov *p++ = '0' + ehp->urgency; 309fbc6cc04SDmitri Tikhonov if (ehp->incremental) 310fbc6cc04SDmitri Tikhonov { 311fbc6cc04SDmitri Tikhonov *p++ = ','; 312fbc6cc04SDmitri Tikhonov *p++ = 'i'; 313fbc6cc04SDmitri Tikhonov } 314fbc6cc04SDmitri Tikhonov } 315fbc6cc04SDmitri Tikhonov 316fbc6cc04SDmitri Tikhonov *len = p - len - 1; 317fbc6cc04SDmitri Tikhonov 318fbc6cc04SDmitri Tikhonov was_empty = lsquic_frab_list_empty(&writer->how_fral); 319fbc6cc04SDmitri Tikhonov 320fbc6cc04SDmitri Tikhonov if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 321fbc6cc04SDmitri Tikhonov { 322fbc6cc04SDmitri Tikhonov LSQ_INFO("cannot write %s frame to frab list", hqft2str(type)); 323fbc6cc04SDmitri Tikhonov return -1; 324fbc6cc04SDmitri Tikhonov } 325fbc6cc04SDmitri Tikhonov 326fbc6cc04SDmitri Tikhonov if (was_empty) 327fbc6cc04SDmitri Tikhonov lsquic_stream_wantwrite(writer->how_stream, 1); 328fbc6cc04SDmitri Tikhonov 329fbc6cc04SDmitri Tikhonov LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf), 330fbc6cc04SDmitri Tikhonov hqft2str(type)); 331fbc6cc04SDmitri Tikhonov return 0; 332fbc6cc04SDmitri Tikhonov} 333fbc6cc04SDmitri Tikhonov 334fbc6cc04SDmitri Tikhonov 3355392f7a3SLiteSpeed Tech#ifndef NDEBUG 3365392f7a3SLiteSpeed Tech#define MIN(a, b) ((a) < (b) ? (a) : (b)) 3375392f7a3SLiteSpeed Techstatic size_t 3385392f7a3SLiteSpeed Techone_byte_limit_read (void *ctx, void *buf, size_t bufsz) 3395392f7a3SLiteSpeed Tech{ 3405392f7a3SLiteSpeed Tech return lsquic_frab_list_read(ctx, buf, MIN(bufsz, 1)); 3415392f7a3SLiteSpeed Tech} 3425392f7a3SLiteSpeed Tech 3435392f7a3SLiteSpeed Tech 3445392f7a3SLiteSpeed Techstatic size_t 3455392f7a3SLiteSpeed Techone_byte_limit_size (void *ctx) 3465392f7a3SLiteSpeed Tech{ 3475392f7a3SLiteSpeed Tech size_t size; 3485392f7a3SLiteSpeed Tech 3495392f7a3SLiteSpeed Tech size = lsquic_frab_list_size(ctx); 3505392f7a3SLiteSpeed Tech return MIN(size, 1); 3515392f7a3SLiteSpeed Tech} 3525392f7a3SLiteSpeed Tech#endif 3535392f7a3SLiteSpeed Tech 3545392f7a3SLiteSpeed Techstatic void 3555392f7a3SLiteSpeed Techhcso_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3565392f7a3SLiteSpeed Tech{ 3575392f7a3SLiteSpeed Tech struct hcso_writer *const writer = (void *) ctx; 3585392f7a3SLiteSpeed Tech struct lsquic_reader reader = { 3595392f7a3SLiteSpeed Tech .lsqr_read = lsquic_frab_list_read, 3605392f7a3SLiteSpeed Tech .lsqr_size = lsquic_frab_list_size, 3615392f7a3SLiteSpeed Tech .lsqr_ctx = &writer->how_fral 3625392f7a3SLiteSpeed Tech }; 3635392f7a3SLiteSpeed Tech ssize_t nw; 3647d09751dSDmitri Tikhonov struct lsquic_conn *lconn; 3655392f7a3SLiteSpeed Tech 3665392f7a3SLiteSpeed Tech#ifndef NDEBUG 3675392f7a3SLiteSpeed Tech if (stream->tosend_off < 8 && (writer->how_flags & HOW_CHOP_STREAM)) 3685392f7a3SLiteSpeed Tech { 3695392f7a3SLiteSpeed Tech reader.lsqr_read = one_byte_limit_read; 3705392f7a3SLiteSpeed Tech reader.lsqr_size = one_byte_limit_size; 3715392f7a3SLiteSpeed Tech } 3725392f7a3SLiteSpeed Tech#endif 3735392f7a3SLiteSpeed Tech 3745392f7a3SLiteSpeed Tech nw = lsquic_stream_writef(stream, &reader); 3755392f7a3SLiteSpeed Tech if (nw >= 0) 3765392f7a3SLiteSpeed Tech { 3775392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to stream", nw); 3785392f7a3SLiteSpeed Tech (void) lsquic_stream_flush(stream); 3795392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&writer->how_fral)) 3805392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 3815392f7a3SLiteSpeed Tech } 3825392f7a3SLiteSpeed Tech else 3835392f7a3SLiteSpeed Tech { 3847d09751dSDmitri Tikhonov lconn = lsquic_stream_conn(stream); 3857d09751dSDmitri Tikhonov lconn->cn_if->ci_internal_error(lconn, "cannot write to stream: %s", 3867d09751dSDmitri Tikhonov strerror(errno)); 3875392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 3885392f7a3SLiteSpeed Tech } 3895392f7a3SLiteSpeed Tech} 3905392f7a3SLiteSpeed Tech 3915392f7a3SLiteSpeed Tech 3925392f7a3SLiteSpeed Techstatic void 3935392f7a3SLiteSpeed Techhcso_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3945392f7a3SLiteSpeed Tech{ 3955392f7a3SLiteSpeed Tech struct hcso_writer *writer = (void *) ctx; 3965392f7a3SLiteSpeed Tech LSQ_DEBUG("close HTTP Control Stream Writer"); 3975392f7a3SLiteSpeed Tech lsquic_frab_list_cleanup(&writer->how_fral); 3985392f7a3SLiteSpeed Tech writer->how_stream = NULL; 3995392f7a3SLiteSpeed Tech} 4005392f7a3SLiteSpeed Tech 4015392f7a3SLiteSpeed Tech 4025392f7a3SLiteSpeed Techstatic void 4035392f7a3SLiteSpeed Techhcso_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 4045392f7a3SLiteSpeed Tech{ 4055392f7a3SLiteSpeed Tech assert(0); 4065392f7a3SLiteSpeed Tech} 4075392f7a3SLiteSpeed Tech 4085392f7a3SLiteSpeed Tech 4095392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if hcso_if = 4105392f7a3SLiteSpeed Tech{ 4115392f7a3SLiteSpeed Tech .on_new_stream = hcso_on_new, 4125392f7a3SLiteSpeed Tech .on_read = hcso_on_read, 4135392f7a3SLiteSpeed Tech .on_write = hcso_on_write, 4145392f7a3SLiteSpeed Tech .on_close = hcso_on_close, 4155392f7a3SLiteSpeed Tech}; 4165392f7a3SLiteSpeed Tech 4175392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_hcso_writer_if = &hcso_if; 418