1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <sys/queue.h> 7#ifndef WIN32 8#include <sys/time.h> 9#endif 10 11#include "lsquic.h" 12#include "lsquic_types.h" 13#include "lsquic_parse.h" 14#include "lsquic_sfcw.h" 15#include "lsquic_varint.h" 16#include "lsquic_hq.h" 17#include "lsquic_hash.h" 18#include "lsquic_stream.h" 19 20struct test { 21 int lineno; 22 const struct parse_funcs * 23 pf; 24 /* Inputs. These are returned by lsquic_stream_tosend_fin(), 25 * lsquic_stream_tosend_read(), and lsquic_stream_tosend_offset(). 26 */ 27 int fin[2]; /* There may be two calls to lsquic_stream_tosend_fin() */ 28 uint64_t offset; 29 uint32_t stream_id; 30 size_t avail; /* Space to write stream frame to */ 31 size_t min_sz; /* Minimum size needed to generate stream frame. Any 32 * sizes smaller than this should fail. 33 */ 34 size_t data_sz; 35 char data[0x100]; 36 37 /* Output. This is how we expect the resulting frame to look. 38 */ 39 int len; /* Return value of gen_stream_frame() */ 40 char out[0x100]; 41}; 42 43 44static struct test_ctx { 45 const struct test *test; 46 int next_fin; 47 lsquic_stream_t stream; 48} test_ctx; 49 50 51static int 52stream_tosend_fin (void *stream) 53{ 54 struct test_ctx *test_ctx2 = stream; 55 return test_ctx2->test->fin[ test_ctx2->next_fin++ ]; 56} 57 58 59static size_t 60stream_tosend_read (void *stream, void *buf, size_t len, int *reached_fin) 61{ 62 struct test_ctx *test_ctx2 = stream; 63 if (test_ctx2->test->data_sz < len) 64 len = test_ctx2->test->data_sz; 65 memcpy(buf, test_ctx2->test->data, len); 66 *reached_fin = stream_tosend_fin(stream); 67 return len; 68} 69 70 71static size_t 72stream_tosend_size (void *stream) 73{ 74 struct test_ctx *test_ctx2 = stream; 75 return test_ctx2->test->data_sz; 76} 77 78 79static void 80reset_ctx (const struct test *test) 81{ 82 test_ctx.test = test; 83 test_ctx.next_fin = 0; 84 test_ctx.stream.id = test->stream_id; 85} 86 87 88static void 89run_test (const struct test *const test) 90{ 91 92 unsigned char out[0x100]; 93 int len; 94 size_t min; 95 96 if (test->len > 0) 97 { 98 /* Test that all sizes under specified min fail to produce a frame */ 99 for (min = 0; min < test->min_sz; ++min) 100 { 101 reset_ctx(test); 102 len = test->pf->pf_gen_stream_frame(out, min, test->stream_id, 103 test_ctx.test->offset, stream_tosend_fin(&test_ctx), 104 stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx); 105 assert(len < 0); 106 } 107 108 /* Test that it succeeds now: */ 109 reset_ctx(test); 110 len = test->pf->pf_gen_stream_frame(out, min, test->stream_id, 111 test_ctx.test->offset, stream_tosend_fin(&test_ctx), 112 stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx); 113 assert(len == (int) min); 114 } 115 116 reset_ctx(test); 117 len = test->pf->pf_gen_stream_frame(out, test->avail, test->stream_id, 118 test_ctx.test->offset, stream_tosend_fin(&test_ctx), 119 stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx); 120 121 if (test->len > 0) { 122 /* Check parser operation */ 123 assert(test->len == len); 124 assert(("Generated frame is correct", 0 == memcmp(test->out, out, test->len))); 125 } 126 else 127 { 128 assert(("This test should fail", len < 0)); 129 } 130} 131 132 133int 134main (void) 135{ 136 const struct test tests[] = { 137 /* 138 * Big-endian: 139 */ 140 { .lineno = __LINE__, 141 .pf = select_pf_by_ver(LSQVER_043), 142 .fin = { 0, 1, }, 143 .offset = 0x0807060504030201UL, 144 .stream_id = 0x210, 145 .data_sz = 10, 146 .data = "0123456789", 147 .avail = 0x100, 148 .out = 149 /* 1 f d ooo ss 1fdoooss */ 150 /* TYPE FIN DLEN OLEN SLEN */ 151 { 0x80 | 0x40 | 0x20 | 0x1C | 0x01, 152 0x02, 0x10, /* Stream ID */ 153 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 154 0x00, 0x0A, /* Data length */ 155 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 156 }, 157 .len = 1 + 2 + 8 + 2 + 10, 158 .min_sz = 1 + 2 + 8 + 0 + 1, 159 }, 160 161 { .lineno = __LINE__, 162 .pf = select_pf_by_ver(LSQVER_043), 163 .fin = { 0, 0, }, 164 .offset = 0x0807060504030201UL, 165 .stream_id = 0x210, 166 .data_sz = 10, 167 .data = "0123456789", 168 .avail = 0x100, 169 .out = 170 /* 1 f d ooo ss 1fdoooss */ 171 /* TYPE FIN DLEN OLEN SLEN */ 172 { 0x80 | 0x00 | 0x20 | 0x1C | 0x01, 173 0x02, 0x10, /* Stream ID */ 174 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 175 0x00, 0x0A, /* Data length */ 176 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 177 }, 178 .len = 1 + 2 + 8 + 2 + 10, 179 .min_sz = 1 + 2 + 8 + 0 + 1, 180 }, 181 182 { .lineno = __LINE__, 183 .pf = select_pf_by_ver(LSQVER_043), 184 .fin = { 1, 0, }, 185 .offset = 0x0807060504030201UL, 186 .stream_id = 0x210, 187 .data_sz = 10, 188 .data = "0123456789", 189 .avail = 0x100, 190 .out = 191 /* 1 f d ooo ss 1fdoooss */ 192 /* TYPE FIN DLEN OLEN SLEN */ 193 { 0x80 | 0x40 | 0x20 | 0x1C | 0x01, 194 0x02, 0x10, /* Stream ID */ 195 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 196 0x00, 0x00, /* Data length */ 197 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 198 }, 199 .len = 1 + 2 + 8 + 2, 200 .min_sz = 1 + 2 + 8 + 2, 201 }, 202 203 { .lineno = __LINE__, 204 .pf = select_pf_by_ver(LSQVER_043), 205 .fin = { 1, 0, }, 206 .offset = 0x0807060504030201UL, 207 .stream_id = 0x21, 208 .data_sz = 10, 209 .data = "0123456789", 210 .avail = 0x100, 211 .out = 212 /* 1 f d ooo ss 1fdoooss */ 213 /* TYPE FIN DLEN OLEN SLEN */ 214 { 0x80 | 0x40 | 0x20 | 0x1C | 0x00, 215 0x21, /* Stream ID */ 216 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 217 0x00, 0x00, /* Data length */ 218 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 219 }, 220 .len = 1 + 1 + 8 + 2, 221 .min_sz = 1 + 1 + 8 + 2, 222 }, 223 224 { .lineno = __LINE__, 225 .pf = select_pf_by_ver(LSQVER_043), 226 .fin = { 0, 0, }, 227 .offset = 0x77, 228 .stream_id = 0x210, 229 .data_sz = 10, 230 .data = "0123456789", 231 .avail = 0x100, 232 .out = 233 /* 1 f d ooo ss 1fdoooss */ 234 /* TYPE FIN DLEN OLEN SLEN */ 235 { 0x80 | 0x00 | 0x20 | 0x04 | 0x01, 236 0x02, 0x10, /* Stream ID */ 237 0x00, 0x77, /* Offset */ 238 0x00, 0x0A, /* Data length */ 239 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 240 }, 241 .len = 1 + 2 + 2 + 2 + 10, 242 .min_sz = 1 + 2 + 2 + 0 + 1, 243 }, 244 245 { .lineno = __LINE__, 246 .pf = select_pf_by_ver(LSQVER_043), 247 .fin = { 0, 0, }, 248 .offset = 0x0, 249 .stream_id = 0x210, 250 .data_sz = 10, 251 .data = "0123456789", 252 .avail = 0x100, 253 .out = 254 /* 1 f d ooo ss 1fdoooss */ 255 /* TYPE FIN DLEN OLEN SLEN */ 256 { 0x80 | 0x00 | 0x20 | 0x00 | 0x01, 257 0x02, 0x10, /* Stream ID */ 258 /* Offset */ 259 0x00, 0x0A, /* Data length */ 260 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 261 }, 262 .len = 1 + 2 + 0 + 2 + 10, 263 .min_sz = 1 + 2 + 0 + 0 + 1, 264 }, 265 266 { .lineno = __LINE__, 267 .pf = select_pf_by_ver(LSQVER_043), 268 .fin = { 0, 1, }, 269 .offset = 0x0, 270 .stream_id = 0x210, 271 .data_sz = 1, 272 .data = "0123456789", 273 .avail = 0x100, 274 .out = 275 /* 1 f d ooo ss 1fdoooss */ 276 /* TYPE FIN DLEN OLEN SLEN */ 277 { 0x80 | 0x40 | 0x20 | 0x00 | 0x01, 278 0x02, 0x10, /* Stream ID */ 279 /* Offset */ 280 0x00, 0x01, /* Data length */ 281 '0', 282 }, 283 .len = 1 + 2 + 0 + 2 + 1, 284 .min_sz = 1 + 2 + 0 + 0 + 1, 285 }, 286 287 { .lineno = __LINE__, 288 .pf = select_pf_by_ver(LSQVER_043), 289 .fin = { 0, 0, }, 290 .offset = 0xFFFFFF, 291 .stream_id = 0x210, 292 .data_sz = 10, 293 .data = "0123456789", 294 .avail = 0x100, 295 .out = 296 /* 1 f d ooo ss 1fdoooss */ 297 /* TYPE FIN DLEN OLEN SLEN */ 298 { 0x80 | 0x00 | 0x20 | 0x08 | 0x01, 299 0x02, 0x10, /* Stream ID */ 300 0xFF, 0xFF, 0xFF, /* Offset */ 301 0x00, 0x0A, /* Data length */ 302 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 303 }, 304 .len = 1 + 2 + 3 + 2 + 10, 305 .min_sz = 1 + 2 + 3 + 0 + 1, 306 }, 307 308 { .lineno = __LINE__, 309 .pf = select_pf_by_ver(LSQVER_043), 310 .fin = { 0, 0, }, 311 .offset = 0xFFFFFF + 1, 312 .stream_id = 0x210, 313 .data_sz = 10, 314 .data = "0123456789", 315 .avail = 0x100, 316 .out = 317 /* 1 f d ooo ss 1fdoooss */ 318 /* TYPE FIN DLEN OLEN SLEN */ 319 { 0x80 | 0x00 | 0x20 | 0x0C | 0x01, 320 0x02, 0x10, /* Stream ID */ 321 0x01, 0x00, 0x00, 0x00, /* Offset */ 322 0x00, 0x0A, /* Data length */ 323 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 324 }, 325 .len = 1 + 2 + 4 + 2 + 10, 326 .min_sz = 1 + 2 + 4 + 0 + 1, 327 }, 328 329 { .lineno = __LINE__, 330 .pf = select_pf_by_ver(LSQVER_043), 331 .fin = { 0, 0, }, 332 .offset = 0xFFFFFF + 1, 333 .stream_id = 0x210, 334 .data_sz = 10, 335 .data = "0123456789", 336 .avail = 10, 337 .out = 338 /* 1 f d ooo ss 1fdoooss */ 339 /* TYPE FIN DLEN OLEN SLEN */ 340 { 0x80 | 0x00 | 0x00 | 0x0C | 0x01, 341 0x02, 0x10, /* Stream ID */ 342 0x01, 0x00, 0x00, 0x00, /* Offset */ 343 '0', '1', '2', 344 }, 345 .len = 1 + 2 + 4 + 0 + 3, 346 .min_sz = 1 + 2 + 4 + 0 + 1, 347 }, 348 349 { .lineno = __LINE__, 350 .pf = select_pf_by_ver(LSQVER_043), 351 .fin = { 1, 0, }, 352 .offset = 0xB4, 353 .stream_id = 0x01, 354 .data_sz = 0, 355 .data = "0123456789", 356 .avail = 0x100, 357 .out = 358 /* 1 f d ooo ss 1fdoooss */ 359 /* TYPE FIN DLEN OLEN SLEN */ 360 { 0x80 | 0x40 | 0x20 | 0x04 | 0x00, 361 0x01, /* Stream ID */ 362 0x00, 0xB4, /* Offset */ 363 0x00, 0x00, /* Data length */ 364 }, 365 .len = 6, 366 .min_sz = 6, 367 }, 368 369 /* 370 * IETF QUIC Internet-Draft 17: 371 */ 372 373 { .lineno = __LINE__, 374 .pf = select_pf_by_ver(LSQVER_ID27), 375 .fin = { 0, 1, }, 376 .offset = 0x0807060504030201UL, 377 .stream_id = 0x210, 378 .data_sz = 10, 379 .data = "0123456789", 380 .avail = 0x100, 381 .out = 382 /* TYPE OFF DLEN FIN */ 383 { 0x08 | 1<<2 | 1<<1 | 1<<0, 384 0x42, 0x10, /* Stream ID */ 385 0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 386 0x0A, /* Data length */ 387 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 388 }, 389 .len = 1 + 2 + 8 + 1 + 10, 390 .min_sz = 1 + 2 + 8 + 0 + 1, 391 }, 392 393 { .lineno = __LINE__, 394 .pf = select_pf_by_ver(LSQVER_ID27), 395 .fin = { 0, 0, }, 396 .offset = 0, 397 .stream_id = 0x210, 398 .data_sz = 10, 399 .data = "0123456789", 400 .avail = 0x100, 401 .out = 402 /* TYPE OFF DLEN FIN */ 403 { 0x08 | 0<<2 | 1<<1 | 0<<0, 404 0x42, 0x10, /* Stream ID */ 405 0x0A, /* Data length */ 406 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 407 }, 408 .len = 1 + 2 + 0 + 1 + 10, 409 .min_sz = 1 + 2 + 0 + 0 + 1, 410 }, 411 412 { .lineno = __LINE__, 413 .pf = select_pf_by_ver(LSQVER_ID27), 414 .fin = { 0, 0, }, 415 .offset = 0, 416 .stream_id = 0x21, 417 .data_sz = 10, 418 .data = "0123456789", 419 .avail = 12, 420 .out = 421 /* TYPE OFF DLEN FIN */ 422 { 0x08 | 0<<2 | 0<<1 | 0<<0, 423 0x21, /* Stream ID */ 424 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 425 }, 426 .len = 1 + 1 + 0 + 0 + 10, 427 .min_sz = 1 + 1 + 0 + 0 + 1, 428 }, 429 430 { .lineno = __LINE__, 431 .pf = select_pf_by_ver(LSQVER_ID27), 432 .fin = { 0, 0, }, 433 .offset = 0x0807060504030201UL, 434 .stream_id = 0x210, 435 .data_sz = 10, 436 .data = "0123456789", 437 .avail = 0x100, 438 .out = 439 /* TYPE OFF DLEN FIN */ 440 { 0x08 | 1<<2 | 1<<1 | 0<<0, 441 0x42, 0x10, /* Stream ID */ 442 0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 443 0x0A, /* Data length */ 444 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 445 }, 446 .len = 1 + 2 + 8 + 1 + 10, 447 .min_sz = 1 + 2 + 8 + 0 + 1, 448 }, 449 450 { .lineno = __LINE__, 451 .pf = select_pf_by_ver(LSQVER_ID27), 452 .fin = { 1, 0, }, 453 .offset = 0x0807060504030201UL, 454 .stream_id = 0x210, 455 .data_sz = 0, 456 .data = "0123456789", 457 .avail = 11, 458 .out = 459 /* TYPE OFF DLEN FIN */ 460 { 0x08 | 1<<2 | 0<<1 | 1<<0, 461 0x42, 0x10, /* Stream ID */ 462 0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 463 }, 464 .len = 1 + 2 + 8, 465 .min_sz = 1 + 2 + 8, 466 }, 467 468 { .lineno = __LINE__, 469 .pf = select_pf_by_ver(LSQVER_ID27), 470 .fin = { 1, 0, }, 471 .offset = 0x0807060504030201UL, 472 .stream_id = 0x210, 473 .data_sz = 0, 474 .data = "0123456789", 475 .avail = 0x100, 476 .out = 477 /* TYPE OFF DLEN FIN */ 478 { 0x08 | 1<<2 | 1<<1 | 1<<0, 479 0x42, 0x10, /* Stream ID */ 480 0xC8, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, /* Offset */ 481 0x00, /* Data length */ 482 }, 483 .len = 1 + 2 + 8 + 1, 484 .min_sz = 1 + 2 + 8, 485 }, 486 487 }; 488 489 unsigned i; 490 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) 491 run_test(&tests[i]); 492 return 0; 493} 494