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