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