test_elision.c revision 9a690580
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_srec_iter posi; 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_posi_first(&posi, packet_out)); 124 125 streams[0].stream_flags |= STREAM_RST_SENT; 126 127 lsquic_packet_out_elide_reset_stream_frames(packet_out, 0); 128 assert(0 == streams[0].n_unacked); 129 assert(0 == packet_out->po_frame_types); 130 assert(!lsquic_posi_first(&posi, 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_srec_iter posi; 146 struct lsquic_engine_public enpub; 147 lsquic_stream_t streams[2]; 148 lsquic_packet_out_t *packet_out; 149 const struct stream_rec *srec; 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_posi_first(&posi, packet_out)); 193 194 streams[0].stream_flags |= STREAM_RST_SENT; 195 196 lsquic_packet_out_elide_reset_stream_frames(packet_out, 0); 197 assert(0 == streams[0].n_unacked); 198 199 assert(QUIC_FTBIT_STREAM == packet_out->po_frame_types); 200 srec = lsquic_posi_first(&posi, packet_out); 201 assert(srec->sr_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_srec_iter posi; 226 struct lsquic_engine_public enpub; 227 lsquic_stream_t streams[5]; 228 lsquic_packet_out_t *packet_out, *ref_out; 229 struct stream_rec *srec; 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 ref_out->po_data_sz = ref_out->po_regen_sz = 5; 245 /* STREAM B */ 246 setup_stream_contents(123, "BBBBBBBBBB"); 247 streams[0].id = 'B'; 248 len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz, 249 lsquic_packet_out_avail(ref_out), 250 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 251 lsquic_stream_tosend_fin(&streams[0]), 252 lsquic_stream_tosend_sz(&streams[0]), 253 (gsf_read_f) lsquic_stream_tosend_read, 254 &streams[0]); 255 b_off = ref_out->po_data_sz; 256 ref_out->po_data_sz += len; 257 len = pf->pf_gen_rst_frame(ref_out->po_data + ref_out->po_data_sz, 258 lsquic_packet_out_avail(ref_out), 'A', 133, 0); 259 ref_out->po_data_sz += len; 260 /* STREAM D */ 261 setup_stream_contents(123, "DDDDDDDDDD"); 262 streams[0].id = 'D'; 263 len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz, 264 lsquic_packet_out_avail(ref_out), 265 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 266 lsquic_stream_tosend_fin(&streams[0]), 267 lsquic_stream_tosend_sz(&streams[0]), 268 (gsf_read_f) lsquic_stream_tosend_read, 269 &streams[0]); 270 d_off = ref_out->po_data_sz; 271 ref_out->po_data_sz += len; 272 } 273 274 /* Construct packet from which we will elide streams. Here, we attach 275 * stream objects to the packet. 276 */ 277 { 278 packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, GQUIC_MAX_PAYLOAD_SZ); 279 /* This is fake data for regeneration */ 280 strcpy((char *) packet_out->po_data, "REGEN"); 281 packet_out->po_data_sz = packet_out->po_regen_sz = 5; 282 /* STREAM A */ 283 setup_stream_contents(123, "AAAAAAAAAA"); 284 streams[0].id = 'A'; 285 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 286 lsquic_packet_out_avail(packet_out), 287 streams[0].id, lsquic_stream_tosend_offset(&streams[0]), 288 lsquic_stream_tosend_fin(&streams[0]), 289 lsquic_stream_tosend_sz(&streams[0]), 290 (gsf_read_f) lsquic_stream_tosend_read, 291 &streams[0]); 292 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 293 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 294 packet_out->po_data_sz += len; 295 /* STREAM B */ 296 setup_stream_contents(123, "BBBBBBBBBB"); 297 streams[1].id = 'B'; 298 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 299 lsquic_packet_out_avail(packet_out), 300 streams[1].id, lsquic_stream_tosend_offset(&streams[1]), 301 lsquic_stream_tosend_fin(&streams[1]), 302 lsquic_stream_tosend_sz(&streams[1]), 303 (gsf_read_f) lsquic_stream_tosend_read, 304 &streams[1]); 305 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1], 306 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 307 packet_out->po_data_sz += len; 308 /* STREAM C */ 309 setup_stream_contents(123, "CCCCCCCCCC"); 310 streams[2].id = 'C'; 311 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 312 lsquic_packet_out_avail(packet_out), 313 streams[2].id, lsquic_stream_tosend_offset(&streams[2]), 314 lsquic_stream_tosend_fin(&streams[2]), 315 lsquic_stream_tosend_sz(&streams[2]), 316 (gsf_read_f) lsquic_stream_tosend_read, 317 &streams[2]); 318 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2], 319 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 320 packet_out->po_data_sz += len; 321 /* Reset A */ 322 len = pf->pf_gen_rst_frame(packet_out->po_data + packet_out->po_data_sz, 323 lsquic_packet_out_avail(packet_out), 'A', 133, 0); 324 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0], 325 QUIC_FRAME_RST_STREAM, packet_out->po_data_sz, len); 326 packet_out->po_data_sz += len; 327 /* STREAM D */ 328 setup_stream_contents(123, "DDDDDDDDDD"); 329 streams[3].id = 'D'; 330 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 331 lsquic_packet_out_avail(packet_out), 332 streams[3].id, lsquic_stream_tosend_offset(&streams[3]), 333 lsquic_stream_tosend_fin(&streams[3]), 334 lsquic_stream_tosend_sz(&streams[3]), 335 (gsf_read_f) lsquic_stream_tosend_read, 336 &streams[3]); 337 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3], 338 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 339 packet_out->po_data_sz += len; 340 /* STREAM E */ 341 setup_stream_contents(123, "EEEEEEEEEE"); 342 streams[4].id = 'E'; 343 len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz, 344 lsquic_packet_out_avail(packet_out), 345 streams[4].id, lsquic_stream_tosend_offset(&streams[4]), 346 lsquic_stream_tosend_fin(&streams[4]), 347 lsquic_stream_tosend_sz(&streams[4]), 348 (gsf_read_f) lsquic_stream_tosend_read, 349 &streams[4]); 350 lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4], 351 QUIC_FRAME_STREAM, packet_out->po_data_sz, len); 352 packet_out->po_data_sz += len; 353 packet_out->po_frame_types = (1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM); 354 } 355 356 /* Reset streams A, C, and E: */ 357 streams[0].stream_flags |= STREAM_RST_SENT; 358 streams[2].stream_flags |= STREAM_RST_SENT; 359 streams[4].stream_flags |= STREAM_RST_SENT; 360 361 if (chop_regen) 362 lsquic_packet_out_chop_regen(packet_out); 363 lsquic_packet_out_elide_reset_stream_frames(packet_out, 0); 364 365 assert(ref_out->po_data_sz == packet_out->po_data_sz + (chop_regen ? 5 : 0)); 366 assert(ref_out->po_regen_sz == packet_out->po_regen_sz + (chop_regen ? 5 : 0)); 367 if (chop_regen) 368 assert(0 == memcmp(ref_out->po_data + 5, packet_out->po_data, packet_out->po_data_sz)); 369 else 370 assert(0 == memcmp(ref_out->po_data, packet_out->po_data, packet_out->po_data_sz)); 371 372 assert(1 == streams[0].n_unacked); /* Still has RST outstanding */ 373 assert(1 == streams[1].n_unacked); 374 assert(0 == streams[2].n_unacked); 375 assert(1 == streams[3].n_unacked); 376 assert(0 == streams[4].n_unacked); 377 378 assert(packet_out->po_frame_types == ((1 << QUIC_FRAME_STREAM) | (1 << QUIC_FRAME_RST_STREAM))); 379 380 srec = lsquic_posi_first(&posi, packet_out); 381 assert(srec->sr_stream == &streams[1]); 382 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 383 assert(srec->sr_off == b_off - (chop_regen ? 5 : 0)); 384 385 srec = lsquic_posi_next(&posi); 386 assert(srec->sr_stream == &streams[0]); 387 assert(srec->sr_frame_type == QUIC_FRAME_RST_STREAM); 388 389 srec = lsquic_posi_next(&posi); 390 assert(srec->sr_stream == &streams[3]); 391 assert(srec->sr_frame_type == QUIC_FRAME_STREAM); 392 assert(srec->sr_off == d_off - (chop_regen ? 5 : 0)); 393 394 srec = lsquic_posi_next(&posi); 395 assert(!srec); 396 397 lsquic_packet_out_destroy(packet_out, &enpub, NULL); 398 lsquic_packet_out_destroy(ref_out, &enpub, NULL); 399 lsquic_mm_cleanup(&enpub.enp_mm); 400} 401 402 403int 404main (void) 405{ 406 /* TODO-ENDIAN: test with every PF */ 407 elide_single_stream_frame(); 408 shrink_packet_post_elision(); 409 elide_three_stream_frames(0); 410 elide_three_stream_frames(1); 411 412 return 0; 413} 414