lsquic_packet_out.c revision a5fa05f9
1/* Copyright (c) 2017 - 2020 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
46static struct stream_rec *
47srec_one_posi_next (struct packet_out_srec_iter *posi)
48{
49    return NULL;
50}
51
52
53static struct 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 *
99lsquic_posi_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 *
108lsquic_posi_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 = lsquic_posi_first(&posi, packet_out); srec;
300                                            srec = lsquic_posi_next(&posi))
301    {
302        if (srec->sr_frame_type == QUIC_FRAME_STREAM)
303        {
304            ++n_stream_frames;
305
306            /* Offsets of all STREAM frames should be adjusted */
307            srec->sr_off -= adj;
308
309            if (stream_id)
310            {
311                victim = srec->sr_stream->id == stream_id;
312                if (victim)
313                {
314                    assert(lsquic_stream_is_reset(srec->sr_stream));
315                }
316            }
317            else
318                victim = lsquic_stream_is_reset(srec->sr_stream);
319
320            if (victim)
321            {
322                ++n_elided;
323
324                /* Move the data and adjust sizes */
325                adj += srec->sr_len;
326                memmove(packet_out->po_data + srec->sr_off,
327                        packet_out->po_data + srec->sr_off + srec->sr_len,
328                        packet_out->po_data_sz - srec->sr_off - srec->sr_len);
329                packet_out->po_data_sz -= srec->sr_len;
330
331                lsquic_stream_acked(srec->sr_stream, srec->sr_frame_type);
332                srec->sr_frame_type = 0;
333            }
334        }
335    }
336
337    assert(n_stream_frames);
338    if (n_elided == n_stream_frames)
339    {
340        packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
341        packet_out->po_flags &= ~PO_STREAM_END;
342    }
343
344    return adj;
345}
346
347
348void
349lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out)
350{
351    struct packet_out_srec_iter posi;
352    struct stream_rec *srec;
353    unsigned delta;
354
355    delta = packet_out->po_regen_sz;
356    packet_out->po_data_sz -= delta;
357    memmove(packet_out->po_data, packet_out->po_data + delta,
358                                                    packet_out->po_data_sz);
359    packet_out->po_regen_sz = 0;
360
361    for (srec = lsquic_posi_first(&posi, packet_out); srec;
362                                                srec = lsquic_posi_next(&posi))
363        if (srec->sr_frame_type == QUIC_FRAME_STREAM)
364            srec->sr_off -= delta;
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 = lsquic_posi_first(&posi, packet_out); srec;
374                                                srec = lsquic_posi_next(&posi))
375        lsquic_stream_acked(srec->sr_stream, srec->sr_frame_type);
376}
377
378
379static int
380split_off_last_frames (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
381    lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
382    unsigned n_srecs, enum quic_frame_type frame_type)
383{
384    unsigned n;
385
386    for (n = 0; n < n_srecs; ++n)
387    {
388        struct stream_rec *const srec = srecs[n];
389        memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
390               packet_out->po_data + srec->sr_off, srec->sr_len);
391        if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
392                            srec->sr_stream, frame_type,
393                            new_packet_out->po_data_sz, srec->sr_len))
394            return -1;
395        srec->sr_frame_type = 0;
396        assert(srec->sr_stream->n_unacked > 1);
397        --srec->sr_stream->n_unacked;
398        new_packet_out->po_data_sz += srec->sr_len;
399    }
400
401    packet_out->po_data_sz = srecs[0]->sr_off;
402
403    return 0;
404}
405
406
407static int
408move_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
409    lsquic_packet_out_t *new_packet_out, struct stream_rec **srecs,
410    unsigned n_srecs, unsigned max_idx, enum quic_frame_type frame_type)
411{
412    unsigned n;
413    struct stream_rec *const max_srec = srecs[max_idx];
414
415    memcpy(new_packet_out->po_data + new_packet_out->po_data_sz,
416           packet_out->po_data + max_srec->sr_off, max_srec->sr_len);
417    memmove(packet_out->po_data + max_srec->sr_off,
418            packet_out->po_data + max_srec->sr_off + max_srec->sr_len,
419            packet_out->po_data_sz - max_srec->sr_off - max_srec->sr_len);
420    if (0 != lsquic_packet_out_add_stream(new_packet_out, mm,
421                        max_srec->sr_stream, frame_type,
422                        new_packet_out->po_data_sz, max_srec->sr_len))
423        return -1;
424
425    max_srec->sr_frame_type = 0;
426    assert(max_srec->sr_stream->n_unacked > 1);
427    --max_srec->sr_stream->n_unacked;
428    new_packet_out->po_data_sz += max_srec->sr_len;
429    packet_out->po_data_sz -= max_srec->sr_len;
430
431    for (n = max_idx + 1; n < n_srecs; ++n)
432        srecs[n]->sr_off -= max_srec->sr_len;
433
434    return 0;
435}
436
437
438struct split_reader_ctx
439{
440    unsigned        off;
441    unsigned        len;
442    signed char     fin;
443    unsigned char   buf[GQUIC_MAX_PAYLOAD_SZ / 2 + 1];
444};
445
446
447static int
448split_reader_fin (void *ctx)
449{
450    struct split_reader_ctx *const reader_ctx = ctx;
451    return reader_ctx->off == reader_ctx->len && reader_ctx->fin;
452}
453
454
455static size_t
456split_reader_size (void *ctx)
457{
458    struct split_reader_ctx *const reader_ctx = ctx;
459    return reader_ctx->len - reader_ctx->off;
460}
461
462
463static size_t
464split_stream_reader_read (void *ctx, void *buf, size_t len, int *fin)
465{
466    struct split_reader_ctx *const reader_ctx = ctx;
467    if (len > reader_ctx->len - reader_ctx->off)
468        len = reader_ctx->len - reader_ctx->off;
469    memcpy(buf, reader_ctx->buf, len);
470    reader_ctx->off += len;
471    *fin = split_reader_fin(reader_ctx);
472    return len;
473}
474
475
476static size_t
477split_crypto_reader_read (void *ctx, void *buf, size_t len)
478{
479    struct split_reader_ctx *const reader_ctx = ctx;
480    if (len > reader_ctx->len - reader_ctx->off)
481        len = reader_ctx->len - reader_ctx->off;
482    memcpy(buf, reader_ctx->buf, len);
483    reader_ctx->off += len;
484    return len;
485}
486
487
488static int
489split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
490    lsquic_packet_out_t *new_packet_out, const struct parse_funcs *pf,
491    struct stream_rec **srecs, unsigned n_srecs, unsigned max_idx,
492    enum quic_frame_type frame_type)
493{
494    struct stream_rec *const max_srec = srecs[max_idx];
495    struct stream_frame frame;
496    int len;
497    unsigned n;
498    struct split_reader_ctx reader_ctx;
499
500    if (frame_type == QUIC_FRAME_STREAM)
501        len = pf->pf_parse_stream_frame(packet_out->po_data + max_srec->sr_off,
502                                        max_srec->sr_len, &frame);
503    else
504        len = pf->pf_parse_crypto_frame(packet_out->po_data + max_srec->sr_off,
505                                        max_srec->sr_len, &frame);
506    if (len < 0)
507    {
508        LSQ_ERROR("could not parse own frame");
509        return -1;
510    }
511
512    assert(frame.data_frame.df_size / 2 <= sizeof(reader_ctx.buf));
513    if (frame.data_frame.df_size / 2 > sizeof(reader_ctx.buf))
514        return -1;
515
516    memcpy(reader_ctx.buf,
517           frame.data_frame.df_data + frame.data_frame.df_size / 2,
518           frame.data_frame.df_size - frame.data_frame.df_size / 2);
519    reader_ctx.off = 0;
520    reader_ctx.len = frame.data_frame.df_size - frame.data_frame.df_size / 2;
521    reader_ctx.fin = frame.data_frame.df_fin;
522
523    if (frame_type == QUIC_FRAME_STREAM)
524        len = pf->pf_gen_stream_frame(
525                new_packet_out->po_data + new_packet_out->po_data_sz,
526                lsquic_packet_out_avail(new_packet_out), frame.stream_id,
527                frame.data_frame.df_offset + frame.data_frame.df_size / 2,
528                split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
529                split_stream_reader_read, &reader_ctx);
530    else
531        len = pf->pf_gen_crypto_frame(
532                new_packet_out->po_data + new_packet_out->po_data_sz,
533                lsquic_packet_out_avail(new_packet_out),
534                frame.data_frame.df_offset + frame.data_frame.df_size / 2,
535                split_reader_size(&reader_ctx),
536                split_crypto_reader_read, &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, max_srec->sr_frame_type,
544                        new_packet_out->po_data_sz, len))
545        return -1;
546    new_packet_out->po_data_sz += len;
547    if (0 == lsquic_packet_out_avail(new_packet_out))
548    {
549        assert(0);  /* We really should not fill here, but JIC */
550        new_packet_out->po_flags |= PO_STREAM_END;
551    }
552
553    memcpy(reader_ctx.buf, frame.data_frame.df_data,
554           frame.data_frame.df_size / 2);
555    reader_ctx.off = 0;
556    reader_ctx.len = frame.data_frame.df_size / 2;
557    reader_ctx.fin = 0;
558    if (frame_type == QUIC_FRAME_STREAM)
559        len = pf->pf_gen_stream_frame(
560                packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
561                frame.stream_id, frame.data_frame.df_offset,
562                split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
563                split_stream_reader_read, &reader_ctx);
564    else
565        len = pf->pf_gen_crypto_frame(
566                packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
567                frame.data_frame.df_offset,
568                split_reader_size(&reader_ctx),
569                split_crypto_reader_read, &reader_ctx);
570    if (len < 0)
571    {
572        LSQ_ERROR("could not generate new frame 2");
573        return -1;
574    }
575
576    const unsigned short adj = max_srec->sr_len - (unsigned short) len;
577    max_srec->sr_len = len;
578    for (n = max_idx + 1; n < n_srecs; ++n)
579        srecs[n]->sr_off -= adj;
580    packet_out->po_data_sz -= adj;
581
582    return 0;
583}
584
585
586#ifndef NDEBUG
587static void
588verify_srecs (lsquic_packet_out_t *packet_out, enum quic_frame_type frame_type)
589{
590    struct packet_out_srec_iter posi;
591    const struct stream_rec *srec;
592    unsigned off;
593
594    srec = lsquic_posi_first(&posi, packet_out);
595    assert(srec);
596
597    off = 0;
598    for ( ; srec; srec = lsquic_posi_next(&posi))
599    {
600        assert(srec->sr_off == off);
601        assert(srec->sr_frame_type == frame_type);
602        off += srec->sr_len;
603    }
604
605    assert(packet_out->po_data_sz == off);
606}
607#endif
608
609
610int
611lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
612        lsquic_packet_out_t *packet_out, lsquic_packet_out_t *new_packet_out,
613        const struct parse_funcs *pf, unsigned excess_bytes)
614{
615    struct packet_out_srec_iter posi;
616    struct stream_rec *local_arr[4];
617    struct stream_rec **new_srecs, **srecs = local_arr;
618    struct stream_rec *srec;
619    unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
620    unsigned n_srecs, max_idx, n, nbytes;
621    enum quic_frame_type frame_type;
622#ifndef NDEBUG
623    unsigned short frame_sum = 0;
624#endif
625    int rv;
626
627    /* We only split buffered packets or initial packets with CRYPTO frames.
628     * Either contain just one frame type: STREAM or CRYPTO.
629     */
630    assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM)
631        || packet_out->po_frame_types == (1 << QUIC_FRAME_CRYPTO));
632    if (packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
633        frame_type = QUIC_FRAME_STREAM;
634    else
635        frame_type = QUIC_FRAME_CRYPTO;
636
637    n_srecs = 0;
638#ifdef WIN32
639    max_idx = 0;
640#endif
641    for (srec = lsquic_posi_first(&posi, packet_out); srec;
642                                                srec = lsquic_posi_next(&posi))
643    {
644        assert(srec->sr_frame_type == QUIC_FRAME_STREAM
645            || srec->sr_frame_type == QUIC_FRAME_CRYPTO);
646        if (n_srecs >= n_srecs_alloced)
647        {
648            n_srecs_alloced *= 2;
649            if (srecs == local_arr)
650            {
651                srecs = malloc(sizeof(srecs[0]) * n_srecs_alloced);
652                if (!srecs)
653                    goto err;
654                memcpy(srecs, local_arr, sizeof(local_arr));
655            }
656            else
657            {
658                new_srecs = realloc(srecs, sizeof(srecs[0]) * n_srecs_alloced);
659                if (!new_srecs)
660                    goto err;
661                srecs = new_srecs;
662            }
663        }
664
665#ifndef NDEBUG
666        frame_sum += srec->sr_len;
667#endif
668        if (n_srecs == 0 || srecs[max_idx]->sr_len < srec->sr_len)
669            max_idx = n_srecs;
670
671        srecs[n_srecs++] = srec;
672    }
673
674    assert(frame_sum == packet_out->po_data_sz);
675
676    if (n_srecs == 1)
677        goto common_case;
678
679    if (n_srecs < 1)
680        goto err;
681
682    /* Case 1: see if we can remove one or more trailing frames to make
683     * packet smaller.
684     */
685    nbytes = 0;
686    for (n = n_srecs - 1; n > max_idx && nbytes < excess_bytes; --n)
687        nbytes += srecs[n]->sr_len;
688    if (nbytes >= excess_bytes)
689    {
690        rv = split_off_last_frames(mm, packet_out, new_packet_out,
691                                   srecs + n + 1, n_srecs - n - 1, frame_type);
692        goto end;
693    }
694
695    /* Case 2: see if we can move the largest frame to new packet. */
696    nbytes = 0;
697    for (n = 0; n < n_srecs; ++n)
698        if (n != max_idx)
699            nbytes += srecs[n]->sr_len;
700    if (nbytes >= excess_bytes)
701    {
702        rv = move_largest_frame(mm, packet_out, new_packet_out, srecs,
703                                n_srecs, max_idx, frame_type);
704        goto end;
705    }
706
707  common_case:
708    /* Case 3: we have to split the largest frame (which could be the
709     * the only frame) in two.
710     */
711    rv = split_largest_frame(mm, packet_out, new_packet_out, pf, srecs,
712                             n_srecs, max_idx, frame_type);
713
714  end:
715    if (srecs != local_arr)
716        free(srecs);
717    if (0 == rv)
718    {
719        new_packet_out->po_frame_types |= 1 << frame_type;
720#ifndef NDEBUG
721        verify_srecs(packet_out, frame_type);
722        verify_srecs(new_packet_out, frame_type);
723#endif
724    }
725    return rv;
726
727  err:
728    rv = -1;
729    goto end;
730}
731
732
733void
734lsquic_packet_out_zero_pad (lsquic_packet_out_t *packet_out)
735{
736    if (packet_out->po_n_alloc > packet_out->po_data_sz)
737    {
738        memset(packet_out->po_data + packet_out->po_data_sz, 0,
739                            packet_out->po_n_alloc - packet_out->po_data_sz);
740        packet_out->po_data_sz = packet_out->po_n_alloc;
741        packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING;
742    }
743}
744
745
746size_t
747lsquic_packet_out_mem_used (const struct lsquic_packet_out *packet_out)
748{
749    const struct stream_rec_arr *srec_arr;
750    size_t size;
751
752    size = 0;   /* The struct is allocated using malo */
753    if (packet_out->po_enc_data)
754        size += packet_out->po_enc_data_sz;
755    if (packet_out->po_data)
756        size += packet_out->po_n_alloc;
757    if (packet_out->po_nonce)
758        size += 32;
759
760    if (packet_out->po_flags & PO_SREC_ARR)
761        TAILQ_FOREACH(srec_arr, &packet_out->po_srecs.arr, next_stream_rec_arr)
762            size += sizeof(*srec_arr);
763
764    return size;
765}
766
767
768int
769lsquic_packet_out_turn_on_fin (struct lsquic_packet_out *packet_out,
770                               const struct parse_funcs *pf,
771                               const struct lsquic_stream *stream)
772{
773    struct packet_out_srec_iter posi;
774    const struct stream_rec *srec;
775    struct stream_frame stream_frame;
776    uint64_t last_offset;
777    int len;
778
779    for (srec = lsquic_posi_first(&posi, packet_out); srec;
780                                                srec = lsquic_posi_next(&posi))
781        if (srec->sr_frame_type == QUIC_FRAME_STREAM
782            && srec->sr_stream == stream)
783        {
784            len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
785                                            srec->sr_len, &stream_frame);
786            assert(len >= 0);
787            if (len < 0)
788                return -1;
789            last_offset = stream_frame.data_frame.df_offset
790                        + stream_frame.data_frame.df_size;
791            if (last_offset == stream->tosend_off)
792            {
793                pf->pf_turn_on_fin(packet_out->po_data + srec->sr_off);
794                EV_LOG_UPDATED_STREAM_FRAME(
795                    lsquic_conn_log_cid(lsquic_stream_conn(stream)),
796                    pf, packet_out->po_data + srec->sr_off, srec->sr_len);
797                return 0;
798            }
799        }
800
801    return -1;
802}
803