lsquic_packet_out.c revision 6aba801d
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 351void 352lsquic_packet_out_ack_streams (lsquic_packet_out_t *packet_out) 353{ 354 struct packet_out_srec_iter posi; 355 struct stream_rec *srec; 356 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 357 lsquic_stream_acked(srec->sr_stream); 358} 359 360 361static int 362split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 363 lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs, 364 unsigned n_srecs) 365{ 366 unsigned n; 367 368 for (n = 0; n < n_srecs; ++n) 369 { 370 struct stream_rec *const srec = srecs[n]; 371 memcpy(new_packet_out->po_data + new_packet_out->po_data_sz, 372 packet_out->po_data + srec->sr_off, srec->sr_len); 373 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 374 srec->sr_stream, QUIC_FRAME_STREAM, 375 new_packet_out->po_data_sz, srec->sr_len)) 376 return -1; 377 srec->sr_frame_type = 0; 378 assert(srec->sr_stream->n_unacked > 1); 379 --srec->sr_stream->n_unacked; 380 new_packet_out->po_data_sz += srec->sr_len; 381 } 382 383 packet_out->po_data_sz = srecs[0]->sr_off; 384 385 return 0; 386} 387 388 389static int 390move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 391 lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs, 392 unsigned n_srecs, unsigned max_idx) 393{ 394 unsigned n; 395 struct stream_rec *const max_srec = srecs[max_idx]; 396 397 memcpy(new_packet_out->po_data + new_packet_out->po_data_sz, 398 packet_out->po_data + max_srec->sr_off, max_srec->sr_len); 399 memmove(packet_out->po_data + max_srec->sr_off, 400 packet_out->po_data + max_srec->sr_off + max_srec->sr_len, 401 packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len); 402 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 403 max_srec->sr_stream, QUIC_FRAME_STREAM, 404 new_packet_out->po_data_sz, max_srec->sr_len)) 405 return -1; 406 407 max_srec->sr_frame_type = 0; 408 assert(max_srec->sr_stream->n_unacked > 1); 409 --max_srec->sr_stream->n_unacked; 410 new_packet_out->po_data_sz += max_srec->sr_len; 411 packet_out->po_data_sz -= max_srec->sr_len; 412 413 for (n = max_idx + 1; n < n_srecs; ++n) 414 srecs[n]->sr_off -= max_srec->sr_len; 415 416 return 0; 417} 418 419 420struct split_reader_ctx 421{ 422 unsigned off; 423 unsigned len; 424 signed char fin; 425 unsigned char buf[QUIC_MAX_PAYLOAD_SZ / 2 + 1]; 426}; 427 428 429static int 430split_reader_fin (void *ctx) 431{ 432 struct split_reader_ctx *const reader_ctx = ctx; 433 return reader_ctx->off == reader_ctx->len && reader_ctx->fin; 434} 435 436 437static size_t 438split_reader_size (void *ctx) 439{ 440 struct split_reader_ctx *const reader_ctx = ctx; 441 return reader_ctx->len - reader_ctx->off; 442} 443 444 445static size_t 446split_reader_read (void *ctx, void *buf, size_t len, int *fin) 447{ 448 struct split_reader_ctx *const reader_ctx = ctx; 449 if (len > reader_ctx->len - reader_ctx->off) 450 len = reader_ctx->len - reader_ctx->off; 451 memcpy(buf, reader_ctx->buf, len); 452 reader_ctx->off += len; 453 *fin = split_reader_fin(reader_ctx); 454 return len; 455} 456 457 458static int 459split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out, 460 lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf, 461 struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx) 462{ 463 struct stream_rec *const max_srec = srecs[max_idx]; 464 struct stream_frame frame; 465 int len; 466 unsigned n; 467 struct split_reader_ctx reader_ctx; 468 469 len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off, 470 max_srec->sr_len, &frame); 471 if (len < 0) 472 { 473 LSQ_ERROR("could not parse own frame"); 474 return -1; 475 } 476 477 assert(frame.data_frame.df_size / 2 <= sizeof(reader_ctx.buf)); 478 if (frame.data_frame.df_size / 2 > sizeof(reader_ctx.buf)) 479 return -1; 480 481 memcpy(reader_ctx.buf, 482 frame.data_frame.df_data + frame.data_frame.df_size / 2, 483 frame.data_frame.df_size - frame.data_frame.df_size / 2); 484 reader_ctx.off = 0; 485 reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2; 486 reader_ctx.fin = frame.data_frame.df_fin; 487 488 len = pf->pf_gen_stream_frame( 489 new_packet_out->po_data + new_packet_out->po_data_sz, 490 lsquic_packet_out_avail(new_packet_out), frame.stream_id, 491 frame.data_frame.df_offset + frame.data_frame.df_size / 2, 492 split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx), 493 split_reader_read, &reader_ctx); 494 if (len < 0) 495 { 496 LSQ_ERROR("could not generate new frame 1"); 497 return -1; 498 } 499 if (0 != lsquic_packet_out_add_stream(new_packet_out, mm, 500 max_srec->sr_stream, QUIC_FRAME_STREAM, 501 new_packet_out->po_data_sz, len)) 502 return -1; 503 new_packet_out->po_data_sz += len; 504 if (0 == lsquic_packet_out_avail(new_packet_out)) 505 { 506 assert(0); /* We really should not fill here, but JIC */ 507 new_packet_out->po_flags |= PO_STREAM_END; 508 } 509 510 memcpy(reader_ctx.buf, frame.data_frame.df_data, 511 frame.data_frame.df_size / 2); 512 reader_ctx.off = 0; 513 reader_ctx.len = frame.data_frame.df_size / 2; 514 reader_ctx.fin = 0; 515 len = pf->pf_gen_stream_frame( 516 packet_out->po_data + max_srec->sr_off, max_srec->sr_len, 517 frame.stream_id, frame.data_frame.df_offset, 518 split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx), 519 split_reader_read, &reader_ctx); 520 if (len < 0) 521 { 522 LSQ_ERROR("could not generate new frame 2"); 523 return -1; 524 } 525 526 const unsigned short adj = max_srec->sr_len - (unsigned short) len; 527 max_srec->sr_len = len; 528 for (n = max_idx + 1; n < n_srecs; ++n) 529 srecs[n]->sr_off -= adj; 530 packet_out->po_data_sz -= adj; 531 532 return 0; 533} 534 535 536#ifndef NDEBUG 537static void 538verify_srecs (lsquic_packet_out_t *packet_out) 539{ 540 struct packet_out_srec_iter posi; 541 const struct stream_rec *srec; 542 unsigned off; 543 544 srec = posi_first(&posi, packet_out); 545 assert(srec); 546 547 off = 0; 548 for ( ; srec; srec = posi_next(&posi)) 549 { 550 assert(srec->sr_off == off); 551 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 552 off += srec->sr_len; 553 } 554 555 assert(packet_out->po_data_sz == off); 556} 557 558 559#endif 560 561 562int 563lsquic_packet_out_split_in_two (struct lsquic_mm *mm, 564 lsquic_packet_out_t *packet_out, lsquic_packet_out_t *new_packet_out, 565 const struct parse_funcs *pf, unsigned excess_bytes) 566{ 567 struct packet_out_srec_iter posi; 568 struct stream_rec *local_arr[4]; 569 struct stream_rec **new_srecs, **srecs = local_arr; 570 struct stream_rec *srec; 571 unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]); 572 unsigned n_srecs, max_idx, n, nbytes; 573#ifndef NDEBUG 574 unsigned short frame_sum = 0; 575#endif 576 int rv; 577 578 /* We only split buffered packets; buffered packets contain only STREAM 579 * frames: 580 */ 581 assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM)); 582 583 n_srecs = 0; 584#ifdef WIN32 585 max_idx = 0; 586#endif 587 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 588 { 589 /* We only expect references to STREAM frames (buffered packets): */ 590 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 591 if (n_srecs >= n_srecs_alloced) 592 { 593 n_srecs_alloced *= 2; 594 if (srecs == local_arr) 595 { 596 srecs = malloc(sizeof(srecs[0]) * n_srecs_alloced); 597 if (!srecs) 598 goto err; 599 memcpy(srecs, local_arr, sizeof(local_arr)); 600 } 601 else 602 { 603 new_srecs = realloc(srecs, sizeof(srecs[0]) * n_srecs_alloced); 604 if (!new_srecs) 605 goto err; 606 srecs = new_srecs; 607 } 608 } 609 610#ifndef NDEBUG 611 frame_sum += srec->sr_len; 612#endif 613 if (n_srecs == 0 || srecs[max_idx]->sr_len < srec->sr_len) 614 max_idx = n_srecs; 615 616 srecs[n_srecs++] = srec; 617 } 618 619 assert(frame_sum == packet_out->po_data_sz); 620 621 if (n_srecs == 1) 622 goto common_case; 623 624 if (n_srecs < 1) 625 goto err; 626 627 /* Case 1: see if we can remove one or more trailing frames to make 628 * packet smaller. 629 */ 630 nbytes = 0; 631 for (n = n_srecs - 1; n > max_idx && nbytes < excess_bytes; --n) 632 nbytes += srecs[n]->sr_len; 633 if (nbytes >= excess_bytes) 634 { 635 rv = split_off_last_frames(mm, packet_out, new_packet_out, 636 srecs + n + 1, n_srecs - n - 1); 637 goto end; 638 } 639 640 /* Case 2: see if we can move the largest frame to new packet. */ 641 nbytes = 0; 642 for (n = 0; n < n_srecs; ++n) 643 if (n != max_idx) 644 nbytes += srecs[n]->sr_len; 645 if (nbytes >= excess_bytes) 646 { 647 rv = move_largest_frame(mm, packet_out, new_packet_out, srecs, 648 n_srecs, max_idx); 649 goto end; 650 } 651 652 common_case: 653 /* Case 3: we have to split the largest frame (which could be the 654 * the only frame) in two. 655 */ 656 rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs, 657 n_srecs, max_idx); 658 659 end: 660 if (srecs != local_arr) 661 free(srecs); 662 if (0 == rv) 663 { 664 new_packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM; 665#ifndef NDEBUG 666 verify_srecs(packet_out); 667 verify_srecs(new_packet_out); 668#endif 669 } 670 return rv; 671 672 err: 673 rv = -1; 674 goto end; 675} 676 677 678void 679lsquic_packet_out_zero_pad (lsquic_packet_out_t *packet_out) 680{ 681 if (packet_out->po_n_alloc > packet_out->po_data_sz) 682 { 683 memset(packet_out->po_data + packet_out->po_data_sz, 0, 684 packet_out->po_n_alloc - packet_out->po_data_sz); 685 packet_out->po_data_sz = packet_out->po_n_alloc; 686 packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING; 687 } 688} 689 690 691size_t 692lsquic_packet_out_mem_used (const struct lsquic_packet_out *packet_out) 693{ 694 const struct stream_rec_arr *srec_arr; 695 size_t size; 696 697 size = 0; /* The struct is allocated using malo */ 698 if (packet_out->po_enc_data) 699 size += packet_out->po_enc_data_sz; 700 if (packet_out->po_data) 701 size += packet_out->po_n_alloc; 702 if (packet_out->po_nonce) 703 size += 32; 704 705 if (packet_out->po_flags & PO_SREC_ARR) 706 TAILQ_FOREACH(srec_arr, &packet_out->po_srecs.arr, next_stream_rec_arr) 707 size += sizeof(*srec_arr); 708 709 return size; 710} 711 712 713int 714lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out, 715 const struct parse_funcs *pf, 716 const struct lsquic_stream *stream) 717{ 718 struct packet_out_srec_iter posi; 719 const struct stream_rec *srec; 720 struct stream_frame stream_frame; 721 uint64_t last_offset; 722 int len; 723 724 for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi)) 725 if (srec->sr_frame_type == QUIC_FRAME_STREAM 726 && srec->sr_stream == stream) 727 { 728 len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off, 729 srec->sr_len, &stream_frame); 730 assert(len >= 0); 731 if (len < 0) 732 return -1; 733 last_offset = stream_frame.data_frame.df_offset 734 + stream_frame.data_frame.df_size; 735 if (last_offset == stream->tosend_off) 736 { 737 pf->pf_turn_on_fin(packet_out->po_data + srec->sr_off); 738 EV_LOG_UPDATED_STREAM_FRAME(lsquic_stream_cid(stream), 739 pf, packet_out->po_data + srec->sr_off, srec->sr_len); 740 return 0; 741 } 742 } 743 744 return -1; 745} 746