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