test_spi.c revision 9a690580
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <errno.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/queue.h>
8#ifndef WIN32
9#include <unistd.h>
10#endif
11
12#include "lsquic.h"
13
14#include "lsquic_int_types.h"
15#include "lsquic_packet_common.h"
16#include "lsquic_packet_in.h"
17#include "lsquic_conn_flow.h"
18#include "lsquic_sfcw.h"
19#include "lsquic_varint.h"
20#include "lsquic_hq.h"
21#include "lsquic_hash.h"
22#include "lsquic_conn.h"
23#include "lsquic_stream.h"
24#include "lsquic_types.h"
25#include "lsquic_spi.h"
26#include "lsquic_logger.h"
27
28
29/* Sharing the same SPI tests safety of reusing the same iterator object
30 * (no need to deinitialize it).
31 */
32static struct stream_prio_iter spi;
33
34static struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
35
36
37static lsquic_stream_t *
38new_stream (unsigned priority)
39{
40    lsquic_stream_t *stream = calloc(1, sizeof(*stream));
41    stream->sm_priority = priority;
42    return stream;
43}
44
45
46static void
47free_streams (lsquic_stream_t **streams, size_t count)
48{
49    size_t n;
50    for (n = 0; n < count; ++n)
51        free(streams[n]);
52}
53
54
55static void
56test_same_priority (unsigned priority)
57{
58    lsquic_stream_t *stream_arr[4] = {
59        new_stream(priority),
60        new_stream(priority),
61        new_stream(priority),
62        new_stream(priority),
63    };
64    struct lsquic_streams_tailq streams;
65    unsigned flags = 0xF00;     /* Arbitrary value */
66    lsquic_stream_t *stream;
67
68    TAILQ_INIT(&streams);
69    TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_write_stream);
70    stream_arr[0]->sm_qflags |= flags;
71    TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_write_stream);
72    stream_arr[1]->sm_qflags |= flags;
73    TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_write_stream);
74    stream_arr[2]->sm_qflags |= flags;
75    TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_write_stream);
76    stream_arr[3]->sm_qflags |= flags;
77
78    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
79        TAILQ_LAST(&streams, lsquic_streams_tailq),
80        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
81        flags, &lconn, __func__, NULL, NULL);
82
83    stream = lsquic_spi_first(&spi);
84    assert(stream == stream_arr[0]);
85    stream = lsquic_spi_next(&spi);
86    assert(stream == stream_arr[1]);
87    stream = lsquic_spi_next(&spi);
88    assert(stream == stream_arr[2]);
89    stream = lsquic_spi_next(&spi);
90    assert(stream == stream_arr[3]);
91    stream = lsquic_spi_next(&spi);
92    assert(stream == NULL);
93
94    /* Test reinitialization: */
95    lsquic_spi_init(&spi, stream_arr[0], stream_arr[1],
96        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
97        flags, &lconn, __func__, NULL, NULL);
98    stream = lsquic_spi_first(&spi);
99    assert(stream == stream_arr[0]);
100    stream = lsquic_spi_next(&spi);
101    assert(stream == stream_arr[1]);
102    stream = lsquic_spi_next(&spi);
103    assert(stream == NULL);
104
105    free_streams(stream_arr, sizeof(stream_arr) / sizeof(stream_arr[0]));
106}
107
108
109static void
110test_different_priorities (int *priority)
111{
112    struct lsquic_streams_tailq streams;
113    unsigned flags = 0xC000;     /* Arbitrary value */
114    lsquic_stream_t *stream;
115    int prio, prev_prio, count, n_streams = 0;
116
117    TAILQ_INIT(&streams);
118
119    for ( ; *priority >= 0; ++priority)
120    {
121        assert(*priority < 256);
122        stream = new_stream(*priority);
123        TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
124        stream->sm_qflags |= flags;
125        ++n_streams;
126    }
127
128    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
129        TAILQ_LAST(&streams, lsquic_streams_tailq),
130        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
131        flags, &lconn, __func__, NULL, NULL);
132
133    for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
134                                        stream = lsquic_spi_next(&spi), ++count)
135    {
136        prio = stream->sm_priority;
137        assert(prio >= prev_prio);
138        if (prio > prev_prio)
139            prev_prio = prio;
140    }
141
142    assert(count == n_streams);
143
144    while ((stream = TAILQ_FIRST(&streams)))
145    {
146        TAILQ_REMOVE(&streams, stream, next_send_stream);
147        free(stream);
148    }
149}
150
151
152struct stream_info
153{
154    uint32_t        stream_id;
155    enum stream_b_flags bflags;
156    unsigned char   prio;
157};
158
159
160const struct stream_info infos1[] = {
161    { 1,                                SMBF_CRITICAL, 0, },
162    { 3,                                SMBF_CRITICAL, 0, },
163    { 5,                                0, 0, },
164    { 7,                                0, 1, },
165    { 127,                              0, 200, },
166};
167
168
169const struct stream_info infos2[] = {
170    { 1,                                SMBF_CRITICAL, 0, },
171    { 3,                                SMBF_CRITICAL, 0, },
172    { 5,                                0, 4, },
173    { 7,                                0, 1, },
174    { 127,                              0, 200, },
175};
176
177
178const struct stream_info infos3[] = {
179    { 0,    0,  0, },
180};
181
182
183struct drop_test
184{
185    const struct stream_info    *infos;
186    unsigned                     n_infos;
187    unsigned                     high_streams;
188};
189
190
191static const struct drop_test drop_tests[] = {
192    { infos1, 5, 0x7, },
193    { infos2, 5, 0x3, },
194    { infos3, 1, 0x0, },
195};
196
197
198static void
199test_drop (const struct drop_test *test)
200{
201
202    struct lsquic_stream stream_arr[20];
203    unsigned seen_mask, n;
204    struct lsquic_streams_tailq streams;
205    lsquic_stream_t *stream;
206    int drop_high;
207
208    TAILQ_INIT(&streams);
209    for (n = 0; n < test->n_infos; ++n)
210    {
211        stream_arr[n].sm_priority = test->infos[n].prio;
212        stream_arr[n].id          = test->infos[n].stream_id;
213        stream_arr[n].sm_bflags   = SMBF_USE_HEADERS | test->infos[n].bflags;
214    }
215
216    for (drop_high = 0; drop_high < 2; ++drop_high)
217    {
218        TAILQ_INIT(&streams);
219        for (n = 0; n < test->n_infos; ++n)
220            TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream);
221
222        lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
223            TAILQ_LAST(&streams, lsquic_streams_tailq),
224            (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream),
225            SMQF_WRITE_Q_FLAGS, &lconn, __func__, NULL, NULL);
226
227        if (drop_high)
228            lsquic_spi_drop_high(&spi);
229        else
230            lsquic_spi_drop_non_high(&spi);
231
232        seen_mask = 0;
233        for (stream = lsquic_spi_first(&spi); stream;
234                                            stream = lsquic_spi_next(&spi))
235            seen_mask |= 1 << (stream - stream_arr);
236
237        if (test->n_infos == 1)
238            assert(seen_mask == (1u << test->infos[0].stream_id));
239        else if (drop_high)
240            assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask);
241        else
242            assert(test->high_streams == seen_mask);
243    }
244}
245
246
247#define MAGIC 0x12312312U
248
249struct my_filter_ctx
250{
251    unsigned magic;
252};
253
254
255static int
256filter_out_odd_priorities (void *ctx, lsquic_stream_t *stream)
257{
258    struct my_filter_ctx *fctx = ctx;
259    assert(fctx->magic == MAGIC);
260    return 0 == (stream->sm_priority & 1);
261}
262
263
264static void
265test_different_priorities_filter_odd (int *priority)
266{
267    struct lsquic_streams_tailq streams;
268    unsigned flags = 0xC000;     /* Arbitrary value */
269    lsquic_stream_t *stream;
270    int prio, prev_prio, count, n_streams = 0;
271
272    TAILQ_INIT(&streams);
273
274    for ( ; *priority >= 0; ++priority)
275    {
276        assert(*priority < 256);
277        stream = new_stream(*priority);
278        TAILQ_INSERT_TAIL(&streams, stream, next_send_stream);
279        stream->stream_flags |= flags;
280        ++n_streams;
281    }
282
283    struct my_filter_ctx my_filter_ctx = { MAGIC };
284
285    lsquic_spi_init(&spi, TAILQ_FIRST(&streams),
286        TAILQ_LAST(&streams, lsquic_streams_tailq),
287        (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream),
288        flags, &lconn, __func__, filter_out_odd_priorities, &my_filter_ctx);
289
290    for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream;
291                                        stream = lsquic_spi_next(&spi), ++count)
292    {
293        prio = stream->sm_priority;
294        assert(0 == (prio & 1));
295        assert(prio >= prev_prio);
296        if (prio > prev_prio)
297            prev_prio = prio;
298    }
299
300    assert(count < n_streams);
301
302    while ((stream = TAILQ_FIRST(&streams)))
303    {
304        TAILQ_REMOVE(&streams, stream, next_send_stream);
305        free(stream);
306    }
307}
308
309
310int
311main (int argc, char **argv)
312{
313    lsquic_log_to_fstream(stderr, LLTS_NONE);
314    lsq_log_levels[LSQLM_SPI] = LSQ_LOG_DEBUG;
315
316    test_same_priority(0);
317    test_same_priority(99);
318    test_same_priority(255);
319
320    {
321        int prio[] = { 1, 2, 3, 4, 5, 6, 7, -1 };
322        test_different_priorities(prio);
323    }
324
325    {
326        int prio[] = { 7, 6, 5, 4, 3, 2, 1, -1 };
327        test_different_priorities(prio);
328    }
329
330    {
331        int prio[] = { 7, 100, 80, 1, 0, 0, 20, 23, 255, 30, 2, 101, -1 };
332        test_different_priorities(prio);
333    }
334
335    {
336        int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
337        test_different_priorities(prio);
338    }
339
340    {
341        int prio[] = { 200, 202, 240, 201, 200, 199, -1 };
342        test_different_priorities_filter_odd(prio);
343    }
344
345    unsigned n;
346    for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n)
347        test_drop(&drop_tests[n]);
348
349    return 0;
350}
351