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