test_elision.c revision 9a690580
1/* Copyright (c) 2017 - 2020 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_srec_iter posi;
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_posi_first(&posi, packet_out));
124
125    streams[0].stream_flags |= STREAM_RST_SENT;
126
127    lsquic_packet_out_elide_reset_stream_frames(packet_out, 0);
128    assert(0 == streams[0].n_unacked);
129    assert(0 == packet_out->po_frame_types);
130    assert(!lsquic_posi_first(&posi, 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_srec_iter posi;
146    struct lsquic_engine_public enpub;
147    lsquic_stream_t streams[2];
148    lsquic_packet_out_t *packet_out;
149    const struct stream_rec *srec;
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_posi_first(&posi, packet_out));
193
194    streams[0].stream_flags |= STREAM_RST_SENT;
195
196    lsquic_packet_out_elide_reset_stream_frames(packet_out, 0);
197    assert(0 == streams[0].n_unacked);
198
199    assert(QUIC_FTBIT_STREAM == packet_out->po_frame_types);
200    srec = lsquic_posi_first(&posi, packet_out);
201    assert(srec->sr_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_srec_iter posi;
226    struct lsquic_engine_public enpub;
227    lsquic_stream_t streams[5];
228    lsquic_packet_out_t *packet_out, *ref_out;
229    struct stream_rec *srec;
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        ref_out->po_data_sz = ref_out->po_regen_sz = 5;
245        /* STREAM B */
246        setup_stream_contents(123, "BBBBBBBBBB");
247        streams[0].id = 'B';
248        len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
249                lsquic_packet_out_avail(ref_out),
250                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
251                lsquic_stream_tosend_fin(&streams[0]),
252                lsquic_stream_tosend_sz(&streams[0]),
253                (gsf_read_f) lsquic_stream_tosend_read,
254                &streams[0]);
255        b_off = ref_out->po_data_sz;
256        ref_out->po_data_sz += len;
257        len = pf->pf_gen_rst_frame(ref_out->po_data + ref_out->po_data_sz,
258                lsquic_packet_out_avail(ref_out), 'A', 133, 0);
259        ref_out->po_data_sz += len;
260        /* STREAM D */
261        setup_stream_contents(123, "DDDDDDDDDD");
262        streams[0].id = 'D';
263        len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
264                lsquic_packet_out_avail(ref_out),
265                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
266                lsquic_stream_tosend_fin(&streams[0]),
267                lsquic_stream_tosend_sz(&streams[0]),
268                (gsf_read_f) lsquic_stream_tosend_read,
269                &streams[0]);
270        d_off = ref_out->po_data_sz;
271        ref_out->po_data_sz += len;
272    }
273
274    /* Construct packet from which we will elide streams.  Here, we attach
275     * stream objects to the packet.
276     */
277    {
278        packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ);
279        /* This is fake data for regeneration */
280        strcpy((char *) packet_out->po_data, "REGEN");
281        packet_out->po_data_sz = packet_out->po_regen_sz = 5;
282        /* STREAM A */
283        setup_stream_contents(123, "AAAAAAAAAA");
284        streams[0].id = 'A';
285        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
286                lsquic_packet_out_avail(packet_out),
287                streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
288                lsquic_stream_tosend_fin(&streams[0]),
289                lsquic_stream_tosend_sz(&streams[0]),
290                (gsf_read_f) lsquic_stream_tosend_read,
291                &streams[0]);
292        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
293                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
294        packet_out->po_data_sz += len;
295        /* STREAM B */
296        setup_stream_contents(123, "BBBBBBBBBB");
297        streams[1].id = 'B';
298        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
299                lsquic_packet_out_avail(packet_out),
300                streams[1].id, lsquic_stream_tosend_offset(&streams[1]),
301                lsquic_stream_tosend_fin(&streams[1]),
302                lsquic_stream_tosend_sz(&streams[1]),
303                (gsf_read_f) lsquic_stream_tosend_read,
304                &streams[1]);
305        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
306                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
307        packet_out->po_data_sz += len;
308        /* STREAM C */
309        setup_stream_contents(123, "CCCCCCCCCC");
310        streams[2].id = 'C';
311        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
312                lsquic_packet_out_avail(packet_out),
313                streams[2].id, lsquic_stream_tosend_offset(&streams[2]),
314                lsquic_stream_tosend_fin(&streams[2]),
315                lsquic_stream_tosend_sz(&streams[2]),
316                (gsf_read_f) lsquic_stream_tosend_read,
317                &streams[2]);
318        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2],
319                                    QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
320        packet_out->po_data_sz += len;
321        /* Reset A */
322        len = pf->pf_gen_rst_frame(packet_out->po_data + packet_out->po_data_sz,
323                lsquic_packet_out_avail(packet_out), 'A', 133, 0);
324        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
325                                     QUIC_FRAME_RST_STREAM, packet_out->po_data_sz, len);
326        packet_out->po_data_sz += len;
327        /* STREAM D */
328        setup_stream_contents(123, "DDDDDDDDDD");
329        streams[3].id = 'D';
330        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
331                lsquic_packet_out_avail(packet_out),
332                streams[3].id, lsquic_stream_tosend_offset(&streams[3]),
333                lsquic_stream_tosend_fin(&streams[3]),
334                lsquic_stream_tosend_sz(&streams[3]),
335                (gsf_read_f) lsquic_stream_tosend_read,
336                &streams[3]);
337        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3],
338                                QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
339        packet_out->po_data_sz += len;
340        /* STREAM E */
341        setup_stream_contents(123, "EEEEEEEEEE");
342        streams[4].id = 'E';
343        len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
344                lsquic_packet_out_avail(packet_out),
345                streams[4].id, lsquic_stream_tosend_offset(&streams[4]),
346                lsquic_stream_tosend_fin(&streams[4]),
347                lsquic_stream_tosend_sz(&streams[4]),
348                (gsf_read_f) lsquic_stream_tosend_read,
349                &streams[4]);
350        lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4],
351                                QUIC_FRAME_STREAM, packet_out->po_data_sz, len);
352        packet_out->po_data_sz += len;
353        packet_out->po_frame_types = (1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM);
354    }
355
356    /* Reset streams A, C, and E: */
357    streams[0].stream_flags |= STREAM_RST_SENT;
358    streams[2].stream_flags |= STREAM_RST_SENT;
359    streams[4].stream_flags |= STREAM_RST_SENT;
360
361    if (chop_regen)
362        lsquic_packet_out_chop_regen(packet_out);
363    lsquic_packet_out_elide_reset_stream_frames(packet_out, 0);
364
365    assert(ref_out->po_data_sz == packet_out->po_data_sz + (chop_regen ? 5 : 0));
366    assert(ref_out->po_regen_sz == packet_out->po_regen_sz + (chop_regen ? 5 : 0));
367    if (chop_regen)
368        assert(0 == memcmp(ref_out->po_data + 5, packet_out->po_data, packet_out->po_data_sz));
369    else
370        assert(0 == memcmp(ref_out->po_data, packet_out->po_data, packet_out->po_data_sz));
371
372    assert(1 == streams[0].n_unacked);  /* Still has RST outstanding */
373    assert(1 == streams[1].n_unacked);
374    assert(0 == streams[2].n_unacked);
375    assert(1 == streams[3].n_unacked);
376    assert(0 == streams[4].n_unacked);
377
378    assert(packet_out->po_frame_types == ((1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM)));
379
380    srec = lsquic_posi_first(&posi, packet_out);
381    assert(srec->sr_stream == &streams[1]);
382    assert(srec->sr_frame_type == QUIC_FRAME_STREAM);
383    assert(srec->sr_off == b_off - (chop_regen ? 5 : 0));
384
385    srec = lsquic_posi_next(&posi);
386    assert(srec->sr_stream == &streams[0]);
387    assert(srec->sr_frame_type == QUIC_FRAME_RST_STREAM);
388
389    srec = lsquic_posi_next(&posi);
390    assert(srec->sr_stream == &streams[3]);
391    assert(srec->sr_frame_type == QUIC_FRAME_STREAM);
392    assert(srec->sr_off == d_off - (chop_regen ? 5 : 0));
393
394    srec = lsquic_posi_next(&posi);
395    assert(!srec);
396
397    lsquic_packet_out_destroy(packet_out, &enpub, NULL);
398    lsquic_packet_out_destroy(ref_out, &enpub, NULL);
399    lsquic_mm_cleanup(&enpub.enp_mm);
400}
401
402
403int
404main (void)
405{
406    /* TODO-ENDIAN: test with every PF */
407    elide_single_stream_frame();
408    shrink_packet_post_elision();
409    elide_three_stream_frames(0);
410    elide_three_stream_frames(1);
411
412    return 0;
413}
414