test_hcsi_reader.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <inttypes.h>
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7#include <sys/queue.h>
8
9#include "lsquic.h"
10#include "lsquic_int_types.h"
11#include "lsquic_varint.h"
12#include "lsquic_hq.h"
13#include "lsquic_hcsi_reader.h"
14#include "lsquic_hash.h"
15#include "lsquic_conn.h"
16
17struct test
18{
19    int             lineno;
20
21    enum {
22        TEST_NO_FLAGS           = 0,
23        TEST_NUL_OUT_LEST_FULL  = 1 << 0,
24    }               flags;
25
26    unsigned char   input[0x100];
27    size_t          input_sz;
28
29    int             retval;
30    char            output[0x1000];
31};
32
33
34static const struct test tests[] =
35{
36    {
37        __LINE__,
38        TEST_NO_FLAGS,
39        {
40            0x03,
41            0x04,
42            0x80, 0x12, 0x34, 0x45,
43        },
44        6,
45        0,
46        "on_cancel_push: 1193029\n",
47    },
48
49    {
50        __LINE__,
51        TEST_NO_FLAGS,
52        {
53            HQFT_MAX_PUSH_ID,
54            0x02,
55            0x41, 0x23,
56        },
57        4,
58        0,
59        "on_max_push_id: 291\n",
60    },
61
62    {
63        __LINE__,
64        TEST_NO_FLAGS,
65        {
66            HQFT_SETTINGS,
67            0x00,
68        },
69        2,
70        0,
71        "have SETTINGS frame\n",
72    },
73
74    {   /* Frame contents do not match frame length */
75        __LINE__,
76        TEST_NO_FLAGS,
77        {
78            HQFT_MAX_PUSH_ID,
79            0x03,
80            0x41, 0x23,
81        },
82        4,
83        -1,
84        "",
85    },
86
87    {
88        __LINE__,
89        TEST_NO_FLAGS,
90        {
91            HQFT_SETTINGS,
92            13,
93            0x52, 0x34,
94            0xC0, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
95            0x52, 0x35,
96            0x00,
97        },
98        15,
99        0,
100        "on_setting: 0x1234=0x12233445566778\n"
101        "on_setting: 0x1235=0x0\n"
102        "have SETTINGS frame\n"
103        ,
104    },
105
106    {
107        __LINE__,
108        TEST_NO_FLAGS,
109        {
110            0x80, 0x0F, 0x07, 0x00, /* HQFT_PRIORITY_UPDATE_STREAM */
111            7,
112            0x52, 0x34,
113            0x41, 0x42, 0x43, 0x44, 0x45,   /* ABCDE */
114            HQFT_MAX_PUSH_ID,
115            0x02,
116            0x41, 0x23,
117        },
118        16,
119        0,
120        "on_priority_update: stream=0x1234, [ABCDE]\n"
121        "on_max_push_id: 291\n"
122        ,
123    },
124
125    {
126        __LINE__,
127        TEST_NO_FLAGS,
128        {
129            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
130            6,
131            0x08,
132            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
133        },
134        11,
135        0,
136        "on_priority_update: push=0x8, [PQRST]\n"
137        ,
138    },
139
140    {
141        __LINE__,
142        TEST_NUL_OUT_LEST_FULL,
143        {
144            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
145            21,
146            0x08,
147            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
148            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
149            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
150            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
151        },
152        26,
153        0,
154        "on_priority_update: push=0x8, [PQRSTPQRSTPQRSTPQRST]\n"
155        ,
156    },
157
158};
159
160
161static void
162on_cancel_push (void *ctx, uint64_t push_id)
163{
164    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
165}
166
167static void
168on_max_push_id (void *ctx, uint64_t push_id)
169{
170    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
171}
172
173static void
174on_settings_frame (void *ctx)
175{
176    fprintf(ctx, "have SETTINGS frame\n");
177}
178
179static void
180on_setting (void *ctx, uint64_t setting_id, uint64_t value)
181{
182    fprintf(ctx, "%s: 0x%"PRIX64"=0x%"PRIX64"\n", __func__, setting_id, value);
183}
184
185static void
186on_goaway (void *ctx, uint64_t stream_id)
187{
188    fprintf(ctx, "%s: %"PRIu64"\n", __func__, stream_id);
189}
190
191static void
192on_frame_error (void *ctx, unsigned code, uint64_t frame_type)
193{
194    fprintf(ctx, "%s: %"PRIu64"\n", __func__, frame_type);
195}
196
197static void
198on_priority_update (void *ctx, enum hq_frame_type frame_type,
199                            /* PFV: Priority Field Value */
200                            uint64_t id, const char *pfv, size_t pfv_sz)
201{
202    const char *type;
203
204    switch (frame_type)
205    {
206    case HQFT_PRIORITY_UPDATE_STREAM:  type = "stream"; break;
207    case HQFT_PRIORITY_UPDATE_PUSH:    type = "push"; break;
208    default:                    assert(0); return;
209    }
210
211    fprintf(ctx, "%s: %s=0x%"PRIX64", [%.*s]\n", __func__, type, id,
212                                                        (int) pfv_sz, pfv);
213}
214
215static const struct hcsi_callbacks callbacks =
216{
217    .on_cancel_push         = on_cancel_push,
218    .on_max_push_id         = on_max_push_id,
219    .on_settings_frame      = on_settings_frame,
220    .on_setting             = on_setting,
221    .on_goaway              = on_goaway,
222    .on_frame_error         = on_frame_error,
223    .on_priority_update     = on_priority_update,
224};
225
226
227static void
228abort_error (struct lsquic_conn *conn, int is_app, unsigned error_code,
229                                                    const char *format, ...)
230{
231}
232
233
234static const struct conn_iface conn_iface = {
235    .ci_abort_error     = abort_error,
236};
237
238
239static void
240run_test (const struct test *test)
241{
242    struct hcsi_reader reader;
243    size_t read_sz, out_sz, toread;
244    FILE *out_f;
245    char *output;
246    const unsigned char *p;
247    int s;
248    struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
249    lconn.cn_if = &conn_iface;
250
251    for (read_sz = 1; read_sz <= test->input_sz; ++read_sz)
252    {
253        out_f = open_memstream(&output, &out_sz);
254        lsquic_hcsi_reader_init(&reader, &lconn, &callbacks, out_f);
255        reader.hr_flag |= HR_FLAG_RCVD_SETTING;
256
257        p = test->input;
258        do
259        {
260            toread = test->input + test->input_sz - p;
261            if (toread > read_sz)
262                toread = read_sz;
263            s = lsquic_hcsi_reader_feed(&reader, p, toread);
264            if (s != 0)
265                break;
266            p += toread;
267        }
268        while (p < test->input + test->input_sz);
269
270        assert(s == test->retval);
271
272        fclose(out_f);
273        if (test->retval == 0 && read_sz < test->input_sz
274                                    && (test->flags & TEST_NUL_OUT_LEST_FULL))
275            assert(0 == strcmp(output, ""));
276        else
277            assert(0 == strcmp(test->output, output));
278        free(output);
279    }
280}
281
282int
283main (void)
284{
285    const struct test *test;
286    struct test coalesced_test;
287
288    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
289        run_test(test);
290
291    memset(&coalesced_test, 0, sizeof(coalesced_test));
292    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
293        if (test->retval == 0 && !(test->flags & TEST_NUL_OUT_LEST_FULL))
294        {
295            memcpy(coalesced_test.input + coalesced_test.input_sz,
296                    test->input, test->input_sz);
297            coalesced_test.input_sz += test->input_sz;
298            strcat(coalesced_test.output, test->output);
299        }
300    run_test(&coalesced_test);
301
302    return 0;
303}
304