lsquic_packet_out.c revision 4d83f5bd
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_packet_out.c 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <stdlib.h> 9#include <string.h> 10#include <sys/queue.h> 11 12#include "lsquic.h" 13#include "lsquic_int_types.h" 14#include "lsquic_malo.h" 15#include "lsquic_mm.h" 16#include "lsquic_engine_public.h" 17#include "lsquic_packet_common.h" 18#include "lsquic_packet_in.h" 19#include "lsquic_packet_out.h" 20#include "lsquic_parse.h" 21#include "lsquic_sfcw.h" 22#include "lsquic_stream.h" 23#include "lsquic_logger.h" 24#include "lsquic_ev_log.h" 25#include "lsquic_conn.h" 26 27typedef char _stream_rec_arr_is_at_most_64bytes[ 28 (sizeof(struct stream_rec_arr) <= 64)? 1: - 1]; 29 30static struct stream_rec * 31srec_one_posi_first (struct packet_out_srec_iter *posi, 32 struct lsquic_packet_out *packet_out) 33{ 34 if (packet_out->po_srecs.one.sr_frame_type) 35 return &packet_out->po_srecs.one; 36 else 37 return NULL; 38} 39 40 41struct stream_rec * 42srec_one_posi_next (struct packet_out_srec_iter *posi) 43{ 44 return NULL; 45} 46 47 48struct stream_rec * 49srec_arr_posi_next (struct packet_out_srec_iter *posi) 50{ 51 while (posi->cur_srec_arr) 52 { 53 for (; posi->srec_idx < sizeof(posi->cur_srec_arr->srecs) / sizeof(posi->cur_srec_arr->srecs[0]); 54 ++posi->srec_idx) 55 { 56 if (posi->cur_srec_arr->srecs[ posi->srec_idx ].sr_frame_type) 57 return &posi->cur_srec_arr->srecs[ posi->srec_idx++ ]; 58 } 59 posi->cur_srec_arr = TAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr); 60 posi->srec_idx = 0; 61 } 62 return NULL; 63} 64 65 66static struct stream_rec * 67srec_arr_posi_first (struct packet_out_srec_iter *posi, 68 struct lsquic_packet_out *packet_out) 69{ 70 posi->packet_out = packet_out; 71 posi->cur_srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr); 72 posi->srec_idx = 0; 73 return srec_arr_posi_next(posi); 74} 75 76 77static struct stream_rec * (* const posi_firsts[]) 78 (struct packet_out_srec_iter *, struct lsquic_packet_out *) = 79{ 80 srec_one_posi_first, 81 srec_arr_posi_first, 82}; 83 84 85static struct stream_rec * (* const posi_nexts[]) 86 (struct packet_out_srec_iter *posi) = 87{ 88 srec_one_posi_next, 89 srec_arr_posi_next, 90}; 91 92 93struct stream_rec * 94posi_first (struct packet_out_srec_iter *posi, 95 lsquic_packet_out_t *packet_out) 96{ 97 posi->impl_idx = !!(packet_out->po_flags & PO_SREC_ARR); 98 return posi_firsts[posi->impl_idx](posi, packet_out); 99} 100 101 102struct stream_rec * 103posi_next (struct packet_out_srec_iter *posi) 104{ 105 return posi_nexts[posi->impl_idx](posi); 106} 107 108 109/* 110 * Assumption: frames are added to the packet_out in order of their placement 111 * in packet_out->po_data. There is no assertion to guard for for this. 112 */ 113int 114lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out, 115 struct lsquic_mm *mm, 116 struct lsquic_stream *new_stream, 117 enum QUIC_FRAME_TYPE frame_type, 118 unsigned short off, unsigned short len) 119{ 120 struct stream_rec_arr *srec_arr; 121 int last_taken; 122 unsigned i; 123 124 assert(!(new_stream->stream_flags & STREAM_FINISHED)); 125 126 if (!(packet_out->po_flags & PO_SREC_ARR)) 127 { 128 if (!srec_taken(&packet_out->po_srecs.one)) 129 { 130 packet_out->po_srecs.one.sr_frame_type = frame_type; 131 packet_out->po_srecs.one.sr_stream = new_stream; 132 packet_out->po_srecs.one.sr_off = off; 133 packet_out->po_srecs.one.sr_len = len; 134 ++new_stream->n_unacked; 135 return 0; /* Insert in first slot */ 136 } 137 srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr); 138 if (!srec_arr) 139 return -1; 140 memset(srec_arr, 0, sizeof(*srec_arr)); 141 srec_arr->srecs[0] = packet_out->po_srecs.one; 142 TAILQ_INIT(&packet_out->po_srecs.arr); 143 TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, 144 next_stream_rec_arr); 145 packet_out->po_flags |= PO_SREC_ARR; 146 i = 1; 147 goto set_elem; 148 } 149 150 /* New records go at the very end: */ 151 srec_arr = TAILQ_LAST(&packet_out->po_srecs.arr, stream_rec_arr_tailq); 152 last_taken = -1; 153 for (i = 0; i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]); ++i) 154 if (srec_taken(&srec_arr->srecs[i])) 155 last_taken = i; 156 157 i = last_taken + 1; 158 if (i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0])) 159 { 160 set_elem: 161 srec_arr->srecs[i].sr_frame_type = frame_type; 162 srec_arr->srecs[i].sr_stream = new_stream; 163 srec_arr->srecs[i].sr_off = off; 164 srec_arr->srecs[i].sr_len = len; 165 ++new_stream->n_unacked; 166 return 0; /* Insert in existing srec */ 167 } 168 169 srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr); 170 if (!srec_arr) 171 return -1; 172 173 memset(srec_arr, 0, sizeof(*srec_arr)); 174 srec_arr->srecs[0].sr_frame_type = frame_type; 175 srec_arr->srecs[0].sr_stream = new_stream; 176 srec_arr->srecs[0].sr_off = off; 177 srec_arr->srecs[0].sr_len = len; 178 TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, next_stream_rec_arr); 179 ++new_stream->n_unacked; 180 return 0; /* Insert in new srec */ 181} 182 183 184lsquic_packet_out_t * 185lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid, 186 const struct lsquic_conn *lconn, enum lsquic_packno_bits bits, 187 const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce) 188{ 189 lsquic_packet_out_t *packet_out; 190 enum packet_out_flags flags; 191 unsigned short header_size, max_size; 192 193 flags = bits << POBIT_SHIFT; 194 if (ver_tag) 195 flags |= PO_VERSION; 196 if (nonce) 197 flags |= PO_NONCE; 198 if (use_cid) 199 flags |= PO_CONN_ID; 200 if ((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS) 201 flags |= PO_GQUIC; 202 if ( 203 0 == (lconn->cn_flags & LSCONN_HANDSHAKE_DONE) 204 ) 205 { 206 flags |= PO_LONGHEAD; 207 if (!((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS)) 208 { 209 flags &= ~(3 << POBIT_SHIFT); 210 flags |= PACKNO_LEN_4 << POBIT_SHIFT; 211 } 212 } 213 214 header_size = lsquic_po_header_length(lconn, flags); 215 max_size = lconn->cn_pack_size; 216 if (header_size + QUIC_PACKET_HASH_SZ >= max_size) 217 { 218 errno = EINVAL; 219 return NULL; 220 } 221 222 packet_out = lsquic_mm_get_packet_out(mm, malo, max_size - header_size 223 - QUIC_PACKET_HASH_SZ); 224 if (!packet_out) 225 return NULL; 226 227 packet_out->po_flags = flags; 228 if (ver_tag) 229 packet_out->po_ver_tag = *ver_tag; 230 if (nonce) 231 { 232 /* Nonces are allocated for a very small number of packets. This 233 * memory is too expensive to carry in every packet. 234 */ 235 packet_out->po_nonce = malloc(32); 236 if (!packet_out->po_nonce) 237 { 238 lsquic_mm_put_packet_out(mm, packet_out); 239 return NULL; 240 } 241 memcpy(packet_out->po_nonce, nonce, 32); 242 } 243 if (flags & PO_LONGHEAD) 244 packet_out->po_header_type = HETY_HANDSHAKE; 245 246 return packet_out; 247} 248 249 250void 251lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out, 252 struct lsquic_engine_public *enpub, void *peer_ctx) 253{ 254 if (packet_out->po_flags & PO_SREC_ARR) 255 { 256 struct stream_rec_arr *srec_arr, *next; 257 for (srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr); 258 srec_arr; srec_arr = next) 259 { 260 next = TAILQ_NEXT(srec_arr, next_stream_rec_arr); 261 lsquic_malo_put(srec_arr); 262 } 263 } 264 if (packet_out->po_flags & PO_ENCRYPTED) 265 enpub->enp_pmi->pmi_release(enpub->enp_pmi_ctx, peer_ctx, 266 packet_out->po_enc_data, lsquic_packet_out_ipv6(packet_out)); 267 if (packet_out->po_nonce) 268 free(packet_out->po_nonce); 269 lsquic_mm_put_packet_out(&enpub->enp_mm, packet_out); 270} 271 272 273/* If `stream_id' is zero, stream frames from all reset streams are elided. 274 * Otherwise, elision is limited to the specified stream. 275 */ 276unsigned 277lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out, 278 uint32_t stream_id) 279{ 280 struct packet_out_srec_iter posi; 281 struct stream_rec *srec; 282 unsigned short adj = 0; 283 int n_stream_frames = 0, n_elided = 0; 284 int victim; 285 286 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 287 { 288 if (srec->sr_frame_type == QUIC_FRAME_STREAM) 289 { 290 ++n_stream_frames; 291 292 /* Offsets of all STREAM frames should be adjusted */ 293 srec->sr_off -= adj; 294 295 if (stream_id) 296 { 297 victim = srec->sr_stream->id == stream_id; 298 if (victim) 299 { 300 assert(lsquic_stream_is_reset(srec->sr_stream)); 301 } 302 } 303 else 304 victim = lsquic_stream_is_reset(srec->sr_stream); 305 306 if (victim) 307 { 308 ++n_elided; 309 310 /* Move the data and adjust sizes */ 311 adj += srec->sr_len; 312 memmove(packet_out->po_data + srec->sr_off, 313 packet_out->po_data + srec->sr_off + srec->sr_len, 314 packet_out->po_data_sz - srec->sr_off - srec->sr_len); 315 packet_out->po_data_sz -= srec->sr_len; 316 317 /* See what we can do with the stream */ 318 srec->sr_frame_type = 0; 319 lsquic_stream_acked(srec->sr_stream); 320 } 321 } 322 } 323 324 assert(n_stream_frames); 325 if (n_elided == n_stream_frames) 326 packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM); 327 328 return adj; 329} 330 331 332void 333lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out) 334{ 335 struct packet_out_srec_iter posi; 336 struct stream_rec *srec; 337 unsigned delta; 338 339 delta = packet_out->po_regen_sz; 340 packet_out->po_data_sz -= delta; 341 memmove(packet_out->po_data, packet_out->po_data + delta, 342 packet_out->po_data_sz); 343 packet_out->po_regen_sz = 0; 344 345 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 346 if (srec->sr_frame_type == QUIC_FRAME_STREAM) 347 srec->sr_off -= delta; 348} 349 350 351int 352lsquic_packet_out_has_hsk_frames (struct lsquic_packet_out *packet_out) 353{ 354 struct packet_out_srec_iter posi; 355 struct stream_rec *srec; 356 357 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 358 if (srec->sr_frame_type == QUIC_FRAME_STREAM 359 && LSQUIC_STREAM_HANDSHAKE == srec->sr_stream->id) 360 { 361 return 1; 362 } 363 364 return 0; 365} 366 367 368void 369lsquic_packet_out_ack_streams (lsquic_packet_out_t *packet_out) 370{ 371 struct packet_out_srec_iter posi; 372 struct stream_rec *srec; 373 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 374 lsquic_stream_acked(srec->sr_stream); 375} 376 377 378static int 379split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 380 lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs, 381 unsigned n_srecs) 382{ 383 unsigned n; 384 385 for (n = 0; n < n_srecs; ++n) 386 { 387 struct stream_rec *const srec = srecs[n]; 388 memcpy(new_packet_out->po_data + new_packet_out->po_data_sz, 389 packet_out->po_data + srec->sr_off, srec->sr_len); 390 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 391 srec->sr_stream, QUIC_FRAME_STREAM, 392 new_packet_out->po_data_sz, srec->sr_len)) 393 return -1; 394 srec->sr_frame_type = 0; 395 assert(srec->sr_stream->n_unacked > 1); 396 --srec->sr_stream->n_unacked; 397 new_packet_out->po_data_sz += srec->sr_len; 398 } 399 400 packet_out->po_data_sz = srecs[0]->sr_off; 401 402 return 0; 403} 404 405 406static int 407move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 408 lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs, 409 unsigned n_srecs, unsigned max_idx) 410{ 411 unsigned n; 412 struct stream_rec *const max_srec = srecs[max_idx]; 413 414 memcpy(new_packet_out->po_data + new_packet_out->po_data_sz, 415 packet_out->po_data + max_srec->sr_off, max_srec->sr_len); 416 memmove(packet_out->po_data + max_srec->sr_off, 417 packet_out->po_data + max_srec->sr_off + max_srec->sr_len, 418 packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len); 419 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 420 max_srec->sr_stream, QUIC_FRAME_STREAM, 421 new_packet_out->po_data_sz, max_srec->sr_len)) 422 return -1; 423 424 max_srec->sr_frame_type = 0; 425 assert(max_srec->sr_stream->n_unacked > 1); 426 --max_srec->sr_stream->n_unacked; 427 new_packet_out->po_data_sz += max_srec->sr_len; 428 packet_out->po_data_sz -= max_srec->sr_len; 429 430 for (n = max_idx + 1; n < n_srecs; ++n) 431 srecs[n]->sr_off -= max_srec->sr_len; 432 433 return 0; 434} 435 436 437struct split_reader_ctx 438{ 439 unsigned off; 440 unsigned len; 441 signed char fin; 442 unsigned char buf[QUIC_MAX_PAYLOAD_SZ / 2 + 1]; 443}; 444 445 446static int 447split_reader_fin (void *ctx) 448{ 449 struct split_reader_ctx *const reader_ctx = ctx; 450 return reader_ctx->off == reader_ctx->len && reader_ctx->fin; 451} 452 453 454static size_t 455split_reader_size (void *ctx) 456{ 457 struct split_reader_ctx *const reader_ctx = ctx; 458 return reader_ctx->len - reader_ctx->off; 459} 460 461 462static size_t 463split_reader_read (void *ctx, void *buf, size_t len, int *fin) 464{ 465 struct split_reader_ctx *const reader_ctx = ctx; 466 if (len > reader_ctx->len - reader_ctx->off) 467 len = reader_ctx->len - reader_ctx->off; 468 memcpy(buf, reader_ctx->buf, len); 469 reader_ctx->off += len; 470 *fin = split_reader_fin(reader_ctx); 471 return len; 472} 473 474 475static int 476split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 477 lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf, 478 struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx) 479{ 480 struct stream_rec *const max_srec = srecs[max_idx]; 481 struct stream_frame frame; 482 int len; 483 unsigned n; 484 struct split_reader_ctx reader_ctx; 485 486 len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off, 487 max_srec->sr_len, &frame); 488 if (len < 0) 489 { 490 LSQ_ERROR("could not parse own frame"); 491 return -1; 492 } 493 494 assert(frame.data_frame.df_size / 2 <= sizeof(reader_ctx.buf)); 495 if (frame.data_frame.df_size / 2 > sizeof(reader_ctx.buf)) 496 return -1; 497 498 memcpy(reader_ctx.buf, 499 frame.data_frame.df_data + frame.data_frame.df_size / 2, 500 frame.data_frame.df_size - frame.data_frame.df_size / 2); 501 reader_ctx.off = 0; 502 reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2; 503 reader_ctx.fin = frame.data_frame.df_fin; 504 505 len = pf->pf_gen_stream_frame( 506 new_packet_out->po_data + new_packet_out->po_data_sz, 507 lsquic_packet_out_avail(new_packet_out), frame.stream_id, 508 frame.data_frame.df_offset + frame.data_frame.df_size / 2, 509 split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx), 510 split_reader_read, &reader_ctx); 511 if (len < 0) 512 { 513 LSQ_ERROR("could not generate new frame 1"); 514 return -1; 515 } 516 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 517 max_srec->sr_stream, QUIC_FRAME_STREAM, 518 new_packet_out->po_data_sz, len)) 519 return -1; 520 new_packet_out->po_data_sz += len; 521 if (0 == lsquic_packet_out_avail(new_packet_out)) 522 { 523 assert(0); /* We really should not fill here, but JIC */ 524 new_packet_out->po_flags |= PO_STREAM_END; 525 } 526 527 memcpy(reader_ctx.buf, frame.data_frame.df_data, 528 frame.data_frame.df_size / 2); 529 reader_ctx.off = 0; 530 reader_ctx.len = frame.data_frame.df_size / 2; 531 reader_ctx.fin = 0; 532 len = pf->pf_gen_stream_frame( 533 packet_out->po_data + max_srec->sr_off, max_srec->sr_len, 534 frame.stream_id, frame.data_frame.df_offset, 535 split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx), 536 split_reader_read, &reader_ctx); 537 if (len < 0) 538 { 539 LSQ_ERROR("could not generate new frame 2"); 540 return -1; 541 } 542 543 const unsigned short adj = max_srec->sr_len - (unsigned short) len; 544 max_srec->sr_len = len; 545 for (n = max_idx + 1; n < n_srecs; ++n) 546 srecs[n]->sr_off -= adj; 547 packet_out->po_data_sz -= adj; 548 549 return 0; 550} 551 552 553#ifndef NDEBUG 554static void 555verify_srecs (lsquic_packet_out_t *packet_out) 556{ 557 struct packet_out_srec_iter posi; 558 const struct stream_rec *srec; 559 unsigned off; 560 561 srec = posi_first(&posi, packet_out); 562 assert(srec); 563 564 off = 0; 565 for ( ; srec; srec = posi_next(&posi)) 566 { 567 assert(srec->sr_off == off); 568 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 569 off += srec->sr_len; 570 } 571 572 assert(packet_out->po_data_sz == off); 573} 574 575 576#endif 577 578 579int 580lsquic_packet_out_split_in_two (struct lsquic_mm *mm, 581 lsquic_packet_out_t *packet_out, lsquic_packet_out_t *new_packet_out, 582 const struct parse_funcs *pf, unsigned excess_bytes) 583{ 584 struct packet_out_srec_iter posi; 585 struct stream_rec *local_arr[4]; 586 struct stream_rec **new_srecs, **srecs = local_arr; 587 struct stream_rec *srec; 588 unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]); 589 unsigned n_srecs, max_idx, n, nbytes; 590#ifndef NDEBUG 591 unsigned short frame_sum = 0; 592#endif 593 int rv; 594 595 /* We only split buffered packets; buffered packets contain only STREAM 596 * frames: 597 */ 598 assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM)); 599 600 n_srecs = 0; 601#ifdef WIN32 602 max_idx = 0; 603#endif 604 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 605 { 606 /* We only expect references to STREAM frames (buffered packets): */ 607 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 608 if (n_srecs >= n_srecs_alloced) 609 { 610 n_srecs_alloced *= 2; 611 if (srecs == local_arr) 612 { 613 srecs = malloc(sizeof(srecs[0]) * n_srecs_alloced); 614 if (!srecs) 615 goto err; 616 memcpy(srecs, local_arr, sizeof(local_arr)); 617 } 618 else 619 { 620 new_srecs = realloc(srecs, sizeof(srecs[0]) * n_srecs_alloced); 621 if (!new_srecs) 622 goto err; 623 srecs = new_srecs; 624 } 625 } 626 627#ifndef NDEBUG 628 frame_sum += srec->sr_len; 629#endif 630 if (n_srecs == 0 || srecs[max_idx]->sr_len < srec->sr_len) 631 max_idx = n_srecs; 632 633 srecs[n_srecs++] = srec; 634 } 635 636 assert(frame_sum == packet_out->po_data_sz); 637 638 if (n_srecs == 1) 639 goto common_case; 640 641 if (n_srecs < 1) 642 goto err; 643 644 /* Case 1: see if we can remove one or more trailing frames to make 645 * packet smaller. 646 */ 647 nbytes = 0; 648 for (n = n_srecs - 1; n > max_idx && nbytes < excess_bytes; --n) 649 nbytes += srecs[n]->sr_len; 650 if (nbytes >= excess_bytes) 651 { 652 rv = split_off_last_frames(mm, packet_out, new_packet_out, 653 srecs + n + 1, n_srecs - n - 1); 654 goto end; 655 } 656 657 /* Case 2: see if we can move the largest frame to new packet. */ 658 nbytes = 0; 659 for (n = 0; n < n_srecs; ++n) 660 if (n != max_idx) 661 nbytes += srecs[n]->sr_len; 662 if (nbytes >= excess_bytes) 663 { 664 rv = move_largest_frame(mm, packet_out, new_packet_out, srecs, 665 n_srecs, max_idx); 666 goto end; 667 } 668 669 common_case: 670 /* Case 3: we have to split the largest frame (which could be the 671 * the only frame) in two. 672 */ 673 rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs, 674 n_srecs, max_idx); 675 676 end: 677 if (srecs != local_arr) 678 free(srecs); 679 if (0 == rv) 680 { 681 new_packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM; 682#ifndef NDEBUG 683 verify_srecs(packet_out); 684 verify_srecs(new_packet_out); 685#endif 686 } 687 return rv; 688 689 err: 690 rv = -1; 691 goto end; 692} 693 694 695void 696lsquic_packet_out_zero_pad (lsquic_packet_out_t *packet_out) 697{ 698 if (packet_out->po_n_alloc > packet_out->po_data_sz) 699 { 700 memset(packet_out->po_data + packet_out->po_data_sz, 0, 701 packet_out->po_n_alloc - packet_out->po_data_sz); 702 packet_out->po_data_sz = packet_out->po_n_alloc; 703 packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING; 704 } 705} 706 707 708size_t 709lsquic_packet_out_mem_used (const struct lsquic_packet_out *packet_out) 710{ 711 const struct stream_rec_arr *srec_arr; 712 size_t size; 713 714 size = 0; /* The struct is allocated using malo */ 715 if (packet_out->po_enc_data) 716 size += packet_out->po_enc_data_sz; 717 if (packet_out->po_data) 718 size += packet_out->po_n_alloc; 719 if (packet_out->po_nonce) 720 size += 32; 721 722 if (packet_out->po_flags & PO_SREC_ARR) 723 TAILQ_FOREACH(srec_arr, &packet_out->po_srecs.arr, next_stream_rec_arr) 724 size += sizeof(*srec_arr); 725 726 return size; 727} 728 729 730int 731lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out, 732 const struct parse_funcs *pf, 733 const struct lsquic_stream *stream) 734{ 735 struct packet_out_srec_iter posi; 736 const struct stream_rec *srec; 737 struct stream_frame stream_frame; 738 uint64_t last_offset; 739 int len; 740 741 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 742 if (srec->sr_frame_type == QUIC_FRAME_STREAM 743 && srec->sr_stream == stream) 744 { 745 len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off, 746 srec->sr_len, &stream_frame); 747 assert(len >= 0); 748 if (len < 0) 749 return -1; 750 last_offset = stream_frame.data_frame.df_offset 751 + stream_frame.data_frame.df_size; 752 if (last_offset == stream->tosend_off) 753 { 754 pf->pf_turn_on_fin(packet_out->po_data + srec->sr_off); 755 EV_LOG_UPDATED_STREAM_FRAME(lsquic_stream_cid(stream), 756 pf, packet_out->po_data + srec->sr_off, srec->sr_len); 757 return 0; 758 } 759 } 760 761 return -1; 762} 763