1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <assert.h>
350aadb33SDmitri Tikhonov#include <stdio.h>
450aadb33SDmitri Tikhonov#include <stdlib.h>
550aadb33SDmitri Tikhonov#include <string.h>
6461e84d8SAmol Deshpande#ifndef WIN32
750aadb33SDmitri Tikhonov#include <sys/time.h>
8461e84d8SAmol Deshpande#endif
950aadb33SDmitri Tikhonov
1050aadb33SDmitri Tikhonov#include "lsquic.h"
1150aadb33SDmitri Tikhonov#include "lsquic_types.h"
1250aadb33SDmitri Tikhonov#include "lsquic_parse.h"
1350aadb33SDmitri Tikhonov
14f07b3eaeSTyler Young//static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_043); // will not work on MSVC
15f07b3eaeSTyler Young#define pf ((const struct parse_funcs *const)select_pf_by_ver(LSQVER_043))
1650aadb33SDmitri Tikhonov
1750aadb33SDmitri Tikhonov
1850aadb33SDmitri Tikhonovstruct goaway_parse_test {
1950aadb33SDmitri Tikhonov    int             lineno;
2050aadb33SDmitri Tikhonov    unsigned char   buf[0x100];
2150aadb33SDmitri Tikhonov    size_t          buf_len;
2250aadb33SDmitri Tikhonov    uint32_t        error_code;
235392f7a3SLiteSpeed Tech    lsquic_stream_id_t        last_stream_id;
2450aadb33SDmitri Tikhonov    uint16_t        reason_len;
2550aadb33SDmitri Tikhonov    const char     *reason;
2650aadb33SDmitri Tikhonov    int             retval;
2750aadb33SDmitri Tikhonov};
2850aadb33SDmitri Tikhonov
2950aadb33SDmitri Tikhonovstatic const struct goaway_parse_test parse_tests[] = {
3050aadb33SDmitri Tikhonov
3150aadb33SDmitri Tikhonov    {
3250aadb33SDmitri Tikhonov        .lineno         = __LINE__,
3350aadb33SDmitri Tikhonov        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
3450aadb33SDmitri Tikhonov        .buf_len        = 0x100,
3550aadb33SDmitri Tikhonov        .error_code     = 0x31,
3650aadb33SDmitri Tikhonov        .last_stream_id = 0x1234,
3750aadb33SDmitri Tikhonov        .reason_len     = 0x05,
3850aadb33SDmitri Tikhonov        .reason         = "Dude!",
3950aadb33SDmitri Tikhonov        .retval         = 11 + 5,
4050aadb33SDmitri Tikhonov    },
4150aadb33SDmitri Tikhonov
4250aadb33SDmitri Tikhonov    {
4350aadb33SDmitri Tikhonov        .lineno         = __LINE__,
4450aadb33SDmitri Tikhonov        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
4550aadb33SDmitri Tikhonov        .buf_len        = 8,    /* Too short #1 */
4650aadb33SDmitri Tikhonov        .error_code     = 0x31,
4750aadb33SDmitri Tikhonov        .last_stream_id = 0x1234,
4850aadb33SDmitri Tikhonov        .reason_len     = 0x05,
4950aadb33SDmitri Tikhonov        .reason         = "Dude!",
5050aadb33SDmitri Tikhonov        .retval         = -1,
5150aadb33SDmitri Tikhonov    },
5250aadb33SDmitri Tikhonov
5350aadb33SDmitri Tikhonov    {
5450aadb33SDmitri Tikhonov        .lineno         = __LINE__,
5550aadb33SDmitri Tikhonov        .buf            = { 0x03, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x12, 0x34, 0x00, 0x05, 'D', 'u', 'd', 'e', '!', },
5650aadb33SDmitri Tikhonov        .buf_len        = 12,    /* Too short #2 */
5750aadb33SDmitri Tikhonov        .error_code     = 0x31,
5850aadb33SDmitri Tikhonov        .last_stream_id = 0x1234,
5950aadb33SDmitri Tikhonov        .reason_len     = 0x05,
6050aadb33SDmitri Tikhonov        .reason         = "Dude!",
6150aadb33SDmitri Tikhonov        .retval         = -2,
6250aadb33SDmitri Tikhonov    },
6350aadb33SDmitri Tikhonov
6450aadb33SDmitri Tikhonov    {   .buf            = { 0 },    }
6550aadb33SDmitri Tikhonov};
6650aadb33SDmitri Tikhonov
6750aadb33SDmitri Tikhonov
6850aadb33SDmitri Tikhonovstruct goaway_gen_test {
6950aadb33SDmitri Tikhonov    int             lineno;
7050aadb33SDmitri Tikhonov    uint32_t        error_code;
715392f7a3SLiteSpeed Tech    lsquic_stream_id_t        last_stream_id;
7250aadb33SDmitri Tikhonov    const char     *reason;
7350aadb33SDmitri Tikhonov    int             retval;
7450aadb33SDmitri Tikhonov    unsigned char   buf[0x100];
7550aadb33SDmitri Tikhonov    size_t          buf_len;
7650aadb33SDmitri Tikhonov};
7750aadb33SDmitri Tikhonov
7850aadb33SDmitri Tikhonov
7950aadb33SDmitri Tikhonovstatic const struct goaway_gen_test gen_tests[] = {
8050aadb33SDmitri Tikhonov
8150aadb33SDmitri Tikhonov    {
8250aadb33SDmitri Tikhonov        .lineno         = __LINE__,
8350aadb33SDmitri Tikhonov        .error_code     = 0x12345678,
8450aadb33SDmitri Tikhonov        .last_stream_id = 0x1234,
8550aadb33SDmitri Tikhonov        .reason         = "Dude, where is my car?",
8650aadb33SDmitri Tikhonov        .retval         = 11 + sizeof("Dude, where is my car?") - 1,
8750aadb33SDmitri Tikhonov        .buf_len        = 0x100,
8850aadb33SDmitri Tikhonov        .buf            = {
8950aadb33SDmitri Tikhonov            0x03,
9050aadb33SDmitri Tikhonov            0x12, 0x34, 0x56, 0x78,
9150aadb33SDmitri Tikhonov            0x00, 0x00, 0x12, 0x34,
9250aadb33SDmitri Tikhonov            0x00, sizeof("Dude, where is my car?") - 1,
9350aadb33SDmitri Tikhonov            'D', 'u', 'd', 'e', ',', ' ', 'w', 'h', 'e', 'r', 'e', ' ', 'i', 's', ' ', 'm', 'y', ' ', 'c', 'a', 'r', '?',
9450aadb33SDmitri Tikhonov        },
9550aadb33SDmitri Tikhonov    },
9650aadb33SDmitri Tikhonov
9750aadb33SDmitri Tikhonov    {
9850aadb33SDmitri Tikhonov        .lineno         = __LINE__,
9950aadb33SDmitri Tikhonov        .error_code     = 0x12345678,
10050aadb33SDmitri Tikhonov        .last_stream_id = 0x2345,
10150aadb33SDmitri Tikhonov        .reason         = NULL,
10250aadb33SDmitri Tikhonov        .retval         = 11,
10350aadb33SDmitri Tikhonov        .buf_len        = 0x100,
10450aadb33SDmitri Tikhonov        .buf            = {
10550aadb33SDmitri Tikhonov            0x02,
10650aadb33SDmitri Tikhonov            0x12, 0x34, 0x56, 0x78,
10750aadb33SDmitri Tikhonov            0x00, 0x00, 0x23, 0x45,
10850aadb33SDmitri Tikhonov            0x00, 0x00, /* Zero-sized string */
10950aadb33SDmitri Tikhonov        },
11050aadb33SDmitri Tikhonov    },
11150aadb33SDmitri Tikhonov
11250aadb33SDmitri Tikhonov    {
11350aadb33SDmitri Tikhonov        .lineno         = __LINE__,
11450aadb33SDmitri Tikhonov        .error_code     = 0x12345678,
11550aadb33SDmitri Tikhonov        .last_stream_id = 0x2345,
11650aadb33SDmitri Tikhonov        .reason         = "Dude, where is my car?",
11750aadb33SDmitri Tikhonov        .retval         = -1,   /* Too short */
11850aadb33SDmitri Tikhonov        .buf_len        = 0x10,
11950aadb33SDmitri Tikhonov    },
12050aadb33SDmitri Tikhonov
12150aadb33SDmitri Tikhonov    {   .buf            = { 0 },    }
12250aadb33SDmitri Tikhonov
12350aadb33SDmitri Tikhonov};
12450aadb33SDmitri Tikhonov
12550aadb33SDmitri Tikhonov
12650aadb33SDmitri Tikhonovstatic void
12750aadb33SDmitri Tikhonovrun_parse_tests (void)
12850aadb33SDmitri Tikhonov{
12950aadb33SDmitri Tikhonov    const struct goaway_parse_test *test;
13050aadb33SDmitri Tikhonov    for (test = parse_tests; test->buf[0]; ++test)
13150aadb33SDmitri Tikhonov    {
13250aadb33SDmitri Tikhonov        uint32_t error_code = ~0;
1335392f7a3SLiteSpeed Tech        lsquic_stream_id_t last_stream_id = ~0;
13450aadb33SDmitri Tikhonov        uint16_t reason_len = ~0;
13550aadb33SDmitri Tikhonov        const char *reason;
13650aadb33SDmitri Tikhonov        int sz = pf->pf_parse_goaway_frame(test->buf, test->buf_len,
13750aadb33SDmitri Tikhonov                    &error_code, &last_stream_id, &reason_len, &reason);
13850aadb33SDmitri Tikhonov        assert(sz == test->retval);
13950aadb33SDmitri Tikhonov        if (0 == sz)
14050aadb33SDmitri Tikhonov        {
14150aadb33SDmitri Tikhonov            assert(test->error_code == error_code);
14250aadb33SDmitri Tikhonov            assert(test->last_stream_id == last_stream_id);
14350aadb33SDmitri Tikhonov            assert(test->reason_len == reason_len);
14450aadb33SDmitri Tikhonov            assert(0 == memcmp(test->reason, reason, reason_len));
14550aadb33SDmitri Tikhonov        }
14650aadb33SDmitri Tikhonov    }
14750aadb33SDmitri Tikhonov}
14850aadb33SDmitri Tikhonov
14950aadb33SDmitri Tikhonov
15050aadb33SDmitri Tikhonovstatic void
15150aadb33SDmitri Tikhonovrun_gen_tests (void)
15250aadb33SDmitri Tikhonov{
15350aadb33SDmitri Tikhonov    const struct goaway_gen_test *test;
15450aadb33SDmitri Tikhonov    for (test = gen_tests; test->buf[0]; ++test)
15550aadb33SDmitri Tikhonov    {
15650aadb33SDmitri Tikhonov        unsigned char buf[0x100];
15750aadb33SDmitri Tikhonov        int sz = pf->pf_gen_goaway_frame(buf, sizeof(buf),
15850aadb33SDmitri Tikhonov                    test->error_code, test->last_stream_id, test->reason,
15950aadb33SDmitri Tikhonov                    test->reason ? strlen(test->reason) : 0);
16050aadb33SDmitri Tikhonov        assert(sz == test->retval);
16150aadb33SDmitri Tikhonov        if (0 == sz)
16250aadb33SDmitri Tikhonov            assert(0 == memcmp(test->buf, buf, sz));
16350aadb33SDmitri Tikhonov    }
16450aadb33SDmitri Tikhonov}
16550aadb33SDmitri Tikhonov
16650aadb33SDmitri Tikhonov
16750aadb33SDmitri Tikhonovint
16850aadb33SDmitri Tikhonovmain (void)
16950aadb33SDmitri Tikhonov{
17050aadb33SDmitri Tikhonov    run_parse_tests();
17150aadb33SDmitri Tikhonov    run_gen_tests();
17250aadb33SDmitri Tikhonov    return 0;
17350aadb33SDmitri Tikhonov}
174