test_streamgen.c revision 6ff1e9b8
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/queue.h>
7#ifndef WIN32
8#include <sys/time.h>
9#endif
10
11#include "lsquic.h"
12#include "lsquic_types.h"
13#include "lsquic_parse.h"
14#include "lsquic_sfcw.h"
15#include "lsquic_varint.h"
16#include "lsquic_hq.h"
17#include "lsquic_hash.h"
18#include "lsquic_stream.h"
19
20struct test {
21    int             lineno;
22    const struct parse_funcs *
23                    pf;
24    /* Inputs.  These are returned by lsquic_stream_tosend_fin(),
25     * lsquic_stream_tosend_read(), and lsquic_stream_tosend_offset().
26     */
27    int             fin[2];         /* There may be two calls to lsquic_stream_tosend_fin() */
28    uint64_t        offset;
29    uint32_t        stream_id;
30    size_t          avail;          /* Space to write stream frame to */
31    size_t          min_sz;         /* Minimum size needed to generate stream frame.  Any
32                                     * sizes smaller than this should fail.
33                                     */
34    size_t          data_sz;
35    char            data[0x100];
36
37    /* Output.  This is how we expect the resulting frame to look.
38     */
39    int             len;            /* Return value of gen_stream_frame() */
40    char            out[0x100];
41};
42
43
44static struct test_ctx {
45    const struct test *test;
46    int                next_fin;
47    lsquic_stream_t    stream;
48} test_ctx;
49
50
51static int
52stream_tosend_fin (void *stream)
53{
54    struct test_ctx *test_ctx2 = stream;
55    return test_ctx2->test->fin[ test_ctx2->next_fin++ ];
56}
57
58
59static size_t
60stream_tosend_read (void *stream, void *buf, size_t len, int *reached_fin)
61{
62    struct test_ctx *test_ctx2 = stream;
63    if (test_ctx2->test->data_sz < len)
64        len = test_ctx2->test->data_sz;
65    memcpy(buf, test_ctx2->test->data, len);
66    *reached_fin = stream_tosend_fin(stream);
67    return len;
68}
69
70
71static size_t
72stream_tosend_size (void *stream)
73{
74    struct test_ctx *test_ctx2 = stream;
75    return test_ctx2->test->data_sz;
76}
77
78
79static void
80reset_ctx (const struct test *test)
81{
82    test_ctx.test      = test;
83    test_ctx.next_fin  = 0;
84    test_ctx.stream.id = test->stream_id;
85}
86
87
88static void
89run_test (const struct test *const test)
90{
91
92    unsigned char out[0x100];
93    int len;
94    size_t min;
95
96    if (test->len > 0)
97    {
98        /* Test that all sizes under specified min fail to produce a frame */
99        for (min = 0; min < test->min_sz; ++min)
100        {
101            reset_ctx(test);
102            len = test->pf->pf_gen_stream_frame(out, min, test->stream_id,
103                        test_ctx.test->offset, stream_tosend_fin(&test_ctx),
104                        stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
105            assert(len < 0);
106        }
107
108        /* Test that it succeeds now: */
109        reset_ctx(test);
110        len = test->pf->pf_gen_stream_frame(out, min, test->stream_id,
111                        test_ctx.test->offset, stream_tosend_fin(&test_ctx),
112                        stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
113        assert(len == (int) min);
114    }
115
116    reset_ctx(test);
117    len = test->pf->pf_gen_stream_frame(out, test->avail, test->stream_id,
118                    test_ctx.test->offset, stream_tosend_fin(&test_ctx),
119                    stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
120
121    if (test->len > 0) {
122        /* Check parser operation */
123        assert(test->len == len);
124        assert(("Generated frame is correct", 0 == memcmp(test->out, out, test->len)));
125    }
126    else
127    {
128        assert(("This test should fail", len < 0));
129    }
130}
131
132
133int
134main (void)
135{
136    const struct test tests[] = {
137        /*
138         * Big-endian:
139         */
140        {   .lineno     = __LINE__,
141            .pf         = select_pf_by_ver(LSQVER_043),
142            .fin        = { 0, 1, },
143            .offset     = 0x0807060504030201UL,
144            .stream_id  = 0x210,
145            .data_sz    = 10,
146            .data       = "0123456789",
147            .avail      = 0x100,
148            .out        =
149          /*  1      f      d      ooo    ss            1fdoooss */
150          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
151            { 0x80 | 0x40 | 0x20 | 0x1C | 0x01,
152              0x02, 0x10,                                       /* Stream ID */
153              0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
154              0x00, 0x0A,                                       /* Data length */
155              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
156            },
157            .len        = 1 + 2 + 8 + 2 + 10,
158            .min_sz     = 1 + 2 + 8 + 0 + 1,
159        },
160
161        {   .lineno     = __LINE__,
162            .pf         = select_pf_by_ver(LSQVER_043),
163            .fin        = { 0, 0, },
164            .offset     = 0x0807060504030201UL,
165            .stream_id  = 0x210,
166            .data_sz    = 10,
167            .data       = "0123456789",
168            .avail      = 0x100,
169            .out        =
170          /*  1      f      d      ooo    ss            1fdoooss */
171          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
172            { 0x80 | 0x00 | 0x20 | 0x1C | 0x01,
173              0x02, 0x10,                                       /* Stream ID */
174              0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
175              0x00, 0x0A,                                       /* Data length */
176              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
177            },
178            .len        = 1 + 2 + 8 + 2 + 10,
179            .min_sz     = 1 + 2 + 8 + 0 + 1,
180        },
181
182        {   .lineno     = __LINE__,
183            .pf         = select_pf_by_ver(LSQVER_043),
184            .fin        = { 1, 0, },
185            .offset     = 0x0807060504030201UL,
186            .stream_id  = 0x210,
187            .data_sz    = 10,
188            .data       = "0123456789",
189            .avail      = 0x100,
190            .out        =
191          /*  1      f      d      ooo    ss            1fdoooss */
192          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
193            { 0x80 | 0x40 | 0x20 | 0x1C | 0x01,
194              0x02, 0x10,                                       /* Stream ID */
195              0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
196              0x00, 0x00,                                       /* Data length */
197              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
198            },
199            .len        = 1 + 2 + 8 + 2,
200            .min_sz     = 1 + 2 + 8 + 2,
201        },
202
203        {   .lineno     = __LINE__,
204            .pf         = select_pf_by_ver(LSQVER_043),
205            .fin        = { 1, 0, },
206            .offset     = 0x0807060504030201UL,
207            .stream_id  = 0x21,
208            .data_sz    = 10,
209            .data       = "0123456789",
210            .avail      = 0x100,
211            .out        =
212          /*  1      f      d      ooo    ss            1fdoooss */
213          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
214            { 0x80 | 0x40 | 0x20 | 0x1C | 0x00,
215              0x21,                                             /* Stream ID */
216              0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
217              0x00, 0x00,                                       /* Data length */
218              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
219            },
220            .len        = 1 + 1 + 8 + 2,
221            .min_sz     = 1 + 1 + 8 + 2,
222        },
223
224        {   .lineno     = __LINE__,
225            .pf         = select_pf_by_ver(LSQVER_043),
226            .fin        = { 0, 0, },
227            .offset     = 0x77,
228            .stream_id  = 0x210,
229            .data_sz    = 10,
230            .data       = "0123456789",
231            .avail      = 0x100,
232            .out        =
233          /*  1      f      d      ooo    ss            1fdoooss */
234          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
235            { 0x80 | 0x00 | 0x20 | 0x04 | 0x01,
236              0x02, 0x10,                                       /* Stream ID */
237              0x00, 0x77,                                       /* Offset */
238              0x00, 0x0A,                                       /* Data length */
239              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
240            },
241            .len        = 1 + 2 + 2 + 2 + 10,
242            .min_sz     = 1 + 2 + 2 + 0 + 1,
243        },
244
245        {   .lineno     = __LINE__,
246            .pf         = select_pf_by_ver(LSQVER_043),
247            .fin        = { 0, 0, },
248            .offset     = 0x0,
249            .stream_id  = 0x210,
250            .data_sz    = 10,
251            .data       = "0123456789",
252            .avail      = 0x100,
253            .out        =
254          /*  1      f      d      ooo    ss            1fdoooss */
255          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
256            { 0x80 | 0x00 | 0x20 | 0x00 | 0x01,
257              0x02, 0x10,                                       /* Stream ID */
258                                                                /* Offset */
259              0x00, 0x0A,                                       /* Data length */
260              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
261            },
262            .len        = 1 + 2 + 0 + 2 + 10,
263            .min_sz     = 1 + 2 + 0 + 0 + 1,
264        },
265
266        {   .lineno     = __LINE__,
267            .pf         = select_pf_by_ver(LSQVER_043),
268            .fin        = { 0, 1, },
269            .offset     = 0x0,
270            .stream_id  = 0x210,
271            .data_sz    = 1,
272            .data       = "0123456789",
273            .avail      = 0x100,
274            .out        =
275          /*  1      f      d      ooo    ss            1fdoooss */
276          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
277            { 0x80 | 0x40 | 0x20 | 0x00 | 0x01,
278              0x02, 0x10,                                       /* Stream ID */
279                                                                /* Offset */
280              0x00, 0x01,                                       /* Data length */
281              '0',
282            },
283            .len        = 1 + 2 + 0 + 2 + 1,
284            .min_sz     = 1 + 2 + 0 + 0 + 1,
285        },
286
287        {   .lineno     = __LINE__,
288            .pf         = select_pf_by_ver(LSQVER_043),
289            .fin        = { 0, 0, },
290            .offset     = 0xFFFFFF,
291            .stream_id  = 0x210,
292            .data_sz    = 10,
293            .data       = "0123456789",
294            .avail      = 0x100,
295            .out        =
296          /*  1      f      d      ooo    ss            1fdoooss */
297          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
298            { 0x80 | 0x00 | 0x20 | 0x08 | 0x01,
299              0x02, 0x10,                                       /* Stream ID */
300              0xFF, 0xFF, 0xFF,                                 /* Offset */
301              0x00, 0x0A,                                       /* Data length */
302              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
303            },
304            .len        = 1 + 2 + 3 + 2 + 10,
305            .min_sz     = 1 + 2 + 3 + 0 + 1,
306        },
307
308        {   .lineno     = __LINE__,
309            .pf         = select_pf_by_ver(LSQVER_043),
310            .fin        = { 0, 0, },
311            .offset     = 0xFFFFFF + 1,
312            .stream_id  = 0x210,
313            .data_sz    = 10,
314            .data       = "0123456789",
315            .avail      = 0x100,
316            .out        =
317          /*  1      f      d      ooo    ss            1fdoooss */
318          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
319            { 0x80 | 0x00 | 0x20 | 0x0C | 0x01,
320              0x02, 0x10,                                       /* Stream ID */
321              0x01, 0x00, 0x00, 0x00,                           /* Offset */
322              0x00, 0x0A,                                       /* Data length */
323              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
324            },
325            .len        = 1 + 2 + 4 + 2 + 10,
326            .min_sz     = 1 + 2 + 4 + 0 + 1,
327        },
328
329        {   .lineno     = __LINE__,
330            .pf         = select_pf_by_ver(LSQVER_043),
331            .fin        = { 0, 0, },
332            .offset     = 0xFFFFFF + 1,
333            .stream_id  = 0x210,
334            .data_sz    = 10,
335            .data       = "0123456789",
336            .avail      = 10,
337            .out        =
338          /*  1      f      d      ooo    ss            1fdoooss */
339          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
340            { 0x80 | 0x00 | 0x00 | 0x0C | 0x01,
341              0x02, 0x10,                                       /* Stream ID */
342              0x01, 0x00, 0x00, 0x00,                           /* Offset */
343              '0', '1', '2',
344            },
345            .len        = 1 + 2 + 4 + 0 + 3,
346            .min_sz     = 1 + 2 + 4 + 0 + 1,
347        },
348
349        {   .lineno     = __LINE__,
350            .pf         = select_pf_by_ver(LSQVER_043),
351            .fin        = { 1, 0, },
352            .offset     = 0xB4,
353            .stream_id  = 0x01,
354            .data_sz    = 0,
355            .data       = "0123456789",
356            .avail      = 0x100,
357            .out        =
358          /*  1      f      d      ooo    ss            1fdoooss */
359          /*  TYPE   FIN    DLEN   OLEN   SLEN  */
360            { 0x80 | 0x40 | 0x20 | 0x04 | 0x00,
361              0x01,                                             /* Stream ID */
362              0x00, 0xB4,                                       /* Offset */
363              0x00, 0x00,                                       /* Data length */
364            },
365            .len        = 6,
366            .min_sz     = 6,
367        },
368
369        /*
370         * IETF QUIC Internet-Draft 17:
371         */
372
373        {   .lineno     = __LINE__,
374            .pf         = select_pf_by_ver(LSQVER_ID27),
375            .fin        = { 0, 1, },
376            .offset     = 0x0807060504030201UL,
377            .stream_id  = 0x210,
378            .data_sz    = 10,
379            .data       = "0123456789",
380            .avail      = 0x100,
381            .out        =
382          /*  TYPE   OFF    DLEN   FIN  */
383            { 0x08 | 1<<2 | 1<<1 | 1<<0,
384              0x42, 0x10,                                       /* Stream ID */
385              0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
386              0x0A,                                             /* Data length */
387              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
388            },
389            .len        = 1 + 2 + 8 + 1 + 10,
390            .min_sz     = 1 + 2 + 8 + 0 + 1,
391        },
392
393        {   .lineno     = __LINE__,
394            .pf         = select_pf_by_ver(LSQVER_ID27),
395            .fin        = { 0, 0, },
396            .offset     = 0,
397            .stream_id  = 0x210,
398            .data_sz    = 10,
399            .data       = "0123456789",
400            .avail      = 0x100,
401            .out        =
402          /*  TYPE   OFF    DLEN   FIN  */
403            { 0x08 | 0<<2 | 1<<1 | 0<<0,
404              0x42, 0x10,                                       /* Stream ID */
405              0x0A,                                             /* Data length */
406              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
407            },
408            .len        = 1 + 2 + 0 + 1 + 10,
409            .min_sz     = 1 + 2 + 0 + 0 + 1,
410        },
411
412        {   .lineno     = __LINE__,
413            .pf         = select_pf_by_ver(LSQVER_ID27),
414            .fin        = { 0, 0, },
415            .offset     = 0,
416            .stream_id  = 0x21,
417            .data_sz    = 10,
418            .data       = "0123456789",
419            .avail      = 12,
420            .out        =
421          /*  TYPE   OFF    DLEN   FIN  */
422            { 0x08 | 0<<2 | 0<<1 | 0<<0,
423              0x21,                                             /* Stream ID */
424              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
425            },
426            .len        = 1 + 1 + 0 + 0 + 10,
427            .min_sz     = 1 + 1 + 0 + 0 + 1,
428        },
429
430        {   .lineno     = __LINE__,
431            .pf         = select_pf_by_ver(LSQVER_ID27),
432            .fin        = { 0, 0, },
433            .offset     = 0x0807060504030201UL,
434            .stream_id  = 0x210,
435            .data_sz    = 10,
436            .data       = "0123456789",
437            .avail      = 0x100,
438            .out        =
439          /*  TYPE   OFF    DLEN   FIN  */
440            { 0x08 | 1<<2 | 1<<1 | 0<<0,
441              0x42, 0x10,                                       /* Stream ID */
442              0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
443              0x0A,                                             /* Data length */
444              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
445            },
446            .len        = 1 + 2 + 8 + 1 + 10,
447            .min_sz     = 1 + 2 + 8 + 0 + 1,
448        },
449
450        {   .lineno     = __LINE__,
451            .pf         = select_pf_by_ver(LSQVER_ID27),
452            .fin        = { 1, 0, },
453            .offset     = 0x0807060504030201UL,
454            .stream_id  = 0x210,
455            .data_sz    = 0,
456            .data       = "0123456789",
457            .avail      = 11,
458            .out        =
459          /*  TYPE   OFF    DLEN   FIN  */
460            { 0x08 | 1<<2 | 0<<1 | 1<<0,
461              0x42, 0x10,                                       /* Stream ID */
462              0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
463            },
464            .len        = 1 + 2 + 8,
465            .min_sz     = 1 + 2 + 8,
466        },
467
468        {   .lineno     = __LINE__,
469            .pf         = select_pf_by_ver(LSQVER_ID27),
470            .fin        = { 1, 0, },
471            .offset     = 0x0807060504030201UL,
472            .stream_id  = 0x210,
473            .data_sz    = 0,
474            .data       = "0123456789",
475            .avail      = 0x100,
476            .out        =
477          /*  TYPE   OFF    DLEN   FIN  */
478            { 0x08 | 1<<2 | 1<<1 | 1<<0,
479              0x42, 0x10,                                       /* Stream ID */
480              0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,   /* Offset */
481              0x00,                                             /* Data length */
482            },
483            .len        = 1 + 2 + 8 + 1,
484            .min_sz     = 1 + 2 + 8,
485        },
486
487    };
488
489    unsigned i;
490    for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
491        run_test(&tests[i]);
492    return 0;
493}
494