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