test_h3_framing.c revision fb73393f
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * test_h3_framing.c -- test generation of H3 frames 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/queue.h> 12#include <sys/types.h> 13#include <fcntl.h> 14#include <limits.h> 15#ifndef WIN32 16#include <unistd.h> 17#else 18#include <getopt.h> 19#endif 20 21#include "lsquic.h" 22 23#include "lsquic_packet_common.h" 24#include "lsquic_packet_ietf.h" 25#include "lsquic_alarmset.h" 26#include "lsquic_packet_in.h" 27#include "lsquic_conn_flow.h" 28#include "lsquic_rtt.h" 29#include "lsquic_sfcw.h" 30#include "lsquic_varint.h" 31#include "lsquic_hq.h" 32#include "lsquic_hash.h" 33#include "lsquic_stream.h" 34#include "lsquic_types.h" 35#include "lsquic_malo.h" 36#include "lsquic_mm.h" 37#include "lsquic_conn_public.h" 38#include "lsquic_logger.h" 39#include "lsquic_parse.h" 40#include "lsquic_conn.h" 41#include "lsquic_engine_public.h" 42#include "lsquic_cubic.h" 43#include "lsquic_pacer.h" 44#include "lsquic_senhist.h" 45#include "lsquic_bw_sampler.h" 46#include "lsquic_minmax.h" 47#include "lsquic_bbr.h" 48#include "lsquic_send_ctl.h" 49#include "lsquic_ver_neg.h" 50#include "lsquic_packet_out.h" 51#include "lsquic_enc_sess.h" 52#include "lsqpack.h" 53#include "lsxpack_header.h" 54#include "lsquic_frab_list.h" 55#include "lsquic_qenc_hdl.h" 56#include "lsquic_http1x_if.h" 57#include "lsquic_qdec_hdl.h" 58#include "lsquic_varint.h" 59#include "lsquic_hq.h" 60#include "lsquic_data_in_if.h" 61 62static const struct parse_funcs *g_pf = select_pf_by_ver(LSQVER_ID27); 63 64struct test_ctl_settings 65{ 66 int tcs_schedule_stream_packets_immediately; 67 int tcs_have_delayed_packets; 68 unsigned tcs_can_send; 69 enum buf_packet_type 70 tcs_bp_type; 71 enum packno_bits 72 tcs_guess_packno_bits, 73 tcs_calc_packno_bits; 74}; 75 76 77static struct test_ctl_settings g_ctl_settings; 78 79 80static void 81init_buf (void *buf, size_t sz); 82 83 84/* Set values to default */ 85static void 86init_test_ctl_settings (struct test_ctl_settings *settings) 87{ 88 settings->tcs_schedule_stream_packets_immediately = 1; 89 settings->tcs_have_delayed_packets = 0; 90 settings->tcs_can_send = UINT_MAX; 91 settings->tcs_bp_type = BPT_HIGHEST_PRIO; 92 settings->tcs_guess_packno_bits = PACKNO_BITS_1; 93 settings->tcs_calc_packno_bits = PACKNO_BITS_1; 94} 95 96 97enum packno_bits 98lsquic_send_ctl_calc_packno_bits (struct lsquic_send_ctl *ctl) 99{ 100 return g_ctl_settings.tcs_calc_packno_bits; 101} 102 103 104int 105lsquic_send_ctl_schedule_stream_packets_immediately (struct lsquic_send_ctl *ctl) 106{ 107 return g_ctl_settings.tcs_schedule_stream_packets_immediately; 108} 109 110 111int 112lsquic_send_ctl_have_delayed_packets (const struct lsquic_send_ctl *ctl) 113{ 114 return g_ctl_settings.tcs_have_delayed_packets; 115} 116 117 118int 119lsquic_send_ctl_can_send (struct lsquic_send_ctl *ctl) 120{ 121 return ctl->sc_n_scheduled < g_ctl_settings.tcs_can_send; 122} 123 124 125enum packno_bits 126lsquic_send_ctl_guess_packno_bits (struct lsquic_send_ctl *ctl) 127{ 128 return g_ctl_settings.tcs_guess_packno_bits; 129} 130 131 132enum buf_packet_type 133lsquic_send_ctl_determine_bpt (struct lsquic_send_ctl *ctl, 134 const struct lsquic_stream *stream) 135{ 136 return g_ctl_settings.tcs_bp_type; 137} 138 139 140/* This function is only here to avoid crash in the test: */ 141void 142lsquic_engine_add_conn_to_tickable (struct lsquic_engine_public *enpub, 143 lsquic_conn_t *conn) 144{ 145} 146 147 148static unsigned n_closed; 149static enum stream_ctor_flags stream_ctor_flags = 150 SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH; 151 152struct test_ctx { 153 lsquic_stream_t *stream; 154}; 155 156 157static lsquic_stream_ctx_t * 158on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream) 159{ 160 struct test_ctx *test_ctx = stream_if_ctx; 161 test_ctx->stream = stream; 162 return NULL; 163} 164 165 166static void 167on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h) 168{ 169 ++n_closed; 170} 171 172 173const struct lsquic_stream_if stream_if = { 174 .on_new_stream = on_new_stream, 175 .on_close = on_close, 176}; 177 178 179static size_t 180read_from_scheduled_packets (lsquic_send_ctl_t *send_ctl, lsquic_stream_id_t stream_id, 181 unsigned char *const begin, size_t bufsz, uint64_t first_offset, int *p_fin, 182 int fullcheck) 183{ 184 const struct parse_funcs *const pf_local = send_ctl->sc_conn_pub->lconn->cn_pf; 185 unsigned char *p = begin; 186 unsigned char *const end = p + bufsz; 187 const struct stream_rec *srec; 188 struct packet_out_srec_iter posi; 189 struct lsquic_packet_out *packet_out; 190 struct stream_frame frame; 191 enum quic_frame_type expected_type; 192 int len, fin = 0; 193 194 expected_type = QUIC_FRAME_STREAM; 195 196 TAILQ_FOREACH(packet_out, &send_ctl->sc_scheduled_packets, po_next) 197 for (srec = lsquic_posi_first(&posi, packet_out); srec; 198 srec = lsquic_posi_next(&posi)) 199 { 200 if (fullcheck) 201 { 202 assert(srec->sr_frame_type == expected_type); 203 if (0 && packet_out->po_packno != 1) 204 { 205 /* First packet may contain two stream frames, do not 206 * check it. 207 */ 208 assert(!lsquic_posi_next(&posi)); 209 if (TAILQ_NEXT(packet_out, po_next)) 210 { 211 assert(packet_out->po_data_sz == packet_out->po_n_alloc); 212 assert(srec->sr_len == packet_out->po_data_sz); 213 } 214 } 215 } 216 if (srec->sr_frame_type == expected_type && 217 srec->sr_stream->id == stream_id) 218 { 219 assert(!fin); 220 if (QUIC_FRAME_STREAM == expected_type) 221 len = pf_local->pf_parse_stream_frame(packet_out->po_data + srec->sr_off, 222 packet_out->po_data_sz - srec->sr_off, &frame); 223 else 224 len = pf_local->pf_parse_crypto_frame(packet_out->po_data + srec->sr_off, 225 packet_out->po_data_sz - srec->sr_off, &frame); 226 assert(len > 0); 227 if (QUIC_FRAME_STREAM == expected_type) 228 assert(frame.stream_id == srec->sr_stream->id); 229 else 230 assert(frame.stream_id == ~0ULL); 231 /* Otherwise not enough to copy to: */ 232 assert(end - p >= frame.data_frame.df_size); 233 /* Checks offset ordering: */ 234 assert(frame.data_frame.df_offset == 235 first_offset + (uintptr_t) (p - begin)); 236 if (frame.data_frame.df_fin) 237 { 238 assert(!fin); 239 fin = 1; 240 } 241 memcpy(p, packet_out->po_data + srec->sr_off + len - 242 frame.data_frame.df_size, frame.data_frame.df_size); 243 p += frame.data_frame.df_size; 244 } 245 } 246 247 if (p_fin) 248 *p_fin = fin; 249 return p + bufsz - end; 250} 251 252 253static struct test_ctx test_ctx; 254 255 256struct test_objs { 257 struct lsquic_engine_public eng_pub; 258 struct lsquic_conn lconn; 259 struct lsquic_conn_public conn_pub; 260 struct lsquic_send_ctl send_ctl; 261 struct lsquic_alarmset alset; 262 void *stream_if_ctx; 263 struct ver_neg ver_neg; 264 const struct lsquic_stream_if * 265 stream_if; 266 unsigned initial_stream_window; 267 enum stream_ctor_flags ctor_flags; 268 struct qpack_enc_hdl qeh; 269 struct qpack_dec_hdl qdh; 270 struct lsquic_hset_if hsi_if; 271}; 272 273 274static int 275unit_test_doesnt_write_ack (struct lsquic_conn *lconn) 276{ 277 return 0; 278} 279 280 281static struct network_path network_path; 282 283static struct network_path * 284get_network_path (struct lsquic_conn *lconn, const struct sockaddr *sa) 285{ 286 return &network_path; 287} 288 289 290static const struct conn_iface our_conn_if = 291{ 292 .ci_can_write_ack = unit_test_doesnt_write_ack, 293 .ci_get_path = get_network_path, 294}; 295 296 297static void 298init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window, 299 unsigned initial_stream_window, unsigned short packet_sz) 300{ 301 int s; 302 memset(tobjs, 0, sizeof(*tobjs)); 303 LSCONN_INITIALIZE(&tobjs->lconn); 304 tobjs->lconn.cn_pf = g_pf; 305 tobjs->lconn.cn_version = LSQVER_ID27; 306 tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1; 307 network_path.np_pack_size = packet_sz; 308 tobjs->lconn.cn_if = &our_conn_if; 309 lsquic_mm_init(&tobjs->eng_pub.enp_mm); 310 TAILQ_INIT(&tobjs->conn_pub.sending_streams); 311 TAILQ_INIT(&tobjs->conn_pub.read_streams); 312 TAILQ_INIT(&tobjs->conn_pub.write_streams); 313 TAILQ_INIT(&tobjs->conn_pub.service_streams); 314 lsquic_cfcw_init(&tobjs->conn_pub.cfcw, &tobjs->conn_pub, 315 initial_conn_window); 316 lsquic_conn_cap_init(&tobjs->conn_pub.conn_cap, initial_conn_window); 317 lsquic_alarmset_init(&tobjs->alset, 0); 318 tobjs->conn_pub.mm = &tobjs->eng_pub.enp_mm; 319 tobjs->conn_pub.lconn = &tobjs->lconn; 320 tobjs->conn_pub.enpub = &tobjs->eng_pub; 321 tobjs->conn_pub.send_ctl = &tobjs->send_ctl; 322 tobjs->conn_pub.packet_out_malo = 323 lsquic_malo_create(sizeof(struct lsquic_packet_out)); 324 tobjs->conn_pub.path = &network_path; 325 tobjs->initial_stream_window = initial_stream_window; 326 tobjs->eng_pub.enp_settings.es_cc_algo = 1; /* Cubic */ 327 tobjs->eng_pub.enp_hsi_if = &tobjs->hsi_if; 328 lsquic_send_ctl_init(&tobjs->send_ctl, &tobjs->alset, &tobjs->eng_pub, 329 &tobjs->ver_neg, &tobjs->conn_pub, 0); 330 tobjs->send_ctl.sc_cong_u.cubic.cu_cwnd = ~0ull; 331 tobjs->stream_if = &stream_if; 332 tobjs->stream_if_ctx = &test_ctx; 333 tobjs->ctor_flags = stream_ctor_flags; 334 if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) 335 { 336 lsquic_qeh_init(&tobjs->qeh, &tobjs->lconn); 337 s = lsquic_qeh_settings(&tobjs->qeh, 0, 0, 0, 0); 338 assert(0 == s); 339 tobjs->conn_pub.u.ietf.qeh = &tobjs->qeh; 340 lsquic_qdh_init(&tobjs->qdh, &tobjs->lconn, 0, &tobjs->eng_pub, 0, 0); 341 tobjs->conn_pub.u.ietf.qdh = &tobjs->qdh; 342 } 343} 344 345 346static void 347deinit_test_objs (struct test_objs *tobjs) 348{ 349 assert(!lsquic_malo_first(tobjs->eng_pub.enp_mm.malo.stream_frame)); 350 lsquic_send_ctl_cleanup(&tobjs->send_ctl); 351 lsquic_malo_destroy(tobjs->conn_pub.packet_out_malo); 352 lsquic_mm_cleanup(&tobjs->eng_pub.enp_mm); 353 if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) 354 lsquic_qeh_cleanup(&tobjs->qeh); 355} 356 357 358static struct lsquic_stream * 359new_stream (struct test_objs *tobjs, unsigned stream_id, uint64_t send_off) 360{ 361 return lsquic_stream_new(stream_id, &tobjs->conn_pub, tobjs->stream_if, 362 tobjs->stream_if_ctx, tobjs->initial_stream_window, send_off, 363 tobjs->ctor_flags); 364} 365 366 367struct packetization_test_stream_ctx 368{ 369 const unsigned char *buf; 370 unsigned len, off, write_size; 371 int flush_after_each_write; 372}; 373 374 375static lsquic_stream_ctx_t * 376packetization_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream) 377{ 378 lsquic_stream_wantwrite(stream, 1); 379 return stream_if_ctx; 380} 381 382 383static void 384packetization_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h) 385{ 386} 387 388 389#define RANDOM_WRITE_SIZE ~0U 390 391static unsigned 392calc_n_to_write (unsigned write_size) 393{ 394 if (write_size == RANDOM_WRITE_SIZE) 395 return rand() % 1000 + 1; 396 else 397 return write_size; 398} 399 400 401static void 402packetization_write_as_much_as_you_can (lsquic_stream_t *stream, 403 lsquic_stream_ctx_t *ctx) 404{ 405 struct packetization_test_stream_ctx *const pack_ctx = (void *) ctx; 406 unsigned n_to_write, n_sched; 407 ssize_t n_written; 408 size_t avail; 409 int s; 410 411 while (pack_ctx->off < pack_ctx->len) 412 { 413 n_to_write = calc_n_to_write(pack_ctx->write_size); 414 n_sched = lsquic_send_ctl_n_scheduled(stream->conn_pub->send_ctl); 415 if (n_to_write > pack_ctx->len - pack_ctx->off) 416 n_to_write = pack_ctx->len - pack_ctx->off; 417 n_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off, 418 n_to_write); 419 if (n_written == 0) 420 { 421 if (n_to_write && SSHS_BEGIN == stream->sm_send_headers_state 422 && lsquic_send_ctl_can_send(stream->conn_pub->send_ctl)) 423 { 424 avail = lsquic_stream_write_avail(stream); 425 assert(avail == 0 426 || lsquic_send_ctl_n_scheduled( 427 stream->conn_pub->send_ctl) > n_sched); 428 } 429 break; 430 } 431 pack_ctx->off += n_written; 432 if (pack_ctx->flush_after_each_write) 433 { 434 s = lsquic_stream_flush(stream); 435 assert(s == 0); 436 } 437 } 438 439 s = lsquic_stream_flush(stream); 440 assert(s == 0); 441 lsquic_stream_wantwrite(stream, 0); 442} 443 444 445static void 446packetization_perform_one_write (lsquic_stream_t *stream, 447 lsquic_stream_ctx_t *ctx) 448{ 449 struct packetization_test_stream_ctx *const pack_ctx = (void *) ctx; 450 unsigned n_to_write, n_sched; 451 ssize_t n_written; 452 size_t avail; 453 int s; 454 455 n_to_write = calc_n_to_write(pack_ctx->write_size); 456 if (n_to_write > pack_ctx->len - pack_ctx->off) 457 n_to_write = pack_ctx->len - pack_ctx->off; 458 n_sched = lsquic_send_ctl_n_scheduled(stream->conn_pub->send_ctl); 459 n_written = lsquic_stream_write(stream, pack_ctx->buf + pack_ctx->off, 460 n_to_write); 461 assert(n_written >= 0); 462 if (n_written == 0 && SSHS_BEGIN == stream->sm_send_headers_state 463 && n_to_write 464 && lsquic_send_ctl_can_send(stream->conn_pub->send_ctl)) 465 { 466 avail = lsquic_stream_write_avail(stream); 467 assert(avail == 0 468 || lsquic_send_ctl_n_scheduled( 469 stream->conn_pub->send_ctl) > n_sched); 470 } 471 pack_ctx->off += n_written; 472 if (pack_ctx->flush_after_each_write) 473 { 474 s = lsquic_stream_flush(stream); 475 assert(s == 0); 476 } 477 if (n_written == 0) 478 lsquic_stream_wantwrite(stream, 0); 479} 480 481 482static const struct lsquic_stream_if packetization_inside_once_stream_if = { 483 .on_new_stream = packetization_on_new_stream, 484 .on_close = packetization_on_close, 485 .on_write = packetization_write_as_much_as_you_can, 486}; 487 488 489static const struct lsquic_stream_if packetization_inside_many_stream_if = { 490 .on_new_stream = packetization_on_new_stream, 491 .on_close = packetization_on_close, 492 .on_write = packetization_perform_one_write, 493}; 494 495 496static void 497test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize, 498 int flush_after_each_write, size_t conn_limit, 499 unsigned n_packets, unsigned short packet_sz) 500{ 501 struct test_objs tobjs; 502 struct lsquic_stream *stream; 503 size_t nw; 504 int fin, s; 505 unsigned char *buf_in, *buf_out; 506 const size_t buf_in_sz = 0x40000, buf_out_sz = 0x500000; 507 508 /* We'll write headers first after which stream will switch to using 509 * data-framing writer. This is simply so that we don't have to 510 * expose more stream things only for testing. 511 */ 512 struct lsxpack_header header; 513 lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3); 514 struct lsquic_http_headers headers = { 1, &header, }; 515 516 buf_in = malloc(buf_in_sz); 517 buf_out = malloc(buf_out_sz); 518 assert(buf_in && buf_out); 519 520 struct packetization_test_stream_ctx packet_stream_ctx = 521 { 522 .buf = buf_in, 523 .off = 0, 524 .len = buf_in_sz, 525 .write_size = wsize, 526 .flush_after_each_write = flush_after_each_write, 527 }; 528 529 init_buf(buf_in, buf_in_sz); 530 531 init_test_ctl_settings(&g_ctl_settings); 532 g_ctl_settings.tcs_schedule_stream_packets_immediately = sched_immed; 533 534 stream_ctor_flags |= SCF_IETF; 535 init_test_objs(&tobjs, conn_limit ? conn_limit : buf_out_sz, buf_out_sz, packet_sz); 536 tobjs.stream_if_ctx = &packet_stream_ctx; 537 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 538 if (sched_immed) 539 { 540 g_ctl_settings.tcs_can_send = n_packets; 541 if (dispatch_once) 542 { 543 tobjs.stream_if = &packetization_inside_once_stream_if; 544 tobjs.ctor_flags |= SCF_DISP_RW_ONCE; 545 } 546 else 547 tobjs.stream_if = &packetization_inside_many_stream_if; 548 } 549 else 550 { 551 lsquic_send_ctl_set_max_bpq_count(n_packets); 552 g_ctl_settings.tcs_can_send = INT_MAX; 553 /* Need this for on_new_stream() callback not to mess with 554 * the context, otherwise this is not used. 555 */ 556 tobjs.stream_if = &packetization_inside_many_stream_if; 557 } 558 559 stream = new_stream(&tobjs, 0, buf_out_sz); 560 561 s = lsquic_stream_send_headers(stream, &headers, 0); 562 assert(0 == s); 563 564 if (sched_immed) 565 { 566 lsquic_stream_dispatch_write_events(stream); 567 lsquic_stream_flush(stream); 568 } 569 else 570 { 571 packetization_write_as_much_as_you_can(stream, 572 (void *) &packet_stream_ctx); 573 g_ctl_settings.tcs_schedule_stream_packets_immediately = 1; 574 lsquic_send_ctl_schedule_buffered(&tobjs.send_ctl, BPT_HIGHEST_PRIO); 575 g_ctl_settings.tcs_schedule_stream_packets_immediately = 0; 576 } 577 lsquic_send_ctl_set_max_bpq_count(10); 578 579 /* Verify written data: */ 580 nw = read_from_scheduled_packets(&tobjs.send_ctl, 0, buf_out, buf_out_sz, 581 0, &fin, 1); 582 if (!conn_limit) 583 assert(nw > buf_in_sz); 584 { /* Remove framing and verify contents */ 585 const unsigned char *src; 586 unsigned char *dst; 587 uint64_t sz; 588 unsigned frame_type; 589 int s; 590 591 src = buf_out; 592 dst = buf_out; 593 while (src < buf_out + nw) 594 { 595 frame_type = *src++; 596 s = vint_read(src, buf_out + buf_out_sz, &sz); 597 assert(s > 0); 598 /* In some rare circumstances it is possible to produce zero-length 599 * DATA frames: 600 * 601 * assert(sz > 0); 602 */ 603 assert(sz < (1 << 14)); 604 src += s; 605 if (src == buf_out + s + 1) 606 { 607 /* Ignore headers */ 608 assert(frame_type == HQFT_HEADERS); 609 src += sz; 610 } 611 else 612 { 613 assert(frame_type == HQFT_DATA); 614 if (src + sz > buf_out + nw) /* Chopped DATA frame (last) */ 615 sz = buf_out + nw - src; 616 memmove(dst, src, sz); 617 dst += sz; 618 src += sz; 619 } 620 } 621 if (!conn_limit) 622 assert(buf_in_sz == (uintptr_t) dst - (uintptr_t) buf_out); 623 assert(0 == memcmp(buf_in, buf_out, (uintptr_t) dst - (uintptr_t) buf_out)); 624 } 625 626 lsquic_stream_destroy(stream); 627 deinit_test_objs(&tobjs); 628 free(buf_in); 629 free(buf_out); 630 631 stream_ctor_flags &= ~SCF_IETF; 632} 633 634 635static void 636main_test_hq_framing (void) 637{ 638 const unsigned wsizes[] = { 1, 2, 3, 7, 10, 50, 100, 201, 211, 1000, 2003, 20000, }; 639 const size_t conn_limits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 640 14, 15, 16, 17, 18, 19, 20, 21, 30, 31, 32, 33, 63, 64, 128, 200, 255, 641 256, 512, 1024, 2045, 2048, 2049, 3000, 4091, 4096, 4097, 5000, 8192, 642 16 * 1024 - 1, 16 * 1024, 32 * 1024, 33 * 1024, }; 643 const unsigned n_packets[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, UINT_MAX, }; 644 const unsigned short packet_sz[] = { 1252, 1370, 0x1000, 0xFF00, }; 645 unsigned i, j, k, l; 646 int sched_immed, dispatch_once, flush_after_each_write; 647 648 for (sched_immed = 0; sched_immed <= 1; ++sched_immed) 649 for (dispatch_once = 0; dispatch_once <= 1; ++dispatch_once) 650 for (i = 0; i < sizeof(wsizes) / sizeof(wsizes[i]); ++i) 651 for (j = 0; j < sizeof(conn_limits) / sizeof(conn_limits[j]); ++j) 652 for (flush_after_each_write = 0; flush_after_each_write < 2; ++flush_after_each_write) 653 for (k = 0; k < sizeof(n_packets) / sizeof(n_packets[0]); ++k) 654 for (l = 0; l < sizeof(packet_sz) / sizeof(packet_sz[0]); ++l) 655 test_hq_framing(sched_immed, dispatch_once, wsizes[i], flush_after_each_write, conn_limits[j], n_packets[k], packet_sz[l]); 656} 657 658 659/* Instead of the not-very-random testing done in main_test_hq_framing(), 660 * the fuzz-guided testing initializes parameters based on the fuzz input 661 * file. This allows afl-fuzz explore the code paths. 662 */ 663void 664fuzz_guided_testing (const char *input) 665{ 666 /* Range */ /* Bytes from file */ 667 unsigned short packet_sz; /* [200, 0x3FFF] */ /* 2 */ 668 unsigned wsize; /* [1, 20000] */ /* 2 */ 669 unsigned n_packets; /* [1, 255] and UINT_MAX */ /* 1 */ 670 size_t conn_limit; /* [1, 33K] */ /* 2 */ 671 int sched_immed; /* 0 or 1 */ /* 1 */ 672 int dispatch_once; /* 0 or 1 */ /* 0 (same as above) */ 673 int flush_after_each_write; /* 0 or 1 */ /* 0 (same as above) */ 674 /* TOTAL: 8 bytes */ 675 676 FILE *f; 677 size_t nread; 678 uint16_t tmp; 679 unsigned char buf[9]; 680 681 f = fopen(input, "rb"); 682 if (!f) 683 { 684 assert(0); 685 return; 686 } 687 688 nread = fread(buf, 1, sizeof(buf), f); 689 if (nread != 8) 690 goto cleanup; 691 692 memcpy(&tmp, &buf[0], 2); 693 if (tmp < 200) 694 tmp = 200; 695 else if (tmp > IQUIC_MAX_OUT_PACKET_SZ) 696 tmp = IQUIC_MAX_OUT_PACKET_SZ; 697 packet_sz = tmp; 698 699 memcpy(&tmp, &buf[2], 2); 700 if (tmp < 1) 701 tmp = 1; 702 else if (tmp > 20000) 703 tmp = 20000; 704 wsize = tmp; 705 706 if (buf[4]) 707 n_packets = buf[4]; 708 else 709 n_packets = UINT_MAX; 710 711 memcpy(&tmp, &buf[5], 2); 712 if (tmp < 1) 713 tmp = 1; 714 else if (tmp > 33 * 1024) 715 tmp = 33 * 1024; 716 conn_limit = tmp; 717 718 sched_immed = !!(buf[7] & 1); 719 dispatch_once = !!(buf[7] & 2); 720 flush_after_each_write = !!(buf[7] & 4); 721 722 test_hq_framing(sched_immed, dispatch_once, wsize, 723 flush_after_each_write, conn_limit, n_packets, packet_sz); 724 725 cleanup: 726 (void) fclose(f); 727} 728 729 730static void 731test_frame_header_split (unsigned n_packets, unsigned extra_sz, 732 int add_one_more) 733{ 734 struct test_objs tobjs; 735 struct lsquic_stream *stream; 736 size_t nw; 737 int fin, s; 738 unsigned char *buf_in, *buf_out; 739 const unsigned wsize = 70; 740 const size_t buf_in_sz = wsize, buf_out_sz = 0x500000; 741 742 struct lsxpack_header header; 743 lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3); 744 struct lsquic_http_headers headers = { 1, &header, }; 745 746 buf_in = malloc(buf_in_sz); 747 buf_out = malloc(buf_out_sz); 748 assert(buf_in && buf_out); 749 750 struct packetization_test_stream_ctx packet_stream_ctx = 751 { 752 .buf = buf_in, 753 .off = 0, 754 .len = buf_in_sz, 755 .write_size = wsize, 756 .flush_after_each_write = 0, 757 }; 758 759 init_buf(buf_in, buf_in_sz); 760 761 init_test_ctl_settings(&g_ctl_settings); 762 g_ctl_settings.tcs_schedule_stream_packets_immediately = 1; 763 764 stream_ctor_flags |= SCF_IETF; 765 init_test_objs(&tobjs, 0x1000, buf_out_sz, 1252); 766 tobjs.stream_if_ctx = &packet_stream_ctx; 767 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 768 769 g_ctl_settings.tcs_can_send = n_packets; 770 tobjs.stream_if = &packetization_inside_once_stream_if; 771 tobjs.ctor_flags |= SCF_DISP_RW_ONCE; 772 773 struct lsquic_packet_out *const packet_out 774 = lsquic_send_ctl_new_packet_out(&tobjs.send_ctl, 0, PNS_APP, &network_path); 775 assert(packet_out); 776 const size_t pad_size = packet_out->po_n_alloc 777 - 2 /* STREAM header */ 778 - 5 /* 3-byte HEADERS frame */ 779 - extra_sz; 780 packet_out->po_data_sz = pad_size; 781 lsquic_send_ctl_scheduled_one(&tobjs.send_ctl, packet_out); 782 783 stream = new_stream(&tobjs, 0, buf_out_sz); 784 785 s = lsquic_stream_send_headers(stream, &headers, 0); 786 assert(0 == s); 787 788 const ssize_t w = lsquic_stream_write(stream, buf_in, buf_in_sz); 789 assert(w >= 0 && (size_t) w == buf_in_sz); 790 lsquic_stream_flush(stream); 791 792 if (add_one_more) 793 { 794 ++g_ctl_settings.tcs_can_send; 795 lsquic_stream_flush(stream); 796 } 797 798 /* Verify written data: */ 799 nw = read_from_scheduled_packets(&tobjs.send_ctl, 0, buf_out, buf_out_sz, 800 0, &fin, 1); 801 { /* Remove framing and verify contents */ 802 const unsigned char *src; 803 unsigned char *dst; 804 uint64_t sz; 805 unsigned frame_type; 806 int s; 807 808 src = buf_out; 809 dst = buf_out; 810 while (src < buf_out + nw) 811 { 812 frame_type = *src++; 813 s = vint_read(src, buf_out + buf_out_sz, &sz); 814 assert(s > 0); 815 assert(sz > 0); 816 assert(sz < (1 << 14)); 817 src += s; 818 if (src == buf_out + s + 1) 819 { 820 /* Ignore headers */ 821 assert(frame_type == HQFT_HEADERS); 822 src += sz; 823 } 824 else 825 { 826 assert(frame_type == HQFT_DATA); 827 if (src + sz > buf_out + nw) /* Chopped DATA frame (last) */ 828 sz = buf_out + nw - src; 829 memmove(dst, src, sz); 830 dst += sz; 831 src += sz; 832 } 833 } 834 assert(0 == memcmp(buf_in, buf_out, (uintptr_t) dst - (uintptr_t) buf_out)); 835 } 836 837 lsquic_stream_destroy(stream); 838 deinit_test_objs(&tobjs); 839 free(buf_in); 840 free(buf_out); 841 842 stream_ctor_flags &= ~SCF_IETF; 843} 844 845 846static void 847test_zero_size_frame (void) 848{ 849 struct test_objs tobjs; 850 struct lsquic_stream *stream; 851 ssize_t w; 852 size_t nw; 853 int fin, s; 854 unsigned char *buf_in, *buf_out; 855 const unsigned wsize = 7000; 856 const size_t buf_in_sz = wsize, buf_out_sz = 0x500000; 857 858 struct lsxpack_header header; 859 lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3); 860 struct lsquic_http_headers headers = { 1, &header, }; 861 862 buf_in = malloc(buf_in_sz); 863 buf_out = malloc(buf_out_sz); 864 assert(buf_in && buf_out); 865 866 struct packetization_test_stream_ctx packet_stream_ctx = 867 { 868 .buf = buf_in, 869 .off = 0, 870 .len = buf_in_sz, 871 .write_size = wsize, 872 .flush_after_each_write = 0, 873 }; 874 875 init_buf(buf_in, buf_in_sz); 876 877 init_test_ctl_settings(&g_ctl_settings); 878 g_ctl_settings.tcs_schedule_stream_packets_immediately = 1; 879 880 stream_ctor_flags |= SCF_IETF; 881 init_test_objs(&tobjs, 0x1000, buf_out_sz, 1252); 882 tobjs.stream_if_ctx = &packet_stream_ctx; 883 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 884 885 g_ctl_settings.tcs_can_send = 1; 886 tobjs.stream_if = &packetization_inside_once_stream_if; 887 tobjs.ctor_flags |= SCF_DISP_RW_ONCE; 888 889 struct lsquic_packet_out *const packet_out 890 = lsquic_send_ctl_new_packet_out(&tobjs.send_ctl, 0, PNS_APP, &network_path); 891 assert(packet_out); 892 const size_t pad_size = packet_out->po_n_alloc 893 - 2 /* STREAM header */ 894 - 5 /* 3-byte HEADERS frame */ 895 - 3; 896 packet_out->po_data_sz = pad_size; 897 lsquic_send_ctl_scheduled_one(&tobjs.send_ctl, packet_out); 898 899 stream = new_stream(&tobjs, 0, buf_out_sz); 900 901 s = lsquic_stream_send_headers(stream, &headers, 0); 902 assert(0 == s); 903 904 w = lsquic_stream_write(stream, buf_in, buf_in_sz); 905 assert(w >= 0); 906 lsquic_stream_flush(stream); 907 908 g_ctl_settings.tcs_can_send++; 909 w = lsquic_stream_write(stream, buf_in, buf_in_sz); 910 assert(w >= 0); 911 lsquic_stream_flush(stream); 912 913 /* Verify written data: */ 914 nw = read_from_scheduled_packets(&tobjs.send_ctl, 0, buf_out, buf_out_sz, 915 0, &fin, 1); 916 { /* Remove framing and verify contents */ 917 const unsigned char *src; 918 unsigned char *dst; 919 uint64_t sz; 920 unsigned frame_type; 921 int s; 922 923 src = buf_out; 924 dst = buf_out; 925 while (src < buf_out + nw) 926 { 927 frame_type = *src++; 928 s = vint_read(src, buf_out + buf_out_sz, &sz); 929 assert(s > 0); 930 assert(sz < (1 << 14)); 931 src += s; 932 if (src == buf_out + s + 1) 933 { 934 /* Ignore headers */ 935 assert(frame_type == HQFT_HEADERS); 936 src += sz; 937 } 938 else 939 { 940 assert(frame_type == HQFT_DATA); 941 if (src + sz > buf_out + nw) /* Chopped DATA frame (last) */ 942 sz = buf_out + nw - src; 943 memmove(dst, src, sz); 944 dst += sz; 945 src += sz; 946 } 947 } 948 assert(0 == memcmp(buf_in, buf_out, (uintptr_t) dst - (uintptr_t) buf_out)); 949 } 950 951 lsquic_stream_destroy(stream); 952 deinit_test_objs(&tobjs); 953 free(buf_in); 954 free(buf_out); 955 956 stream_ctor_flags &= ~SCF_IETF; 957} 958 959 960/* Create a new stream frame. Each stream frame has a real packet_in to 961 * back it up, just like in real code. The contents of the packet do 962 * not matter. 963 */ 964static stream_frame_t * 965new_frame_in_ext (struct test_objs *tobjs, size_t off, size_t sz, int fin, 966 const void *data) 967{ 968 lsquic_packet_in_t *packet_in; 969 stream_frame_t *frame; 970 971 assert(sz <= 1370); 972 973 packet_in = lsquic_mm_get_packet_in(&tobjs->eng_pub.enp_mm); 974 if (data) 975 packet_in->pi_data = (void *) data; 976 else 977 { 978 packet_in->pi_data = lsquic_mm_get_packet_in_buf(&tobjs->eng_pub.enp_mm, 1370); 979 packet_in->pi_flags |= PI_OWN_DATA; 980 memset(packet_in->pi_data, 'A', sz); 981 } 982 /* This is not how stream frame looks in the packet: we have no 983 * header. In our test case it does not matter, as we only care 984 * about stream frame. 985 */ 986 packet_in->pi_data_sz = sz; 987 packet_in->pi_refcnt = 1; 988 989 frame = lsquic_malo_get(tobjs->eng_pub.enp_mm.malo.stream_frame); 990 memset(frame, 0, sizeof(*frame)); 991 frame->packet_in = packet_in; 992 frame->data_frame.df_offset = off; 993 frame->data_frame.df_size = sz; 994 frame->data_frame.df_data = &packet_in->pi_data[0]; 995 frame->data_frame.df_fin = fin; 996 997 return frame; 998} 999 1000 1001/* Receiving DATA frame with zero payload should result in lsquic_stream_read() 1002 * returning -1. 1003 */ 1004static void 1005test_reading_zero_size_data_frame (void) 1006{ 1007 struct test_objs tobjs; 1008 struct lsquic_stream *stream; 1009 struct stream_frame *frame; 1010 ssize_t nr; 1011 int s; 1012 unsigned char buf[2]; 1013 1014 init_test_ctl_settings(&g_ctl_settings); 1015 1016 stream_ctor_flags |= SCF_IETF; 1017 init_test_objs(&tobjs, 0x1000, 0x2000, 1252); 1018 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 1019 1020 stream = new_stream(&tobjs, 0, 0x1000); 1021 1022 /* Fake out reading of HEADERS frame: */ 1023 stream->stream_flags |= STREAM_HAVE_UH; 1024 stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */; 1025 stream->sm_hq_filter.hqfi_hist_idx++; 1026 1027 /* One-byte DATA frame */ 1028 frame = new_frame_in_ext(&tobjs, 0, 3, 0, (uint8_t[3]){ 0, 1, 'a', }); 1029 s = lsquic_stream_frame_in(stream, frame); 1030 assert(s == 0); /* Self-check */ 1031 1032 /* Zero-length DATA frame */ 1033 frame = new_frame_in_ext(&tobjs, 3, 2, 0, (uint8_t[2]){ 0, 0, }); 1034 s = lsquic_stream_frame_in(stream, frame); 1035 assert(s == 0); /* Self-check */ 1036 1037 assert(stream->read_offset == 2); /* Self-check */ 1038 1039 /* Read 'a' */ 1040 nr = lsquic_stream_read(stream, buf, 1); 1041 assert(nr == 1); 1042 assert(buf[0] == 'a'); 1043 1044 /* Check that read returns -1 */ 1045 nr = lsquic_stream_read(stream, buf, sizeof(buf)); 1046 assert(nr == -1); 1047 1048 /* DATA frame was consumed: */ 1049 assert(stream->read_offset == 5); 1050 1051 lsquic_stream_destroy(stream); 1052 deinit_test_objs(&tobjs); 1053 1054 stream_ctor_flags &= ~SCF_IETF; 1055} 1056 1057 1058/* Receiving DATA frame with zero payload should result in lsquic_stream_read() 1059 * returning -1. 1060 */ 1061static void 1062test_reading_zero_size_data_frame_scenario2 (void) 1063{ 1064 struct test_objs tobjs; 1065 struct lsquic_stream *stream; 1066 struct stream_frame *frame; 1067 ssize_t nr; 1068 int s; 1069 unsigned char buf[2]; 1070 1071 init_test_ctl_settings(&g_ctl_settings); 1072 1073 stream_ctor_flags |= SCF_IETF; 1074 init_test_objs(&tobjs, 0x1000, 0x2000, 1252); 1075 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 1076 1077 stream = new_stream(&tobjs, 0, 0x1000); 1078 1079 /* Fake out reading of HEADERS frame: */ 1080 stream->stream_flags |= STREAM_HAVE_UH; 1081 stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */; 1082 stream->sm_hq_filter.hqfi_hist_idx++; 1083 1084 /* Zero-length DATA frame */ 1085 frame = new_frame_in_ext(&tobjs, 0, 5, 0, (uint8_t[5]){ 0, 1, 'a', 0, 0, }); 1086 s = lsquic_stream_frame_in(stream, frame); 1087 assert(s == 0); /* Self-check */ 1088 1089 assert(stream->read_offset == 2); /* Self-check */ 1090 1091 /* Read 'a' */ 1092 nr = lsquic_stream_read(stream, buf, 1); 1093 assert(nr == 1); 1094 assert(buf[0] == 'a'); 1095 1096 /* Check that read returns -1 */ 1097 nr = lsquic_stream_read(stream, buf, sizeof(buf)); 1098 assert(nr == -1); 1099 1100 /* DATA frame was consumed: */ 1101 assert(stream->read_offset == 5); 1102 1103 lsquic_stream_destroy(stream); 1104 deinit_test_objs(&tobjs); 1105 1106 stream_ctor_flags &= ~SCF_IETF; 1107} 1108 1109 1110/* Receiving DATA frame with zero payload should result in lsquic_stream_read() 1111 * returning -1. 1112 */ 1113static void 1114test_reading_zero_size_data_frame_scenario3 (void) 1115{ 1116 struct test_objs tobjs; 1117 struct lsquic_stream *stream; 1118 struct stream_frame *frame; 1119 ssize_t nr; 1120 int s; 1121 unsigned char buf[2]; 1122 1123 init_test_ctl_settings(&g_ctl_settings); 1124 1125 stream_ctor_flags |= SCF_IETF; 1126 init_test_objs(&tobjs, 0x1000, 0x2000, 1252); 1127 tobjs.ctor_flags |= SCF_HTTP|SCF_IETF; 1128 1129 stream = new_stream(&tobjs, 0, 0x1000); 1130 1131 /* Fake out reading of HEADERS frame: */ 1132 stream->stream_flags |= STREAM_HAVE_UH; 1133 stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */; 1134 stream->sm_hq_filter.hqfi_hist_idx++; 1135 1136 /* Zero-length DATA frame */ 1137 frame = new_frame_in_ext(&tobjs, 0, 4, 0, (uint8_t[4]){ 0, 1, 'a', 0, }); 1138 s = lsquic_stream_frame_in(stream, frame); 1139 assert(s == 0); /* Self-check */ 1140 1141 assert(stream->read_offset == 2); /* Self-check */ 1142 1143 /* Read 'a' */ 1144 nr = lsquic_stream_read(stream, buf, 1); 1145 assert(nr == 1); 1146 assert(buf[0] == 'a'); 1147 1148 /* Check that read returns -1 */ 1149 nr = lsquic_stream_read(stream, buf, sizeof(buf)); 1150 assert(nr == -1); 1151 1152 /* Zero-length DATA frame */ 1153 frame = new_frame_in_ext(&tobjs, 4, 1, 0, (uint8_t[1]){ 0, }); 1154 s = lsquic_stream_frame_in(stream, frame); 1155 assert(s == 0); /* Self-check */ 1156 1157 /* Check that read returns -1 */ 1158 nr = lsquic_stream_read(stream, buf, sizeof(buf)); 1159 assert(nr == -1); 1160 1161 /* DATA frame was consumed: */ 1162 assert(stream->read_offset == 5); 1163 1164 lsquic_stream_destroy(stream); 1165 deinit_test_objs(&tobjs); 1166 1167 stream_ctor_flags &= ~SCF_IETF; 1168} 1169 1170 1171int 1172main (int argc, char **argv) 1173{ 1174 const char *fuzz_input = NULL; 1175 int opt, add_one_more; 1176 unsigned n_packets, extra_sz; 1177 1178 lsquic_global_init(LSQUIC_GLOBAL_SERVER); 1179 1180 while (-1 != (opt = getopt(argc, argv, "f:l:"))) 1181 { 1182 switch (opt) 1183 { 1184 case 'f': 1185 fuzz_input = optarg; 1186 break; 1187 case 'l': 1188 lsquic_log_to_fstream(stderr, 0); 1189 lsquic_logger_lopt(optarg); 1190 break; 1191 default: 1192 exit(1); 1193 } 1194 } 1195 1196 init_test_ctl_settings(&g_ctl_settings); 1197 1198 if (fuzz_input) 1199 fuzz_guided_testing(fuzz_input); 1200 else 1201 { 1202 main_test_hq_framing(); 1203 for (n_packets = 1; n_packets <= 2; ++n_packets) 1204 for (extra_sz = 0; extra_sz <= 2; ++extra_sz) 1205 for (add_one_more = 0; add_one_more <= 1; ++add_one_more) 1206 test_frame_header_split(n_packets, extra_sz, add_one_more); 1207 test_zero_size_frame(); 1208 test_reading_zero_size_data_frame(); 1209 test_reading_zero_size_data_frame_scenario2(); 1210 test_reading_zero_size_data_frame_scenario3(); 1211 } 1212 1213 return 0; 1214} 1215 1216static const char on_being_idle[] = 1217"ON BEING IDLE." 1218"" 1219"Now, this is a subject on which I flatter myself I really am _au fait_." 1220"The gentleman who, when I was young, bathed me at wisdom's font for nine" 1221"guineas a term--no extras--used to say he never knew a boy who could" 1222"do less work in more time; and I remember my poor grandmother once" 1223"incidentally observing, in the course of an instruction upon the use" 1224"of the Prayer-book, that it was highly improbable that I should ever do" 1225"much that I ought not to do, but that she felt convinced beyond a doubt" 1226"that I should leave undone pretty well everything that I ought to do." 1227"" 1228"I am afraid I have somewhat belied half the dear old lady's prophecy." 1229"Heaven help me! I have done a good many things that I ought not to have" 1230"done, in spite of my laziness. But I have fully confirmed the accuracy" 1231"of her judgment so far as neglecting much that I ought not to have" 1232"neglected is concerned. Idling always has been my strong point. I take" 1233"no credit to myself in the matter--it is a gift. Few possess it. There" 1234"are plenty of lazy people and plenty of slow-coaches, but a genuine" 1235"idler is a rarity. He is not a man who slouches about with his hands in" 1236"his pockets. On the contrary, his most startling characteristic is that" 1237"he is always intensely busy." 1238"" 1239"It is impossible to enjoy idling thoroughly unless one has plenty of" 1240"work to do. There is no fun in doing nothing when you have nothing to" 1241"do. Wasting time is merely an occupation then, and a most exhausting" 1242"one. Idleness, like kisses, to be sweet must be stolen." 1243"" 1244"Many years ago, when I was a young man, I was taken very ill--I never" 1245"could see myself that much was the matter with me, except that I had" 1246"a beastly cold. But I suppose it was something very serious, for the" 1247"doctor said that I ought to have come to him a month before, and that" 1248"if it (whatever it was) had gone on for another week he would not have" 1249"answered for the consequences. It is an extraordinary thing, but I" 1250"never knew a doctor called into any case yet but what it transpired" 1251"that another day's delay would have rendered cure hopeless. Our medical" 1252"guide, philosopher, and friend is like the hero in a melodrama--he" 1253"always comes upon the scene just, and only just, in the nick of time. It" 1254"is Providence, that is what it is." 1255"" 1256"Well, as I was saying, I was very ill and was ordered to Buxton for a" 1257"month, with strict injunctions to do nothing whatever all the while" 1258"that I was there. \"Rest is what you require,\" said the doctor, \"perfect" 1259"rest.\"" 1260"" 1261"It seemed a delightful prospect. \"This man evidently understands my" 1262"complaint,\" said I, and I pictured to myself a glorious time--a four" 1263"weeks' _dolce far niente_ with a dash of illness in it. Not too much" 1264"illness, but just illness enough--just sufficient to give it the flavor" 1265"of suffering and make it poetical. I should get up late, sip chocolate," 1266"and have my breakfast in slippers and a dressing-gown. I should lie out" 1267"in the garden in a hammock and read sentimental novels with a melancholy" 1268"ending, until the books should fall from my listless hand, and I should" 1269"recline there, dreamily gazing into the deep blue of the firmament," 1270"watching the fleecy clouds floating like white-sailed ships across" 1271"its depths, and listening to the joyous song of the birds and the low" 1272"rustling of the trees. Or, on becoming too weak to go out of doors," 1273"I should sit propped up with pillows at the open window of the" 1274"ground-floor front, and look wasted and interesting, so that all the" 1275"pretty girls would sigh as they passed by." 1276"" 1277"And twice a day I should go down in a Bath chair to the Colonnade to" 1278"drink the waters. Oh, those waters! I knew nothing about them then," 1279"and was rather taken with the idea. \"Drinking the waters\" sounded" 1280"fashionable and Queen Anne-fied, and I thought I should like them. But," 1281"ugh! after the first three or four mornings! Sam Weller's description of" 1282"them as \"having a taste of warm flat-irons\" conveys only a faint idea of" 1283"their hideous nauseousness. If anything could make a sick man get well" 1284"quickly, it would be the knowledge that he must drink a glassful of them" 1285"every day until he was recovered. I drank them neat for six consecutive" 1286"days, and they nearly killed me; but after then I adopted the plan of" 1287"taking a stiff glass of brandy-and-water immediately on the top of them," 1288"and found much relief thereby. I have been informed since, by various" 1289"eminent medical gentlemen, that the alcohol must have entirely" 1290"counteracted the effects of the chalybeate properties contained in the" 1291"water. I am glad I was lucky enough to hit upon the right thing." 1292; 1293 1294static void 1295init_buf (void *buf, size_t sz) 1296{ 1297 unsigned char *p = buf; 1298 unsigned char *const end = (unsigned char*)buf + sz; 1299 size_t n; 1300 1301 while (p < end) 1302 { 1303 n = end - p; 1304 if (sizeof(on_being_idle) - 1 < n) 1305 n = sizeof(on_being_idle) - 1; 1306 memcpy(p, on_being_idle, n); 1307 p +=n; 1308 } 1309 1310 assert(p == end); 1311} 1312