test_elision.c revision a74702c6
1/* Copyright (c) 2017 - 2022 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 9#include "lsquic.h" 10 11#include "lsquic_int_types.h" 12#include "lsquic_packet_common.h" 13#include "lsquic_packet_gquic.h" 14#include "lsquic_packet_out.h" 15#include "lsquic_parse.h" 16#include "lsquic_conn_flow.h" 17#include "lsquic_sfcw.h" 18#include "lsquic_varint.h" 19#include "lsquic_hq.h" 20#include "lsquic_hash.h" 21#include "lsquic_stream.h" 22#include "lsquic_types.h" 23#include "lsquic_malo.h" 24#include "lsquic_mm.h" 25#include "lsquic_engine_public.h" 26#include "lsquic_logger.h" 27 28 29//static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_043); // will not work on MSVC 30#define pf ((const struct parse_funcs *const)select_pf_by_ver(LSQVER_043)) 31 32static struct { 33 unsigned char buf[0x1000]; 34 size_t bufsz; 35 uint64_t off; 36} stream_contents; 37 38 39void 40setup_stream_contents (uint64_t off, const char *str) 41{ 42 stream_contents.bufsz = strlen(str); 43 stream_contents.off = off; 44 memcpy(stream_contents.buf, str, stream_contents.bufsz); 45} 46 47 48void 49setup_stream_contents_n (uint64_t off, const unsigned char *buf, size_t size) 50{ 51 stream_contents.bufsz = size; 52 stream_contents.off = off; 53 memcpy(stream_contents.buf, buf, size); 54} 55 56 57int 58lsquic_stream_tosend_fin (const lsquic_stream_t *stream) 59{ 60 return 0; 61} 62 63 64uint64_t 65lsquic_stream_tosend_offset (const lsquic_stream_t *stream) 66{ 67 return stream_contents.off; 68} 69 70 71size_t 72lsquic_stream_tosend_read (lsquic_stream_t *stream, void *buf, size_t len, 73 int *reached_fin) 74{ 75 if (stream_contents.bufsz < len) 76 len = stream_contents.bufsz; 77 memcpy(buf, stream_contents.buf, len); 78 *reached_fin = lsquic_stream_tosend_fin(stream); 79 return len; 80} 81 82 83size_t 84lsquic_stream_tosend_sz (const lsquic_stream_t *stream) 85{ 86 return stream_contents.bufsz; 87} 88 89 90void 91lsquic_stream_acked (lsquic_stream_t *stream, enum quic_frame_type frame_type) 92{ 93 --stream->n_unacked; 94} 95 96 97static void 98elide_single_stream_frame (void) 99{ 100 struct packet_out_frec_iter pofi; 101 struct lsquic_engine_public enpub; 102 lsquic_stream_t streams[1]; 103 lsquic_packet_out_t *packet_out; 104 int len, off = 0; 105 106 memset(streams, 0, sizeof(streams)); 107 memset(&enpub, 0, sizeof(enpub)); 108 lsquic_mm_init(&enpub.enp_mm); 109 packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ); 110 111 setup_stream_contents(123, "Dude, where is my car?"); 112 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 113 lsquic_packet_out_avail(packet_out), 114 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 115 lsquic_stream_tosend_fin(&streams[0]), 116 lsquic_stream_tosend_sz(&streams[0]), 117 (gsf_read_f) lsquic_stream_tosend_read, 118 &streams[0]); 119 packet_out->po_data_sz += len; 120 packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM); 121 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 122 QUIC_FRAME_STREAM, off, len); 123 assert(1 == streams[0].n_unacked); 124 assert(lsquic_pofi_first(&pofi, packet_out)); 125 126 streams[0].stream_flags |= STREAM_RST_SENT; 127 128 lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX); 129 assert(0 == streams[0].n_unacked); 130 assert(0 == packet_out->po_frame_types); 131 assert(!lsquic_pofi_first(&pofi, packet_out)); 132 133 lsquic_packet_out_destroy(packet_out, &enpub, NULL); 134 lsquic_mm_cleanup(&enpub.enp_mm); 135} 136 137 138/* In this test, we check that if the last STREAM frame is moved due to 139 * elision and PO_STREAM_END is set, the packet size is adjusted. This 140 * is needed to prevent data corruption for STREAM frames that have 141 * implicit length. 142 */ 143static void 144shrink_packet_post_elision (void) 145{ 146 struct packet_out_frec_iter pofi; 147 struct lsquic_engine_public enpub; 148 lsquic_stream_t streams[2]; 149 lsquic_packet_out_t *packet_out; 150 const struct frame_rec *frec; 151 int len, off = 0; 152 unsigned char stream2_data[0x1000]; 153 154 memset(stream2_data, '2', sizeof(stream2_data)); 155 memset(streams, 0, sizeof(streams)); 156 memset(&enpub, 0, sizeof(enpub)); 157 lsquic_mm_init(&enpub.enp_mm); 158 packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ); 159 160 setup_stream_contents(123, "Dude, where is my car?"); 161 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 162 lsquic_packet_out_avail(packet_out), 163 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 164 lsquic_stream_tosend_fin(&streams[0]), 165 lsquic_stream_tosend_sz(&streams[0]), 166 (gsf_read_f) lsquic_stream_tosend_read, 167 &streams[0]); 168 packet_out->po_data_sz += len; 169 packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM); 170 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 171 QUIC_FRAME_STREAM, off, len); 172 173 /* We want to fill the packet just right so that PO_STREAM_END gets set */ 174 const int exp = lsquic_packet_out_avail(packet_out); 175 setup_stream_contents_n(0, stream2_data, exp - 2); 176 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 177 lsquic_packet_out_avail(packet_out), 178 streams[1].id, lsquic_stream_tosend_offset(&streams[1]), 179 lsquic_stream_tosend_fin(&streams[1]), 180 lsquic_stream_tosend_sz(&streams[1]), 181 (gsf_read_f) lsquic_stream_tosend_read, 182 &streams[1]); 183 assert(len == exp); 184 packet_out->po_data_sz += len; 185 packet_out->po_frame_types |= (1 << QUIC_FRAME_STREAM); 186 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], 187 QUIC_FRAME_STREAM, off, len); 188 assert(0 == lsquic_packet_out_avail(packet_out)); /* Same as len == exp check really */ 189 packet_out->po_flags |= PO_STREAM_END; 190 191 assert(1 == streams[0].n_unacked); 192 assert(1 == streams[1].n_unacked); 193 assert(lsquic_pofi_first(&pofi, packet_out)); 194 195 streams[0].stream_flags |= STREAM_RST_SENT; 196 197 lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX); 198 assert(0 == streams[0].n_unacked); 199 200 assert(QUIC_FTBIT_STREAM == packet_out->po_frame_types); 201 frec = lsquic_pofi_first(&pofi, packet_out); 202 assert(frec->fe_stream == &streams[1]); 203 assert(packet_out->po_data_sz == exp); 204 205 lsquic_packet_out_destroy(packet_out, &enpub, NULL); 206 lsquic_mm_cleanup(&enpub.enp_mm); 207} 208 209 210/* This test is more involved. We will construct the following packet: 211 * 212 * | ACK | STREAM A | STREAM B | STREAM C | RST A | STREAM D | STREAM E 213 * 214 * and elide STREAM A, STREAM C, and STREAM E to get 215 * 216 * | ACK | STREAM B | RST A | STREAM D | 217 * 218 * If `chop_regen' is set, ACK is dropped (this tests what happens when 219 * packet is resent). 220 * 221 * This should test most of the corner cases. 222 */ 223static void 224elide_three_stream_frames (int chop_regen) 225{ 226 struct packet_out_frec_iter pofi; 227 struct lsquic_engine_public enpub; 228 lsquic_stream_t streams[5]; 229 lsquic_packet_out_t *packet_out, *ref_out; 230 struct frame_rec *frec; 231 unsigned short b_off, d_off; 232 int len; 233 234 memset(streams, 0, sizeof(streams)); 235 memset(&enpub, 0, sizeof(enpub)); 236 lsquic_mm_init(&enpub.enp_mm); 237 238 /* First, we construct the reference packet. We will only use it to 239 * compare payload and sizes: 240 */ 241 { 242 ref_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ); 243 /* This is fake data for regeneration */ 244 strcpy((char *) ref_out->po_data, "REGEN"); 245 lsquic_packet_out_add_frame(ref_out, &enpub.enp_mm, 0, 246 QUIC_FRAME_ACK, ref_out->po_data_sz, 5); 247 ref_out->po_data_sz = ref_out->po_regen_sz = 5; 248 /* STREAM B */ 249 setup_stream_contents(123, "BBBBBBBBBB"); 250 streams[0].id = 'B'; 251 len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz, 252 lsquic_packet_out_avail(ref_out), 253 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 254 lsquic_stream_tosend_fin(&streams[0]), 255 lsquic_stream_tosend_sz(&streams[0]), 256 (gsf_read_f) lsquic_stream_tosend_read, 257 &streams[0]); 258 b_off = ref_out->po_data_sz; 259 ref_out->po_data_sz += len; 260 len = pf->pf_gen_rst_frame(ref_out->po_data + ref_out->po_data_sz, 261 lsquic_packet_out_avail(ref_out), 'A', 133, 0); 262 ref_out->po_data_sz += len; 263 /* STREAM D */ 264 setup_stream_contents(123, "DDDDDDDDDD"); 265 streams[0].id = 'D'; 266 len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz, 267 lsquic_packet_out_avail(ref_out), 268 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 269 lsquic_stream_tosend_fin(&streams[0]), 270 lsquic_stream_tosend_sz(&streams[0]), 271 (gsf_read_f) lsquic_stream_tosend_read, 272 &streams[0]); 273 d_off = ref_out->po_data_sz; 274 ref_out->po_data_sz += len; 275 } 276 277 /* Construct packet from which we will elide streams. Here, we attach 278 * stream objects to the packet. 279 */ 280 { 281 packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ); 282 /* This is fake data for regeneration */ 283 strcpy((char *) packet_out->po_data, "REGEN"); 284 lsquic_packet_out_add_frame(packet_out, &enpub.enp_mm, 0, 285 QUIC_FRAME_ACK, packet_out->po_data_sz, 5); 286 packet_out->po_data_sz = packet_out->po_regen_sz = 5; 287 /* STREAM A */ 288 setup_stream_contents(123, "AAAAAAAAAA"); 289 streams[0].id = 'A'; 290 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 291 lsquic_packet_out_avail(packet_out), 292 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 293 lsquic_stream_tosend_fin(&streams[0]), 294 lsquic_stream_tosend_sz(&streams[0]), 295 (gsf_read_f) lsquic_stream_tosend_read, 296 &streams[0]); 297 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 298 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 299 packet_out->po_data_sz += len; 300 /* STREAM B */ 301 setup_stream_contents(123, "BBBBBBBBBB"); 302 streams[1].id = 'B'; 303 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 304 lsquic_packet_out_avail(packet_out), 305 streams[1].id, lsquic_stream_tosend_offset(&streams[1]), 306 lsquic_stream_tosend_fin(&streams[1]), 307 lsquic_stream_tosend_sz(&streams[1]), 308 (gsf_read_f) lsquic_stream_tosend_read, 309 &streams[1]); 310 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], 311 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 312 packet_out->po_data_sz += len; 313 /* STREAM C */ 314 setup_stream_contents(123, "CCCCCCCCCC"); 315 streams[2].id = 'C'; 316 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 317 lsquic_packet_out_avail(packet_out), 318 streams[2].id, lsquic_stream_tosend_offset(&streams[2]), 319 lsquic_stream_tosend_fin(&streams[2]), 320 lsquic_stream_tosend_sz(&streams[2]), 321 (gsf_read_f) lsquic_stream_tosend_read, 322 &streams[2]); 323 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2], 324 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 325 packet_out->po_data_sz += len; 326 /* Reset A */ 327 len = pf->pf_gen_rst_frame(packet_out->po_data + packet_out->po_data_sz, 328 lsquic_packet_out_avail(packet_out), 'A', 133, 0); 329 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 330 QUIC_FRAME_RST_STREAM, packet_out->po_data_sz, len); 331 packet_out->po_data_sz += len; 332 /* STREAM D */ 333 setup_stream_contents(123, "DDDDDDDDDD"); 334 streams[3].id = 'D'; 335 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 336 lsquic_packet_out_avail(packet_out), 337 streams[3].id, lsquic_stream_tosend_offset(&streams[3]), 338 lsquic_stream_tosend_fin(&streams[3]), 339 lsquic_stream_tosend_sz(&streams[3]), 340 (gsf_read_f) lsquic_stream_tosend_read, 341 &streams[3]); 342 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3], 343 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 344 packet_out->po_data_sz += len; 345 /* STREAM E */ 346 setup_stream_contents(123, "EEEEEEEEEE"); 347 streams[4].id = 'E'; 348 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 349 lsquic_packet_out_avail(packet_out), 350 streams[4].id, lsquic_stream_tosend_offset(&streams[4]), 351 lsquic_stream_tosend_fin(&streams[4]), 352 lsquic_stream_tosend_sz(&streams[4]), 353 (gsf_read_f) lsquic_stream_tosend_read, 354 &streams[4]); 355 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4], 356 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 357 packet_out->po_data_sz += len; 358 packet_out->po_frame_types = (1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM); 359 } 360 361 /* Reset streams A, C, and E: */ 362 streams[0].stream_flags |= STREAM_RST_SENT; 363 streams[2].stream_flags |= STREAM_RST_SENT; 364 streams[4].stream_flags |= STREAM_RST_SENT; 365 366 if (chop_regen) 367 lsquic_packet_out_chop_regen(packet_out); 368 lsquic_packet_out_elide_reset_stream_frames(packet_out, UINT64_MAX); 369 370 assert(ref_out->po_data_sz == packet_out->po_data_sz + (chop_regen ? 5 : 0)); 371 assert(ref_out->po_regen_sz == packet_out->po_regen_sz + (chop_regen ? 5 : 0)); 372 if (chop_regen) 373 assert(0 == memcmp(ref_out->po_data + 5, packet_out->po_data, packet_out->po_data_sz)); 374 else 375 assert(0 == memcmp(ref_out->po_data, packet_out->po_data, packet_out->po_data_sz)); 376 377 assert(1 == streams[0].n_unacked); /* Still has RST outstanding */ 378 assert(1 == streams[1].n_unacked); 379 assert(0 == streams[2].n_unacked); 380 assert(1 == streams[3].n_unacked); 381 assert(0 == streams[4].n_unacked); 382 383 assert(packet_out->po_frame_types == ((1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM))); 384 385 frec = lsquic_pofi_first(&pofi, packet_out); 386 if (!chop_regen) 387 frec = lsquic_pofi_next(&pofi); 388 assert(frec->fe_stream == &streams[1]); 389 assert(frec->fe_frame_type == QUIC_FRAME_STREAM); 390 assert(frec->fe_off == b_off - (chop_regen ? 5 : 0)); 391 392 frec = lsquic_pofi_next(&pofi); 393 assert(frec->fe_stream == &streams[0]); 394 assert(frec->fe_frame_type == QUIC_FRAME_RST_STREAM); 395 396 frec = lsquic_pofi_next(&pofi); 397 assert(frec->fe_stream == &streams[3]); 398 assert(frec->fe_frame_type == QUIC_FRAME_STREAM); 399 assert(frec->fe_off == d_off - (chop_regen ? 5 : 0)); 400 401 frec = lsquic_pofi_next(&pofi); 402 assert(!frec); 403 404 lsquic_packet_out_destroy(packet_out, &enpub, NULL); 405 lsquic_packet_out_destroy(ref_out, &enpub, NULL); 406 lsquic_mm_cleanup(&enpub.enp_mm); 407} 408 409 410int 411main (void) 412{ 413 /* TODO-ENDIAN: test with every PF */ 414 elide_single_stream_frame(); 415 shrink_packet_post_elision(); 416 elide_three_stream_frames(0); 417 elide_three_stream_frames(1); 418 419 return 0; 420} 421