test_streamgen.c revision f07b3eae
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