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