1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech#include <assert.h>
35392f7a3SLiteSpeed Tech#include <inttypes.h>
45392f7a3SLiteSpeed Tech#include <stdlib.h>
55392f7a3SLiteSpeed Tech#include <string.h>
65392f7a3SLiteSpeed Tech#include <stdio.h>
75392f7a3SLiteSpeed Tech#include <sys/queue.h>
85392f7a3SLiteSpeed Tech
95392f7a3SLiteSpeed Tech#include "lsquic.h"
105392f7a3SLiteSpeed Tech#include "lsquic_int_types.h"
115392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
125392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
135392f7a3SLiteSpeed Tech#include "lsquic_hcsi_reader.h"
145392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
155392f7a3SLiteSpeed Tech#include "lsquic_conn.h"
165392f7a3SLiteSpeed Tech
175392f7a3SLiteSpeed Techstruct test
185392f7a3SLiteSpeed Tech{
195392f7a3SLiteSpeed Tech    int             lineno;
205392f7a3SLiteSpeed Tech
21fbc6cc04SDmitri Tikhonov    enum {
22fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS           = 0,
23fbc6cc04SDmitri Tikhonov        TEST_NUL_OUT_LEST_FULL  = 1 << 0,
24fbc6cc04SDmitri Tikhonov    }               flags;
25fbc6cc04SDmitri Tikhonov
265392f7a3SLiteSpeed Tech    unsigned char   input[0x100];
275392f7a3SLiteSpeed Tech    size_t          input_sz;
285392f7a3SLiteSpeed Tech
295392f7a3SLiteSpeed Tech    int             retval;
305392f7a3SLiteSpeed Tech    char            output[0x1000];
315392f7a3SLiteSpeed Tech};
325392f7a3SLiteSpeed Tech
335392f7a3SLiteSpeed Tech
345392f7a3SLiteSpeed Techstatic const struct test tests[] =
355392f7a3SLiteSpeed Tech{
365392f7a3SLiteSpeed Tech    {
375392f7a3SLiteSpeed Tech        __LINE__,
38fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
395392f7a3SLiteSpeed Tech        {
405392f7a3SLiteSpeed Tech            0x03,
415392f7a3SLiteSpeed Tech            0x04,
425392f7a3SLiteSpeed Tech            0x80, 0x12, 0x34, 0x45,
435392f7a3SLiteSpeed Tech        },
445392f7a3SLiteSpeed Tech        6,
455392f7a3SLiteSpeed Tech        0,
465392f7a3SLiteSpeed Tech        "on_cancel_push: 1193029\n",
475392f7a3SLiteSpeed Tech    },
485392f7a3SLiteSpeed Tech
495392f7a3SLiteSpeed Tech    {
505392f7a3SLiteSpeed Tech        __LINE__,
51fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
525392f7a3SLiteSpeed Tech        {
535392f7a3SLiteSpeed Tech            HQFT_MAX_PUSH_ID,
545392f7a3SLiteSpeed Tech            0x02,
555392f7a3SLiteSpeed Tech            0x41, 0x23,
565392f7a3SLiteSpeed Tech        },
575392f7a3SLiteSpeed Tech        4,
585392f7a3SLiteSpeed Tech        0,
595392f7a3SLiteSpeed Tech        "on_max_push_id: 291\n",
605392f7a3SLiteSpeed Tech    },
615392f7a3SLiteSpeed Tech
625392f7a3SLiteSpeed Tech    {
635392f7a3SLiteSpeed Tech        __LINE__,
64fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
655392f7a3SLiteSpeed Tech        {
665392f7a3SLiteSpeed Tech            HQFT_SETTINGS,
675392f7a3SLiteSpeed Tech            0x00,
685392f7a3SLiteSpeed Tech        },
695392f7a3SLiteSpeed Tech        2,
705392f7a3SLiteSpeed Tech        0,
715392f7a3SLiteSpeed Tech        "have SETTINGS frame\n",
725392f7a3SLiteSpeed Tech    },
735392f7a3SLiteSpeed Tech
745392f7a3SLiteSpeed Tech    {   /* Frame contents do not match frame length */
755392f7a3SLiteSpeed Tech        __LINE__,
76fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
775392f7a3SLiteSpeed Tech        {
785392f7a3SLiteSpeed Tech            HQFT_MAX_PUSH_ID,
795392f7a3SLiteSpeed Tech            0x03,
805392f7a3SLiteSpeed Tech            0x41, 0x23,
815392f7a3SLiteSpeed Tech        },
825392f7a3SLiteSpeed Tech        4,
835392f7a3SLiteSpeed Tech        -1,
845392f7a3SLiteSpeed Tech        "",
855392f7a3SLiteSpeed Tech    },
865392f7a3SLiteSpeed Tech
875392f7a3SLiteSpeed Tech    {
885392f7a3SLiteSpeed Tech        __LINE__,
89fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
905392f7a3SLiteSpeed Tech        {
915392f7a3SLiteSpeed Tech            HQFT_SETTINGS,
925392f7a3SLiteSpeed Tech            13,
935392f7a3SLiteSpeed Tech            0x52, 0x34,
945392f7a3SLiteSpeed Tech            0xC0, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
955392f7a3SLiteSpeed Tech            0x52, 0x35,
965392f7a3SLiteSpeed Tech            0x00,
975392f7a3SLiteSpeed Tech        },
985392f7a3SLiteSpeed Tech        15,
995392f7a3SLiteSpeed Tech        0,
1005392f7a3SLiteSpeed Tech        "on_setting: 0x1234=0x12233445566778\n"
1015392f7a3SLiteSpeed Tech        "on_setting: 0x1235=0x0\n"
1025392f7a3SLiteSpeed Tech        "have SETTINGS frame\n"
1035392f7a3SLiteSpeed Tech        ,
1045392f7a3SLiteSpeed Tech    },
1055392f7a3SLiteSpeed Tech
106fbc6cc04SDmitri Tikhonov    {
107fbc6cc04SDmitri Tikhonov        __LINE__,
108fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
109fbc6cc04SDmitri Tikhonov        {
110fbc6cc04SDmitri Tikhonov            0x80, 0x0F, 0x07, 0x00, /* HQFT_PRIORITY_UPDATE_STREAM */
111fbc6cc04SDmitri Tikhonov            7,
112fbc6cc04SDmitri Tikhonov            0x52, 0x34,
113fbc6cc04SDmitri Tikhonov            0x41, 0x42, 0x43, 0x44, 0x45,   /* ABCDE */
114fbc6cc04SDmitri Tikhonov            HQFT_MAX_PUSH_ID,
115fbc6cc04SDmitri Tikhonov            0x02,
116fbc6cc04SDmitri Tikhonov            0x41, 0x23,
117fbc6cc04SDmitri Tikhonov        },
118fbc6cc04SDmitri Tikhonov        16,
119fbc6cc04SDmitri Tikhonov        0,
120fbc6cc04SDmitri Tikhonov        "on_priority_update: stream=0x1234, [ABCDE]\n"
121fbc6cc04SDmitri Tikhonov        "on_max_push_id: 291\n"
122fbc6cc04SDmitri Tikhonov        ,
123fbc6cc04SDmitri Tikhonov    },
124fbc6cc04SDmitri Tikhonov
125fbc6cc04SDmitri Tikhonov    {
126fbc6cc04SDmitri Tikhonov        __LINE__,
127fbc6cc04SDmitri Tikhonov        TEST_NO_FLAGS,
128fbc6cc04SDmitri Tikhonov        {
129fbc6cc04SDmitri Tikhonov            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
130fbc6cc04SDmitri Tikhonov            6,
131fbc6cc04SDmitri Tikhonov            0x08,
132fbc6cc04SDmitri Tikhonov            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
133fbc6cc04SDmitri Tikhonov        },
134fbc6cc04SDmitri Tikhonov        11,
135fbc6cc04SDmitri Tikhonov        0,
136fbc6cc04SDmitri Tikhonov        "on_priority_update: push=0x8, [PQRST]\n"
137fbc6cc04SDmitri Tikhonov        ,
138fbc6cc04SDmitri Tikhonov    },
139fbc6cc04SDmitri Tikhonov
140fbc6cc04SDmitri Tikhonov    {
141fbc6cc04SDmitri Tikhonov        __LINE__,
142fbc6cc04SDmitri Tikhonov        TEST_NUL_OUT_LEST_FULL,
143fbc6cc04SDmitri Tikhonov        {
144fbc6cc04SDmitri Tikhonov            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
145fbc6cc04SDmitri Tikhonov            21,
146fbc6cc04SDmitri Tikhonov            0x08,
147fbc6cc04SDmitri Tikhonov            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
148fbc6cc04SDmitri Tikhonov            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
149fbc6cc04SDmitri Tikhonov            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
150fbc6cc04SDmitri Tikhonov            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
151fbc6cc04SDmitri Tikhonov        },
152fbc6cc04SDmitri Tikhonov        26,
153fbc6cc04SDmitri Tikhonov        0,
154fbc6cc04SDmitri Tikhonov        "on_priority_update: push=0x8, [PQRSTPQRSTPQRSTPQRST]\n"
155fbc6cc04SDmitri Tikhonov        ,
156fbc6cc04SDmitri Tikhonov    },
157fbc6cc04SDmitri Tikhonov
1585392f7a3SLiteSpeed Tech};
1595392f7a3SLiteSpeed Tech
1605392f7a3SLiteSpeed Tech
1615392f7a3SLiteSpeed Techstatic void
1625392f7a3SLiteSpeed Techon_cancel_push (void *ctx, uint64_t push_id)
1635392f7a3SLiteSpeed Tech{
1645392f7a3SLiteSpeed Tech    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
1655392f7a3SLiteSpeed Tech}
1665392f7a3SLiteSpeed Tech
1675392f7a3SLiteSpeed Techstatic void
1685392f7a3SLiteSpeed Techon_max_push_id (void *ctx, uint64_t push_id)
1695392f7a3SLiteSpeed Tech{
1705392f7a3SLiteSpeed Tech    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
1715392f7a3SLiteSpeed Tech}
1725392f7a3SLiteSpeed Tech
1735392f7a3SLiteSpeed Techstatic void
1745392f7a3SLiteSpeed Techon_settings_frame (void *ctx)
1755392f7a3SLiteSpeed Tech{
1765392f7a3SLiteSpeed Tech    fprintf(ctx, "have SETTINGS frame\n");
1775392f7a3SLiteSpeed Tech}
1785392f7a3SLiteSpeed Tech
1795392f7a3SLiteSpeed Techstatic void
1805392f7a3SLiteSpeed Techon_setting (void *ctx, uint64_t setting_id, uint64_t value)
1815392f7a3SLiteSpeed Tech{
1825392f7a3SLiteSpeed Tech    fprintf(ctx, "%s: 0x%"PRIX64"=0x%"PRIX64"\n", __func__, setting_id, value);
1835392f7a3SLiteSpeed Tech}
1845392f7a3SLiteSpeed Tech
1855392f7a3SLiteSpeed Techstatic void
1865392f7a3SLiteSpeed Techon_goaway (void *ctx, uint64_t stream_id)
1875392f7a3SLiteSpeed Tech{
1885392f7a3SLiteSpeed Tech    fprintf(ctx, "%s: %"PRIu64"\n", __func__, stream_id);
1895392f7a3SLiteSpeed Tech}
1905392f7a3SLiteSpeed Tech
1915392f7a3SLiteSpeed Techstatic void
19255d69529SGeorge Wangon_frame_error (void *ctx, unsigned code, uint64_t frame_type)
1935392f7a3SLiteSpeed Tech{
1945392f7a3SLiteSpeed Tech    fprintf(ctx, "%s: %"PRIu64"\n", __func__, frame_type);
1955392f7a3SLiteSpeed Tech}
1965392f7a3SLiteSpeed Tech
197fbc6cc04SDmitri Tikhonovstatic void
198fbc6cc04SDmitri Tikhonovon_priority_update (void *ctx, enum hq_frame_type frame_type,
199fbc6cc04SDmitri Tikhonov                            /* PFV: Priority Field Value */
200fbc6cc04SDmitri Tikhonov                            uint64_t id, const char *pfv, size_t pfv_sz)
201fbc6cc04SDmitri Tikhonov{
202fbc6cc04SDmitri Tikhonov    const char *type;
203fbc6cc04SDmitri Tikhonov
204fbc6cc04SDmitri Tikhonov    switch (frame_type)
205fbc6cc04SDmitri Tikhonov    {
206fbc6cc04SDmitri Tikhonov    case HQFT_PRIORITY_UPDATE_STREAM:  type = "stream"; break;
207fbc6cc04SDmitri Tikhonov    case HQFT_PRIORITY_UPDATE_PUSH:    type = "push"; break;
208fbc6cc04SDmitri Tikhonov    default:                    assert(0); return;
209fbc6cc04SDmitri Tikhonov    }
210fbc6cc04SDmitri Tikhonov
211fbc6cc04SDmitri Tikhonov    fprintf(ctx, "%s: %s=0x%"PRIX64", [%.*s]\n", __func__, type, id,
212fbc6cc04SDmitri Tikhonov                                                        (int) pfv_sz, pfv);
213fbc6cc04SDmitri Tikhonov}
214fbc6cc04SDmitri Tikhonov
2155392f7a3SLiteSpeed Techstatic const struct hcsi_callbacks callbacks =
2165392f7a3SLiteSpeed Tech{
2175392f7a3SLiteSpeed Tech    .on_cancel_push         = on_cancel_push,
2185392f7a3SLiteSpeed Tech    .on_max_push_id         = on_max_push_id,
2195392f7a3SLiteSpeed Tech    .on_settings_frame      = on_settings_frame,
2205392f7a3SLiteSpeed Tech    .on_setting             = on_setting,
2215392f7a3SLiteSpeed Tech    .on_goaway              = on_goaway,
22255d69529SGeorge Wang    .on_frame_error         = on_frame_error,
223fbc6cc04SDmitri Tikhonov    .on_priority_update     = on_priority_update,
2245392f7a3SLiteSpeed Tech};
2255392f7a3SLiteSpeed Tech
2265392f7a3SLiteSpeed Tech
2275392f7a3SLiteSpeed Techstatic void
2285392f7a3SLiteSpeed Techabort_error (struct lsquic_conn *conn, int is_app, unsigned error_code,
2295392f7a3SLiteSpeed Tech                                                    const char *format, ...)
2305392f7a3SLiteSpeed Tech{
2315392f7a3SLiteSpeed Tech}
2325392f7a3SLiteSpeed Tech
2335392f7a3SLiteSpeed Tech
2345392f7a3SLiteSpeed Techstatic const struct conn_iface conn_iface = {
2355392f7a3SLiteSpeed Tech    .ci_abort_error     = abort_error,
2365392f7a3SLiteSpeed Tech};
2375392f7a3SLiteSpeed Tech
2385392f7a3SLiteSpeed Tech
2395392f7a3SLiteSpeed Techstatic void
2405392f7a3SLiteSpeed Techrun_test (const struct test *test)
2415392f7a3SLiteSpeed Tech{
2425392f7a3SLiteSpeed Tech    struct hcsi_reader reader;
2435392f7a3SLiteSpeed Tech    size_t read_sz, out_sz, toread;
2445392f7a3SLiteSpeed Tech    FILE *out_f;
2455392f7a3SLiteSpeed Tech    char *output;
2465392f7a3SLiteSpeed Tech    const unsigned char *p;
2475392f7a3SLiteSpeed Tech    int s;
2485392f7a3SLiteSpeed Tech    struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
2495392f7a3SLiteSpeed Tech    lconn.cn_if = &conn_iface;
2505392f7a3SLiteSpeed Tech
251fbc6cc04SDmitri Tikhonov    for (read_sz = 1; read_sz <= test->input_sz; ++read_sz)
2525392f7a3SLiteSpeed Tech    {
2535392f7a3SLiteSpeed Tech        out_f = open_memstream(&output, &out_sz);
2545392f7a3SLiteSpeed Tech        lsquic_hcsi_reader_init(&reader, &lconn, &callbacks, out_f);
25555d69529SGeorge Wang        reader.hr_flag |= HR_FLAG_RCVD_SETTING;
2565392f7a3SLiteSpeed Tech
2575392f7a3SLiteSpeed Tech        p = test->input;
2585392f7a3SLiteSpeed Tech        do
2595392f7a3SLiteSpeed Tech        {
2605392f7a3SLiteSpeed Tech            toread = test->input + test->input_sz - p;
2615392f7a3SLiteSpeed Tech            if (toread > read_sz)
2625392f7a3SLiteSpeed Tech                toread = read_sz;
2635392f7a3SLiteSpeed Tech            s = lsquic_hcsi_reader_feed(&reader, p, toread);
2645392f7a3SLiteSpeed Tech            if (s != 0)
2655392f7a3SLiteSpeed Tech                break;
2665392f7a3SLiteSpeed Tech            p += toread;
2675392f7a3SLiteSpeed Tech        }
2685392f7a3SLiteSpeed Tech        while (p < test->input + test->input_sz);
2695392f7a3SLiteSpeed Tech
2705392f7a3SLiteSpeed Tech        assert(s == test->retval);
2715392f7a3SLiteSpeed Tech
2725392f7a3SLiteSpeed Tech        fclose(out_f);
273fbc6cc04SDmitri Tikhonov        if (test->retval == 0 && read_sz < test->input_sz
274fbc6cc04SDmitri Tikhonov                                    && (test->flags & TEST_NUL_OUT_LEST_FULL))
275fbc6cc04SDmitri Tikhonov            assert(0 == strcmp(output, ""));
276fbc6cc04SDmitri Tikhonov        else
277fbc6cc04SDmitri Tikhonov            assert(0 == strcmp(test->output, output));
2785392f7a3SLiteSpeed Tech        free(output);
2795392f7a3SLiteSpeed Tech    }
2805392f7a3SLiteSpeed Tech}
2815392f7a3SLiteSpeed Tech
2825392f7a3SLiteSpeed Techint
2835392f7a3SLiteSpeed Techmain (void)
2845392f7a3SLiteSpeed Tech{
2855392f7a3SLiteSpeed Tech    const struct test *test;
2865392f7a3SLiteSpeed Tech    struct test coalesced_test;
2875392f7a3SLiteSpeed Tech
2885392f7a3SLiteSpeed Tech    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
2895392f7a3SLiteSpeed Tech        run_test(test);
2905392f7a3SLiteSpeed Tech
2915392f7a3SLiteSpeed Tech    memset(&coalesced_test, 0, sizeof(coalesced_test));
2925392f7a3SLiteSpeed Tech    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
293fbc6cc04SDmitri Tikhonov        if (test->retval == 0 && !(test->flags & TEST_NUL_OUT_LEST_FULL))
2945392f7a3SLiteSpeed Tech        {
2955392f7a3SLiteSpeed Tech            memcpy(coalesced_test.input + coalesced_test.input_sz,
2965392f7a3SLiteSpeed Tech                    test->input, test->input_sz);
2975392f7a3SLiteSpeed Tech            coalesced_test.input_sz += test->input_sz;
2985392f7a3SLiteSpeed Tech            strcat(coalesced_test.output, test->output);
2995392f7a3SLiteSpeed Tech        }
3005392f7a3SLiteSpeed Tech    run_test(&coalesced_test);
3015392f7a3SLiteSpeed Tech
3025392f7a3SLiteSpeed Tech    return 0;
3035392f7a3SLiteSpeed Tech}
304