1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2b8fa6195SDmitri Tikhonov/* Functions to resize packets */
3b8fa6195SDmitri Tikhonov
4b8fa6195SDmitri Tikhonov#include <assert.h>
5b8fa6195SDmitri Tikhonov#include <inttypes.h>
6b8fa6195SDmitri Tikhonov#include <stdint.h>
7b8fa6195SDmitri Tikhonov#include <string.h>
8b8fa6195SDmitri Tikhonov#include <sys/queue.h>
9b8fa6195SDmitri Tikhonov
10b8fa6195SDmitri Tikhonov#include "lsquic.h"
11b8fa6195SDmitri Tikhonov#include "lsquic_int_types.h"
12b8fa6195SDmitri Tikhonov#include "lsquic_packet_common.h"
13b8fa6195SDmitri Tikhonov#include "lsquic_packet_in.h"
14b8fa6195SDmitri Tikhonov#include "lsquic_packet_out.h"
15b8fa6195SDmitri Tikhonov#include "lsquic_packet_resize.h"
16b8fa6195SDmitri Tikhonov#include "lsquic_parse.h"
17b8fa6195SDmitri Tikhonov#include "lsquic_hash.h"
18b8fa6195SDmitri Tikhonov#include "lsquic_varint.h"
19b8fa6195SDmitri Tikhonov#include "lsquic_hq.h"
20b8fa6195SDmitri Tikhonov#include "lsquic_sfcw.h"
21b8fa6195SDmitri Tikhonov#include "lsquic_stream.h"
22b8fa6195SDmitri Tikhonov#include "lsquic_mm.h"
23b8fa6195SDmitri Tikhonov#include "lsquic_engine_public.h"
24b8fa6195SDmitri Tikhonov#include "lsquic_conn.h"
25b8fa6195SDmitri Tikhonov
26b8fa6195SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_PACKET_RESIZE
27b8fa6195SDmitri Tikhonov#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(prctx->prc_conn)
28b8fa6195SDmitri Tikhonov#include "lsquic_logger.h"
29b8fa6195SDmitri Tikhonov
30b8fa6195SDmitri Tikhonov
31b8fa6195SDmitri Tikhonovvoid
32b8fa6195SDmitri Tikhonovlsquic_packet_resize_init (struct packet_resize_ctx *prctx,
33b8fa6195SDmitri Tikhonov    struct lsquic_engine_public *enpub, struct lsquic_conn *lconn, void *ctx,
34b8fa6195SDmitri Tikhonov    const struct packet_resize_if *pr_if)
35b8fa6195SDmitri Tikhonov{
36b8fa6195SDmitri Tikhonov    memset(prctx, 0, sizeof(*prctx));
37b8fa6195SDmitri Tikhonov    prctx->prc_conn = lconn;
38b8fa6195SDmitri Tikhonov    prctx->prc_pri = pr_if;
39b8fa6195SDmitri Tikhonov    prctx->prc_enpub = enpub;
40b8fa6195SDmitri Tikhonov    prctx->prc_data = ctx;
41b8fa6195SDmitri Tikhonov    LSQ_DEBUG("initialized");
42b8fa6195SDmitri Tikhonov}
43b8fa6195SDmitri Tikhonov
44b8fa6195SDmitri Tikhonov
45b8fa6195SDmitri Tikhonovstatic const struct frame_rec *
46b8fa6195SDmitri Tikhonovpacket_resize_next_frec (struct packet_resize_ctx *prctx)
47b8fa6195SDmitri Tikhonov{
48b8fa6195SDmitri Tikhonov    const struct frame_rec *frec;
49b8fa6195SDmitri Tikhonov
50b8fa6195SDmitri Tikhonov    assert(!prctx->prc_cur_frec);
51b8fa6195SDmitri Tikhonov    if (prctx->prc_cur_packet)
52b8fa6195SDmitri Tikhonov    {
53b8fa6195SDmitri Tikhonov        LSQ_DEBUG("get next frec from current packet %"PRIu64,
54b8fa6195SDmitri Tikhonov                                            prctx->prc_cur_packet->po_packno);
55b8fa6195SDmitri Tikhonov        frec = lsquic_pofi_next(&prctx->prc_pofi);
56b8fa6195SDmitri Tikhonov        if (frec)
57b8fa6195SDmitri Tikhonov            return frec;
58b8fa6195SDmitri Tikhonov        LSQ_DEBUG("discard packet %"PRIu64, prctx->prc_cur_packet->po_packno);
59b8fa6195SDmitri Tikhonov        prctx->prc_pri->pri_discard_packet(prctx->prc_data,
60b8fa6195SDmitri Tikhonov                                                        prctx->prc_cur_packet);
61b8fa6195SDmitri Tikhonov        prctx->prc_cur_packet = NULL; /* Not necessary; just future-proofing */
62b8fa6195SDmitri Tikhonov    }
63b8fa6195SDmitri Tikhonov
64b8fa6195SDmitri Tikhonov    prctx->prc_cur_packet = prctx->prc_pri->pri_next_packet(prctx->prc_data);
65b8fa6195SDmitri Tikhonov    if (!prctx->prc_cur_packet)
66b8fa6195SDmitri Tikhonov    {
67b8fa6195SDmitri Tikhonov        LSQ_DEBUG("out of input packets");
68b8fa6195SDmitri Tikhonov        return NULL;
69b8fa6195SDmitri Tikhonov    }
70b8fa6195SDmitri Tikhonov    frec = lsquic_pofi_first(&prctx->prc_pofi, prctx->prc_cur_packet);
71b8fa6195SDmitri Tikhonov    assert(frec);
72b8fa6195SDmitri Tikhonov    LSQ_DEBUG("return first frec from new current packet %"PRIu64,
73b8fa6195SDmitri Tikhonov                                        prctx->prc_cur_packet->po_packno);
74b8fa6195SDmitri Tikhonov    return frec;
75b8fa6195SDmitri Tikhonov}
76b8fa6195SDmitri Tikhonov
77b8fa6195SDmitri Tikhonov
78b8fa6195SDmitri Tikhonovstatic const struct frame_rec *
79b8fa6195SDmitri Tikhonovpacket_resize_get_frec (struct packet_resize_ctx *prctx)
80b8fa6195SDmitri Tikhonov{
81b8fa6195SDmitri Tikhonov    if (!prctx->prc_cur_frec)
82b8fa6195SDmitri Tikhonov    {
83b8fa6195SDmitri Tikhonov        prctx->prc_cur_frec = packet_resize_next_frec(prctx);
84b8fa6195SDmitri Tikhonov        if (prctx->prc_cur_frec)
85b8fa6195SDmitri Tikhonov            prctx->prc_flags |= PRC_NEW_FREC;
86b8fa6195SDmitri Tikhonov    }
87b8fa6195SDmitri Tikhonov    return prctx->prc_cur_frec;
88b8fa6195SDmitri Tikhonov}
89b8fa6195SDmitri Tikhonov
90b8fa6195SDmitri Tikhonov
91b8fa6195SDmitri Tikhonovstatic size_t
92b8fa6195SDmitri Tikhonovpacket_resize_gsf_read (void *ctx, void *buf, size_t len, int *fin)
93b8fa6195SDmitri Tikhonov{
94b8fa6195SDmitri Tikhonov    struct packet_resize_ctx *const prctx = ctx;
95b8fa6195SDmitri Tikhonov    size_t left;
96b8fa6195SDmitri Tikhonov
97b8fa6195SDmitri Tikhonov    left = (size_t) prctx->prc_data_frame.df_size
98b8fa6195SDmitri Tikhonov                                - (size_t) prctx->prc_data_frame.df_read_off;
99b8fa6195SDmitri Tikhonov    if (len > left)
100b8fa6195SDmitri Tikhonov        len = left;
101b8fa6195SDmitri Tikhonov    memcpy(buf,
102b8fa6195SDmitri Tikhonov        prctx->prc_data_frame.df_data + prctx->prc_data_frame.df_read_off, len);
103b8fa6195SDmitri Tikhonov    prctx->prc_data_frame.df_read_off += len;
104b8fa6195SDmitri Tikhonov    *fin = prctx->prc_data_frame.df_fin
105b8fa6195SDmitri Tikhonov        && prctx->prc_data_frame.df_size == prctx->prc_data_frame.df_read_off;
106b8fa6195SDmitri Tikhonov
107b8fa6195SDmitri Tikhonov    return len;
108b8fa6195SDmitri Tikhonov}
109b8fa6195SDmitri Tikhonov
110b8fa6195SDmitri Tikhonov
111b8fa6195SDmitri Tikhonovstruct lsquic_packet_out *
112b8fa6195SDmitri Tikhonovlsquic_packet_resize_next (struct packet_resize_ctx *prctx)
113b8fa6195SDmitri Tikhonov{
114b8fa6195SDmitri Tikhonov    const unsigned char *data_in;
115b8fa6195SDmitri Tikhonov    struct lsquic_packet_out *new;
116b8fa6195SDmitri Tikhonov    struct stream_frame stream_frame;
117b8fa6195SDmitri Tikhonov    const struct frame_rec *frec;
118b8fa6195SDmitri Tikhonov    int s, w, fin, parsed_len;
119b8fa6195SDmitri Tikhonov    size_t nbytes;
120b8fa6195SDmitri Tikhonov
121b8fa6195SDmitri Tikhonov    if (frec = packet_resize_get_frec(prctx), frec == NULL)
122b8fa6195SDmitri Tikhonov        return NULL;
123b8fa6195SDmitri Tikhonov
124b8fa6195SDmitri Tikhonov    new = prctx->prc_pri->pri_new_packet(prctx->prc_data);
125b8fa6195SDmitri Tikhonov    if (!new)
126b8fa6195SDmitri Tikhonov    {
127b8fa6195SDmitri Tikhonov        LSQ_DEBUG("cannot allocate new packet");
128b8fa6195SDmitri Tikhonov        goto err;
129b8fa6195SDmitri Tikhonov    }
130b8fa6195SDmitri Tikhonov
131b8fa6195SDmitri Tikhonov  proc_frec:
132b8fa6195SDmitri Tikhonov    if ((1 << frec->fe_frame_type) & (QUIC_FTBIT_STREAM|QUIC_FTBIT_CRYPTO))
133b8fa6195SDmitri Tikhonov    {
134b8fa6195SDmitri Tikhonov        if (prctx->prc_flags & PRC_NEW_FREC)
135b8fa6195SDmitri Tikhonov        {
136b8fa6195SDmitri Tikhonov            data_in = prctx->prc_cur_packet->po_data + frec->fe_off;
137b8fa6195SDmitri Tikhonov            parsed_len = (&prctx->prc_conn->cn_pf->pf_parse_stream_frame)
138b8fa6195SDmitri Tikhonov                [frec->fe_frame_type == QUIC_FRAME_CRYPTO]
139b8fa6195SDmitri Tikhonov                (data_in, frec->fe_len, &stream_frame);
140b8fa6195SDmitri Tikhonov            if (parsed_len < 0)
141b8fa6195SDmitri Tikhonov            {
142b8fa6195SDmitri Tikhonov                LSQ_WARN("cannot parse %s frame",
143b8fa6195SDmitri Tikhonov                                        frame_type_2_str[frec->fe_frame_type]);
144b8fa6195SDmitri Tikhonov                goto err;
145b8fa6195SDmitri Tikhonov            }
146b8fa6195SDmitri Tikhonov            if ((unsigned) parsed_len != frec->fe_len)
147b8fa6195SDmitri Tikhonov            {
148b8fa6195SDmitri Tikhonov                LSQ_WARN("parsed %s frame size does not match frame record",
149b8fa6195SDmitri Tikhonov                                        frame_type_2_str[frec->fe_frame_type]);
150b8fa6195SDmitri Tikhonov                goto err;
151b8fa6195SDmitri Tikhonov            }
152b8fa6195SDmitri Tikhonov            prctx->prc_data_frame = stream_frame.data_frame;
153b8fa6195SDmitri Tikhonov            prctx->prc_flags &= ~PRC_NEW_FREC;
154b8fa6195SDmitri Tikhonov            LSQ_DEBUG("parsed %s frame record for stream %"PRIu64
155b8fa6195SDmitri Tikhonov                "; off: %"PRIu64"; size: %"PRIu16"; fin: %d",
156b8fa6195SDmitri Tikhonov                frame_type_2_str[frec->fe_frame_type],
157b8fa6195SDmitri Tikhonov                frec->fe_stream->id,
158b8fa6195SDmitri Tikhonov                stream_frame.data_frame.df_offset,
159b8fa6195SDmitri Tikhonov                stream_frame.data_frame.df_size,
160b8fa6195SDmitri Tikhonov                stream_frame.data_frame.df_fin);
161b8fa6195SDmitri Tikhonov        }
162b8fa6195SDmitri Tikhonov        fin = prctx->prc_data_frame.df_fin
163b8fa6195SDmitri Tikhonov            && prctx->prc_data_frame.df_read_off == prctx->prc_data_frame.df_size;
164b8fa6195SDmitri Tikhonov        nbytes = prctx->prc_data_frame.df_size - prctx->prc_data_frame.df_read_off;
165b8fa6195SDmitri Tikhonov        w = (&prctx->prc_conn->cn_pf->pf_gen_stream_frame)
166b8fa6195SDmitri Tikhonov                [frec->fe_frame_type == QUIC_FRAME_CRYPTO](
167b8fa6195SDmitri Tikhonov                new->po_data + new->po_data_sz, lsquic_packet_out_avail(new),
168b8fa6195SDmitri Tikhonov                frec->fe_stream->id,
169b8fa6195SDmitri Tikhonov                prctx->prc_data_frame.df_offset + prctx->prc_data_frame.df_read_off,
170b8fa6195SDmitri Tikhonov                fin, nbytes, packet_resize_gsf_read, prctx);
171b8fa6195SDmitri Tikhonov        if (w < 0)
172b8fa6195SDmitri Tikhonov        {
173b8fa6195SDmitri Tikhonov            /* We rely on stream-generating function returning an error instead
174b8fa6195SDmitri Tikhonov             * of pre-calculating required size and checking.
175b8fa6195SDmitri Tikhonov             */
176b8fa6195SDmitri Tikhonov            LSQ_DEBUG("cannot fit another %s frame, new packet done",
177b8fa6195SDmitri Tikhonov                frame_type_2_str[frec->fe_frame_type]);
178b8fa6195SDmitri Tikhonov            goto done;
179b8fa6195SDmitri Tikhonov        }
180b8fa6195SDmitri Tikhonov        if (0 != lsquic_packet_out_add_stream(new, &prctx->prc_enpub->enp_mm,
181b8fa6195SDmitri Tikhonov                        frec->fe_stream, frec->fe_frame_type,
182b8fa6195SDmitri Tikhonov                        new->po_data_sz, w))
183b8fa6195SDmitri Tikhonov        {
184b8fa6195SDmitri Tikhonov            LSQ_WARN("cannot add stream frame record to new packet");
185b8fa6195SDmitri Tikhonov            goto err;
186b8fa6195SDmitri Tikhonov        }
187b8fa6195SDmitri Tikhonov        new->po_data_sz += w;
188b8fa6195SDmitri Tikhonov        new->po_frame_types |= 1 << frec->fe_frame_type;
189b8fa6195SDmitri Tikhonov        if (0 == lsquic_packet_out_avail(new))
190b8fa6195SDmitri Tikhonov            new->po_flags |= PO_STREAM_END;
191b8fa6195SDmitri Tikhonov        if (prctx->prc_data_frame.df_size == prctx->prc_data_frame.df_read_off)
192b8fa6195SDmitri Tikhonov        {
193b8fa6195SDmitri Tikhonov            LSQ_DEBUG("finished using %s frame record",
194b8fa6195SDmitri Tikhonov                                        frame_type_2_str[frec->fe_frame_type]);
195b8fa6195SDmitri Tikhonov            --frec->fe_stream->n_unacked;
196b8fa6195SDmitri Tikhonov            frec = prctx->prc_cur_frec = NULL;
197b8fa6195SDmitri Tikhonov            if (lsquic_packet_out_avail(new) > 0)
198b8fa6195SDmitri Tikhonov                if (frec = packet_resize_get_frec(prctx), frec != NULL)
199b8fa6195SDmitri Tikhonov                    goto proc_frec;
200b8fa6195SDmitri Tikhonov        }
201b8fa6195SDmitri Tikhonov    }
202b8fa6195SDmitri Tikhonov    else if (prctx->prc_cur_frec->fe_len <= lsquic_packet_out_avail(new))
203b8fa6195SDmitri Tikhonov    {
20449f1f4f6SDmitri Tikhonov        if ((1 << frec->fe_frame_type) & BQUIC_FRAME_REGEN_MASK)
205b8fa6195SDmitri Tikhonov        {
206b8fa6195SDmitri Tikhonov            if (new->po_regen_sz == new->po_data_sz)
207b8fa6195SDmitri Tikhonov                new->po_regen_sz += frec->fe_len;
208b8fa6195SDmitri Tikhonov            else
209b8fa6195SDmitri Tikhonov            {
210b8fa6195SDmitri Tikhonov                LSQ_DEBUG("got non-contiguous regen frame %s, packet done",
211b8fa6195SDmitri Tikhonov                                        frame_type_2_str[frec->fe_frame_type]);
212b8fa6195SDmitri Tikhonov                goto done;
213b8fa6195SDmitri Tikhonov            }
214b8fa6195SDmitri Tikhonov        }
215b8fa6195SDmitri Tikhonov        memcpy(new->po_data + new->po_data_sz,
216b8fa6195SDmitri Tikhonov            prctx->prc_cur_packet->po_data + frec->fe_off, frec->fe_len);
217b8fa6195SDmitri Tikhonov        if (frec->fe_frame_type == QUIC_FRAME_RST_STREAM)
218b8fa6195SDmitri Tikhonov            s = lsquic_packet_out_add_stream(new, &prctx->prc_enpub->enp_mm,
219b8fa6195SDmitri Tikhonov                        frec->fe_stream, frec->fe_frame_type,
220b8fa6195SDmitri Tikhonov                        new->po_data_sz, frec->fe_len);
221b8fa6195SDmitri Tikhonov        else
222b8fa6195SDmitri Tikhonov           s = lsquic_packet_out_add_frame(new, &prctx->prc_enpub->enp_mm,
223b8fa6195SDmitri Tikhonov                        frec->fe_u.data, frec->fe_frame_type,
224b8fa6195SDmitri Tikhonov                        new->po_data_sz, frec->fe_len);
225b8fa6195SDmitri Tikhonov        if (s != 0)
226b8fa6195SDmitri Tikhonov        {
227b8fa6195SDmitri Tikhonov            LSQ_WARN("cannot add %s frame record to new packet",
228b8fa6195SDmitri Tikhonov                                    frame_type_2_str[frec->fe_frame_type]);
229b8fa6195SDmitri Tikhonov            goto err;
230b8fa6195SDmitri Tikhonov        }
231b8fa6195SDmitri Tikhonov        new->po_data_sz += frec->fe_len;
232b8fa6195SDmitri Tikhonov        new->po_frame_types |= 1 << frec->fe_frame_type;
233b8fa6195SDmitri Tikhonov        LSQ_DEBUG("copy %hu-byte %s frame into new packet", frec->fe_len,
234b8fa6195SDmitri Tikhonov                                    frame_type_2_str[frec->fe_frame_type]);
235b8fa6195SDmitri Tikhonov        if (frec->fe_frame_type == QUIC_FRAME_RST_STREAM)
236b8fa6195SDmitri Tikhonov            --frec->fe_stream->n_unacked;
237b8fa6195SDmitri Tikhonov        frec = prctx->prc_cur_frec = NULL;
238b8fa6195SDmitri Tikhonov        if (lsquic_packet_out_avail(new) > 0)
239b8fa6195SDmitri Tikhonov            if (frec = packet_resize_get_frec(prctx), frec != NULL)
240b8fa6195SDmitri Tikhonov                goto proc_frec;
241b8fa6195SDmitri Tikhonov    }
242b8fa6195SDmitri Tikhonov
243b8fa6195SDmitri Tikhonov  done:
244b8fa6195SDmitri Tikhonov    if (0 == new->po_data_sz)
245b8fa6195SDmitri Tikhonov    {
246b8fa6195SDmitri Tikhonov        LSQ_WARN("frame too large");
247b8fa6195SDmitri Tikhonov        goto err;
248b8fa6195SDmitri Tikhonov    }
249b8fa6195SDmitri Tikhonov
250b8fa6195SDmitri Tikhonov    return new;
251b8fa6195SDmitri Tikhonov
252b8fa6195SDmitri Tikhonov  err:
253b8fa6195SDmitri Tikhonov    if (new)
254b8fa6195SDmitri Tikhonov        lsquic_packet_out_destroy(new, prctx->prc_enpub,
255b8fa6195SDmitri Tikhonov                                            new->po_path->np_peer_ctx);
256b8fa6195SDmitri Tikhonov    prctx->prc_flags |= PRC_ERROR;
257b8fa6195SDmitri Tikhonov    return NULL;
258b8fa6195SDmitri Tikhonov}
259