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