test_elision.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <errno.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/queue.h>
8
9#include "lsquic.h"
10
11#include "lsquic_int_types.h"
12#include "lsquic_packet_common.h"
13#include "lsquic_packet_gquic.h"
14#include "lsquic_packet_out.h"
15#include "lsquic_parse.h"
16#include "lsquic_conn_flow.h"
17#include "lsquic_sfcw.h"
18#include "lsquic_varint.h"
19#include "lsquic_hq.h"
20#include "lsquic_hash.h"
21#include "lsquic_stream.h"
22#include "lsquic_types.h"
23#include "lsquic_malo.h"
24#include "lsquic_mm.h"
25#include "lsquic_engine_public.h"
26#include "lsquic_logger.h"
27
28
29static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_043);
30
31static struct {
32    unsigned char   buf[0x1000];
33    size_t      bufsz;
34    uint64_t    off;
35} stream_contents;
36
37
38void
39setup_stream_contents (uint64_t off, const char *str)
40{
41    stream_contents.bufsz = strlen(str);
42    stream_contents.off   = off;
43    memcpy(stream_contents.buf, str, stream_contents.bufsz);
44}
45
46
47void
48setup_stream_contents_n (uint64_t off, const unsigned char *buf, size_t size)
49{
50    stream_contents.bufsz = size;
51    stream_contents.off   = off;
52    memcpy(stream_contents.buf, buf, size);
53}
54
55
56int
57lsquic_stream_tosend_fin (const lsquic_stream_t *stream)
58{
59    return 0;
60}
61
62
63uint64_t
64lsquic_stream_tosend_offset (const lsquic_stream_t *stream)
65{
66    return stream_contents.off;
67}
68
69
70size_t
71lsquic_stream_tosend_read (lsquic_stream_t *stream, void *buf, size_t len,
72                           int *reached_fin)
73{
74    if (stream_contents.bufsz < len)
75        len = stream_contents.bufsz;
76    memcpy(buf, stream_contents.buf, len);
77    *reached_fin = lsquic_stream_tosend_fin(stream);
78    return len;
79}
80
81
82size_t
83lsquic_stream_tosend_sz (const lsquic_stream_t *stream)
84{
85    return stream_contents.bufsz;
86}
87
88
89void
90lsquic_stream_acked (lsquic_stream_t *stream, enum quic_frame_type frame_type)
91{
92    --stream->n_unacked;
93}
94
95
96static void
97elide_single_stream_frame (void)
98{
99    struct packet_out_frec_iter pofi;
100    struct lsquic_engine_public enpub;
101    lsquic_stream_t streams[1];
102    lsquic_packet_out_t *packet_out;
103    int len, off = 0;
104
105    memset(streams, 0, sizeof(streams));
106    memset(&enpub, 0, sizeof(enpub));
107    lsquic_mm_init(&enpub.enp_mm);
108    packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ);
109
110    setup_stream_contents(123, "Dude, where is my car?");
111    len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
112            lsquic_packet_out_avail(packet_out),
113            streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
114            lsquic_stream_tosend_fin(&streams[0]),
115            lsquic_stream_tosend_sz(&streams[0]),
116            (gsf_read_f) lsquic_stream_tosend_read,
117            &streams[0]);
118    packet_out->po_data_sz += len;
119    packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM);
120    lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
121                                                QUIC_FRAME_STREAM, off, len);
122    assert(1 == streams[0].n_unacked);
123    assert(lsquic_pofi_first(&pofi, packet_out));
124
125    streams[0].stream_flags |= STREAM_RST_SENT;
126
127    lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX);
128    assert(0 == streams[0].n_unacked);
129    assert(0 == packet_out->po_frame_types);
130    assert(!lsquic_pofi_first(&pofi, packet_out));
131
132    lsquic_packet_out_destroy(packet_out, &enpub, NULL);
133    lsquic_mm_cleanup(&enpub.enp_mm);
134}
135
136
137/* In this test, we check that if the last STREAM frame is moved due to
138 * elision and PO_STREAM_END is set, the packet size is adjusted.  This
139 * is needed to prevent data corruption for STREAM frames that have
140 * implicit length.
141 */
142static void
143shrink_packet_post_elision (void)
144{
145    struct packet_out_frec_iter pofi;
146    struct lsquic_engine_public enpub;
147    lsquic_stream_t streams[2];
148    lsquic_packet_out_t *packet_out;
149    const struct frame_rec *frec;
150    int len, off = 0;
151    unsigned char stream2_data[0x1000];
152
153    memset(stream2_data, '2', sizeof(stream2_data));
154    memset(streams, 0, sizeof(streams));
155    memset(&enpub, 0, sizeof(enpub));
156    lsquic_mm_init(&enpub.enp_mm);
157    packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ);
158
159    setup_stream_contents(123, "Dude, where is my car?");
160    len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
161            lsquic_packet_out_avail(packet_out),
162            streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
163            lsquic_stream_tosend_fin(&streams[0]),
164            lsquic_stream_tosend_sz(&streams[0]),
165            (gsf_read_f) lsquic_stream_tosend_read,
166            &streams[0]);
167    packet_out->po_data_sz += len;
168    packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM);
169    lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
170                                                QUIC_FRAME_STREAM, off, len);
171
172    /* We want to fill the packet just right so that PO_STREAM_END gets set */
173    const int exp = lsquic_packet_out_avail(packet_out);
174    setup_stream_contents_n(0, stream2_data, exp - 2);
175    len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
176            lsquic_packet_out_avail(packet_out),
177            streams[1].id, lsquic_stream_tosend_offset(&streams[1]),
178            lsquic_stream_tosend_fin(&streams[1]),
179            lsquic_stream_tosend_sz(&streams[1]),
180            (gsf_read_f) lsquic_stream_tosend_read,
181            &streams[1]);
182    assert(len == exp);
183    packet_out->po_data_sz += len;
184    packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM);
185    lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
186                                                QUIC_FRAME_STREAM, off, len);
187    assert(0 == lsquic_packet_out_avail(packet_out));   /* Same as len == exp check really */
188    packet_out->po_flags |= PO_STREAM_END;
189
190    assert(1 == streams[0].n_unacked);
191    assert(1 == streams[1].n_unacked);
192    assert(lsquic_pofi_first(&pofi, packet_out));
193
194    streams[0].stream_flags |= STREAM_RST_SENT;
195
196    lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX);
197    assert(0 == streams[0].n_unacked);
198
199    assert(QUIC_FTBIT_STREAM == packet_out->po_frame_types);
200    frec = lsquic_pofi_first(&pofi, packet_out);
201    assert(frec->fe_stream == &streams[1]);
202    assert(packet_out->po_data_sz == exp);
203
204    lsquic_packet_out_destroy(packet_out, &enpub, NULL);
205    lsquic_mm_cleanup(&enpub.enp_mm);
206}
207
208
209/* This test is more involved.  We will construct the following packet:
210 *
211 *      | ACK | STREAM A | STREAM B | STREAM C | RST A | STREAM D | STREAM E
212 *
213 * and elide STREAM A, STREAM C, and STREAM E to get
214 *
215 *      | ACK | STREAM B | RST A | STREAM D |
216 *
217 * If `chop_regen' is set, ACK is dropped (this tests what happens when
218 * packet is resent).
219 *
220 * This should test most of the corner cases.
221 */
222static void
223elide_three_stream_frames (int chop_regen)
224{
225    struct packet_out_frec_iter pofi;
226    struct lsquic_engine_public enpub;
227    lsquic_stream_t streams[5];
228    lsquic_packet_out_t *packet_out, *ref_out;
229    struct frame_rec *frec;
230    unsigned short b_off, d_off;
231    int len;
232
233    memset(streams, 0, sizeof(streams));
234    memset(&enpub, 0, sizeof(enpub));
235    lsquic_mm_init(&enpub.enp_mm);
236
237    /* First, we construct the reference packet.  We will only use it to
238     * compare payload and sizes:
239     */
240    {
241        ref_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ);
242        /* This is fake data for regeneration */
243        strcpy((char *) ref_out->po_data, "REGEN");
244        lsquic_packet_out_add_frame(ref_out, &enpub.enp_mm, 0,
245                                QUIC_FRAME_ACK, ref_out->po_data_sz, 5);
246        ref_out->po_data_sz = ref_out->po_regen_sz = 5;
247        /* STREAM B */
248        setup_stream_contents(123, "BBBBBBBBBB");
249        streams[0].id = 'B';
250        len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
251                lsquic_packet_out_avail(ref_out),
252                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
253                lsquic_stream_tosend_fin(&streams[0]),
254                lsquic_stream_tosend_sz(&streams[0]),
255                (gsf_read_f) lsquic_stream_tosend_read,
256                &streams[0]);
257        b_off = ref_out->po_data_sz;
258        ref_out->po_data_sz += len;
259        len = pf->pf_gen_rst_frame(ref_out->po_data + ref_out->po_data_sz,
260                lsquic_packet_out_avail(ref_out), 'A', 133, 0);
261        ref_out->po_data_sz += len;
262        /* STREAM D */
263        setup_stream_contents(123, "DDDDDDDDDD");
264        streams[0].id = 'D';
265        len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
266                lsquic_packet_out_avail(ref_out),
267                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
268                lsquic_stream_tosend_fin(&streams[0]),
269                lsquic_stream_tosend_sz(&streams[0]),
270                (gsf_read_f) lsquic_stream_tosend_read,
271                &streams[0]);
272        d_off = ref_out->po_data_sz;
273        ref_out->po_data_sz += len;
274    }
275
276    /* Construct packet from which we will elide streams.  Here, we attach
277     * stream objects to the packet.
278     */
279    {
280        packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ);
281        /* This is fake data for regeneration */
282        strcpy((char *) packet_out->po_data, "REGEN");
283        lsquic_packet_out_add_frame(packet_out, &enpub.enp_mm, 0,
284                                QUIC_FRAME_ACK, packet_out->po_data_sz, 5);
285        packet_out->po_data_sz = packet_out->po_regen_sz = 5;
286        /* STREAM A */
287        setup_stream_contents(123, "AAAAAAAAAA");
288        streams[0].id = 'A';
289        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
290                lsquic_packet_out_avail(packet_out),
291                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
292                lsquic_stream_tosend_fin(&streams[0]),
293                lsquic_stream_tosend_sz(&streams[0]),
294                (gsf_read_f) lsquic_stream_tosend_read,
295                &streams[0]);
296        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
297                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
298        packet_out->po_data_sz += len;
299        /* STREAM B */
300        setup_stream_contents(123, "BBBBBBBBBB");
301        streams[1].id = 'B';
302        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
303                lsquic_packet_out_avail(packet_out),
304                streams[1].id, lsquic_stream_tosend_offset(&streams[1]),
305                lsquic_stream_tosend_fin(&streams[1]),
306                lsquic_stream_tosend_sz(&streams[1]),
307                (gsf_read_f) lsquic_stream_tosend_read,
308                &streams[1]);
309        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
310                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
311        packet_out->po_data_sz += len;
312        /* STREAM C */
313        setup_stream_contents(123, "CCCCCCCCCC");
314        streams[2].id = 'C';
315        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
316                lsquic_packet_out_avail(packet_out),
317                streams[2].id, lsquic_stream_tosend_offset(&streams[2]),
318                lsquic_stream_tosend_fin(&streams[2]),
319                lsquic_stream_tosend_sz(&streams[2]),
320                (gsf_read_f) lsquic_stream_tosend_read,
321                &streams[2]);
322        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2],
323                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
324        packet_out->po_data_sz += len;
325        /* Reset A */
326        len = pf->pf_gen_rst_frame(packet_out->po_data + packet_out->po_data_sz,
327                lsquic_packet_out_avail(packet_out), 'A', 133, 0);
328        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
329                                     QUIC_FRAME_RST_STREAM, packet_out->po_data_sz, len);
330        packet_out->po_data_sz += len;
331        /* STREAM D */
332        setup_stream_contents(123, "DDDDDDDDDD");
333        streams[3].id = 'D';
334        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
335                lsquic_packet_out_avail(packet_out),
336                streams[3].id, lsquic_stream_tosend_offset(&streams[3]),
337                lsquic_stream_tosend_fin(&streams[3]),
338                lsquic_stream_tosend_sz(&streams[3]),
339                (gsf_read_f) lsquic_stream_tosend_read,
340                &streams[3]);
341        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3],
342                                QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
343        packet_out->po_data_sz += len;
344        /* STREAM E */
345        setup_stream_contents(123, "EEEEEEEEEE");
346        streams[4].id = 'E';
347        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
348                lsquic_packet_out_avail(packet_out),
349                streams[4].id, lsquic_stream_tosend_offset(&streams[4]),
350                lsquic_stream_tosend_fin(&streams[4]),
351                lsquic_stream_tosend_sz(&streams[4]),
352                (gsf_read_f) lsquic_stream_tosend_read,
353                &streams[4]);
354        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4],
355                                QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
356        packet_out->po_data_sz += len;
357        packet_out->po_frame_types = (1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM);
358    }
359
360    /* Reset streams A, C, and E: */
361    streams[0].stream_flags |= STREAM_RST_SENT;
362    streams[2].stream_flags |= STREAM_RST_SENT;
363    streams[4].stream_flags |= STREAM_RST_SENT;
364
365    if (chop_regen)
366        lsquic_packet_out_chop_regen(packet_out);
367    lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX);
368
369    assert(ref_out->po_data_sz == packet_out->po_data_sz + (chop_regen ? 5 : 0));
370    assert(ref_out->po_regen_sz == packet_out->po_regen_sz + (chop_regen ? 5 : 0));
371    if (chop_regen)
372        assert(0 == memcmp(ref_out->po_data + 5, packet_out->po_data, packet_out->po_data_sz));
373    else
374        assert(0 == memcmp(ref_out->po_data, packet_out->po_data, packet_out->po_data_sz));
375
376    assert(1 == streams[0].n_unacked);  /* Still has RST outstanding */
377    assert(1 == streams[1].n_unacked);
378    assert(0 == streams[2].n_unacked);
379    assert(1 == streams[3].n_unacked);
380    assert(0 == streams[4].n_unacked);
381
382    assert(packet_out->po_frame_types == ((1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM)));
383
384    frec = lsquic_pofi_first(&pofi, packet_out);
385    if (!chop_regen)
386        frec = lsquic_pofi_next(&pofi);
387    assert(frec->fe_stream == &streams[1]);
388    assert(frec->fe_frame_type == QUIC_FRAME_STREAM);
389    assert(frec->fe_off == b_off - (chop_regen ? 5 : 0));
390
391    frec = lsquic_pofi_next(&pofi);
392    assert(frec->fe_stream == &streams[0]);
393    assert(frec->fe_frame_type == QUIC_FRAME_RST_STREAM);
394
395    frec = lsquic_pofi_next(&pofi);
396    assert(frec->fe_stream == &streams[3]);
397    assert(frec->fe_frame_type == QUIC_FRAME_STREAM);
398    assert(frec->fe_off == d_off - (chop_regen ? 5 : 0));
399
400    frec = lsquic_pofi_next(&pofi);
401    assert(!frec);
402
403    lsquic_packet_out_destroy(packet_out, &enpub, NULL);
404    lsquic_packet_out_destroy(ref_out, &enpub, NULL);
405    lsquic_mm_cleanup(&enpub.enp_mm);
406}
407
408
409int
410main (void)
411{
412    /* TODO-ENDIAN: test with every PF */
413    elide_single_stream_frame();
414    shrink_packet_post_elision();
415    elide_three_stream_frames(0);
416    elide_three_stream_frames(1);
417
418    return 0;
419}
420