1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#ifndef WIN32
7#include <sys/time.h>
8#endif
9
10#include "lsquic.h"
11#include "lsquic_types.h"
12#include "lsquic_parse.h"
13
14//static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_043); // will not work on MSVC
15#define pf ((const struct parse_funcs *const)select_pf_by_ver(LSQVER_043))
16
17
18struct goaway_parse_test {
19    int             lineno;
20    unsigned char   buf[0x100];
21    size_t          buf_len;
22    uint32_t        error_code;
23    lsquic_stream_id_t        last_stream_id;
24    uint16_t        reason_len;
25    const char     *reason;
26    int             retval;
27};
28
29static const struct goaway_parse_test parse_tests[] = {
30
31    {
32        .lineno         = __LINE__,
33        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
34        .buf_len        = 0x100,
35        .error_code     = 0x31,
36        .last_stream_id = 0x1234,
37        .reason_len     = 0x05,
38        .reason         = "Dude!",
39        .retval         = 11 + 5,
40    },
41
42    {
43        .lineno         = __LINE__,
44        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
45        .buf_len        = 8,    /* Too short #1 */
46        .error_code     = 0x31,
47        .last_stream_id = 0x1234,
48        .reason_len     = 0x05,
49        .reason         = "Dude!",
50        .retval         = -1,
51    },
52
53    {
54        .lineno         = __LINE__,
55        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
56        .buf_len        = 12,    /* Too short #2 */
57        .error_code     = 0x31,
58        .last_stream_id = 0x1234,
59        .reason_len     = 0x05,
60        .reason         = "Dude!",
61        .retval         = -2,
62    },
63
64    {   .buf            = { 0 },    }
65};
66
67
68struct goaway_gen_test {
69    int             lineno;
70    uint32_t        error_code;
71    lsquic_stream_id_t        last_stream_id;
72    const char     *reason;
73    int             retval;
74    unsigned char   buf[0x100];
75    size_t          buf_len;
76};
77
78
79static const struct goaway_gen_test gen_tests[] = {
80
81    {
82        .lineno         = __LINE__,
83        .error_code     = 0x12345678,
84        .last_stream_id = 0x1234,
85        .reason         = "Dude, where is my car?",
86        .retval         = 11 + sizeof("Dude, where is my car?") - 1,
87        .buf_len        = 0x100,
88        .buf            = {
89            0x03,
90            0x12, 0x34, 0x56, 0x78,
91            0x00, 0x00, 0x12, 0x34,
92            0x00, sizeof("Dude, where is my car?") - 1,
93            'D', 'u', 'd', 'e', ',', ' ', 'w', 'h', 'e', 'r', 'e', ' ', 'i', 's', ' ', 'm', 'y', ' ', 'c', 'a', 'r', '?',
94        },
95    },
96
97    {
98        .lineno         = __LINE__,
99        .error_code     = 0x12345678,
100        .last_stream_id = 0x2345,
101        .reason         = NULL,
102        .retval         = 11,
103        .buf_len        = 0x100,
104        .buf            = {
105            0x02,
106            0x12, 0x34, 0x56, 0x78,
107            0x00, 0x00, 0x23, 0x45,
108            0x00, 0x00, /* Zero-sized string */
109        },
110    },
111
112    {
113        .lineno         = __LINE__,
114        .error_code     = 0x12345678,
115        .last_stream_id = 0x2345,
116        .reason         = "Dude, where is my car?",
117        .retval         = -1,   /* Too short */
118        .buf_len        = 0x10,
119    },
120
121    {   .buf            = { 0 },    }
122
123};
124
125
126static void
127run_parse_tests (void)
128{
129    const struct goaway_parse_test *test;
130    for (test = parse_tests; test->buf[0]; ++test)
131    {
132        uint32_t error_code = ~0;
133        lsquic_stream_id_t last_stream_id = ~0;
134        uint16_t reason_len = ~0;
135        const char *reason;
136        int sz = pf->pf_parse_goaway_frame(test->buf, test->buf_len,
137                    &error_code, &last_stream_id, &reason_len, &reason);
138        assert(sz == test->retval);
139        if (0 == sz)
140        {
141            assert(test->error_code == error_code);
142            assert(test->last_stream_id == last_stream_id);
143            assert(test->reason_len == reason_len);
144            assert(0 == memcmp(test->reason, reason, reason_len));
145        }
146    }
147}
148
149
150static void
151run_gen_tests (void)
152{
153    const struct goaway_gen_test *test;
154    for (test = gen_tests; test->buf[0]; ++test)
155    {
156        unsigned char buf[0x100];
157        int sz = pf->pf_gen_goaway_frame(buf, sizeof(buf),
158                    test->error_code, test->last_stream_id, test->reason,
159                    test->reason ? strlen(test->reason) : 0);
160        assert(sz == test->retval);
161        if (0 == sz)
162            assert(0 == memcmp(test->buf, buf, sz));
163    }
164}
165
166
167int
168main (void)
169{
170    run_parse_tests();
171    run_gen_tests();
172    return 0;
173}
174