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