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