lsquic_frame_writer.c revision 3b55e6ae
1/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_frame_writer.c -- write frames to HEADERS stream. 4 * 5 * The frame is first written to list of frame_buf's (frabs) and then 6 * out to the stream. This is done because frame's size is written out 7 * to the stream and we may not have enough room in the stream to fit 8 * the whole frame. 9 */ 10 11#ifndef WIN32 12#include <arpa/inet.h> 13#endif 14#include <assert.h> 15#include <errno.h> 16#include <inttypes.h> 17#include <stdlib.h> 18#include <string.h> 19#include <sys/queue.h> 20 21#include "lshpack.h" 22#include "lsquic_mm.h" 23#include "lsquic.h" 24 25#include "lsquic_frame_writer.h" 26#include "lsquic_frame_common.h" 27#include "lsquic_ev_log.h" 28 29#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER 30#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(fw->fw_stream)) 31#include "lsquic_logger.h" 32 33#ifndef LSQUIC_FRAB_SZ 34# define LSQUIC_FRAB_SZ 0x1000 35#endif 36 37struct frame_buf 38{ 39 TAILQ_ENTRY(frame_buf) frab_next; 40 unsigned short frab_size, 41 frab_off; 42 unsigned char frab_buf[ 43 LSQUIC_FRAB_SZ 44 - sizeof(TAILQ_ENTRY(frame_buf)) 45 - sizeof(unsigned short) * 2 46 ]; 47}; 48 49#define frab_left_to_read(f) ((f)->frab_size - (f)->frab_off) 50#define frab_left_to_write(f) ((unsigned short) sizeof((f)->frab_buf) - (f)->frab_size) 51#define frab_write_to(f) ((f)->frab_buf + (f)->frab_size) 52 53/* Make sure that frab_buf is at least five bytes long, otherwise a frame 54 * won't fit into two adjacent frabs. 55 */ 56typedef char three_byte_frab_buf[(sizeof(((struct frame_buf *)0)->frab_buf) >= 5) ?1 : - 1]; 57 58 59TAILQ_HEAD(frame_buf_head, frame_buf); 60 61 62struct lsquic_frame_writer 63{ 64 struct lsquic_stream *fw_stream; 65 fw_write_f fw_write; 66 struct lsquic_mm *fw_mm; 67 struct lshpack_enc *fw_henc; 68 struct frame_buf_head fw_frabs; 69 unsigned fw_max_frame_sz; 70 uint32_t fw_max_header_list_sz; /* 0 means unlimited */ 71 enum { 72 FW_SERVER = (1 << 0), 73 } fw_flags; 74}; 75 76 77/* RFC 7540, Section 4.2 */ 78#define MIN_MAX_FRAME_SIZE (1 << 14) 79#define MAX_MAX_FRAME_SIZE ((1 << 24) - 1) 80 81#define MAX(a, b) ((a) > (b) ? (a) : (b)) 82#define SETTINGS_FRAME_SZ 6 83#define ABS_MIN_FRAME_SIZE MAX(SETTINGS_FRAME_SZ, \ 84 sizeof(struct http_prio_frame)) 85 86struct lsquic_frame_writer * 87lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream, 88 unsigned max_frame_sz, struct lshpack_enc *henc, fw_write_f write, 89 int is_server) 90{ 91 struct lsquic_frame_writer *fw; 92 93 /* When frame writer is instantiated, limit the maximum size to 94 * MIN_MAX_FRAME_SIZE. The reference implementation has this value 95 * hardcoded and QUIC does not provide a mechanism to advertise a 96 * different value. 97 */ 98 if (0 == max_frame_sz) 99 max_frame_sz = MIN_MAX_FRAME_SIZE; 100 else 101 LSQ_LOG1(LSQ_LOG_WARN, "max frame size specified to be %u bytes " 102 "-- this better be test code!", max_frame_sz); 103 104 if (!is_server && max_frame_sz < ABS_MIN_FRAME_SIZE) 105 { 106 LSQ_LOG1(LSQ_LOG_ERROR, "max frame size must be at least %zd bytes, " 107 "which is the size of priority information that client always " 108 "writes", ABS_MIN_FRAME_SIZE); 109 return NULL; 110 } 111 112 fw = malloc(sizeof(*fw)); 113 if (!fw) 114 return NULL; 115 116 fw->fw_mm = mm; 117 fw->fw_henc = henc; 118 fw->fw_stream = stream; 119 fw->fw_write = write; 120 fw->fw_max_frame_sz = max_frame_sz; 121 fw->fw_max_header_list_sz = 0; 122 if (is_server) 123 fw->fw_flags = FW_SERVER; 124 else 125 fw->fw_flags = 0; 126 TAILQ_INIT(&fw->fw_frabs); 127 return fw; 128} 129 130 131void 132lsquic_frame_writer_destroy (struct lsquic_frame_writer *fw) 133{ 134 struct frame_buf *frab; 135 while ((frab = TAILQ_FIRST(&fw->fw_frabs))) 136 { 137 TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next); 138 lsquic_mm_put_4k(fw->fw_mm, frab); 139 } 140 free(fw); 141} 142 143 144static struct frame_buf * 145fw_get_frab (struct lsquic_frame_writer *fw) 146{ 147 struct frame_buf *frab; 148 frab = lsquic_mm_get_4k(fw->fw_mm); 149 if (frab) 150 memset(frab, 0, offsetof(struct frame_buf, frab_buf)); 151 return frab; 152} 153 154 155static void 156fw_put_frab (struct lsquic_frame_writer *fw, struct frame_buf *frab) 157{ 158 TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next); 159 lsquic_mm_put_4k(fw->fw_mm, frab); 160} 161 162 163static int 164fw_write_to_frab (struct lsquic_frame_writer *fw, const void *buf, size_t bufsz) 165{ 166 const unsigned char *p = buf; 167 const unsigned char *const end = p + bufsz; 168 struct frame_buf *frab; 169 unsigned ntowrite; 170 171 while (p < end) 172 { 173 frab = TAILQ_LAST(&fw->fw_frabs, frame_buf_head); 174 if (!(frab && (ntowrite = frab_left_to_write(frab)) > 0)) 175 { 176 frab = fw_get_frab(fw); 177 if (!frab) 178 return -1; 179 TAILQ_INSERT_TAIL(&fw->fw_frabs, frab, frab_next); 180 ntowrite = frab_left_to_write(frab); 181 } 182 if (ntowrite > bufsz) 183 ntowrite = bufsz; 184 memcpy(frab_write_to(frab), p, ntowrite); 185 p += ntowrite; 186 bufsz -= ntowrite; 187 frab->frab_size += ntowrite; 188 } 189 190 return 0; 191} 192 193 194int 195lsquic_frame_writer_have_leftovers (const struct lsquic_frame_writer *fw) 196{ 197 return !TAILQ_EMPTY(&fw->fw_frabs); 198} 199 200 201int 202lsquic_frame_writer_flush (struct lsquic_frame_writer *fw) 203{ 204 struct frame_buf *frab; 205 206 while ((frab = TAILQ_FIRST(&fw->fw_frabs))) 207 { 208 size_t ntowrite = frab_left_to_read(frab); 209 ssize_t nw = fw->fw_write(fw->fw_stream, 210 frab->frab_buf + frab->frab_off, ntowrite); 211 if (nw > 0) 212 { 213 frab->frab_off += nw; 214 if (frab->frab_off == frab->frab_size) 215 { 216 TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next); 217 fw_put_frab(fw, frab); 218 } 219 } 220 else if (nw == 0) 221 break; 222 else 223 return -1; 224 } 225 226 return 0; 227} 228 229 230struct header_framer_ctx 231{ 232 struct lsquic_frame_writer 233 *hfc_fw; 234 struct { 235 struct frame_buf *frab; 236 unsigned short off; 237 } hfc_header_ptr; /* Points to byte *after* current frame header */ 238 unsigned hfc_max_frame_sz; /* Maximum frame size. We always fill it. */ 239 unsigned hfc_cur_sz; /* Number of bytes in the current frame. */ 240 unsigned hfc_n_frames; /* Number of frames written. */ 241 uint32_t hfc_stream_id; /* Stream ID */ 242 enum http_frame_header_flags 243 hfc_first_flags; 244 enum http_frame_type 245 hfc_frame_type; 246}; 247 248 249static void 250hfc_init (struct header_framer_ctx *hfc, struct lsquic_frame_writer *fw, 251 unsigned max_frame_sz, enum http_frame_type frame_type, 252 uint32_t stream_id, enum http_frame_header_flags first_flags) 253{ 254 memset(hfc, 0, sizeof(*hfc)); 255 hfc->hfc_fw = fw; 256 hfc->hfc_frame_type = frame_type; 257 hfc->hfc_stream_id = stream_id; 258 hfc->hfc_first_flags = first_flags; 259 hfc->hfc_max_frame_sz = max_frame_sz; 260 hfc->hfc_cur_sz = max_frame_sz; 261} 262 263 264static void 265hfc_save_ptr (struct header_framer_ctx *hfc) 266{ 267 hfc->hfc_header_ptr.frab = TAILQ_LAST(&hfc->hfc_fw->fw_frabs, frame_buf_head); 268 hfc->hfc_header_ptr.off = hfc->hfc_header_ptr.frab->frab_size; 269} 270 271 272static void 273hfc_terminate_frame (struct header_framer_ctx *hfc, 274 enum http_frame_header_flags flags) 275{ 276 union { 277 struct http_frame_header fh; 278 unsigned char buf[ sizeof(struct http_frame_header) ]; 279 } u; 280 uint32_t stream_id; 281 struct frame_buf *frab; 282 283 /* Construct the frame */ 284 u.fh.hfh_length[0] = hfc->hfc_cur_sz >> 16; 285 u.fh.hfh_length[1] = hfc->hfc_cur_sz >> 8; 286 u.fh.hfh_length[2] = hfc->hfc_cur_sz; 287 u.fh.hfh_flags = flags; 288 if (1 == hfc->hfc_n_frames) 289 { 290 u.fh.hfh_type = hfc->hfc_frame_type; 291 u.fh.hfh_flags |= hfc->hfc_first_flags; 292 } 293 else 294 u.fh.hfh_type = HTTP_FRAME_CONTINUATION; 295 stream_id = htonl(hfc->hfc_stream_id); 296 memcpy(u.fh.hfh_stream_id, &stream_id, sizeof(stream_id)); 297 298 if (hfc->hfc_header_ptr.off >= sizeof(u.fh)) 299 { /* Write in a single chunk */ 300 assert(0 == memcmp("123456789", hfc->hfc_header_ptr.frab->frab_buf + 301 hfc->hfc_header_ptr.off - sizeof(u.buf), sizeof(u.buf))); 302 memcpy(hfc->hfc_header_ptr.frab->frab_buf + hfc->hfc_header_ptr.off - 303 sizeof(u.buf), u.buf, sizeof(u.buf)); 304 } 305 else 306 { /* Write across frab boundary */ 307 memcpy(hfc->hfc_header_ptr.frab->frab_buf, 308 u.buf + sizeof(u.buf) - hfc->hfc_header_ptr.off, 309 hfc->hfc_header_ptr.off); 310 frab = TAILQ_PREV(hfc->hfc_header_ptr.frab, frame_buf_head, frab_next); 311 memcpy(frab->frab_buf + frab->frab_size - sizeof(u.buf) + 312 hfc->hfc_header_ptr.off, u.buf, 313 sizeof(u.buf) - hfc->hfc_header_ptr.off); 314 } 315} 316 317 318static int 319hfc_write (struct header_framer_ctx *hfc, const void *buf, size_t sz) 320{ 321 const unsigned char *p = buf; 322 unsigned avail; 323 int s; 324 325 while (sz > 0) 326 { 327 if (hfc->hfc_max_frame_sz == hfc->hfc_cur_sz) 328 { 329 if (hfc->hfc_n_frames > 0) 330 hfc_terminate_frame(hfc, 0); 331 s = fw_write_to_frab(hfc->hfc_fw, "123456789", 332 sizeof(struct http_frame_header)); 333 if (s < 0) 334 return s; 335 ++hfc->hfc_n_frames; 336 hfc_save_ptr(hfc); 337 hfc->hfc_cur_sz = 0; 338 } 339 340 avail = hfc->hfc_max_frame_sz - hfc->hfc_cur_sz; 341 if (sz < avail) 342 avail = sz; 343 if (avail) 344 { 345 s = fw_write_to_frab(hfc->hfc_fw, p, avail); 346 if (s < 0) 347 return s; 348 hfc->hfc_cur_sz += avail; 349 sz -= avail; 350 p += avail; 351 } 352 } 353 354 return 0; 355} 356 357 358static unsigned 359count_uppercase (const unsigned char *buf, size_t sz) 360{ 361 static const unsigned char uppercase[0x100] = { 362 ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, 363 ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, 364 ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, 365 ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, 366 ['Y'] = 1, ['Z'] = 1, 367 }; 368 unsigned n_uppercase, i; 369 n_uppercase = 0; 370 for (i = 0; i < sz; ++i) 371 n_uppercase += uppercase[ buf[i] ]; 372 return n_uppercase; 373} 374 375 376static uint32_t 377calc_headers_size (const struct lsquic_http_headers *headers) 378{ 379 int i; 380 uint32_t size = 0; 381 for (i = 0; i < headers->count; ++i) 382 size += 32 + headers->headers[i].name.iov_len + 383 headers->headers[i].value.iov_len; 384 return size; 385} 386 387 388static int 389have_oversize_strings (const struct lsquic_http_headers *headers) 390{ 391 int i, have; 392 for (i = 0, have = 0; i < headers->count; ++i) 393 { 394 have |= headers->headers[i].name.iov_len > LSHPACK_MAX_STRLEN; 395 have |= headers->headers[i].value.iov_len > LSHPACK_MAX_STRLEN; 396 } 397 return have; 398} 399 400 401static int 402check_headers_size (const struct lsquic_frame_writer *fw, 403 const struct lsquic_http_headers *headers, 404 const struct lsquic_http_headers *extra_headers) 405{ 406 uint32_t headers_sz; 407 headers_sz = calc_headers_size(headers); 408 if (extra_headers) 409 headers_sz += calc_headers_size(extra_headers); 410 if (headers_sz > fw->fw_max_header_list_sz) 411 { 412 LSQ_INFO("Headers size %u is larger than max allowed (%u)", 413 headers_sz, fw->fw_max_header_list_sz); 414 errno = EMSGSIZE; 415 return -1; 416 } 417 return 0; 418} 419 420 421static int 422check_headers_case (const struct lsquic_frame_writer *fw, 423 const struct lsquic_http_headers *headers) 424{ 425 unsigned n_uppercase; 426 int i; 427 n_uppercase = 0; 428 for (i = 0; i < headers->count; ++i) 429 n_uppercase += count_uppercase(headers->headers[i].name.iov_base, 430 headers->headers[i].name.iov_len); 431 if (n_uppercase) 432 { 433 LSQ_INFO("Uppercase letters in header names"); 434 errno = EINVAL; 435 return -1; 436 } 437 return 0; 438} 439 440 441static int 442write_headers (struct lsquic_frame_writer *fw, 443 const struct lsquic_http_headers *headers, 444 struct header_framer_ctx *hfc, unsigned char *buf, 445 const unsigned buf_sz) 446{ 447 unsigned char *end; 448 int i, s; 449 450 for (i = 0; i < headers->count; ++i) 451 { 452 end = lshpack_enc_encode(fw->fw_henc, buf, buf + buf_sz, 453 headers->headers[i].name.iov_base, headers->headers[i].name.iov_len, 454 headers->headers[i].value.iov_base, headers->headers[i].value.iov_len, 0); 455 if (end > buf) 456 { 457 s = hfc_write(hfc, buf, end - buf); 458 if (s < 0) 459 return s; 460 } 461 else 462 { 463 LSQ_WARN("error encoding header"); 464 errno = EBADMSG; 465 return -1; 466 } 467 } 468 469 return 0; 470} 471 472 473int 474lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw, 475 uint32_t stream_id, 476 const struct lsquic_http_headers *headers, 477 int eos, unsigned weight) 478{ 479 struct header_framer_ctx hfc; 480 int s; 481 struct http_prio_frame prio_frame; 482 enum http_frame_header_flags flags; 483 unsigned char *buf; 484 485 /* Internal function: weight must be valid here */ 486 assert(weight >= 1 && weight <= 256); 487 488 if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers, NULL)) 489 return -1; 490 491 if (0 != check_headers_case(fw, headers)) 492 return -1; 493 494 if (have_oversize_strings(headers)) 495 return -1; 496 497 if (eos) 498 flags = HFHF_END_STREAM; 499 else 500 flags = 0; 501 502 if (!(fw->fw_flags & FW_SERVER)) 503 flags |= HFHF_PRIORITY; 504 505 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_HEADERS, stream_id, 506 flags); 507 508 if (!(fw->fw_flags & FW_SERVER)) 509 { 510 memset(&prio_frame.hpf_stream_id, 0, sizeof(prio_frame.hpf_stream_id)); 511 prio_frame.hpf_weight = weight - 1; 512 s = hfc_write(&hfc, &prio_frame, sizeof(struct http_prio_frame)); 513 if (s < 0) 514 return s; 515 } 516 517 buf = malloc(MAX_HEADERS_SIZE); 518 if (!buf) 519 return -1; 520 s = write_headers(fw, headers, &hfc, buf, MAX_HEADERS_SIZE); 521 free(buf); 522 if (0 == s) 523 { 524 EV_LOG_GENERATED_HTTP_HEADERS(LSQUIC_LOG_CONN_ID, stream_id, 525 fw->fw_flags & FW_SERVER, &prio_frame, headers); 526 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 527 return lsquic_frame_writer_flush(fw); 528 } 529 else 530 return s; 531} 532 533 534int 535lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw, 536 uint32_t stream_id, uint32_t promised_stream_id, 537 const struct iovec *path, const struct iovec *host, 538 const struct lsquic_http_headers *extra_headers) 539{ 540 struct header_framer_ctx hfc; 541 struct http_push_promise_frame push_frame; 542 lsquic_http_header_t mpas_headers[4]; 543 struct lsquic_http_headers mpas = { /* method, path, authority, scheme */ 544 .headers = mpas_headers, 545 .count = 4, 546 }; 547 unsigned char *buf; 548 int s; 549 550 mpas_headers[0].name. iov_base = ":method"; 551 mpas_headers[0].name. iov_len = 7; 552 mpas_headers[0].value.iov_base = "GET"; 553 mpas_headers[0].value.iov_len = 3; 554 mpas_headers[1].name .iov_base = ":path"; 555 mpas_headers[1].name .iov_len = 5; 556 mpas_headers[1].value = *path; 557 mpas_headers[2].name .iov_base = ":authority"; 558 mpas_headers[2].name .iov_len = 10; 559 mpas_headers[2].value = *host; 560 mpas_headers[3].name. iov_base = ":scheme"; 561 mpas_headers[3].name. iov_len = 7; 562 mpas_headers[3].value.iov_base = "https"; 563 mpas_headers[3].value.iov_len = 5; 564 565 if (fw->fw_max_header_list_sz && 566 0 != check_headers_size(fw, &mpas, extra_headers)) 567 return -1; 568 569 if (extra_headers && 0 != check_headers_case(fw, extra_headers)) 570 return -1; 571 572 if (have_oversize_strings(&mpas)) 573 return -1; 574 575 if (extra_headers && have_oversize_strings(extra_headers)) 576 return -1; 577 578 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_PUSH_PROMISE, 579 stream_id, 0); 580 581 promised_stream_id = htonl(promised_stream_id); 582 memcpy(push_frame.hppf_promised_id, &promised_stream_id, 4); 583 s = hfc_write(&hfc, &push_frame, sizeof(struct http_push_promise_frame)); 584 if (s < 0) 585 return s; 586 587 buf = malloc(MAX_HEADERS_SIZE); 588 if (!buf) 589 return -1; 590 591 s = write_headers(fw, &mpas, &hfc, buf, MAX_HEADERS_SIZE); 592 if (s != 0) 593 { 594 free(buf); 595 return -1; 596 } 597 598 if (extra_headers) 599 s = write_headers(fw, extra_headers, &hfc, buf, MAX_HEADERS_SIZE); 600 601 free(buf); 602 603 if (0 == s) 604 { 605 EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id, 606 htonl(promised_stream_id), &mpas, extra_headers); 607 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 608 return lsquic_frame_writer_flush(fw); 609 } 610 else 611 return -1; 612} 613 614 615void 616lsquic_frame_writer_max_header_list_size (struct lsquic_frame_writer *fw, 617 uint32_t max_size) 618{ 619 LSQ_DEBUG("set max_header_list_sz to %u", max_size); 620 fw->fw_max_header_list_sz = max_size; 621} 622 623 624static int 625write_settings (struct lsquic_frame_writer *fw, 626 const struct lsquic_http2_setting *settings, unsigned n_settings) 627{ 628 struct http_frame_header fh; 629 unsigned payload_length; 630 uint32_t val; 631 uint16_t id; 632 int s; 633 634 payload_length = n_settings * 6; 635 636 memset(&fh, 0, sizeof(fh)); 637 fh.hfh_type = HTTP_FRAME_SETTINGS; 638 fh.hfh_length[0] = payload_length >> 16; 639 fh.hfh_length[1] = payload_length >> 8; 640 fh.hfh_length[2] = payload_length; 641 642 s = fw_write_to_frab(fw, &fh, sizeof(fh)); 643 if (s != 0) 644 return s; 645 646 do 647 { 648 id = htons(settings->id); 649 val = htonl(settings->value); 650 if (0 != (s = fw_write_to_frab(fw, &id, sizeof(id))) || 651 0 != (s = fw_write_to_frab(fw, &val, sizeof(val)))) 652 return s; 653 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP SETTINGS frame: " 654 "%s=%"PRIu32, lsquic_http_setting_id2str(settings->id), 655 settings->value); 656 ++settings; 657 } 658 while (--n_settings); 659 660 return 0; 661} 662 663 664int 665lsquic_frame_writer_write_settings (struct lsquic_frame_writer *fw, 666 const struct lsquic_http2_setting *settings, unsigned n_settings) 667{ 668 unsigned settings_per_frame; 669 unsigned n; 670 671 if (0 == n_settings) 672 { 673 errno = EINVAL; 674 return -1; 675 } 676 677 settings_per_frame = fw->fw_max_frame_sz / SETTINGS_FRAME_SZ; 678 n = 0; 679 680 do { 681 if (settings_per_frame > n_settings - n) 682 settings_per_frame = n_settings - n; 683 if (0 != write_settings(fw, &settings[n], settings_per_frame)) 684 return -1; 685 n += settings_per_frame; 686 } while (n < n_settings); 687 688 return lsquic_frame_writer_flush(fw); 689} 690 691 692int 693lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw, 694 uint32_t stream_id, int exclusive, uint32_t stream_dep_id, 695 unsigned weight) 696{ 697 unsigned char buf[ sizeof(struct http_frame_header) + 698 sizeof(struct http_prio_frame) ]; 699 struct http_frame_header *fh = (void *) &buf[0]; 700 struct http_prio_frame *prio_frame = (void *) &buf[sizeof(*fh)]; 701 int s; 702 703 if (stream_dep_id & (1UL << 31)) 704 { 705 LSQ_WARN("stream ID too high (%u): cannot write PRIORITY frame", 706 stream_dep_id); 707 return -1; 708 } 709 710 if (weight < 1 || weight > 256) 711 return -1; 712 713 memset(fh, 0, sizeof(*fh)); 714 fh->hfh_type = HTTP_FRAME_PRIORITY; 715 fh->hfh_length[2] = sizeof(struct http_prio_frame); 716 stream_id = htonl(stream_id); 717 memcpy(fh->hfh_stream_id, &stream_id, 4); 718 719 stream_dep_id |= !!exclusive << 31; 720 stream_id = htonl(stream_dep_id); 721 memcpy(prio_frame->hpf_stream_id, &stream_id, 4); 722 prio_frame->hpf_weight = weight - 1; 723 724 s = fw_write_to_frab(fw, buf, sizeof(buf)); 725 if (s != 0) 726 return s; 727 728 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP PRIORITY frame: " 729 "stream %"PRIu32"; weight: %u; exclusive: %d", 730 htonl(stream_id), weight, !!exclusive); 731 732 return lsquic_frame_writer_flush(fw); 733} 734 735 736size_t 737lsquic_frame_writer_mem_used (const struct lsquic_frame_writer *fw) 738{ 739 const struct frame_buf *frab; 740 size_t size; 741 742 size = sizeof(*fw); 743 TAILQ_FOREACH(frab, &fw->fw_frabs, frab_next) 744 size += sizeof(*frab); 745 746 return size; 747} 748