lsquic_hcso_writer.c revision fbc6cc04
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_hcso_writer.c - write to outgoing HTTP Control Stream 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <stdlib.h> 9#include <string.h> 10#include <sys/queue.h> 11 12#include "lsquic.h" 13#include "lsquic_types.h" 14#include "lsquic_int_types.h" 15#include "lsquic_sfcw.h" 16#include "lsquic_varint.h" 17#include "lsquic_hq.h" 18#include "lsquic_hash.h" 19#include "lsquic_stream.h" 20#include "lsquic_frab_list.h" 21#include "lsquic_byteswap.h" 22#include "lsquic_hcso_writer.h" 23#include "lsquic_conn.h" 24 25#define LSQUIC_LOGGER_MODULE LSQLM_HCSO_WRITER 26#define LSQUIC_LOG_CONN_ID \ 27 lsquic_conn_log_cid(lsquic_stream_conn(writer->how_stream)) 28#include "lsquic_logger.h" 29 30 31static int 32hcso_write_type (struct hcso_writer *writer) 33{ 34 int s; 35 36#ifndef NDEBUG 37 if (writer->how_flags & HOW_RAND_VARINT) 38 { 39 s = rand() & 3; 40 LSQ_DEBUG("writing %d-byte stream type", 1 << s); 41 } 42 else 43#endif 44 s = 0; 45 46 switch (s) 47 { 48 case 0: 49 return lsquic_frab_list_write(&writer->how_fral, 50 (unsigned char []) { HQUST_CONTROL }, 1); 51 case 1: 52 return lsquic_frab_list_write(&writer->how_fral, 53 (unsigned char []) { 0x40, HQUST_CONTROL }, 2); 54 case 2: 55 return lsquic_frab_list_write(&writer->how_fral, 56 (unsigned char []) { 0x80, 0x00, 0x00, HQUST_CONTROL }, 4); 57 default: 58 return lsquic_frab_list_write(&writer->how_fral, 59 (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 HQUST_CONTROL }, 8); 61 } 62} 63 64 65 66static lsquic_stream_ctx_t * 67hcso_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 68{ 69 struct hcso_writer *writer = stream_if_ctx; 70 struct lsquic_conn *lconn; 71 72 writer->how_stream = stream; 73 lsquic_frab_list_init(&writer->how_fral, 0x100, NULL, NULL, NULL); 74#ifndef NDEBUG 75 const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 76 if (env && atoi(env)) 77 { 78 writer->how_flags |= HOW_RAND_VARINT; 79 LSQ_INFO("will randomize varints"); 80 if (0 == (rand() & 3)) 81 { 82 writer->how_flags |= HOW_CHOP_STREAM; 83 LSQ_INFO("will chop beginning of stream into tiny STREAM frames"); 84 } 85 } 86#endif 87 if (0 != hcso_write_type(writer)) 88 { 89 LSQ_INFO("cannot write to frab list"); 90 lconn = lsquic_stream_conn(stream); 91 lconn->cn_if->ci_internal_error(lconn, "cannot write to frab list"); 92 } 93 LSQ_DEBUG("create HTTP Control Stream Writer"); 94 lsquic_stream_wantwrite(stream, 1); 95 return stream_if_ctx; 96} 97 98 99static unsigned 100hcso_setting_type2bits (struct hcso_writer *writer, unsigned setting) 101{ 102 unsigned bits = vint_val2bits(setting); 103 104#ifndef NDEBUG 105 unsigned max_bits; 106 if (writer->how_flags & HOW_RAND_VARINT) 107 { 108 max_bits = rand() & 3; 109 if (max_bits > bits) 110 bits = max_bits; 111 LSQ_DEBUG("writing out HTTP/3 setting %u as %d-byte varint", 112 setting, 1 << bits); 113 } 114#endif 115 116 return bits; 117} 118 119 120int 121lsquic_hcso_write_settings (struct hcso_writer *writer, 122 const struct lsquic_engine_settings *settings, 123 int is_server) 124{ 125 unsigned char *p; 126 unsigned bits; 127 int was_empty; 128#ifdef NDEBUG 129# define frame_size_len 1 130#else 131 /* Need to use two bytes for frame length, as randomization may require 132 * more than 63 bytes. 133 */ 134# define frame_size_len 2 135#endif 136 unsigned char buf[1 /* Frame type */ + /* Frame size */ frame_size_len 137 /* There are maximum three settings that need to be written out and 138 * each value can be encoded in maximum 8 bytes: 139 */ 140 + 3 * ( 141#ifdef NDEBUG 142 1 /* Each setting needs 1-byte varint number, */ 143#else 144 8 /* but it can be up to 8 bytes when randomized */ 145#endif 146 + 8) ]; 147 148 p = buf; 149 *p++ = HQFT_SETTINGS; 150 p += frame_size_len; 151 152 if (settings->es_max_header_list_size != HQ_DF_MAX_HEADER_LIST_SIZE) 153 { 154 /* Write out SETTINGS_MAX_HEADER_LIST_SIZE */ 155 bits = hcso_setting_type2bits(writer, HQSID_MAX_HEADER_LIST_SIZE); 156 vint_write(p, HQSID_MAX_HEADER_LIST_SIZE, bits, 1 << bits); 157 p += 1 << bits; 158 bits = vint_val2bits(settings->es_max_header_list_size); 159 vint_write(p, settings->es_max_header_list_size, bits, 1 << bits); 160 p += 1 << bits; 161 } 162 163 if (settings->es_qpack_dec_max_size != HQ_DF_QPACK_MAX_TABLE_CAPACITY) 164 { 165 /* Write out SETTINGS_QPACK_MAX_TABLE_CAPACITY */ 166 bits = hcso_setting_type2bits(writer, HQSID_QPACK_MAX_TABLE_CAPACITY); 167 vint_write(p, HQSID_QPACK_MAX_TABLE_CAPACITY, bits, 1 << bits); 168 p += 1 << bits; 169 bits = vint_val2bits(settings->es_qpack_dec_max_size); 170 vint_write(p, settings->es_qpack_dec_max_size, bits, 1 << bits); 171 p += 1 << bits; 172 } 173 174 if (settings->es_qpack_dec_max_blocked != HQ_DF_QPACK_BLOCKED_STREAMS) 175 { 176 /* Write out SETTINGS_QPACK_BLOCKED_STREAMS */ 177 bits = hcso_setting_type2bits(writer, HQSID_QPACK_BLOCKED_STREAMS); 178 vint_write(p, HQSID_QPACK_BLOCKED_STREAMS, bits, 1 << bits); 179 p += 1 << bits; 180 bits = vint_val2bits(settings->es_qpack_dec_max_blocked); 181 vint_write(p, settings->es_qpack_dec_max_blocked, bits, 1 << bits); 182 p += 1 << bits; 183 } 184 185#ifdef NDEBUG 186 buf[1] = p - buf - 2; 187#else 188 vint_write(buf + 1, p - buf - 3, 1, 2); 189#endif 190 191 was_empty = lsquic_frab_list_empty(&writer->how_fral); 192 193 if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 194 { 195 LSQ_INFO("cannot write SETTINGS frame to frab list"); 196 return -1; 197 } 198 199 if (was_empty) 200 lsquic_stream_wantwrite(writer->how_stream, 1); 201 202 LSQ_DEBUG("generated %u-byte SETTINGS frame", (unsigned) (p - buf)); 203 return 0; 204} 205 206 207static const char * 208hqft2str (enum hq_frame_type type) 209{ 210 switch (type) 211 { 212 case HQFT_PUSH_PROMISE: return "PUSH_PROMISE"; 213 case HQFT_MAX_PUSH_ID: return "MAX_PUSH_ID"; 214 case HQFT_CANCEL_PUSH: return "CANCEL_PUSH"; 215 case HQFT_GOAWAY: return "GOAWAY"; 216 case HQFT_PRIORITY_UPDATE_PUSH:return "PRIORITY_UPDATE (push)"; 217 case HQFT_PRIORITY_UPDATE_STREAM:return "PRIORITY_UPDATE (stream)"; 218 default: return "<unknown>"; 219 } 220} 221 222 223static int 224hcso_write_number_frame (struct hcso_writer *writer, 225 enum hq_frame_type type, uint64_t value) 226{ 227 unsigned char *p; 228 unsigned bits; 229 int was_empty; 230 unsigned char buf[1 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ ]; 231 232 p = buf; 233 *p++ = type; 234 235 bits = vint_val2bits(value); 236 *p++ = 1 << bits; 237 238 vint_write(p, value, bits, 1 << bits); 239 p += 1 << bits; 240 241 was_empty = lsquic_frab_list_empty(&writer->how_fral); 242 243 if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 244 { 245 LSQ_INFO("cannot write %s frame to frab list", hqft2str(type)); 246 return -1; 247 } 248 249 if (was_empty) 250 lsquic_stream_wantwrite(writer->how_stream, 1); 251 252 LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf), 253 hqft2str(type)); 254 return 0; 255} 256 257 258int 259lsquic_hcso_write_goaway (struct hcso_writer *writer, 260 lsquic_stream_id_t stream_id) 261{ 262 return hcso_write_number_frame(writer, HQFT_GOAWAY, stream_id); 263} 264 265 266int 267lsquic_hcso_write_max_push_id (struct hcso_writer *writer, uint64_t max_push_id) 268{ 269 return hcso_write_number_frame(writer, HQFT_MAX_PUSH_ID, max_push_id); 270} 271 272 273int 274lsquic_hcso_write_cancel_push (struct hcso_writer *writer, uint64_t push_id) 275{ 276 return hcso_write_number_frame(writer, HQFT_CANCEL_PUSH, push_id); 277} 278 279 280int 281lsquic_hcso_write_priority_update (struct hcso_writer *writer, 282 enum hq_frame_type type, uint64_t stream_or_push_id, 283 const struct lsquic_ext_http_prio *ehp) 284{ 285 unsigned char *p, *len; 286 unsigned bits; 287 int was_empty; 288 unsigned char buf[8 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ 289 + 5 /* PFV: "u=.,i" or "u=." */]; 290 291 p = buf; 292 bits = vint_val2bits(type); 293 vint_write(p, type, bits, 1 << bits); 294 p += 1 << bits; 295 296 bits = vint_val2bits(stream_or_push_id); 297 len = p; 298 ++p; 299 300 vint_write(p, stream_or_push_id, bits, 1 << bits); 301 p += 1 << bits; 302 if (!(ehp->urgency == LSQUIC_DEF_HTTP_URGENCY 303 && ehp->incremental == LSQUIC_DEF_HTTP_INCREMENTAL)) 304 { 305 *p++ = 'u'; 306 *p++ = '='; 307 *p++ = '0' + ehp->urgency; 308 if (ehp->incremental) 309 { 310 *p++ = ','; 311 *p++ = 'i'; 312 } 313 } 314 315 *len = p - len - 1; 316 317 was_empty = lsquic_frab_list_empty(&writer->how_fral); 318 319 if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf)) 320 { 321 LSQ_INFO("cannot write %s frame to frab list", hqft2str(type)); 322 return -1; 323 } 324 325 if (was_empty) 326 lsquic_stream_wantwrite(writer->how_stream, 1); 327 328 LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf), 329 hqft2str(type)); 330 return 0; 331} 332 333 334#ifndef NDEBUG 335#define MIN(a, b) ((a) < (b) ? (a) : (b)) 336static size_t 337one_byte_limit_read (void *ctx, void *buf, size_t bufsz) 338{ 339 return lsquic_frab_list_read(ctx, buf, MIN(bufsz, 1)); 340} 341 342 343static size_t 344one_byte_limit_size (void *ctx) 345{ 346 size_t size; 347 348 size = lsquic_frab_list_size(ctx); 349 return MIN(size, 1); 350} 351#endif 352 353static void 354hcso_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 355{ 356 struct hcso_writer *const writer = (void *) ctx; 357 struct lsquic_reader reader = { 358 .lsqr_read = lsquic_frab_list_read, 359 .lsqr_size = lsquic_frab_list_size, 360 .lsqr_ctx = &writer->how_fral 361 }; 362 ssize_t nw; 363 struct lsquic_conn *lconn; 364 365#ifndef NDEBUG 366 if (stream->tosend_off < 8 && (writer->how_flags & HOW_CHOP_STREAM)) 367 { 368 reader.lsqr_read = one_byte_limit_read; 369 reader.lsqr_size = one_byte_limit_size; 370 } 371#endif 372 373 nw = lsquic_stream_writef(stream, &reader); 374 if (nw >= 0) 375 { 376 LSQ_DEBUG("wrote %zd bytes to stream", nw); 377 (void) lsquic_stream_flush(stream); 378 if (lsquic_frab_list_empty(&writer->how_fral)) 379 lsquic_stream_wantwrite(stream, 0); 380 } 381 else 382 { 383 lconn = lsquic_stream_conn(stream); 384 lconn->cn_if->ci_internal_error(lconn, "cannot write to stream: %s", 385 strerror(errno)); 386 lsquic_stream_wantwrite(stream, 0); 387 } 388} 389 390 391static void 392hcso_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 393{ 394 struct hcso_writer *writer = (void *) ctx; 395 LSQ_DEBUG("close HTTP Control Stream Writer"); 396 lsquic_frab_list_cleanup(&writer->how_fral); 397 writer->how_stream = NULL; 398} 399 400 401static void 402hcso_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 403{ 404 assert(0); 405} 406 407 408static const struct lsquic_stream_if hcso_if = 409{ 410 .on_new_stream = hcso_on_new, 411 .on_read = hcso_on_read, 412 .on_write = hcso_on_write, 413 .on_close = hcso_on_close, 414}; 415 416const struct lsquic_stream_if *const lsquic_hcso_writer_if = &hcso_if; 417