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