lsquic_packet_out.c revision 7a8b2ece
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_gquic.h"
19#include "lsquic_packet_in.h"
20#include "lsquic_packet_out.h"
21#include "lsquic_parse.h"
22#include "lsquic_sfcw.h"
23#include "lsquic_varint.h"
24#include "lsquic_hq.h"
25#include "lsquic_hash.h"
26#include "lsquic_stream.h"
27#include "lsquic_logger.h"
28#include "lsquic_ev_log.h"
29#include "lsquic_conn.h"
30#include "lsquic_enc_sess.h"
31
32typedef char _stream_rec_arr_is_at_most_64bytes[
33                                (sizeof(struct stream_rec_arr) <= 64)? 1: - 1];
34
35static struct stream_rec *
36srec_one_posi_first (struct packet_out_srec_iter *posi,
37                     struct lsquic_packet_out *packet_out)
38{
39    if (packet_out->po_srecs.one.sr_frame_type)
40        return &packet_out->po_srecs.one;
41    else
42        return NULL;
43}
44
45
46struct stream_rec *
47srec_one_posi_next (struct packet_out_srec_iter *posi)
48{
49    return NULL;
50}
51
52
53struct stream_rec *
54srec_arr_posi_next (struct packet_out_srec_iter *posi)
55{
56    while (posi->cur_srec_arr)
57    {
58        for (; posi->srec_idx < sizeof(posi->cur_srec_arr->srecs) / sizeof(posi->cur_srec_arr->srecs[0]);
59                ++posi->srec_idx)
60        {
61            if (posi->cur_srec_arr->srecs[ posi->srec_idx ].sr_frame_type)
62                return &posi->cur_srec_arr->srecs[ posi->srec_idx++ ];
63        }
64        posi->cur_srec_arr = TAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr);
65        posi->srec_idx = 0;
66    }
67    return NULL;
68}
69
70
71static struct stream_rec *
72srec_arr_posi_first (struct packet_out_srec_iter *posi,
73                     struct lsquic_packet_out *packet_out)
74{
75    posi->packet_out = packet_out;
76    posi->cur_srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr);
77    posi->srec_idx = 0;
78    return srec_arr_posi_next(posi);
79}
80
81
82static struct stream_rec * (* const posi_firsts[])
83    (struct packet_out_srec_iter *, struct lsquic_packet_out *) =
84{
85    srec_one_posi_first,
86    srec_arr_posi_first,
87};
88
89
90static struct stream_rec * (* const posi_nexts[])
91    (struct packet_out_srec_iter *posi) =
92{
93    srec_one_posi_next,
94    srec_arr_posi_next,
95};
96
97
98struct stream_rec *
99posi_first (struct packet_out_srec_iter *posi,
100            lsquic_packet_out_t *packet_out)
101{
102    posi->impl_idx = !!(packet_out->po_flags & PO_SREC_ARR);
103    return posi_firsts[posi->impl_idx](posi, packet_out);
104}
105
106
107struct stream_rec *
108posi_next (struct packet_out_srec_iter *posi)
109{
110    return posi_nexts[posi->impl_idx](posi);
111}
112
113
114/*
115 * Assumption: frames are added to the packet_out in order of their placement
116 * in packet_out->po_data.  There is no assertion to guard for 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 stream_rec_arr *srec_arr;
126    int last_taken;
127    unsigned i;
128
129    assert(!(new_stream->stream_flags & STREAM_FINISHED));
130
131    if (!(packet_out->po_flags & PO_SREC_ARR))
132    {
133        if (!srec_taken(&packet_out->po_srecs.one))
134        {
135            packet_out->po_srecs.one.sr_frame_type  = frame_type;
136            packet_out->po_srecs.one.sr_stream      = new_stream;
137            packet_out->po_srecs.one.sr_off         = off;
138            packet_out->po_srecs.one.sr_len         = len;
139            ++new_stream->n_unacked;
140            return 0;                           /* Insert in first slot */
141        }
142        srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
143        if (!srec_arr)
144            return -1;
145        memset(srec_arr, 0, sizeof(*srec_arr));
146        srec_arr->srecs[0] = packet_out->po_srecs.one;
147        TAILQ_INIT(&packet_out->po_srecs.arr);
148        TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr,
149                           next_stream_rec_arr);
150        packet_out->po_flags |= PO_SREC_ARR;
151        i = 1;
152        goto set_elem;
153    }
154
155    /* New records go at the very end: */
156    srec_arr = TAILQ_LAST(&packet_out->po_srecs.arr, stream_rec_arr_tailq);
157    last_taken = -1;
158    for (i = 0; i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]); ++i)
159        if (srec_taken(&srec_arr->srecs[i]))
160            last_taken = i;
161
162    i = last_taken + 1;
163    if (i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]))
164    {
165  set_elem:
166        srec_arr->srecs[i].sr_frame_type  = frame_type;
167        srec_arr->srecs[i].sr_stream      = new_stream;
168        srec_arr->srecs[i].sr_off         = off;
169        srec_arr->srecs[i].sr_len         = len;
170        ++new_stream->n_unacked;
171        return 0;                   /* Insert in existing srec */
172    }
173
174    srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
175    if (!srec_arr)
176        return -1;
177
178    memset(srec_arr, 0, sizeof(*srec_arr));
179    srec_arr->srecs[0].sr_frame_type  = frame_type;
180    srec_arr->srecs[0].sr_stream      = new_stream;
181    srec_arr->srecs[0].sr_off         = off;
182    srec_arr->srecs[0].sr_len         = len;
183    TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, next_stream_rec_arr);
184    ++new_stream->n_unacked;
185    return 0;                               /* Insert in new srec */
186}
187
188
189lsquic_packet_out_t *
190lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
191                const struct lsquic_conn *lconn, enum packno_bits bits,
192                const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce,
193                const struct network_path *path)
194{
195    lsquic_packet_out_t *packet_out;
196    enum packet_out_flags flags;
197    size_t header_size, tag_len, max_size;
198
199    flags = bits << POBIT_SHIFT;
200    if (ver_tag)
201        flags |= PO_VERSION;
202    if (nonce)
203        flags |= PO_NONCE;
204    if (use_cid)
205        flags |= PO_CONN_ID;
206    if ((lconn->cn_flags & (LSCONN_MINI|LSCONN_HANDSHAKE_DONE))
207                                                != LSCONN_HANDSHAKE_DONE)
208        flags |= PO_LONGHEAD;
209
210    header_size = lconn->cn_pf->pf_packout_max_header_size(lconn, flags,
211                                                        path->np_dcid.len);
212    tag_len = lconn->cn_esf_c->esf_tag_len;
213    max_size = path->np_pack_size;
214    if (header_size + tag_len >= max_size)
215    {
216        errno = EINVAL;
217        return NULL;
218    }
219
220    packet_out = lsquic_mm_get_packet_out(mm, malo, max_size - header_size
221                                                - tag_len);
222    if (!packet_out)
223        return NULL;
224
225    packet_out->po_flags = flags;
226    if ((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS)
227        packet_out->po_lflags = POL_GQUIC;
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    {
245        if (lconn->cn_version == LSQVER_050)
246        {
247            if (lconn->cn_flags & (LSCONN_SERVER|LSCONN_HANDSHAKE_DONE))
248                packet_out->po_header_type = HETY_0RTT;
249            else
250                packet_out->po_header_type = HETY_INITIAL;
251        }
252        else
253            packet_out->po_header_type = HETY_HANDSHAKE;
254    }
255    packet_out->po_path = path;
256
257    return packet_out;
258}
259
260
261void
262lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out,
263                           struct lsquic_engine_public *enpub, void *peer_ctx)
264{
265    if (packet_out->po_flags & PO_SREC_ARR)
266    {
267        struct stream_rec_arr *srec_arr, *next;
268        for (srec_arr = TAILQ_FIRST(&packet_out->po_srecs.arr);
269                                             srec_arr; srec_arr = next)
270        {
271            next = TAILQ_NEXT(srec_arr, next_stream_rec_arr);
272            lsquic_malo_put(srec_arr);
273        }
274    }
275    if (packet_out->po_flags & PO_ENCRYPTED)
276        enpub->enp_pmi->pmi_release(enpub->enp_pmi_ctx, peer_ctx,
277                packet_out->po_enc_data, lsquic_packet_out_ipv6(packet_out));
278    if (packet_out->po_nonce)
279        free(packet_out->po_nonce);
280    if (packet_out->po_bwp_state)
281        lsquic_malo_put(packet_out->po_bwp_state);
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                                             lsquic_stream_id_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_type == 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                lsquic_stream_acked(srec->sr_stream, srec->sr_frame_type);
331                srec->sr_frame_type = 0;
332            }
333        }
334    }
335
336    assert(n_stream_frames);
337    if (n_elided == n_stream_frames)
338    {
339        packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
340        packet_out->po_flags &= ~PO_STREAM_END;
341    }
342
343    return adj;
344}
345
346
347void
348lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out)
349{
350    struct packet_out_srec_iter posi;
351    struct stream_rec *srec;
352    unsigned delta;
353
354    delta = packet_out->po_regen_sz;
355    packet_out->po_data_sz -= delta;
356    memmove(packet_out->po_data, packet_out->po_data + delta,
357                                                    packet_out->po_data_sz);
358    packet_out->po_regen_sz = 0;
359
360    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
361        if (srec->sr_frame_type == QUIC_FRAME_STREAM)
362            srec->sr_off -= delta;
363}
364
365
366void
367lsquic_packet_out_ack_streams (lsquic_packet_out_t *packet_out)
368{
369    struct packet_out_srec_iter posi;
370    struct stream_rec *srec;
371    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
372        lsquic_stream_acked(srec->sr_stream, srec->sr_frame_type);
373}
374
375
376static int
377split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
378    lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
379    unsigned n_srecs, enum quic_frame_type frame_type)
380{
381    unsigned n;
382
383    for (n = 0; n < n_srecs; ++n)
384    {
385        struct stream_rec *const srec = srecs[n];
386        memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
387               packet_out->po_data + srec->sr_off, srec->sr_len);
388        if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
389                            srec->sr_stream, frame_type,
390                            new_packet_out->po_data_sz, srec->sr_len))
391            return -1;
392        srec->sr_frame_type = 0;
393        assert(srec->sr_stream->n_unacked > 1);
394        --srec->sr_stream->n_unacked;
395        new_packet_out->po_data_sz += srec->sr_len;
396    }
397
398    packet_out->po_data_sz = srecs[0]->sr_off;
399
400    return 0;
401}
402
403
404static int
405move_largest_frame (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, unsigned max_idx, enum quic_frame_type frame_type)
408{
409    unsigned n;
410    struct stream_rec *const max_srec = srecs[max_idx];
411
412    memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
413           packet_out->po_data + max_srec->sr_off, max_srec->sr_len);
414    memmove(packet_out->po_data + max_srec->sr_off,
415            packet_out->po_data + max_srec->sr_off + max_srec->sr_len,
416            packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len);
417    if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
418                        max_srec->sr_stream, frame_type,
419                        new_packet_out->po_data_sz, max_srec->sr_len))
420        return -1;
421
422    max_srec->sr_frame_type = 0;
423    assert(max_srec->sr_stream->n_unacked > 1);
424    --max_srec->sr_stream->n_unacked;
425    new_packet_out->po_data_sz += max_srec->sr_len;
426    packet_out->po_data_sz -= max_srec->sr_len;
427
428    for (n = max_idx + 1; n < n_srecs; ++n)
429        srecs[n]->sr_off -= max_srec->sr_len;
430
431    return 0;
432}
433
434
435struct split_reader_ctx
436{
437    unsigned        off;
438    unsigned        len;
439    signed char     fin;
440    unsigned char   buf[GQUIC_MAX_PAYLOAD_SZ / 2 + 1];
441};
442
443
444static int
445split_reader_fin (void *ctx)
446{
447    struct split_reader_ctx *const reader_ctx = ctx;
448    return reader_ctx->off == reader_ctx->len && reader_ctx->fin;
449}
450
451
452static size_t
453split_reader_size (void *ctx)
454{
455    struct split_reader_ctx *const reader_ctx = ctx;
456    return reader_ctx->len - reader_ctx->off;
457}
458
459
460static size_t
461split_stream_reader_read (void *ctx, void *buf, size_t len, int *fin)
462{
463    struct split_reader_ctx *const reader_ctx = ctx;
464    if (len > reader_ctx->len - reader_ctx->off)
465        len = reader_ctx->len - reader_ctx->off;
466    memcpy(buf, reader_ctx->buf, len);
467    reader_ctx->off += len;
468    *fin = split_reader_fin(reader_ctx);
469    return len;
470}
471
472
473static size_t
474split_crypto_reader_read (void *ctx, void *buf, size_t len)
475{
476    struct split_reader_ctx *const reader_ctx = ctx;
477    if (len > reader_ctx->len - reader_ctx->off)
478        len = reader_ctx->len - reader_ctx->off;
479    memcpy(buf, reader_ctx->buf, len);
480    reader_ctx->off += len;
481    return len;
482}
483
484
485static int
486split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
487    lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf,
488    struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx,
489    enum quic_frame_type frame_type)
490{
491    struct stream_rec *const max_srec = srecs[max_idx];
492    struct stream_frame frame;
493    int len;
494    unsigned n;
495    struct split_reader_ctx reader_ctx;
496
497    if (frame_type == QUIC_FRAME_STREAM)
498        len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off,
499                                        max_srec->sr_len, &frame);
500    else
501        len = pf->pf_parse_crypto_frame(packet_out->po_data + max_srec->sr_off,
502                                        max_srec->sr_len, &frame);
503    if (len < 0)
504    {
505        LSQ_ERROR("could not parse own frame");
506        return -1;
507    }
508
509    assert(frame.data_frame.df_size / 2 <= sizeof(reader_ctx.buf));
510    if (frame.data_frame.df_size / 2 > sizeof(reader_ctx.buf))
511        return -1;
512
513    memcpy(reader_ctx.buf,
514           frame.data_frame.df_data + frame.data_frame.df_size / 2,
515           frame.data_frame.df_size - frame.data_frame.df_size / 2);
516    reader_ctx.off = 0;
517    reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2;
518    reader_ctx.fin = frame.data_frame.df_fin;
519
520    if (frame_type == QUIC_FRAME_STREAM)
521        len = pf->pf_gen_stream_frame(
522                new_packet_out->po_data + new_packet_out->po_data_sz,
523                lsquic_packet_out_avail(new_packet_out), frame.stream_id,
524                frame.data_frame.df_offset + frame.data_frame.df_size / 2,
525                split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
526                split_stream_reader_read, &reader_ctx);
527    else
528        len = pf->pf_gen_crypto_frame(
529                new_packet_out->po_data + new_packet_out->po_data_sz,
530                lsquic_packet_out_avail(new_packet_out),
531                frame.data_frame.df_offset + frame.data_frame.df_size / 2,
532                split_reader_size(&reader_ctx),
533                split_crypto_reader_read, &reader_ctx);
534    if (len < 0)
535    {
536        LSQ_ERROR("could not generate new frame 1");
537        return -1;
538    }
539    if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
540                        max_srec->sr_stream, max_srec->sr_frame_type,
541                        new_packet_out->po_data_sz, len))
542        return -1;
543    new_packet_out->po_data_sz += len;
544    if (0 == lsquic_packet_out_avail(new_packet_out))
545    {
546        assert(0);  /* We really should not fill here, but JIC */
547        new_packet_out->po_flags |= PO_STREAM_END;
548    }
549
550    memcpy(reader_ctx.buf, frame.data_frame.df_data,
551           frame.data_frame.df_size / 2);
552    reader_ctx.off = 0;
553    reader_ctx.len = frame.data_frame.df_size / 2;
554    reader_ctx.fin = 0;
555    if (frame_type == QUIC_FRAME_STREAM)
556        len = pf->pf_gen_stream_frame(
557                packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
558                frame.stream_id, frame.data_frame.df_offset,
559                split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
560                split_stream_reader_read, &reader_ctx);
561    else
562        len = pf->pf_gen_crypto_frame(
563                packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
564                frame.data_frame.df_offset,
565                split_reader_size(&reader_ctx),
566                split_crypto_reader_read, &reader_ctx);
567    if (len < 0)
568    {
569        LSQ_ERROR("could not generate new frame 2");
570        return -1;
571    }
572
573    const unsigned short adj = max_srec->sr_len - (unsigned short) len;
574    max_srec->sr_len = len;
575    for (n = max_idx + 1; n < n_srecs; ++n)
576        srecs[n]->sr_off -= adj;
577    packet_out->po_data_sz -= adj;
578
579    return 0;
580}
581
582
583#ifndef NDEBUG
584static void
585verify_srecs (lsquic_packet_out_t *packet_out, enum quic_frame_type frame_type)
586{
587    struct packet_out_srec_iter posi;
588    const struct stream_rec *srec;
589    unsigned off;
590
591    srec = posi_first(&posi, packet_out);
592    assert(srec);
593
594    off = 0;
595    for ( ; srec; srec = posi_next(&posi))
596    {
597        assert(srec->sr_off == off);
598        assert(srec->sr_frame_type == frame_type);
599        off += srec->sr_len;
600    }
601
602    assert(packet_out->po_data_sz == off);
603}
604#endif
605
606
607int
608lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
609        lsquic_packet_out_t *packet_out, lsquic_packet_out_t *new_packet_out,
610        const struct parse_funcs *pf, unsigned excess_bytes)
611{
612    struct packet_out_srec_iter posi;
613    struct stream_rec *local_arr[4];
614    struct stream_rec **new_srecs, **srecs = local_arr;
615    struct stream_rec *srec;
616    unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
617    unsigned n_srecs, max_idx, n, nbytes;
618    enum quic_frame_type frame_type;
619#ifndef NDEBUG
620    unsigned short frame_sum = 0;
621#endif
622    int rv;
623
624    /* We only split buffered packets or initial packets with CRYPTO frames.
625     * Either contain just one frame type: STREAM or CRYPTO.
626     */
627    assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM)
628        || packet_out->po_frame_types == (1 << QUIC_FRAME_CRYPTO));
629    if (packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
630        frame_type = QUIC_FRAME_STREAM;
631    else
632        frame_type = QUIC_FRAME_CRYPTO;
633
634    n_srecs = 0;
635#ifdef WIN32
636    max_idx = 0;
637#endif
638    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
639    {
640        assert(srec->sr_frame_type == QUIC_FRAME_STREAM
641            || srec->sr_frame_type == QUIC_FRAME_CRYPTO);
642        if (n_srecs >= n_srecs_alloced)
643        {
644            n_srecs_alloced *= 2;
645            if (srecs == local_arr)
646            {
647                srecs = malloc(sizeof(srecs[0]) * n_srecs_alloced);
648                if (!srecs)
649                    goto err;
650                memcpy(srecs, local_arr, sizeof(local_arr));
651            }
652            else
653            {
654                new_srecs = realloc(srecs, sizeof(srecs[0]) * n_srecs_alloced);
655                if (!new_srecs)
656                    goto err;
657                srecs = new_srecs;
658            }
659        }
660
661#ifndef NDEBUG
662        frame_sum += srec->sr_len;
663#endif
664        if (n_srecs == 0 || srecs[max_idx]->sr_len < srec->sr_len)
665            max_idx = n_srecs;
666
667        srecs[n_srecs++] = srec;
668    }
669
670    assert(frame_sum == packet_out->po_data_sz);
671
672    if (n_srecs == 1)
673        goto common_case;
674
675    if (n_srecs < 1)
676        goto err;
677
678    /* Case 1: see if we can remove one or more trailing frames to make
679     * packet smaller.
680     */
681    nbytes = 0;
682    for (n = n_srecs - 1; n > max_idx && nbytes < excess_bytes; --n)
683        nbytes += srecs[n]->sr_len;
684    if (nbytes >= excess_bytes)
685    {
686        rv = split_off_last_frames(mm, packet_out, new_packet_out,
687                                   srecs + n + 1, n_srecs - n - 1, frame_type);
688        goto end;
689    }
690
691    /* Case 2: see if we can move the largest frame to new packet. */
692    nbytes = 0;
693    for (n = 0; n < n_srecs; ++n)
694        if (n != max_idx)
695            nbytes += srecs[n]->sr_len;
696    if (nbytes >= excess_bytes)
697    {
698        rv = move_largest_frame(mm, packet_out, new_packet_out, srecs,
699                                n_srecs, max_idx, frame_type);
700        goto end;
701    }
702
703  common_case:
704    /* Case 3: we have to split the largest frame (which could be the
705     * the only frame) in two.
706     */
707    rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs,
708                             n_srecs, max_idx, frame_type);
709
710  end:
711    if (srecs != local_arr)
712        free(srecs);
713    if (0 == rv)
714    {
715        new_packet_out->po_frame_types |= 1 << frame_type;
716#ifndef NDEBUG
717        verify_srecs(packet_out, frame_type);
718        verify_srecs(new_packet_out, frame_type);
719#endif
720    }
721    return rv;
722
723  err:
724    rv = -1;
725    goto end;
726}
727
728
729void
730lsquic_packet_out_zero_pad (lsquic_packet_out_t *packet_out)
731{
732    if (packet_out->po_n_alloc > packet_out->po_data_sz)
733    {
734        memset(packet_out->po_data + packet_out->po_data_sz, 0,
735                            packet_out->po_n_alloc - packet_out->po_data_sz);
736        packet_out->po_data_sz = packet_out->po_n_alloc;
737        packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING;
738    }
739}
740
741
742size_t
743lsquic_packet_out_mem_used (const struct lsquic_packet_out *packet_out)
744{
745    const struct stream_rec_arr *srec_arr;
746    size_t size;
747
748    size = 0;   /* The struct is allocated using malo */
749    if (packet_out->po_enc_data)
750        size += packet_out->po_enc_data_sz;
751    if (packet_out->po_data)
752        size += packet_out->po_n_alloc;
753    if (packet_out->po_nonce)
754        size += 32;
755
756    if (packet_out->po_flags & PO_SREC_ARR)
757        TAILQ_FOREACH(srec_arr, &packet_out->po_srecs.arr, next_stream_rec_arr)
758            size += sizeof(*srec_arr);
759
760    return size;
761}
762
763
764int
765lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out,
766                               const struct parse_funcs *pf,
767                               const struct lsquic_stream *stream)
768{
769    struct packet_out_srec_iter posi;
770    const struct stream_rec *srec;
771    struct stream_frame stream_frame;
772    uint64_t last_offset;
773    int len;
774
775    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
776        if (srec->sr_frame_type == QUIC_FRAME_STREAM
777            && srec->sr_stream == stream)
778        {
779            len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
780                                            srec->sr_len, &stream_frame);
781            assert(len >= 0);
782            if (len < 0)
783                return -1;
784            last_offset = stream_frame.data_frame.df_offset
785                        + stream_frame.data_frame.df_size;
786            if (last_offset == stream->tosend_off)
787            {
788                pf->pf_turn_on_fin(packet_out->po_data + srec->sr_off);
789                EV_LOG_UPDATED_STREAM_FRAME(
790                    lsquic_conn_log_cid(lsquic_stream_conn(stream)),
791                    pf, packet_out->po_data + srec->sr_off, srec->sr_len);
792                return 0;
793            }
794        }
795
796    return -1;
797}
798