Coverage Report

Created: 2026-01-10 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2o/fuzz/quicly_mock.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2021 Fastly, Inc.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
23
#include <assert.h>
24
#include "khash.h"
25
#include "quicly.h"
26
#include "quicly/sendstate.h"
27
#include "quicly/recvstate.h"
28
#include "quicly_mock.h"
29
30
KHASH_MAP_INIT_INT64(quicly_stream_t, quicly_stream_t *)
31
32
mquicly_context_t mquicly_context;
33
34
struct st_quicly_conn_t {
35
    struct _st_quicly_conn_public_t super;
36
    khash_t(quicly_stream_t) * streams;
37
    struct {
38
        quicly_address_t local, remote;
39
    } address;
40
};
41
42
struct st_quicly_send_context_t {
43
};
44
45
static quicly_conn_t *create_connection(quicly_context_t *ctx, int is_client, struct sockaddr *remote_addr,
46
                                        struct sockaddr *local_addr)
47
6.66k
{
48
6.66k
    quicly_conn_t *conn = calloc(1, sizeof(*conn));
49
6.66k
    assert(conn != NULL);
50
6.66k
    conn->super.ctx = ctx;
51
6.66k
    if (is_client) {
52
0
        conn->super.local.bidi.next_stream_id = 0;
53
0
        conn->super.local.uni.next_stream_id = 2;
54
0
        conn->super.remote.bidi.next_stream_id = 1;
55
0
        conn->super.remote.uni.next_stream_id = 3;
56
6.66k
    } else {
57
6.66k
        conn->super.local.bidi.next_stream_id = 1;
58
6.66k
        conn->super.local.uni.next_stream_id = 3;
59
6.66k
        conn->super.remote.bidi.next_stream_id = 0;
60
6.66k
        conn->super.remote.uni.next_stream_id = 2;
61
6.66k
    }
62
6.66k
    conn->streams = kh_init(quicly_stream_t);
63
64
6.66k
    conn->address.local.sa = *local_addr;
65
6.66k
    conn->address.remote.sa = *remote_addr;
66
67
6.66k
    return conn;
68
6.66k
}
69
70
quicly_error_t quicly_accept(quicly_conn_t **conn, quicly_context_t *ctx, struct sockaddr *dest_addr, struct sockaddr *src_addr,
71
                             quicly_decoded_packet_t *packet, quicly_address_token_plaintext_t *address_token,
72
                             const quicly_cid_plaintext_t *new_cid, ptls_handshake_properties_t *handshake_properties,
73
                             void *appdata)
74
6.66k
{
75
6.66k
    *conn = create_connection(ctx, 0, src_addr, dest_addr);
76
6.66k
    (*conn)->super.state = QUICLY_STATE_CONNECTED;
77
6.66k
    return 0;
78
6.66k
}
79
80
int quicly_stream_sync_sendbuf(quicly_stream_t *stream, int activate)
81
22.2k
{
82
22.2k
    int ret;
83
84
22.2k
    if (activate) {
85
22.2k
        if ((ret = quicly_sendstate_activate(&stream->sendstate)) != 0)
86
0
            return ret;
87
22.2k
    }
88
89
22.2k
    quicly_stream_scheduler_t *scheduler = stream->conn->super.ctx->stream_scheduler;
90
22.2k
    scheduler->update_state(scheduler, stream);
91
22.2k
    return 0;
92
22.2k
}
93
94
void quicly_stream_sync_recvbuf(quicly_stream_t *stream, size_t shift_amount)
95
2.08k
{
96
2.08k
    stream->recvstate.data_off += shift_amount;
97
2.08k
}
98
99
int quicly_stream_can_send(quicly_stream_t *stream, int at_stream_level)
100
45.2k
{
101
    /* return if there is nothing to be sent */
102
45.2k
    if (stream->sendstate.pending.num_ranges == 0)
103
22.4k
        return 0;
104
22.7k
    return 1;
105
45.2k
}
106
107
ptls_t *quicly_get_tls(quicly_conn_t *conn)
108
576
{
109
    /* TODO: is this okay */
110
576
    return NULL;
111
576
}
112
113
int quicly_is_blocked(quicly_conn_t *conn)
114
44.7k
{
115
44.7k
    return 0;
116
44.7k
}
117
118
struct sockaddr *quicly_get_sockname(quicly_conn_t *conn)
119
0
{
120
0
    return &conn->address.local.sa;
121
0
}
122
123
struct sockaddr *quicly_get_peername(quicly_conn_t *conn)
124
576
{
125
576
    return &conn->address.remote.sa;
126
576
}
127
128
void quicly_request_stop(quicly_stream_t *stream, quicly_error_t err)
129
1.98k
{
130
1.98k
    stream->_send_aux.stop_sending.sender_state = QUICLY_SENDER_STATE_SEND;
131
1.98k
}
132
133
void quicly_reset_stream(quicly_stream_t *stream, quicly_error_t err)
134
1.07k
{
135
    /* dispose sendbuf state */
136
1.07k
    quicly_sendstate_reset(&stream->sendstate);
137
138
1.07k
    stream->_send_aux.reset_stream.sender_state = QUICLY_SENDER_STATE_SEND;
139
140
    /* inline expansion of resched_stream_data() */
141
    /* TODO: consider streams_blocked? */
142
1.07k
    quicly_stream_scheduler_t *scheduler = stream->conn->super.ctx->stream_scheduler;
143
1.07k
    scheduler->update_state(scheduler, stream);
144
1.07k
}
145
146
socklen_t quicly_get_socklen(struct sockaddr *sa)
147
576
{
148
576
    switch (sa->sa_family) {
149
576
    case AF_INET:
150
576
        return sizeof(struct sockaddr_in);
151
0
    case AF_INET6:
152
0
        return sizeof(struct sockaddr_in6);
153
0
    default:
154
0
        assert(!"unexpected socket type");
155
0
        return 0;
156
576
    }
157
576
}
158
159
size_t quicly_decode_packet(quicly_context_t *ctx, quicly_decoded_packet_t *packet, const uint8_t *datagram, size_t datagram_size,
160
                            size_t *off)
161
0
{
162
0
    assert(0 && "unimplemented");
163
0
    return 0;
164
0
}
165
166
quicly_error_t quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s)
167
21.9k
{
168
    /* quicly_send -> scheduler->do_send -> quicly_send_stream -> on_send_emit */
169
21.9k
    uint8_t buff[1024];
170
21.9k
    uint64_t off = stream->sendstate.pending.ranges[0].start, end_off;
171
21.9k
    size_t capacity = sizeof(buff);
172
21.9k
    int wrote_all = 0, is_fin;
173
21.9k
    quicly_error_t ret;
174
175
21.9k
    if (!quicly_sendstate_is_open(&stream->sendstate) && off == stream->sendstate.final_size) {
176
        /* special case for emitting FIN only */
177
511
        end_off = off;
178
511
        wrote_all = 1;
179
511
        is_fin = 1;
180
511
        goto UpdateState;
181
511
    }
182
21.4k
    { /* cap the capacity to the current range */
183
21.4k
        uint64_t range_capacity = stream->sendstate.pending.ranges[0].end - off;
184
21.4k
        if (!quicly_sendstate_is_open(&stream->sendstate) && off + range_capacity > stream->sendstate.final_size) {
185
904
            assert(range_capacity > 1); /* see the special case above */
186
904
            range_capacity -= 1;
187
904
        }
188
21.4k
        if (capacity > range_capacity)
189
904
            capacity = range_capacity;
190
21.4k
    }
191
0
    size_t len = capacity;
192
21.4k
    size_t emit_off = (size_t)(off - stream->sendstate.acked.ranges[0].end);
193
21.4k
    stream->callbacks->on_send_emit(stream, emit_off, buff, &len, &wrote_all);
194
195
21.4k
    end_off = off + len;
196
197
    /* determine if the frame incorporates FIN */
198
21.4k
    if (!quicly_sendstate_is_open(&stream->sendstate) && end_off == stream->sendstate.final_size) {
199
904
        is_fin = 1;
200
20.5k
    } else {
201
20.5k
        is_fin = 0;
202
20.5k
    }
203
204
21.9k
UpdateState:
205
    /* notify the fuzzing driver of stream send event */
206
21.9k
    if (mquicly_context.on_stream_send != NULL) {
207
21.9k
        mquicly_context.on_stream_send->cb(mquicly_context.on_stream_send, stream->conn, stream, buff, off, len, is_fin);
208
21.9k
    }
209
21.9k
    if (stream->sendstate.size_inflight < end_off) {
210
21.4k
        stream->sendstate.size_inflight = end_off;
211
21.4k
    }
212
21.9k
    if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, off, end_off + is_fin)) != 0)
213
0
        return ret;
214
21.9k
    if (wrote_all) {
215
21.9k
        if ((ret = quicly_ranges_subtract(&stream->sendstate.pending, stream->sendstate.size_inflight, UINT64_MAX)) != 0)
216
0
            return ret;
217
21.9k
    }
218
219
21.9k
    return 0;
220
21.9k
}
221
222
static quicly_stream_t *open_stream(quicly_conn_t *conn, quicly_stream_id_t stream_id)
223
26.6k
{
224
26.6k
    quicly_stream_t *stream;
225
226
26.6k
    if ((stream = calloc(1, sizeof(*stream))) == NULL)
227
0
        return NULL;
228
26.6k
    stream->conn = conn;
229
26.6k
    stream->stream_id = stream_id;
230
26.6k
    stream->callbacks = NULL;
231
26.6k
    stream->data = NULL;
232
233
26.6k
    int r;
234
26.6k
    khiter_t iter = kh_put(quicly_stream_t, conn->streams, stream_id, &r);
235
26.6k
    assert(iter != kh_end(conn->streams));
236
26.6k
    kh_val(conn->streams, iter) = stream;
237
238
26.6k
    int is_client = quicly_is_client(stream->conn);
239
240
26.6k
    if (quicly_stream_has_send_side(is_client, stream->stream_id)) {
241
26.6k
        quicly_sendstate_init(&stream->sendstate);
242
26.6k
    } else {
243
0
        quicly_sendstate_init_closed(&stream->sendstate);
244
0
    }
245
26.6k
    if (quicly_stream_has_receive_side(is_client, stream->stream_id)) {
246
6.66k
        quicly_recvstate_init(&stream->recvstate);
247
19.9k
    } else {
248
19.9k
        quicly_recvstate_init_closed(&stream->recvstate);
249
19.9k
    }
250
251
26.6k
    return stream;
252
26.6k
}
253
254
static struct st_quicly_conn_streamgroup_state_t *get_streamgroup_state(quicly_conn_t *conn, quicly_stream_id_t stream_id)
255
33.3k
{
256
33.3k
    if (quicly_is_client(conn) == quicly_stream_is_client_initiated(stream_id)) {
257
19.9k
        return quicly_stream_is_unidirectional(stream_id) ? &conn->super.local.uni : &conn->super.local.bidi;
258
19.9k
    } else {
259
13.3k
        return quicly_stream_is_unidirectional(stream_id) ? &conn->super.remote.uni : &conn->super.remote.bidi;
260
13.3k
    }
261
33.3k
}
262
263
int mquicly_open_stream(quicly_conn_t *conn, quicly_stream_t **stream, int is_remote_initiated, int unidirectional)
264
26.6k
{
265
26.6k
    struct st_quicly_conn_streamgroup_state_t *group;
266
267
26.6k
    if (is_remote_initiated) {
268
6.66k
        group = unidirectional ? &conn->super.remote.uni : &conn->super.remote.bidi;
269
19.9k
    } else {
270
19.9k
        group = unidirectional ? &conn->super.local.uni : &conn->super.local.bidi;
271
19.9k
    }
272
273
26.6k
    *stream = open_stream(conn, group->next_stream_id);
274
26.6k
    group->next_stream_id += 4;
275
26.6k
    group->num_streams++;
276
277
26.6k
    conn->super.ctx->stream_open->cb(conn->super.ctx->stream_open, *stream);
278
279
26.6k
    return 0;
280
26.6k
}
281
282
static void destroy_stream(quicly_stream_t *stream, int err)
283
26.6k
{
284
26.6k
    quicly_conn_t *conn = stream->conn;
285
286
26.6k
    if (stream->callbacks != NULL)
287
26.6k
        stream->callbacks->on_destroy(stream, err);
288
289
26.6k
    khiter_t iter = kh_get(quicly_stream_t, conn->streams, stream->stream_id);
290
26.6k
    assert(iter != kh_end(conn->streams));
291
26.6k
    kh_del(quicly_stream_t, conn->streams, iter);
292
293
26.6k
    struct st_quicly_conn_streamgroup_state_t *group = get_streamgroup_state(conn, stream->stream_id);
294
26.6k
    --group->num_streams;
295
296
26.6k
    quicly_sendstate_dispose(&stream->sendstate);
297
26.6k
    quicly_recvstate_dispose(&stream->recvstate);
298
299
26.6k
    free(stream);
300
26.6k
}
301
302
static void destroy_all_streams(quicly_conn_t *conn, int err)
303
9.15k
{
304
9.15k
    quicly_stream_t *stream;
305
9.15k
    kh_foreach_value(conn->streams, stream, { destroy_stream(stream, err); });
306
9.15k
    assert(quicly_num_streams(conn) == 0);
307
9.15k
}
308
309
int mquicly_closed_by_remote(quicly_conn_t *conn, int err, uint64_t frame_type, ptls_iovec_t reason_phrase)
310
2.49k
{
311
    /* TODO: invoke conn->super.ctx->closed_by_remote->cb() but h2o does not use it so far */
312
2.49k
    assert(conn->super.ctx->closed_by_remote == NULL);
313
2.49k
    conn->super.state = QUICLY_STATE_DRAINING;
314
2.49k
    destroy_all_streams(conn, err);
315
2.49k
    return 0;
316
2.49k
}
317
318
quicly_error_t quicly_open_stream(quicly_conn_t *conn, quicly_stream_t **stream, int unidirectional)
319
19.9k
{
320
19.9k
    return mquicly_open_stream(conn, stream, 0, unidirectional);
321
19.9k
}
322
323
quicly_error_t quicly_get_or_open_stream(quicly_conn_t *conn, uint64_t stream_id, quicly_stream_t **stream)
324
0
{
325
    /* conn->super.ctx->stream_open->cb */
326
0
    assert(0 && "unimplemented");
327
0
    return 0;
328
0
}
329
330
int quicly_is_destination(quicly_conn_t *conn, struct sockaddr *dest_addr, struct sockaddr *src_addr,
331
                          quicly_decoded_packet_t *decoded)
332
0
{
333
0
    assert(0 && "unimplemented");
334
0
    return 0;
335
0
}
336
337
uint32_t quicly_num_streams_by_group(quicly_conn_t *conn, int uni, int locally_initiated)
338
6.66k
{
339
6.66k
    int server_initiated = quicly_is_client(conn) != locally_initiated;
340
6.66k
    struct st_quicly_conn_streamgroup_state_t *state = get_streamgroup_state(conn, uni * 2 + server_initiated);
341
6.66k
    return state->num_streams;
342
6.66k
}
343
344
quicly_error_t quicly_get_delivery_rate(quicly_conn_t *conn, quicly_rate_t *delivery_rate)
345
0
{
346
    /* Do nothing */
347
0
    *delivery_rate = (quicly_rate_t){};
348
0
    return 0;
349
0
}
350
351
quicly_error_t quicly_get_stats(quicly_conn_t *conn, quicly_stats_t *stats)
352
6.66k
{
353
    /* Do nothing */
354
6.66k
    memset(stats, 0, sizeof(*stats));
355
6.66k
    return 0;
356
6.66k
}
357
358
void quicly_stream_noop_on_destroy(quicly_stream_t *stream, quicly_error_t err)
359
0
{
360
0
}
361
362
void quicly_stream_noop_on_send_shift(quicly_stream_t *stream, size_t delta)
363
0
{
364
0
}
365
366
void quicly_stream_noop_on_send_emit(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all)
367
0
{
368
0
}
369
370
void quicly_stream_noop_on_send_stop(quicly_stream_t *stream, quicly_error_t err)
371
0
{
372
0
}
373
374
void quicly_stream_noop_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len)
375
0
{
376
0
}
377
378
void quicly_stream_noop_on_receive_reset(quicly_stream_t *stream, quicly_error_t err)
379
0
{
380
0
}
381
382
const quicly_stream_callbacks_t quicly_stream_noop_callbacks = {
383
    quicly_stream_noop_on_destroy,   quicly_stream_noop_on_send_shift, quicly_stream_noop_on_send_emit,
384
    quicly_stream_noop_on_send_stop, quicly_stream_noop_on_receive,    quicly_stream_noop_on_receive_reset};
385
386
size_t quicly_send_version_negotiation(quicly_context_t *ctx, ptls_iovec_t dest_cid, ptls_iovec_t src_cid, const uint32_t *versions,
387
                                       void *payload)
388
0
{
389
0
    assert(0 && "unimplemented");
390
0
    return 0;
391
0
}
392
393
size_t quicly_send_stateless_reset(quicly_context_t *ctx, const void *src_cid, void *payload)
394
0
{
395
0
    assert(0 && "unimplemented");
396
0
    return 0;
397
0
}
398
399
int quicly_can_send_data(quicly_conn_t *conn, quicly_send_context_t *s)
400
41.0k
{
401
41.0k
    return 1;
402
41.0k
}
403
404
quicly_error_t quicly_connect(quicly_conn_t **conn, quicly_context_t *ctx, const char *server_name, struct sockaddr *dest_addr,
405
                              struct sockaddr *src_addr, const quicly_cid_plaintext_t *new_cid, ptls_iovec_t address_token,
406
                              ptls_handshake_properties_t *handshake_properties,
407
                              const quicly_transport_parameters_t *resumed_transport_params, void *appdata)
408
0
{
409
0
    assert(0 && "unimplemented");
410
0
    return 0;
411
0
}
412
413
int quicly_connection_is_ready(quicly_conn_t *conn)
414
0
{
415
0
    assert(0 && "unimplemented");
416
0
    return 0;
417
0
}
418
419
void quicly_amend_ptls_context(ptls_context_t *ptls)
420
0
{
421
0
    assert(0 && "unimplemented");
422
0
}
423
424
quicly_error_t quicly_receive(quicly_conn_t *conn, struct sockaddr *dest_addr, struct sockaddr *src_addr,
425
                              quicly_decoded_packet_t *packet)
426
0
{
427
0
    assert(0 && "unimplemented");
428
0
    return 0;
429
0
}
430
431
quicly_error_t quicly_close(quicly_conn_t *conn, quicly_error_t err, const char *reason_phrase)
432
4.17k
{
433
4.17k
    if (conn->super.state >= QUICLY_STATE_CLOSING)
434
0
        return 0;
435
436
4.17k
    conn->super.state = QUICLY_STATE_CLOSING;
437
4.17k
    return 0;
438
4.17k
}
439
440
int64_t quicly_get_first_timeout(quicly_conn_t *conn)
441
34.2k
{
442
    /* TODO: simulate delay */
443
34.2k
    return conn->super.ctx->now->cb(conn->super.ctx->now) + 1;
444
34.2k
}
445
446
void quicly_free(quicly_conn_t *conn)
447
6.66k
{
448
6.66k
    destroy_all_streams(conn, 0);
449
6.66k
    kh_destroy(quicly_stream_t, conn->streams);
450
6.66k
    free(conn);
451
6.66k
}
452
453
quicly_error_t quicly_send(quicly_conn_t *conn, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams,
454
                           size_t *num_datagrams, void *buf, size_t bufsize)
455
25.7k
{
456
25.7k
    quicly_send_context_t s = {};
457
25.7k
    quicly_error_t ret;
458
25.7k
    if (conn->super.state >= QUICLY_STATE_CLOSING) {
459
6.66k
        ret = QUICLY_ERROR_FREE_CONNECTION;
460
6.66k
        goto Exit;
461
6.66k
    }
462
19.1k
    ret = conn->super.ctx->stream_scheduler->do_send(conn->super.ctx->stream_scheduler, conn, &s);
463
464
25.7k
Exit:
465
25.7k
    *num_datagrams = 0;
466
25.7k
    return ret;
467
19.1k
}
468
469
int64_t quicly_foreach_stream(quicly_conn_t *conn, void *thunk, int64_t (*cb)(void *thunk, quicly_stream_t *stream))
470
0
{
471
0
    assert(0 && "unimplemented");
472
0
    return 0;
473
0
}
474
475
quicly_stream_t *quicly_get_stream(quicly_conn_t *conn, quicly_stream_id_t stream_id)
476
0
{
477
0
    assert(0 && "unimplemented");
478
0
    return NULL;
479
0
}
480
481
void quicly_send_datagram_frames(quicly_conn_t *conn, ptls_iovec_t *datagrams, size_t num_datagrams)
482
0
{
483
0
    assert(0 && "unimplemented");
484
0
}
485
486
void quicly_get_max_data(quicly_conn_t *conn, uint64_t *send_permitted, uint64_t *sent, uint64_t *consumed)
487
8.08k
{
488
8.08k
    if (send_permitted != NULL)
489
0
        *send_permitted = 0xdeadbeef;
490
8.08k
    if (sent != NULL)
491
8.08k
        *sent = 0xdeadbeef;
492
8.08k
    if (consumed != NULL)
493
0
        *consumed = 0xdeadbeef;
494
8.08k
}
495
496
quicly_error_t quicly_send_resumption_token(quicly_conn_t *conn)
497
6.66k
{
498
6.66k
    return 0;
499
6.66k
}
500
501
const uint32_t quicly_supported_versions[] = {QUICLY_PROTOCOL_VERSION_1, QUICLY_PROTOCOL_VERSION_DRAFT29,
502
                                              QUICLY_PROTOCOL_VERSION_DRAFT27, 0};