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