test_ack.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc.  See LICENSE. */
2/* Test both generation and parsing of IETF ACK frames */
3
4#include <assert.h>
5#include <string.h>
6
7#include "lsquic.h"
8#include "lsquic_types.h"
9#include "lsquic_int_types.h"
10#include "lsquic_sizes.h"
11#include "lsquic_parse.h"
12#include "lsquic_trans_params.h"
13
14struct test
15{
16    int                 lineno;
17    int                 skip_gen;
18
19    struct ack_info     acki;
20
21    size_t              encoded_sz;
22    unsigned char       encoded[0x1000];
23};
24
25static const lsquic_time_t now = 0x12345676890;
26
27static const struct test tests[] =
28{
29    {
30        .lineno         = __LINE__,
31        .acki           =
32        {
33            .n_ranges   = 2,
34            .lack_delta = 0xFEDCB0,
35            .ranges     =
36            {
37                [0] = { 7, 7, },
38                [1] = { 0, 0, },
39            },
40        },
41        .encoded    =
42        {
43        /* Type */              0x02,
44        /* Largest acked */     0x07,
45        /* ACK delay */         0x80, 0x1F, 0xDB, 0x96,
46        /* Addl block count */  0x01,
47        /* First ACK block */   0x00,
48        /* Gap */               0x05,
49        /* ACK block */         0x00,
50        },
51        .encoded_sz = 10,
52    },
53
54    {
55        .lineno         = __LINE__,
56        .acki           =
57        {
58            .n_ranges   = 3,
59            .lack_delta = 0xFEDCB0,
60            .ranges     =
61            {
62                [0] = { 10, 10, },
63                [1] = { 7, 7, },
64                [2] = { 0, 0, },
65            },
66        },
67        .encoded    =
68        {
69        /* Type */              0x02,
70        /* Largest acked */     10,
71        /* ACK delay */         0x80, 0x1F, 0xDB, 0x96,
72        /* Addl block count */  2,
73        /* First ACK block */   0x00,
74        /* Gap */               0x01,
75        /* ACK block */         0x00,
76        /* Gap */               0x05,
77        /* ACK block */         0x00,
78        },
79        .encoded_sz = 12,
80    },
81
82    {
83        .lineno         = __LINE__,
84        .acki           =
85        {
86            .flags      = AI_ECN,
87            .n_ranges   = 3,
88            .lack_delta = 0xFEDCB0,
89            .ecn_counts = { 0, 0x010203, 1, 0x49, },
90            .ranges     =
91            {
92                [0] = { 10, 10, },
93                [1] = { 7, 7, },
94                [2] = { 0, 0, },
95            },
96        },
97        .encoded    =
98        {
99        /* Type */              0x03,
100        /* Largest acked */     10,
101        /* ACK delay */         0x80, 0x1F, 0xDB, 0x96,
102        /* Addl block count */  2,
103        /* First ACK block */   0x00,
104        /* Gap */               0x01,
105        /* ACK block */         0x00,
106        /* Gap */               0x05,
107        /* ACK block */         0x00,
108        /* ECT(1) count */      0x01,
109        /* ECT(0) count */      0x80, 0x01, 0x02, 0x03,
110        /* ECN-CE count */      0x40, 0x49,
111        },
112        .encoded_sz = 19,
113    },
114
115};
116
117struct rechist
118{
119    const struct ack_info   *acki;
120    unsigned                 next_range;
121};
122
123
124static const struct lsquic_packno_range *
125rechist_next (void *ctx)
126{
127    struct rechist *rechist = ctx;
128    if (rechist->next_range < rechist->acki->n_ranges)
129        return rechist->acki->ranges + rechist->next_range++;
130    else
131        return NULL;
132}
133
134static const struct lsquic_packno_range *
135rechist_first (void *ctx)
136{
137    struct rechist *rechist = ctx;
138    rechist->next_range = 0;
139    return rechist_next(rechist);
140}
141
142static lsquic_time_t
143rechist_largest_recv (void *ctx)
144{
145    struct rechist *rechist = ctx;
146    return now - rechist->acki->lack_delta;
147}
148
149
150static void
151compare_ackis (const struct ack_info *exp, const struct ack_info *got)
152{
153    unsigned i;
154
155    assert(exp->flags == got->flags);
156    assert(exp->n_ranges == got->n_ranges);
157    assert(exp->lack_delta == got->lack_delta);
158
159    for (i = 0; i < exp->n_ranges; ++i)
160    {
161        assert(exp->ranges[i].high == got->ranges[i].high);
162        assert(exp->ranges[i].low == got->ranges[i].low);
163    }
164
165    if (exp->flags & AI_ECN)
166        for (i = 1; i <= 3; ++i)
167            assert(exp->ecn_counts[i] == got->ecn_counts[i]);
168}
169
170
171static void
172run_test (const struct test *test)
173{
174    int len, has_missing;
175    lsquic_packno_t largest_received;
176    const struct parse_funcs *pf;
177    struct rechist rechist;
178    struct ack_info acki;
179    size_t sz;
180    unsigned char buf[0x1000];
181
182    pf = select_pf_by_ver(LSQVER_ID27);
183    if (!test->skip_gen)
184    {
185        rechist.acki = &test->acki;
186        len = pf->pf_gen_ack_frame(buf, sizeof(buf), rechist_first, rechist_next,
187            rechist_largest_recv, &rechist, now, &has_missing, &largest_received,
188            test->acki.flags & AI_ECN ? rechist.acki->ecn_counts : NULL);
189        assert(len > 0);
190        assert(largest_received == largest_acked(&test->acki));
191        assert((size_t) len == test->encoded_sz);
192        assert(0 == memcmp(test->encoded, buf, test->encoded_sz));
193    }
194
195    /* Test that shorter buffers cannot get parsed */
196    for (sz = 1; sz < test->encoded_sz; ++sz)
197    {
198        len = pf->pf_parse_ack_frame(test->encoded, sz, &acki,
199                                                        TP_DEF_ACK_DELAY_EXP);
200        assert(len < 0);
201    }
202
203    len = pf->pf_parse_ack_frame(test->encoded, sizeof(test->encoded), &acki,
204                                                        TP_DEF_ACK_DELAY_EXP);
205    assert(len > 0);
206    assert((size_t) len == test->encoded_sz);
207    compare_ackis(&test->acki, &acki);
208}
209
210int
211main (void)
212{
213    const struct test *test;
214
215    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
216        run_test(test);
217
218    return 0;
219}
220