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