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