test_di_nocopy.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * Test the "nocopy" data in stream
4 */
5
6#include <assert.h>
7#include <stdio.h>
8#include <string.h>
9#include <sys/queue.h>
10#ifdef WIN32
11#include "getopt.h"
12#else
13#include <unistd.h>
14#endif
15
16#include "lsquic.h"
17#include "lsquic_int_types.h"
18#include "lsquic_sfcw.h"
19#include "lsquic_rtt.h"
20#include "lsquic_conn_flow.h"
21#include "lsquic_varint.h"
22#include "lsquic_hq.h"
23#include "lsquic_hash.h"
24#include "lsquic_stream.h"
25#include "lsquic_conn.h"
26#include "lsquic_conn_public.h"
27#include "lsquic_malo.h"
28#include "lsquic_packet_common.h"
29#include "lsquic_packet_in.h"
30#include "lsquic_packet_out.h"
31#include "lsquic_mm.h"
32#include "lsquic_logger.h"
33#include "lsquic_data_in_if.h"
34
35
36struct nocopy_test
37{
38    int     lineno;
39
40    /* Setup: initial set of frames to insert and read until some offset */
41    unsigned            n_init_frames;
42    struct data_frame   initial_frames[5];
43    unsigned            read_until;
44
45    /* Test: data frame to insert and expected insert result */
46    struct data_frame   data_frame;
47    enum ins_frame      ins;
48};
49
50
51#define F(off, size, fin) { .df_offset = (off), .df_fin = (fin), .df_size = (size), }
52
53static const struct nocopy_test tests[] =
54{
55
56    {   .lineno         = __LINE__,
57        .n_init_frames  = 1,
58        .initial_frames = { F(0, 300, 0), },
59        .read_until     = 300,
60        .data_frame     = F(200, 100, 0),
61        .ins            = INS_FRAME_DUP,
62    },
63
64    {   .lineno         = __LINE__,
65        .n_init_frames  = 2,
66        .initial_frames = { F(0, 300, 0), F(300, 100, 0), },
67        .read_until     = 300,
68        .data_frame     = F(200, 100, 0),
69        .ins            = INS_FRAME_DUP,
70    },
71
72    {   .lineno         = __LINE__,
73        .n_init_frames  = 2,
74        .initial_frames = { F(0, 300, 0), F(300, 0, 1), },
75        .read_until     = 300,
76        .data_frame     = F(200, 100, 1),
77        .ins            = INS_FRAME_DUP,
78    },
79
80    {   .lineno         = __LINE__,
81        .n_init_frames  = 1,
82        .initial_frames = { F(0, 301, 0), },
83        .read_until     = 301,
84        .data_frame     = F(200, 100, 1),
85        .ins            = INS_FRAME_ERR,
86    },
87
88    {   .lineno         = __LINE__,
89        .n_init_frames  = 1,
90        .initial_frames = { F(0, 400, 0), },
91        .read_until     = 301,
92        .data_frame     = F(200, 100, 0),
93        .ins            = INS_FRAME_DUP,
94    },
95
96    {   .lineno         = __LINE__,
97        .n_init_frames  = 1,
98        .initial_frames = { F(200, 100, 1), },
99        .read_until     = 0,
100        .data_frame     = F(200, 50, 1),
101        .ins            = INS_FRAME_ERR,
102    },
103
104    {   .lineno         = __LINE__,
105        .n_init_frames  = 1,
106        .initial_frames = { F(200, 100, 1), },
107        .read_until     = 0,
108        .data_frame     = F(200, 150, 1),
109        .ins            = INS_FRAME_ERR,
110    },
111
112    {   .lineno         = __LINE__,
113        .n_init_frames  = 1,
114        .initial_frames = { F(200, 100, 1), },
115        .read_until     = 0,
116        .data_frame     = F(200, 101, 0),
117        .ins            = INS_FRAME_ERR,
118    },
119
120    {   .lineno         = __LINE__,
121        .n_init_frames  = 1,
122        .initial_frames = { F(200, 100, 1), },
123        .read_until     = 0,
124        .data_frame     = F(500, 1, 0),
125        .ins            = INS_FRAME_ERR,
126    },
127
128    {   .lineno         = __LINE__,
129        .n_init_frames  = 1,
130        .initial_frames = { F(0, 100, 0), },
131        .read_until     = 100,
132        .data_frame     = F(0, 100, 1),
133        .ins            = INS_FRAME_OVERLAP,
134    },
135
136    {   .lineno         = __LINE__,
137        .n_init_frames  = 1,
138        .initial_frames = { F(0, 100, 1), },
139        .read_until     = 100,
140        .data_frame     = F(0, 100, 1),
141        .ins            = INS_FRAME_DUP,
142    },
143
144    /* TODO: Case 'F' and 'L' -- remove "case 'F'" */
145    {   .lineno         = __LINE__,
146        .n_init_frames  = 1,
147        .initial_frames = { F(0, 100, 0), },
148        .read_until     = 100,
149        .data_frame     = F(0, 100, 0),
150        .ins            = INS_FRAME_DUP,
151    },
152
153    {   .lineno         = __LINE__,
154        .n_init_frames  = 1,
155        .initial_frames = { F(0, 100, 1), },
156        .read_until     = 10,
157        .data_frame     = F(0, 100, 0),
158        .ins            = INS_FRAME_DUP,
159    },
160
161    {   .lineno         = __LINE__,
162        .n_init_frames  = 1,
163        .initial_frames = { F(0, 100, 0), },
164        .read_until     = 10,
165        .data_frame     = F(0, 100, 1),
166        .ins            = INS_FRAME_OVERLAP,
167    },
168
169    {   .lineno         = __LINE__,
170        .n_init_frames  = 1,
171        .initial_frames = { F(0, 100, 0), },
172        .read_until     = 100,
173        .data_frame     = F(100, 0, 0),
174        .ins            = INS_FRAME_DUP,
175    },
176
177    {   .lineno         = __LINE__,
178        .n_init_frames  = 1,
179        .initial_frames = { F(0, 100, 0), },
180        .read_until     = 0,
181        .data_frame     = F(50, 100, 0),
182        .ins            = INS_FRAME_OVERLAP,
183    },
184
185    {   .lineno         = __LINE__,
186        .n_init_frames  = 1,
187        .initial_frames = { F(0, 100, 1), },
188        .read_until     = 0,
189        .data_frame     = F(50, 100, 0),
190        .ins            = INS_FRAME_ERR,
191    },
192
193    {   .lineno         = __LINE__,
194        .n_init_frames  = 1,
195        .initial_frames = { F(100, 100, 0), },
196        .read_until     = 0,
197        .data_frame     = F(50, 100, 0),
198        .ins            = INS_FRAME_OVERLAP,
199    },
200
201    {   .lineno         = __LINE__,
202        .n_init_frames  = 1,
203        .initial_frames = { F(100, 100, 0), },
204        .read_until     = 0,
205        .data_frame     = F(50, 100, 1),
206        .ins            = INS_FRAME_OVERLAP,    /* This is really an error,
207                                                 * but we ignore it.
208                                                 */
209    },
210
211    {   .lineno         = __LINE__,
212        .n_init_frames  = 1,
213        .initial_frames = { F(100, 100, 1), },
214        .read_until     = 0,
215        .data_frame     = F(50, 100, 0),
216        .ins            = INS_FRAME_OVERLAP,
217    },
218
219    {   .lineno         = __LINE__,
220        .n_init_frames  = 1,
221        .initial_frames = { F(0, 100, 1), },
222        .read_until     = 60,
223        .data_frame     = F(50, 2, 0),
224        .ins            = INS_FRAME_DUP,
225    },
226
227    {   .lineno         = __LINE__,
228        .n_init_frames  = 2,
229        .initial_frames = { F(0, 100, 0), F(200, 100, 0), },
230        .read_until     = 0,
231        .data_frame     = F(50, 200, 0),
232        .ins            = INS_FRAME_OVERLAP,
233    },
234
235    {   .lineno         = __LINE__,
236        .n_init_frames  = 2,
237        .initial_frames = { F(0, 100, 0), F(200, 100, 0), },
238        .read_until     = 0,
239        .data_frame     = F(100, 100, 0),
240        .ins            = INS_FRAME_OK,
241    },
242
243    {   .lineno         = __LINE__,
244        .n_init_frames  = 2,
245        .initial_frames = { F(0, 100, 0), F(200, 100, 0), },
246        .read_until     = 0,
247        .data_frame     = F(100, 100, 1),
248        .ins            = INS_FRAME_OK,     /* Ignore another error */
249    },
250
251    {   .lineno         = __LINE__,
252        .n_init_frames  = 2,
253        .initial_frames = { F(0, 60, 0), F(60, 60, 0), },
254        .read_until     = 120,
255        .data_frame     = F(0, 180, 0),
256        .ins            = INS_FRAME_OVERLAP,
257    },
258
259    {   .lineno         = __LINE__,
260        .n_init_frames  = 3,
261        .initial_frames = { F(0, 60, 0), F(60, 60, 0), F(180, 60, 0), },
262        .read_until     = 120,
263        .data_frame     = F(0, 180, 0),
264        .ins            = INS_FRAME_OVERLAP,
265    },
266
267};
268
269
270static void
271run_di_nocopy_test (const struct nocopy_test *test)
272{
273    struct lsquic_mm mm;
274    struct lsquic_conn_public conn_pub;
275    struct lsquic_conn conn;
276    struct stream_frame *frame;
277    struct data_in *di;
278    struct data_frame *data_frame;
279    enum ins_frame ins;
280    unsigned i;
281    unsigned nread, n_to_read;
282
283    LSQ_NOTICE("running test on line %d", test->lineno);
284
285    lsquic_mm_init(&mm);
286    memset(&conn, 0, sizeof(conn));
287    conn_pub.lconn = &conn;
288    conn_pub.mm = &mm;
289
290    di = lsquic_data_in_nocopy_new(&conn_pub, 3);
291
292    for (i = 0; i < test->n_init_frames; ++i)
293    {
294        frame = lsquic_malo_get(mm.malo.stream_frame);
295        frame->packet_in = lsquic_mm_get_packet_in(&mm);
296        frame->packet_in->pi_refcnt = 1;
297        frame->data_frame = test->initial_frames[i];
298        ins = di->di_if->di_insert_frame(di, frame, 0);
299        assert(INS_FRAME_OK == ins);    /* Self-test */
300    }
301
302    nread = 0;
303    while (nread < test->read_until)
304    {
305        data_frame = di->di_if->di_get_frame(di, nread);
306        assert(data_frame);  /* Self-check */
307        n_to_read = test->read_until - nread > (unsigned) data_frame->df_size - data_frame->df_read_off
308                            ? (unsigned) data_frame->df_size - data_frame->df_read_off : test->read_until - nread;
309        data_frame->df_read_off += n_to_read;
310        nread += n_to_read;
311        if (data_frame->df_read_off == data_frame->df_size)
312            di->di_if->di_frame_done(di, data_frame);
313        else
314        {
315            assert(nread == test->read_until);
316            break;
317        }
318    }
319
320    frame = lsquic_malo_get(mm.malo.stream_frame);
321    frame->packet_in = lsquic_mm_get_packet_in(&mm);
322    frame->packet_in->pi_refcnt = 1;
323    frame->data_frame = test->data_frame;
324    ins = di->di_if->di_insert_frame(di, frame, test->read_until);
325    assert(test->ins == ins);
326
327    di->di_if->di_destroy(di);
328    lsquic_mm_cleanup(&mm);
329}
330
331
332int
333main (int argc, char **argv)
334{
335    const struct nocopy_test *test;
336    int opt;
337
338    lsquic_log_to_fstream(stderr, LLTS_NONE);
339
340    while (-1 != (opt = getopt(argc, argv, "l:")))
341    {
342        switch (opt)
343        {
344        case 'l':
345            lsquic_logger_lopt(optarg);
346            break;
347        default:
348            return 1;
349        }
350    }
351
352    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
353        run_di_nocopy_test(test);
354
355    return 0;
356}
357