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