lsquic_frame_writer.c revision 50aadb33
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/* Make sure that frab_buf is at least five bytes long, otherwise a frame 53 * won't fit into two adjacent frabs. 54 */ 55typedef char three_byte_frab_buf[(sizeof(((struct frame_buf *)0)->frab_buf) >= 5) - 1]; 56 57 58TAILQ_HEAD(frame_buf_head, frame_buf); 59 60 61struct lsquic_frame_writer 62{ 63 struct lsquic_stream *fw_stream; 64 fw_write_f fw_write; 65 fw_wavail_f fw_wavail; 66 fw_flush_f fw_flush; 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 fw_wavail_f wavail, fw_flush_f flush, 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_wavail = wavail; 122 fw->fw_flush = flush; 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 size_t navail = fw->fw_wavail(fw->fw_stream); 208 struct frame_buf *frab; 209 210 while (navail > 0 && (frab = TAILQ_FIRST(&fw->fw_frabs))) 211 { 212 size_t ntowrite = frab_left_to_read(frab); 213 if (navail < ntowrite) 214 ntowrite = navail; 215 ssize_t nw = fw->fw_write(fw->fw_stream, 216 frab->frab_buf + frab->frab_off, ntowrite); 217 if (nw > 0) 218 { 219 navail -= nw; 220 frab->frab_off += nw; 221 if (frab->frab_off == frab->frab_size) 222 { 223 TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next); 224 fw_put_frab(fw, frab); 225 } 226 } 227 else 228 return -1; 229 } 230 231 (void) fw->fw_flush(fw->fw_stream); 232 233 return 0; 234} 235 236 237struct header_framer_ctx 238{ 239 struct lsquic_frame_writer 240 *hfc_fw; 241 struct { 242 struct frame_buf *frab; 243 unsigned short off; 244 } hfc_header_ptr; /* Points to byte *after* current frame header */ 245 unsigned hfc_max_frame_sz; /* Maximum frame size. We always fill it. */ 246 unsigned hfc_cur_sz; /* Number of bytes in the current frame. */ 247 unsigned hfc_n_frames; /* Number of frames written. */ 248 uint32_t hfc_stream_id; /* Stream ID */ 249 enum http_frame_header_flags 250 hfc_first_flags; 251 enum http_frame_type 252 hfc_frame_type; 253}; 254 255 256static void 257hfc_init (struct header_framer_ctx *hfc, struct lsquic_frame_writer *fw, 258 unsigned max_frame_sz, enum http_frame_type frame_type, 259 uint32_t stream_id, enum http_frame_header_flags first_flags) 260{ 261 memset(hfc, 0, sizeof(*hfc)); 262 hfc->hfc_fw = fw; 263 hfc->hfc_frame_type = frame_type; 264 hfc->hfc_stream_id = stream_id; 265 hfc->hfc_first_flags = first_flags; 266 hfc->hfc_max_frame_sz = max_frame_sz; 267 hfc->hfc_cur_sz = max_frame_sz; 268} 269 270 271static void 272hfc_save_ptr (struct header_framer_ctx *hfc) 273{ 274 hfc->hfc_header_ptr.frab = TAILQ_LAST(&hfc->hfc_fw->fw_frabs, frame_buf_head); 275 hfc->hfc_header_ptr.off = hfc->hfc_header_ptr.frab->frab_size; 276} 277 278 279static void 280hfc_terminate_frame (struct header_framer_ctx *hfc, 281 enum http_frame_header_flags flags) 282{ 283 union { 284 struct http_frame_header fh; 285 unsigned char buf[ sizeof(struct http_frame_header) ]; 286 } u; 287 uint32_t stream_id; 288 struct frame_buf *frab; 289 290 /* Construct the frame */ 291 u.fh.hfh_length[0] = hfc->hfc_cur_sz >> 16; 292 u.fh.hfh_length[1] = hfc->hfc_cur_sz >> 8; 293 u.fh.hfh_length[2] = hfc->hfc_cur_sz; 294 u.fh.hfh_flags = flags; 295 if (1 == hfc->hfc_n_frames) 296 { 297 u.fh.hfh_type = hfc->hfc_frame_type; 298 u.fh.hfh_flags |= hfc->hfc_first_flags; 299 } 300 else 301 u.fh.hfh_type = HTTP_FRAME_CONTINUATION; 302 stream_id = htonl(hfc->hfc_stream_id); 303 memcpy(u.fh.hfh_stream_id, &stream_id, sizeof(stream_id)); 304 305 if (hfc->hfc_header_ptr.off >= sizeof(u.fh)) 306 { /* Write in a single chunk */ 307 assert(0 == memcmp("123456789", hfc->hfc_header_ptr.frab->frab_buf + 308 hfc->hfc_header_ptr.off - sizeof(u.buf), sizeof(u.buf))); 309 memcpy(hfc->hfc_header_ptr.frab->frab_buf + hfc->hfc_header_ptr.off - 310 sizeof(u.buf), u.buf, sizeof(u.buf)); 311 } 312 else 313 { /* Write across frab boundary */ 314 memcpy(hfc->hfc_header_ptr.frab->frab_buf, 315 u.buf + sizeof(u.buf) - hfc->hfc_header_ptr.off, 316 hfc->hfc_header_ptr.off); 317 frab = TAILQ_PREV(hfc->hfc_header_ptr.frab, frame_buf_head, frab_next); 318 memcpy(frab->frab_buf + frab->frab_size - sizeof(u.buf) + 319 hfc->hfc_header_ptr.off, u.buf, 320 sizeof(u.buf) - hfc->hfc_header_ptr.off); 321 } 322} 323 324 325static int 326hfc_write (struct header_framer_ctx *hfc, const void *buf, size_t sz) 327{ 328 const unsigned char *p = buf; 329 unsigned avail; 330 int s; 331 332 while (sz > 0) 333 { 334 if (hfc->hfc_max_frame_sz == hfc->hfc_cur_sz) 335 { 336 if (hfc->hfc_n_frames > 0) 337 hfc_terminate_frame(hfc, 0); 338 s = fw_write_to_frab(hfc->hfc_fw, "123456789", 339 sizeof(struct http_frame_header)); 340 if (s < 0) 341 return s; 342 ++hfc->hfc_n_frames; 343 hfc_save_ptr(hfc); 344 hfc->hfc_cur_sz = 0; 345 } 346 347 avail = hfc->hfc_max_frame_sz - hfc->hfc_cur_sz; 348 if (sz < avail) 349 avail = sz; 350 if (avail) 351 { 352 s = fw_write_to_frab(hfc->hfc_fw, p, avail); 353 if (s < 0) 354 return s; 355 hfc->hfc_cur_sz += avail; 356 sz -= avail; 357 p += avail; 358 } 359 } 360 361 return 0; 362} 363 364 365static unsigned 366count_uppercase (const unsigned char *buf, size_t sz) 367{ 368 static const unsigned char uppercase[0x100] = { 369 ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, 370 ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, 371 ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, 372 ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, 373 ['Y'] = 1, ['Z'] = 1, 374 }; 375 unsigned n_uppercase, i; 376 n_uppercase = 0; 377 for (i = 0; i < sz; ++i) 378 n_uppercase += uppercase[ buf[i] ]; 379 return n_uppercase; 380} 381 382 383static uint32_t 384calc_headers_size (const struct lsquic_http_headers *headers) 385{ 386 int i; 387 uint32_t size = 0; 388 for (i = 0; i < headers->count; ++i) 389 size += 32 + headers->headers[i].name.iov_len + 390 headers->headers[i].value.iov_len; 391 return size; 392} 393 394 395static int 396check_headers_size (const struct lsquic_frame_writer *fw, 397 const struct lsquic_http_headers *headers, 398 const struct lsquic_http_headers *extra_headers) 399{ 400 uint32_t headers_sz; 401 headers_sz = calc_headers_size(headers); 402 if (extra_headers) 403 headers_sz += calc_headers_size(extra_headers); 404 if (headers_sz > fw->fw_max_header_list_sz) 405 { 406 LSQ_INFO("Headers size %u is larger than max allowed (%u)", 407 headers_sz, fw->fw_max_header_list_sz); 408 errno = EMSGSIZE; 409 return -1; 410 } 411 return 0; 412} 413 414 415static int 416check_headers_case (const struct lsquic_frame_writer *fw, 417 const struct lsquic_http_headers *headers) 418{ 419 unsigned n_uppercase; 420 int i; 421 n_uppercase = 0; 422 for (i = 0; i < headers->count; ++i) 423 n_uppercase += count_uppercase(headers->headers[i].name.iov_base, 424 headers->headers[i].name.iov_len); 425 if (n_uppercase) 426 { 427 LSQ_INFO("Uppercase letters in header names"); 428 errno = EINVAL; 429 return -1; 430 } 431 return 0; 432} 433 434 435static int 436write_headers (struct lsquic_frame_writer *fw, 437 const struct lsquic_http_headers *headers, 438 struct header_framer_ctx *hfc, unsigned char *buf4k) 439{ 440 unsigned char *end; 441 int i, s; 442 443 for (i = 0; i < headers->count; ++i) 444 { 445 end = lsquic_henc_encode(fw->fw_henc, buf4k, buf4k + 0x1000, 446 headers->headers[i].name.iov_base, headers->headers[i].name.iov_len, 447 headers->headers[i].value.iov_base, headers->headers[i].value.iov_len, 0); 448 if (!(end > buf4k)) 449 { 450 LSQ_WARN("error encoding header"); 451 errno = EBADMSG; 452 return -1; 453 } 454 s = hfc_write(hfc, buf4k, end - buf4k); 455 if (s < 0) 456 return s; 457 } 458 459 return 0; 460} 461 462 463int 464lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw, 465 uint32_t stream_id, 466 const struct lsquic_http_headers *headers, 467 int eos, unsigned weight) 468{ 469 struct header_framer_ctx hfc; 470 int s; 471 struct http_prio_frame prio_frame; 472 enum http_frame_header_flags flags; 473 unsigned char *buf; 474 475 /* Internal function: weight must be valid here */ 476 assert(weight >= 1 && weight <= 256); 477 478 if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers, NULL)) 479 return -1; 480 481 if (0 != check_headers_case(fw, headers)) 482 return -1; 483 484 if (eos) 485 flags = HFHF_END_STREAM; 486 else 487 flags = 0; 488 489 if (!(fw->fw_flags & FW_SERVER)) 490 flags |= HFHF_PRIORITY; 491 492 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_HEADERS, stream_id, 493 flags); 494 495 if (!(fw->fw_flags & FW_SERVER)) 496 { 497 memset(&prio_frame.hpf_stream_id, 0, sizeof(prio_frame.hpf_stream_id)); 498 prio_frame.hpf_weight = weight - 1; 499 s = hfc_write(&hfc, &prio_frame, sizeof(struct http_prio_frame)); 500 if (s < 0) 501 return s; 502 } 503 504 buf = lsquic_mm_get_4k(fw->fw_mm); 505 if (!buf) 506 return -1; 507 s = write_headers(fw, headers, &hfc, buf); 508 lsquic_mm_put_4k(fw->fw_mm, buf); 509 if (0 == s) 510 { 511 EV_LOG_GENERATED_HTTP_HEADERS(LSQUIC_LOG_CONN_ID, stream_id, 512 fw->fw_flags & FW_SERVER, &prio_frame, headers); 513 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 514 return lsquic_frame_writer_flush(fw); 515 } 516 else 517 return s; 518} 519 520 521int 522lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw, 523 uint32_t stream_id, uint32_t promised_stream_id, 524 const struct iovec *path, const struct iovec *host, 525 const struct lsquic_http_headers *extra_headers) 526{ 527 struct header_framer_ctx hfc; 528 struct http_push_promise_frame push_frame; 529 lsquic_http_header_t mpas_headers[4]; 530 struct lsquic_http_headers mpas = { /* method, path, authority, scheme */ 531 .headers = mpas_headers, 532 .count = 4, 533 }; 534 unsigned char *buf; 535 int s; 536 537 mpas_headers[0].name. iov_base = ":method"; 538 mpas_headers[0].name. iov_len = 7; 539 mpas_headers[0].value.iov_base = "GET"; 540 mpas_headers[0].value.iov_len = 3; 541 mpas_headers[1].name .iov_base = ":path"; 542 mpas_headers[1].name .iov_len = 5; 543 mpas_headers[1].value = *path; 544 mpas_headers[2].name .iov_base = ":authority"; 545 mpas_headers[2].name .iov_len = 10; 546 mpas_headers[2].value = *host; 547 mpas_headers[3].name. iov_base = ":scheme"; 548 mpas_headers[3].name. iov_len = 7; 549 mpas_headers[3].value.iov_base = "https"; 550 mpas_headers[3].value.iov_len = 5; 551 552 if (fw->fw_max_header_list_sz && 553 0 != check_headers_size(fw, &mpas, extra_headers)) 554 return -1; 555 556 if (extra_headers && 0 != check_headers_case(fw, extra_headers)) 557 return -1; 558 559 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_PUSH_PROMISE, 560 stream_id, 0); 561 562 promised_stream_id = htonl(promised_stream_id); 563 memcpy(push_frame.hppf_promised_id, &promised_stream_id, 4); 564 s = hfc_write(&hfc, &push_frame, sizeof(struct http_push_promise_frame)); 565 if (s < 0) 566 return s; 567 568 buf = lsquic_mm_get_4k(fw->fw_mm); 569 if (!buf) 570 return -1; 571 572 s = write_headers(fw, &mpas, &hfc, buf); 573 if (s != 0) 574 { 575 lsquic_mm_put_4k(fw->fw_mm, buf); 576 return -1; 577 } 578 579 if (extra_headers) 580 s = write_headers(fw, extra_headers, &hfc, buf); 581 582 lsquic_mm_put_4k(fw->fw_mm, buf); 583 584 if (0 == s) 585 { 586 EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id, 587 htonl(promised_stream_id), &mpas, extra_headers); 588 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 589 return lsquic_frame_writer_flush(fw); 590 } 591 else 592 return -1; 593} 594 595 596void 597lsquic_frame_writer_max_header_list_size (struct lsquic_frame_writer *fw, 598 uint32_t max_size) 599{ 600 LSQ_DEBUG("set max_header_list_sz to %u", max_size); 601 fw->fw_max_header_list_sz = max_size; 602} 603 604 605static int 606write_settings (struct lsquic_frame_writer *fw, 607 const struct lsquic_http2_setting *settings, unsigned n_settings) 608{ 609 struct http_frame_header fh; 610 unsigned payload_length; 611 uint32_t val; 612 uint16_t id; 613 int s; 614 615 payload_length = n_settings * 6; 616 617 memset(&fh, 0, sizeof(fh)); 618 fh.hfh_type = HTTP_FRAME_SETTINGS; 619 fh.hfh_length[0] = payload_length >> 16; 620 fh.hfh_length[1] = payload_length >> 8; 621 fh.hfh_length[2] = payload_length; 622 623 s = fw_write_to_frab(fw, &fh, sizeof(fh)); 624 if (s != 0) 625 return s; 626 627 do 628 { 629 id = htons(settings->id); 630 val = htonl(settings->value); 631 if (0 != (s = fw_write_to_frab(fw, &id, sizeof(id))) || 632 0 != (s = fw_write_to_frab(fw, &val, sizeof(val)))) 633 return s; 634 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP SETTINGS frame: " 635 "%s=%"PRIu32, lsquic_http_setting_id2str(settings->id), 636 settings->value); 637 ++settings; 638 } 639 while (--n_settings); 640 641 return 0; 642} 643 644int 645lsquic_frame_writer_write_settings (struct lsquic_frame_writer *fw, 646 const struct lsquic_http2_setting *settings, unsigned n_settings) 647{ 648 unsigned settings_per_frame; 649 unsigned n; 650 651 if (0 == n_settings) 652 { 653 errno = EINVAL; 654 return -1; 655 } 656 657 settings_per_frame = fw->fw_max_frame_sz / SETTINGS_FRAME_SZ; 658 n = 0; 659 660 do { 661 if (settings_per_frame > n_settings - n) 662 settings_per_frame = n_settings - n; 663 if (0 != write_settings(fw, &settings[n], settings_per_frame)) 664 return -1; 665 n += settings_per_frame; 666 } while (n < n_settings); 667 668 return lsquic_frame_writer_flush(fw); 669} 670 671 672int 673lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw, 674 uint32_t stream_id, int exclusive, uint32_t stream_dep_id, 675 unsigned weight) 676{ 677 unsigned char buf[ sizeof(struct http_frame_header) + 678 sizeof(struct http_prio_frame) ]; 679 struct http_frame_header *fh = (void *) &buf[0]; 680 struct http_prio_frame *prio_frame = (void *) &buf[sizeof(*fh)]; 681 int s; 682 683 if (stream_dep_id & (1UL << 31)) 684 { 685 LSQ_WARN("stream ID too high (%u): cannot write PRIORITY frame", 686 stream_dep_id); 687 return -1; 688 } 689 690 if (weight < 1 || weight > 256) 691 return -1; 692 693 memset(fh, 0, sizeof(*fh)); 694 fh->hfh_type = HTTP_FRAME_PRIORITY; 695 fh->hfh_length[2] = sizeof(struct http_prio_frame); 696 stream_id = htonl(stream_id); 697 memcpy(fh->hfh_stream_id, &stream_id, 4); 698 699 stream_dep_id |= !!exclusive << 31; 700 stream_id = htonl(stream_dep_id); 701 memcpy(prio_frame->hpf_stream_id, &stream_id, 4); 702 prio_frame->hpf_weight = weight - 1; 703 704 s = fw_write_to_frab(fw, buf, sizeof(buf)); 705 if (s != 0) 706 return s; 707 708 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP PRIORITY frame: " 709 "stream %"PRIu32"; weight: %u; exclusive: %d", 710 htonl(stream_id), weight, !!exclusive); 711 712 return lsquic_frame_writer_flush(fw); 713} 714