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