test_h3_framing.c revision fb3e20e0
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
496#define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1,
497
498static void
499test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize,
500                    int flush_after_each_write, size_t conn_limit,
501                    unsigned n_packets, unsigned short packet_sz)
502{
503    struct test_objs tobjs;
504    struct lsquic_stream *stream;
505    size_t nw;
506    int fin, s;
507    unsigned char *buf_in, *buf_out;
508    const size_t buf_in_sz = 0x40000, buf_out_sz = 0x500000;
509
510    /* We'll write headers first after which stream will switch to using
511     * data-framing writer.  This is simply so that we don't have to
512     * expose more stream things only for testing.
513     */
514    struct lsxpack_header header = { XHDR(":method", "GET") };
515    struct lsquic_http_headers headers = { 1, &header, };
516
517    buf_in = malloc(buf_in_sz);
518    buf_out = malloc(buf_out_sz);
519    assert(buf_in && buf_out);
520
521    struct packetization_test_stream_ctx packet_stream_ctx =
522    {
523        .buf = buf_in,
524        .off = 0,
525        .len = buf_in_sz,
526        .write_size = wsize,
527        .flush_after_each_write = flush_after_each_write,
528    };
529
530    init_buf(buf_in, buf_in_sz);
531
532    init_test_ctl_settings(&g_ctl_settings);
533    g_ctl_settings.tcs_schedule_stream_packets_immediately = sched_immed;
534
535    stream_ctor_flags |= SCF_IETF;
536    init_test_objs(&tobjs, conn_limit ? conn_limit : buf_out_sz, buf_out_sz, packet_sz);
537    tobjs.stream_if_ctx = &packet_stream_ctx;
538    tobjs.ctor_flags |= SCF_HTTP|SCF_IETF;
539    if (sched_immed)
540    {
541        g_ctl_settings.tcs_can_send = n_packets;
542        if (dispatch_once)
543        {
544            tobjs.stream_if = &packetization_inside_once_stream_if;
545            tobjs.ctor_flags |= SCF_DISP_RW_ONCE;
546        }
547        else
548            tobjs.stream_if = &packetization_inside_many_stream_if;
549    }
550    else
551    {
552        lsquic_send_ctl_set_max_bpq_count(n_packets);
553        g_ctl_settings.tcs_can_send = INT_MAX;
554        /* Need this for on_new_stream() callback not to mess with
555         * the context, otherwise this is not used.
556         */
557        tobjs.stream_if = &packetization_inside_many_stream_if;
558    }
559
560    stream = new_stream(&tobjs, 0, buf_out_sz);
561
562    s = lsquic_stream_send_headers(stream, &headers, 0);
563    assert(0 == s);
564
565    if (sched_immed)
566    {
567        lsquic_stream_dispatch_write_events(stream);
568        lsquic_stream_flush(stream);
569    }
570    else
571    {
572        packetization_write_as_much_as_you_can(stream,
573                                                (void *) &packet_stream_ctx);
574        g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
575        lsquic_send_ctl_schedule_buffered(&tobjs.send_ctl, BPT_HIGHEST_PRIO);
576        g_ctl_settings.tcs_schedule_stream_packets_immediately = 0;
577    }
578    lsquic_send_ctl_set_max_bpq_count(10);
579
580    /* Verify written data: */
581    nw = read_from_scheduled_packets(&tobjs.send_ctl, 0, buf_out, buf_out_sz,
582                                     0, &fin, 1);
583    if (!conn_limit)
584        assert(nw > buf_in_sz);
585    {   /* Remove framing and verify contents */
586        const unsigned char *src;
587        unsigned char *dst;
588        uint64_t sz;
589        unsigned frame_type;
590        int s;
591
592        src = buf_out;
593        dst = buf_out;
594        while (src < buf_out + nw)
595        {
596            frame_type = *src++;
597            s = vint_read(src, buf_out + buf_out_sz, &sz);
598            assert(s > 0);
599            /* In some rare circumstances it is possible to produce zero-length
600             * DATA frames:
601             *
602             * assert(sz > 0);
603             */
604            assert(sz < (1 << 14));
605            src += s;
606            if (src == buf_out + s + 1)
607            {
608                /* Ignore headers */
609                assert(frame_type == HQFT_HEADERS);
610                src += sz;
611            }
612            else
613            {
614                assert(frame_type == HQFT_DATA);
615                if (src + sz > buf_out + nw)    /* Chopped DATA frame (last) */
616                    sz = buf_out + nw - src;
617                memmove(dst, src, sz);
618                dst += sz;
619                src += sz;
620            }
621        }
622        if (!conn_limit)
623            assert(buf_in_sz == (uintptr_t) dst - (uintptr_t) buf_out);
624        assert(0 == memcmp(buf_in, buf_out, (uintptr_t) dst - (uintptr_t) buf_out));
625    }
626
627    lsquic_stream_destroy(stream);
628    deinit_test_objs(&tobjs);
629    free(buf_in);
630    free(buf_out);
631
632    stream_ctor_flags &= ~SCF_IETF;
633}
634
635
636static void
637main_test_hq_framing (void)
638{
639    const unsigned wsizes[] = { 1, 2, 3, 7, 10, 50, 100, 201, 211, 1000, 2003, 20000, };
640    const size_t conn_limits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
641        14, 15, 16, 17, 18, 19, 20, 21, 30, 31, 32, 33, 63, 64, 128, 200, 255,
642        256, 512, 1024, 2045, 2048, 2049, 3000, 4091, 4096, 4097, 5000, 8192,
643        16 * 1024 - 1, 16 * 1024, 32 * 1024, 33 * 1024, };
644    const unsigned n_packets[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, UINT_MAX, };
645    const unsigned short packet_sz[] = { 1252, 1370, 0x1000, 0xFF00, };
646    unsigned i, j, k, l;
647    int sched_immed, dispatch_once, flush_after_each_write;
648
649    for (sched_immed = 0; sched_immed <= 1; ++sched_immed)
650        for (dispatch_once = 0; dispatch_once <= 1; ++dispatch_once)
651            for (i = 0; i < sizeof(wsizes) / sizeof(wsizes[i]); ++i)
652                for (j = 0; j < sizeof(conn_limits) / sizeof(conn_limits[j]); ++j)
653                    for (flush_after_each_write = 0; flush_after_each_write < 2; ++flush_after_each_write)
654                        for (k = 0; k < sizeof(n_packets) / sizeof(n_packets[0]); ++k)
655                            for (l = 0; l < sizeof(packet_sz) / sizeof(packet_sz[0]); ++l)
656                                test_hq_framing(sched_immed, dispatch_once, wsizes[i], flush_after_each_write, conn_limits[j], n_packets[k], packet_sz[l]);
657}
658
659
660/* Instead of the not-very-random testing done in main_test_hq_framing(),
661 * the fuzz-guided testing initializes parameters based on the fuzz input
662 * file.  This allows afl-fuzz explore the code paths.
663 */
664void
665fuzz_guided_testing (const char *input)
666{
667                                /* Range */                 /* Bytes from file */
668    unsigned short packet_sz;   /* [200, 0x3FFF] */         /* 2 */
669    unsigned wsize;             /* [1, 20000] */            /* 2 */
670    unsigned n_packets;         /* [1, 255] and UINT_MAX */ /* 1 */
671    size_t conn_limit;          /* [1, 33K] */              /* 2 */
672    int sched_immed;            /* 0 or 1 */                /* 1 */
673    int dispatch_once;          /* 0 or 1 */                /* 0 (same as above) */
674    int flush_after_each_write; /* 0 or 1 */                /* 0 (same as above) */
675                                                     /* TOTAL: 8 bytes */
676
677    FILE *f;
678    size_t nread;
679    uint16_t tmp;
680    unsigned char buf[9];
681
682    f = fopen(input, "rb");
683    if (!f)
684    {
685        assert(0);
686        return;
687    }
688
689    nread = fread(buf, 1, sizeof(buf), f);
690    if (nread != 8)
691        goto cleanup;
692
693    memcpy(&tmp, &buf[0], 2);
694    if (tmp < 200)
695        tmp = 200;
696    else if (tmp > IQUIC_MAX_OUT_PACKET_SZ)
697        tmp = IQUIC_MAX_OUT_PACKET_SZ;
698    packet_sz = tmp;
699
700    memcpy(&tmp, &buf[2], 2);
701    if (tmp < 1)
702        tmp = 1;
703    else if (tmp > 20000)
704        tmp = 20000;
705    wsize = tmp;
706
707    if (buf[4])
708        n_packets = buf[4];
709    else
710        n_packets = UINT_MAX;
711
712    memcpy(&tmp, &buf[5], 2);
713    if (tmp < 1)
714        tmp = 1;
715    else if (tmp > 33 * 1024)
716        tmp = 33 * 1024;
717    conn_limit = tmp;
718
719    sched_immed             = !!(buf[7] & 1);
720    dispatch_once           = !!(buf[7] & 2);
721    flush_after_each_write  = !!(buf[7] & 4);
722
723    test_hq_framing(sched_immed, dispatch_once, wsize,
724        flush_after_each_write, conn_limit, n_packets, packet_sz);
725
726  cleanup:
727    (void) fclose(f);
728}
729
730
731static void
732test_frame_header_split (unsigned n_packets, unsigned extra_sz,
733                                                        int add_one_more)
734{
735    struct test_objs tobjs;
736    struct lsquic_stream *stream;
737    size_t nw;
738    int fin, s;
739    unsigned char *buf_in, *buf_out;
740    const unsigned wsize = 70;
741    const size_t buf_in_sz = wsize, buf_out_sz = 0x500000;
742
743    struct lsxpack_header header = { XHDR(":method", "GET") };
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 = { XHDR(":method", "GET") };
859    struct lsquic_http_headers headers = { 1, &header, };
860
861    buf_in = malloc(buf_in_sz);
862    buf_out = malloc(buf_out_sz);
863    assert(buf_in && buf_out);
864
865    struct packetization_test_stream_ctx packet_stream_ctx =
866    {
867        .buf = buf_in,
868        .off = 0,
869        .len = buf_in_sz,
870        .write_size = wsize,
871        .flush_after_each_write = 0,
872    };
873
874    init_buf(buf_in, buf_in_sz);
875
876    init_test_ctl_settings(&g_ctl_settings);
877    g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
878
879    stream_ctor_flags |= SCF_IETF;
880    init_test_objs(&tobjs, 0x1000, buf_out_sz, 1252);
881    tobjs.stream_if_ctx = &packet_stream_ctx;
882    tobjs.ctor_flags |= SCF_HTTP|SCF_IETF;
883
884    g_ctl_settings.tcs_can_send = 1;
885    tobjs.stream_if = &packetization_inside_once_stream_if;
886    tobjs.ctor_flags |= SCF_DISP_RW_ONCE;
887
888    struct lsquic_packet_out *const packet_out
889        = lsquic_send_ctl_new_packet_out(&tobjs.send_ctl, 0, PNS_APP, &network_path);
890    assert(packet_out);
891    const size_t pad_size = packet_out->po_n_alloc
892                          - 2   /* STREAM header */
893                          - 5   /* 3-byte HEADERS frame */
894                          - 3;
895    packet_out->po_data_sz = pad_size;
896    lsquic_send_ctl_scheduled_one(&tobjs.send_ctl, packet_out);
897
898    stream = new_stream(&tobjs, 0, buf_out_sz);
899
900    s = lsquic_stream_send_headers(stream, &headers, 0);
901    assert(0 == s);
902
903    w = lsquic_stream_write(stream, buf_in, buf_in_sz);
904    assert(w >= 0);
905    lsquic_stream_flush(stream);
906
907    g_ctl_settings.tcs_can_send++;
908    w = lsquic_stream_write(stream, buf_in, buf_in_sz);
909    assert(w >= 0);
910    lsquic_stream_flush(stream);
911
912    /* Verify written data: */
913    nw = read_from_scheduled_packets(&tobjs.send_ctl, 0, buf_out, buf_out_sz,
914                                     0, &fin, 1);
915    {   /* Remove framing and verify contents */
916        const unsigned char *src;
917        unsigned char *dst;
918        uint64_t sz;
919        unsigned frame_type;
920        int s;
921
922        src = buf_out;
923        dst = buf_out;
924        while (src < buf_out + nw)
925        {
926            frame_type = *src++;
927            s = vint_read(src, buf_out + buf_out_sz, &sz);
928            assert(s > 0);
929            assert(sz < (1 << 14));
930            src += s;
931            if (src == buf_out + s + 1)
932            {
933                /* Ignore headers */
934                assert(frame_type == HQFT_HEADERS);
935                src += sz;
936            }
937            else
938            {
939                assert(frame_type == HQFT_DATA);
940                if (src + sz > buf_out + nw)    /* Chopped DATA frame (last) */
941                    sz = buf_out + nw - src;
942                memmove(dst, src, sz);
943                dst += sz;
944                src += sz;
945            }
946        }
947        assert(0 == memcmp(buf_in, buf_out, (uintptr_t) dst - (uintptr_t) buf_out));
948    }
949
950    lsquic_stream_destroy(stream);
951    deinit_test_objs(&tobjs);
952    free(buf_in);
953    free(buf_out);
954
955    stream_ctor_flags &= ~SCF_IETF;
956}
957
958
959/* Create a new stream frame.  Each stream frame has a real packet_in to
960 * back it up, just like in real code.  The contents of the packet do
961 * not matter.
962 */
963static stream_frame_t *
964new_frame_in_ext (struct test_objs *tobjs, size_t off, size_t sz, int fin,
965                                                            const void *data)
966{
967    lsquic_packet_in_t *packet_in;
968    stream_frame_t *frame;
969
970    assert(sz <= 1370);
971
972    packet_in = lsquic_mm_get_packet_in(&tobjs->eng_pub.enp_mm);
973    if (data)
974        packet_in->pi_data = (void *) data;
975    else
976    {
977        packet_in->pi_data = lsquic_mm_get_packet_in_buf(&tobjs->eng_pub.enp_mm, 1370);
978        packet_in->pi_flags |= PI_OWN_DATA;
979        memset(packet_in->pi_data, 'A', sz);
980    }
981    /* This is not how stream frame looks in the packet: we have no
982     * header.  In our test case it does not matter, as we only care
983     * about stream frame.
984     */
985    packet_in->pi_data_sz = sz;
986    packet_in->pi_refcnt = 1;
987
988    frame = lsquic_malo_get(tobjs->eng_pub.enp_mm.malo.stream_frame);
989    memset(frame, 0, sizeof(*frame));
990    frame->packet_in = packet_in;
991    frame->data_frame.df_offset = off;
992    frame->data_frame.df_size = sz;
993    frame->data_frame.df_data = &packet_in->pi_data[0];
994    frame->data_frame.df_fin  = fin;
995
996    return frame;
997}
998
999
1000/* Receiving DATA frame with zero payload should result in lsquic_stream_read()
1001 * returning -1.
1002 */
1003static void
1004test_reading_zero_size_data_frame (void)
1005{
1006    struct test_objs tobjs;
1007    struct lsquic_stream *stream;
1008    struct stream_frame *frame;
1009    ssize_t nr;
1010    int s;
1011    unsigned char buf[2];
1012
1013    init_test_ctl_settings(&g_ctl_settings);
1014
1015    stream_ctor_flags |= SCF_IETF;
1016    init_test_objs(&tobjs, 0x1000, 0x2000, 1252);
1017    tobjs.ctor_flags |= SCF_HTTP|SCF_IETF;
1018
1019    stream = new_stream(&tobjs, 0, 0x1000);
1020
1021    /* Fake out reading of HEADERS frame: */
1022    stream->stream_flags |= STREAM_HAVE_UH;
1023    stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */;
1024    stream->sm_hq_filter.hqfi_hist_idx++;
1025
1026    /* One-byte DATA frame */
1027    frame = new_frame_in_ext(&tobjs, 0, 3, 0, (uint8_t[3]){ 0, 1, 'a', });
1028    s = lsquic_stream_frame_in(stream, frame);
1029    assert(s == 0);     /* Self-check */
1030
1031    /* Zero-length DATA frame */
1032    frame = new_frame_in_ext(&tobjs, 3, 2, 0, (uint8_t[2]){ 0, 0, });
1033    s = lsquic_stream_frame_in(stream, frame);
1034    assert(s == 0);     /* Self-check */
1035
1036    assert(stream->read_offset == 2);   /* Self-check */
1037
1038    /* Read 'a' */
1039    nr = lsquic_stream_read(stream, buf, 1);
1040    assert(nr == 1);
1041    assert(buf[0] == 'a');
1042
1043    /* Check that read returns -1 */
1044    nr = lsquic_stream_read(stream, buf, sizeof(buf));
1045    assert(nr == -1);
1046
1047    /* DATA frame was consumed: */
1048    assert(stream->read_offset == 5);
1049
1050    lsquic_stream_destroy(stream);
1051    deinit_test_objs(&tobjs);
1052
1053    stream_ctor_flags &= ~SCF_IETF;
1054}
1055
1056
1057/* Receiving DATA frame with zero payload should result in lsquic_stream_read()
1058 * returning -1.
1059 */
1060static void
1061test_reading_zero_size_data_frame_scenario2 (void)
1062{
1063    struct test_objs tobjs;
1064    struct lsquic_stream *stream;
1065    struct stream_frame *frame;
1066    ssize_t nr;
1067    int s;
1068    unsigned char buf[2];
1069
1070    init_test_ctl_settings(&g_ctl_settings);
1071
1072    stream_ctor_flags |= SCF_IETF;
1073    init_test_objs(&tobjs, 0x1000, 0x2000, 1252);
1074    tobjs.ctor_flags |= SCF_HTTP|SCF_IETF;
1075
1076    stream = new_stream(&tobjs, 0, 0x1000);
1077
1078    /* Fake out reading of HEADERS frame: */
1079    stream->stream_flags |= STREAM_HAVE_UH;
1080    stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */;
1081    stream->sm_hq_filter.hqfi_hist_idx++;
1082
1083    /* Zero-length DATA frame */
1084    frame = new_frame_in_ext(&tobjs, 0, 5, 0, (uint8_t[5]){ 0, 1, 'a', 0, 0, });
1085    s = lsquic_stream_frame_in(stream, frame);
1086    assert(s == 0);     /* Self-check */
1087
1088    assert(stream->read_offset == 2);   /* Self-check */
1089
1090    /* Read 'a' */
1091    nr = lsquic_stream_read(stream, buf, 1);
1092    assert(nr == 1);
1093    assert(buf[0] == 'a');
1094
1095    /* Check that read returns -1 */
1096    nr = lsquic_stream_read(stream, buf, sizeof(buf));
1097    assert(nr == -1);
1098
1099    /* DATA frame was consumed: */
1100    assert(stream->read_offset == 5);
1101
1102    lsquic_stream_destroy(stream);
1103    deinit_test_objs(&tobjs);
1104
1105    stream_ctor_flags &= ~SCF_IETF;
1106}
1107
1108
1109/* Receiving DATA frame with zero payload should result in lsquic_stream_read()
1110 * returning -1.
1111 */
1112static void
1113test_reading_zero_size_data_frame_scenario3 (void)
1114{
1115    struct test_objs tobjs;
1116    struct lsquic_stream *stream;
1117    struct stream_frame *frame;
1118    ssize_t nr;
1119    int s;
1120    unsigned char buf[2];
1121
1122    init_test_ctl_settings(&g_ctl_settings);
1123
1124    stream_ctor_flags |= SCF_IETF;
1125    init_test_objs(&tobjs, 0x1000, 0x2000, 1252);
1126    tobjs.ctor_flags |= SCF_HTTP|SCF_IETF;
1127
1128    stream = new_stream(&tobjs, 0, 0x1000);
1129
1130    /* Fake out reading of HEADERS frame: */
1131    stream->stream_flags |= STREAM_HAVE_UH;
1132    stream->sm_hq_filter.hqfi_hist_buf = 1 /* CODE_HEADER */;
1133    stream->sm_hq_filter.hqfi_hist_idx++;
1134
1135    /* Zero-length DATA frame */
1136    frame = new_frame_in_ext(&tobjs, 0, 4, 0, (uint8_t[4]){ 0, 1, 'a', 0, });
1137    s = lsquic_stream_frame_in(stream, frame);
1138    assert(s == 0);     /* Self-check */
1139
1140    assert(stream->read_offset == 2);   /* Self-check */
1141
1142    /* Read 'a' */
1143    nr = lsquic_stream_read(stream, buf, 1);
1144    assert(nr == 1);
1145    assert(buf[0] == 'a');
1146
1147    /* Check that read returns -1 */
1148    nr = lsquic_stream_read(stream, buf, sizeof(buf));
1149    assert(nr == -1);
1150
1151    /* Zero-length DATA frame */
1152    frame = new_frame_in_ext(&tobjs, 4, 1, 0, (uint8_t[1]){ 0, });
1153    s = lsquic_stream_frame_in(stream, frame);
1154    assert(s == 0);     /* Self-check */
1155
1156    /* Check that read returns -1 */
1157    nr = lsquic_stream_read(stream, buf, sizeof(buf));
1158    assert(nr == -1);
1159
1160    /* DATA frame was consumed: */
1161    assert(stream->read_offset == 5);
1162
1163    lsquic_stream_destroy(stream);
1164    deinit_test_objs(&tobjs);
1165
1166    stream_ctor_flags &= ~SCF_IETF;
1167}
1168
1169
1170int
1171main (int argc, char **argv)
1172{
1173    const char *fuzz_input = NULL;
1174    int opt, add_one_more;
1175    unsigned n_packets, extra_sz;
1176
1177    lsquic_global_init(LSQUIC_GLOBAL_SERVER);
1178
1179    while (-1 != (opt = getopt(argc, argv, "f:l:")))
1180    {
1181        switch (opt)
1182        {
1183        case 'f':
1184            fuzz_input = optarg;
1185            break;
1186        case 'l':
1187            lsquic_log_to_fstream(stderr, 0);
1188            lsquic_logger_lopt(optarg);
1189            break;
1190        default:
1191            exit(1);
1192        }
1193    }
1194
1195    init_test_ctl_settings(&g_ctl_settings);
1196
1197    if (fuzz_input)
1198        fuzz_guided_testing(fuzz_input);
1199    else
1200    {
1201        main_test_hq_framing();
1202        for (n_packets = 1; n_packets <= 2; ++n_packets)
1203            for (extra_sz = 0; extra_sz <= 2; ++extra_sz)
1204                for (add_one_more = 0; add_one_more <= 1; ++add_one_more)
1205                    test_frame_header_split(n_packets, extra_sz, add_one_more);
1206        test_zero_size_frame();
1207        test_reading_zero_size_data_frame();
1208        test_reading_zero_size_data_frame_scenario2();
1209        test_reading_zero_size_data_frame_scenario3();
1210    }
1211
1212    return 0;
1213}
1214
1215static const char on_being_idle[] =
1216"ON BEING IDLE."
1217""
1218"Now, this is a subject on which I flatter myself I really am _au fait_."
1219"The gentleman who, when I was young, bathed me at wisdom's font for nine"
1220"guineas a term--no extras--used to say he never knew a boy who could"
1221"do less work in more time; and I remember my poor grandmother once"
1222"incidentally observing, in the course of an instruction upon the use"
1223"of the Prayer-book, that it was highly improbable that I should ever do"
1224"much that I ought not to do, but that she felt convinced beyond a doubt"
1225"that I should leave undone pretty well everything that I ought to do."
1226""
1227"I am afraid I have somewhat belied half the dear old lady's prophecy."
1228"Heaven help me! I have done a good many things that I ought not to have"
1229"done, in spite of my laziness. But I have fully confirmed the accuracy"
1230"of her judgment so far as neglecting much that I ought not to have"
1231"neglected is concerned. Idling always has been my strong point. I take"
1232"no credit to myself in the matter--it is a gift. Few possess it. There"
1233"are plenty of lazy people and plenty of slow-coaches, but a genuine"
1234"idler is a rarity. He is not a man who slouches about with his hands in"
1235"his pockets. On the contrary, his most startling characteristic is that"
1236"he is always intensely busy."
1237""
1238"It is impossible to enjoy idling thoroughly unless one has plenty of"
1239"work to do. There is no fun in doing nothing when you have nothing to"
1240"do. Wasting time is merely an occupation then, and a most exhausting"
1241"one. Idleness, like kisses, to be sweet must be stolen."
1242""
1243"Many years ago, when I was a young man, I was taken very ill--I never"
1244"could see myself that much was the matter with me, except that I had"
1245"a beastly cold. But I suppose it was something very serious, for the"
1246"doctor said that I ought to have come to him a month before, and that"
1247"if it (whatever it was) had gone on for another week he would not have"
1248"answered for the consequences. It is an extraordinary thing, but I"
1249"never knew a doctor called into any case yet but what it transpired"
1250"that another day's delay would have rendered cure hopeless. Our medical"
1251"guide, philosopher, and friend is like the hero in a melodrama--he"
1252"always comes upon the scene just, and only just, in the nick of time. It"
1253"is Providence, that is what it is."
1254""
1255"Well, as I was saying, I was very ill and was ordered to Buxton for a"
1256"month, with strict injunctions to do nothing whatever all the while"
1257"that I was there. \"Rest is what you require,\" said the doctor, \"perfect"
1258"rest.\""
1259""
1260"It seemed a delightful prospect. \"This man evidently understands my"
1261"complaint,\" said I, and I pictured to myself a glorious time--a four"
1262"weeks' _dolce far niente_ with a dash of illness in it. Not too much"
1263"illness, but just illness enough--just sufficient to give it the flavor"
1264"of suffering and make it poetical. I should get up late, sip chocolate,"
1265"and have my breakfast in slippers and a dressing-gown. I should lie out"
1266"in the garden in a hammock and read sentimental novels with a melancholy"
1267"ending, until the books should fall from my listless hand, and I should"
1268"recline there, dreamily gazing into the deep blue of the firmament,"
1269"watching the fleecy clouds floating like white-sailed ships across"
1270"its depths, and listening to the joyous song of the birds and the low"
1271"rustling of the trees. Or, on becoming too weak to go out of doors,"
1272"I should sit propped up with pillows at the open window of the"
1273"ground-floor front, and look wasted and interesting, so that all the"
1274"pretty girls would sigh as they passed by."
1275""
1276"And twice a day I should go down in a Bath chair to the Colonnade to"
1277"drink the waters. Oh, those waters! I knew nothing about them then,"
1278"and was rather taken with the idea. \"Drinking the waters\" sounded"
1279"fashionable and Queen Anne-fied, and I thought I should like them. But,"
1280"ugh! after the first three or four mornings! Sam Weller's description of"
1281"them as \"having a taste of warm flat-irons\" conveys only a faint idea of"
1282"their hideous nauseousness. If anything could make a sick man get well"
1283"quickly, it would be the knowledge that he must drink a glassful of them"
1284"every day until he was recovered. I drank them neat for six consecutive"
1285"days, and they nearly killed me; but after then I adopted the plan of"
1286"taking a stiff glass of brandy-and-water immediately on the top of them,"
1287"and found much relief thereby. I have been informed since, by various"
1288"eminent medical gentlemen, that the alcohol must have entirely"
1289"counteracted the effects of the chalybeate properties contained in the"
1290"water. I am glad I was lucky enough to hit upon the right thing."
1291;
1292
1293static void
1294init_buf (void *buf, size_t sz)
1295{
1296    unsigned char *p = buf;
1297    unsigned char *const end = (unsigned char*)buf + sz;
1298    size_t n;
1299
1300    while (p < end)
1301    {
1302        n = end - p;
1303        if (sizeof(on_being_idle) - 1 < n)
1304            n = sizeof(on_being_idle) - 1;
1305        memcpy(p, on_being_idle, n);
1306        p +=n;
1307    }
1308
1309    assert(p == end);
1310}
1311