Coverage Report

Created: 2026-08-13 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2o/lib/http3/common.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018 Fastly, Kazuho Oku
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
#ifdef __APPLE__
23
#define __APPLE_USE_RFC_3542 /* to use IPV6_PKTINFO */
24
#endif
25
#include <errno.h>
26
#include <sys/types.h>
27
#include <netinet/in.h>
28
#include <netinet/ip.h>
29
#include <netinet/udp.h>
30
#include <pthread.h>
31
#include <stdio.h>
32
#include <sys/socket.h>
33
#include <unistd.h>
34
#include "picotls/openssl.h"
35
#include "h2o.h"
36
#include "h2o/string_.h"
37
#include "h2o/http3_common.h"
38
#include "h2o/http3_internal.h"
39
#include "h2o/multithread.h"
40
#include "../probes_.h"
41
42
h2o_quic_conn_t h2o_quic_accept_conn_decryption_failed;
43
h2o_http3_conn_t h2o_http3_accept_conn_closed;
44
45
struct st_h2o_http3_ingress_unistream_t {
46
    /**
47
     * back pointer
48
     */
49
    quicly_stream_t *quic;
50
    /**
51
     *
52
     */
53
    h2o_buffer_t *recvbuf;
54
    /**
55
     * Points to the counter that records the number of bytes received on a control or QPACK stream; remains NULL until such a
56
     * stream type is identified.
57
     */
58
    uint64_t *bytes_received;
59
    /**
60
     * A callback that passes unparsed input to be handled. `src` is set to NULL when receiving a reset.
61
     */
62
    void (*handle_input)(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream, const uint8_t **src,
63
                         const uint8_t *src_end, int is_eos);
64
};
65
66
const char h2o_http3_err_frame_too_large[] = "HTTP/3 frame is too large";
67
68
const ptls_iovec_t h2o_http3_alpn[3] = {{(void *)H2O_STRLIT("h3")}, {(void *)H2O_STRLIT("h3-29")}, {(void *)H2O_STRLIT("h3-27")}};
69
70
static void report_sendmsg_errors(h2o_error_reporter_t *reporter, uint64_t total_successes, uint64_t cur_successes)
71
0
{
72
0
    char errstr[256];
73
0
    fprintf(stderr, "sendmsg failed %" PRIu64 " time%s, succeeded: %" PRIu64 " time%s, over the last minute: %s\n",
74
0
            reporter->cur_errors, reporter->cur_errors > 1 ? "s" : "", cur_successes, cur_successes > 1 ? "s" : "",
75
0
            h2o_strerror_r((int)reporter->data, errstr, sizeof(errstr)));
76
0
}
77
78
static h2o_error_reporter_t track_sendmsg = H2O_ERROR_REPORTER_INITIALIZER(report_sendmsg_errors);
79
80
#if !H2O_USE_LIBUV
81
h2o_socket_t *h2o_quic_create_client_socket(h2o_loop_t *loop, int family)
82
0
{
83
0
    int fd, on = 1;
84
0
    quicly_address_t addr = {.sa.sa_family = family};
85
0
    socklen_t addrlen;
86
87
0
    if ((fd = socket(family, SOCK_DGRAM, 0)) == -1)
88
0
        return NULL;
89
90
0
    switch (family) {
91
0
    case AF_INET:
92
0
#ifdef IP_RECVTOS
93
0
        setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on));
94
0
#endif
95
0
        addrlen = sizeof(addr.sin);
96
0
        break;
97
0
    case AF_INET6:
98
0
#ifdef IPV6_V6ONLY
99
0
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) != 0)
100
0
            goto Error;
101
0
#endif
102
0
#ifdef IPV6_RECVTCLASS
103
0
        setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on));
104
0
#endif
105
0
        addrlen = sizeof(addr.sin6);
106
0
        break;
107
0
    default:
108
0
        assert(!"unexpected address family");
109
0
        goto Error;
110
0
    }
111
112
0
    if (bind(fd, &addr.sa, addrlen) != 0)
113
0
        goto Error;
114
115
0
    return h2o_evloop_socket_create(loop, fd, H2O_SOCKET_FLAG_DONT_READ);
116
117
0
Error: {
118
0
    int saved_errno = errno;
119
0
    close(fd);
120
0
    errno = saved_errno;
121
0
}
122
0
    return NULL;
123
0
}
124
#endif
125
126
int h2o_quic_send_datagrams(h2o_quic_ctx_t *ctx, quicly_address_t *dest, quicly_address_t *src, struct iovec *datagrams,
127
                            size_t num_datagrams, uint8_t ecn)
128
0
{
129
0
    union {
130
0
        struct cmsghdr hdr;
131
0
        char buf[
132
0
#ifdef IPV6_PKTINFO
133
0
            CMSG_SPACE(sizeof(struct in6_pktinfo))
134
#elif defined(IP_PKTINFO)
135
            CMSG_SPACE(sizeof(struct in_pktinfo))
136
#elif defined(IP_SENDSRCADDR)
137
            CMSG_SPACE(sizeof(struct in_addr))
138
#else
139
            CMSG_SPACE(1)
140
#endif
141
0
#ifdef UDP_SEGMENT
142
0
            + CMSG_SPACE(sizeof(uint16_t))
143
0
#endif
144
            + CMSG_SPACE(sizeof(int)) /* IP_TOS or IPV6_TCLASS */
145
            + CMSG_SPACE(1)           /* sentry */
146
0
        ];
147
0
    } cmsgbuf = {.buf = {} /* zero-cleared so that CMSG_NXTHDR can be used for locating the *next* cmsghdr */};
148
0
    struct msghdr mess = {
149
0
        .msg_name = &dest->sa,
150
0
        .msg_namelen = quicly_get_socklen(&dest->sa),
151
0
        .msg_control = cmsgbuf.buf,
152
0
        .msg_controllen = sizeof(cmsgbuf.buf),
153
0
    };
154
0
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mess);
155
0
    h2o_quic_socket_t *sock;
156
0
    int ret;
157
158
0
#define PUSH_CMSG(level, type, value)                                                                                              \
159
0
    do {                                                                                                                           \
160
0
        cmsg->cmsg_level = (level);                                                                                                \
161
0
        cmsg->cmsg_type = (type);                                                                                                  \
162
0
        cmsg->cmsg_len = CMSG_LEN(sizeof(value));                                                                                  \
163
0
        memcpy(CMSG_DATA(cmsg), &value, sizeof(value));                                                                            \
164
0
        cmsg = CMSG_NXTHDR(&mess, cmsg);                                                                                           \
165
0
    } while (0)
166
167
0
    if (ctx->sock.addr.ss_family == dest->sa.sa_family) {
168
0
        sock = &ctx->sock;
169
0
    } else if (ctx->sock_alt_family.sock != NULL && ctx->sock_alt_family.addr.ss_family == dest->sa.sa_family) {
170
0
        sock = &ctx->sock_alt_family;
171
0
    } else {
172
0
        return 0;
173
0
    }
174
175
    /* first CMSG is the source address */
176
0
    if (src->sa.sa_family != AF_UNSPEC) {
177
0
        switch (src->sa.sa_family) {
178
0
        case AF_INET: {
179
0
#if defined(IP_PKTINFO)
180
0
            if (*sock->port != src->sin.sin_port)
181
0
                return 0;
182
0
            struct in_pktinfo info = {.ipi_spec_dst = src->sin.sin_addr};
183
0
            PUSH_CMSG(IPPROTO_IP, IP_PKTINFO, info);
184
#elif defined(IP_SENDSRCADDR)
185
            if (*sock->port != src->sin.sin_port)
186
                return 0;
187
            struct sockaddr_in *fdaddr = (struct sockaddr_in *)&sock->addr;
188
            assert(fdaddr->sin_family == AF_INET);
189
            if (fdaddr->sin_addr.s_addr == INADDR_ANY)
190
                PUSH_CMSG(IPPROTO_IP, IP_SENDSRCADDR, src->sin.sin_addr);
191
#else
192
            h2o_fatal("IP_PKTINFO not available");
193
#endif
194
0
        } break;
195
0
        case AF_INET6:
196
0
#ifdef IPV6_PKTINFO
197
0
            if (*sock->port != src->sin6.sin6_port)
198
0
                return 0;
199
0
            struct in6_pktinfo info = {.ipi6_addr = src->sin6.sin6_addr};
200
0
            PUSH_CMSG(IPPROTO_IPV6, IPV6_PKTINFO, info);
201
#else
202
            h2o_fatal("IPV6_PKTINFO not available");
203
#endif
204
0
            break;
205
0
        default:
206
0
            h2o_fatal("unexpected address family");
207
0
            break;
208
0
        }
209
0
    }
210
211
    /* next CMSG is UDP_SEGMENT size (for GSO); assert that the input follows the expected pattern (see the doc-comment of
212
     * `quicly_send`), then set the CMSG and convert `datagrams` into one. */
213
0
    for (size_t i = 1; i < num_datagrams; ++i) {
214
0
        assert(datagrams[i - 1].iov_base + datagrams[i - 1].iov_len == datagrams[i].iov_base);
215
0
        assert(i == num_datagrams - 1 || datagrams[i].iov_len == datagrams[0].iov_len);
216
0
    }
217
0
#ifdef UDP_SEGMENT
218
0
    struct iovec gso_iovec;
219
0
    if (num_datagrams > 1 && ctx->use_gso) {
220
0
        uint16_t segsize = (uint16_t)datagrams[0].iov_len;
221
0
        PUSH_CMSG(SOL_UDP, UDP_SEGMENT, segsize);
222
0
        gso_iovec = (struct iovec){
223
0
            .iov_base = datagrams[0].iov_base,
224
0
            .iov_len = datagrams[num_datagrams - 1].iov_base + datagrams[num_datagrams - 1].iov_len - datagrams[0].iov_base,
225
0
        };
226
0
        datagrams = &gso_iovec;
227
0
        num_datagrams = 1;
228
0
    }
229
0
#endif
230
231
0
    if (ecn != 0) {
232
0
        int tos = ecn; /* IPV6_TCLASS uses int, and draft-ietf-tsvwg-udp-ecn-05 says IP_TOS assumes int too, on all platforms */
233
0
        switch (dest->sa.sa_family) {
234
0
        case AF_INET:
235
0
            PUSH_CMSG(IPPROTO_IP, IP_TOS, tos);
236
0
            break;
237
0
        case AF_INET6:
238
0
#ifdef IPV6_TCLASS
239
0
            PUSH_CMSG(IPPROTO_IPV6, IPV6_TCLASS, tos);
240
0
#endif
241
0
            break;
242
0
        default:
243
0
            break;
244
0
        }
245
0
    }
246
247
    /* commit CMSG length */
248
0
    if ((mess.msg_controllen = (socklen_t)((char *)cmsg - (char *)cmsgbuf.buf)) == 0)
249
0
        mess.msg_control = NULL;
250
251
    /* send datagrams */
252
0
    for (size_t i = 0; i < num_datagrams; ++i) {
253
0
        mess.msg_iov = datagrams + i;
254
0
        mess.msg_iovlen = 1;
255
0
        while ((ret = (int)sendmsg(h2o_socket_get_fd(sock->sock), &mess, 0)) == -1 && errno == EINTR)
256
0
            ;
257
0
        if (ret == -1)
258
0
            goto SendmsgError;
259
0
    }
260
261
0
    h2o_error_reporter_record_success(&track_sendmsg);
262
263
0
    return 1;
264
265
0
SendmsgError:
266
    /* The UDP stack returns EINVAL (linux) or EADDRNOTAVAIL (darwin, and presumably other BSD) when it was unable to use the
267
     * designated source address.  We communicate that back to the caller so that the connection can be closed immediately. */
268
0
    if (src->sa.sa_family != AF_UNSPEC && (errno == EINVAL || errno == EADDRNOTAVAIL))
269
0
        return 0;
270
271
    /* Temporary failure to send a packet is not a permanent error fo the connection. (TODO do we want do something more
272
     * specific?) */
273
274
    /* Log the number of failed invocations once per minute, if there has been such a failure. */
275
0
    h2o_error_reporter_record_error(ctx->loop, &track_sendmsg, 60000, errno);
276
277
0
    return 1;
278
279
0
#undef PUSH_CMSG
280
0
}
281
282
static inline const h2o_http3_conn_callbacks_t *get_callbacks(h2o_http3_conn_t *conn)
283
0
{
284
0
    return (const h2o_http3_conn_callbacks_t *)conn->super.callbacks;
285
0
}
286
287
static void ingress_unistream_on_destroy(quicly_stream_t *qs, quicly_error_t err)
288
0
{
289
0
    struct st_h2o_http3_ingress_unistream_t *stream = qs->data;
290
0
    h2o_buffer_dispose(&stream->recvbuf);
291
0
    free(stream);
292
0
}
293
294
static void ingress_unistream_on_receive(quicly_stream_t *qs, size_t off, const void *input, size_t len)
295
0
{
296
0
    h2o_http3_conn_t *conn = *quicly_get_data(qs->conn);
297
0
    struct st_h2o_http3_ingress_unistream_t *stream = qs->data;
298
299
    /* save received data */
300
0
    h2o_http3_update_recvbuf(&stream->recvbuf, off, input, len);
301
302
    /* determine bytes that can be handled */
303
0
    size_t bytes_available = quicly_recvstate_bytes_available(&stream->quic->recvstate);
304
0
    const uint8_t *src = (const uint8_t *)stream->recvbuf->bytes;
305
0
    if (bytes_available == 0 && !quicly_recvstate_transfer_complete(&stream->quic->recvstate))
306
0
        return;
307
0
    uint64_t bytes_received = stream->quic->recvstate.data_off + bytes_available;
308
309
    /* handle the bytes */
310
0
    stream->handle_input(conn, stream, &src, src + bytes_available, quicly_recvstate_transfer_complete(&stream->quic->recvstate));
311
0
    if (stream->bytes_received != NULL && *stream->bytes_received < bytes_received)
312
0
        *stream->bytes_received = bytes_received;
313
0
    if (quicly_get_state(conn->super.quic) >= QUICLY_STATE_CLOSING)
314
0
        return;
315
316
    /* remove bytes that have been consumed */
317
0
    size_t bytes_consumed = src - (const uint8_t *)stream->recvbuf->bytes;
318
0
    if (bytes_consumed != 0) {
319
0
        h2o_buffer_consume(&stream->recvbuf, bytes_consumed);
320
0
        quicly_stream_sync_recvbuf(stream->quic, bytes_consumed);
321
0
    }
322
0
}
323
324
static void ingress_unistream_on_receive_reset(quicly_stream_t *qs, quicly_error_t err)
325
0
{
326
0
    h2o_http3_conn_t *conn = *quicly_get_data(qs->conn);
327
0
    struct st_h2o_http3_ingress_unistream_t *stream = qs->data;
328
329
0
    stream->handle_input(conn, stream, NULL, NULL, 1);
330
0
}
331
332
static void qpack_encoder_stream_handle_input(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream,
333
                                              const uint8_t **src, const uint8_t *src_end, int is_eos)
334
0
{
335
0
    if (src == NULL || is_eos) {
336
0
        h2o_quic_close_connection(&conn->super, H2O_HTTP3_ERROR_CLOSED_CRITICAL_STREAM, NULL);
337
0
        return;
338
0
    }
339
340
0
    uint64_t insert_count;
341
0
    int ret;
342
0
    const char *err_desc = NULL;
343
0
    if ((ret = h2o_qpack_decoder_handle_input(conn->qpack.dec, &insert_count, src, src_end, &err_desc)) != 0) {
344
0
        h2o_quic_close_connection(&conn->super, ret, err_desc);
345
0
        return;
346
0
    }
347
0
    if (insert_count != 0)
348
0
        get_callbacks(conn)->qpack_unblock_streams(conn, insert_count);
349
0
}
350
351
static void qpack_decoder_stream_handle_input(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream,
352
                                              const uint8_t **src, const uint8_t *src_end, int is_eos)
353
0
{
354
0
    if (src == NULL || is_eos) {
355
0
        h2o_quic_close_connection(&conn->super, H2O_HTTP3_ERROR_CLOSED_CRITICAL_STREAM, NULL);
356
0
        return;
357
0
    }
358
359
0
    int ret;
360
0
    const char *err_desc = NULL;
361
0
    if ((ret = h2o_qpack_encoder_handle_input(conn->qpack.enc, src, src_end, &err_desc)) != 0)
362
0
        h2o_quic_close_connection(&conn->super, ret, err_desc);
363
0
}
364
365
static void control_stream_handle_input(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream,
366
                                        const uint8_t **src, const uint8_t *src_end, int is_eos)
367
0
{
368
0
    if (src == NULL || is_eos) {
369
0
        h2o_quic_close_connection(&conn->super, H2O_HTTP3_ERROR_CLOSED_CRITICAL_STREAM, NULL);
370
0
        return;
371
0
    }
372
373
0
    do {
374
0
        h2o_http3_read_frame_t frame;
375
0
        quicly_error_t ret;
376
0
        const char *err_desc = NULL;
377
378
0
        if ((ret = h2o_http3_read_frame(&frame, quicly_is_client(conn->super.quic), H2O_HTTP3_STREAM_TYPE_CONTROL,
379
0
                                        conn->max_frame_payload_size, src, src_end, &err_desc)) != 0) {
380
0
            if (ret != H2O_HTTP3_ERROR_INCOMPLETE)
381
0
                h2o_quic_close_connection(&conn->super, ret, err_desc);
382
0
            break;
383
0
        }
384
0
        if (h2o_http3_has_received_settings(conn) == (frame.type == H2O_HTTP3_FRAME_TYPE_SETTINGS) ||
385
0
            frame.type == H2O_HTTP3_FRAME_TYPE_DATA) {
386
0
            h2o_quic_close_connection(&conn->super, H2O_HTTP3_ERROR_FRAME_UNEXPECTED, NULL);
387
0
            break;
388
0
        }
389
0
        get_callbacks(conn)->handle_control_stream_frame(conn, frame.type, frame.payload, frame.length);
390
0
        if (quicly_get_state(conn->super.quic) >= QUICLY_STATE_CLOSING)
391
0
            break;
392
0
    } while (*src != src_end);
393
0
}
394
395
static void discard_handle_input(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream, const uint8_t **src,
396
                                 const uint8_t *src_end, int is_eos)
397
0
{
398
0
    if (src == NULL)
399
0
        return;
400
0
    *src = src_end;
401
0
}
402
403
static void unknown_type_handle_input(h2o_http3_conn_t *conn, struct st_h2o_http3_ingress_unistream_t *stream, const uint8_t **src,
404
                                      const uint8_t *src_end, int is_eos)
405
0
{
406
0
    uint64_t type;
407
408
    /* resets are allowed at least until the type is being determined */
409
0
    if (src == NULL)
410
0
        return;
411
412
    /* read the type, or just return if incomplete */
413
0
    if ((type = quicly_decodev(src, src_end)) == UINT64_MAX)
414
0
        return;
415
416
0
    switch (type) {
417
0
    case H2O_HTTP3_STREAM_TYPE_CONTROL:
418
0
        conn->_control_streams.ingress.control = stream;
419
0
        stream->bytes_received = &conn->stats.bytes_received.control_stream;
420
0
        stream->handle_input = control_stream_handle_input;
421
0
        break;
422
0
    case H2O_HTTP3_STREAM_TYPE_QPACK_ENCODER:
423
0
        conn->_control_streams.ingress.qpack_encoder = stream;
424
0
        stream->bytes_received = &conn->stats.bytes_received.qpack_encoder;
425
0
        stream->handle_input = qpack_encoder_stream_handle_input;
426
0
        break;
427
0
    case H2O_HTTP3_STREAM_TYPE_QPACK_DECODER:
428
0
        conn->_control_streams.ingress.qpack_decoder = stream;
429
0
        stream->bytes_received = &conn->stats.bytes_received.qpack_decoder;
430
0
        stream->handle_input = qpack_decoder_stream_handle_input;
431
0
        break;
432
0
    default:
433
0
        quicly_request_stop(stream->quic, H2O_HTTP3_ERROR_STREAM_CREATION);
434
0
        stream->handle_input = discard_handle_input;
435
0
        break;
436
0
    }
437
438
0
    return stream->handle_input(conn, stream, src, src_end, is_eos);
439
0
}
440
441
static void egress_unistream_on_destroy(quicly_stream_t *qs, quicly_error_t err)
442
18.8k
{
443
18.8k
    struct st_h2o_http3_egress_unistream_t *stream = qs->data;
444
18.8k
    h2o_buffer_dispose(&stream->sendbuf);
445
18.8k
    free(stream);
446
18.8k
}
447
448
static void egress_unistream_on_send_shift(quicly_stream_t *qs, size_t delta)
449
0
{
450
0
    struct st_h2o_http3_egress_unistream_t *stream = qs->data;
451
0
    h2o_buffer_consume(&stream->sendbuf, delta);
452
0
}
453
454
static void egress_unistream_on_send_emit(quicly_stream_t *qs, size_t off, void *dst, size_t *len, int *wrote_all)
455
19.8k
{
456
19.8k
    struct st_h2o_http3_egress_unistream_t *stream = qs->data;
457
458
19.8k
    if (*len >= stream->sendbuf->size - off) {
459
19.8k
        *len = stream->sendbuf->size - off;
460
19.8k
        *wrote_all = 1;
461
19.8k
    } else {
462
0
        *wrote_all = 0;
463
0
    }
464
19.8k
    memcpy(dst, stream->sendbuf->bytes + off, *len);
465
19.8k
    uint64_t bytes_sent = off + *len;
466
19.8k
    if (stream->bytes_sent != NULL && *stream->bytes_sent < bytes_sent)
467
19.8k
        *stream->bytes_sent = bytes_sent;
468
19.8k
}
469
470
static void egress_unistream_on_send_stop(quicly_stream_t *qs, quicly_error_t err)
471
0
{
472
0
    struct st_h2o_http3_conn_t *conn = *quicly_get_data(qs->conn);
473
0
    h2o_quic_close_connection(&conn->super, H2O_HTTP3_ERROR_CLOSED_CRITICAL_STREAM, NULL);
474
0
}
475
476
void h2o_http3_on_create_unidirectional_stream(quicly_stream_t *qs)
477
18.8k
{
478
18.8k
    if (quicly_stream_is_self_initiated(qs)) {
479
        /* create egress unistream */
480
18.8k
        static const quicly_stream_callbacks_t callbacks = {egress_unistream_on_destroy, egress_unistream_on_send_shift,
481
18.8k
                                                            egress_unistream_on_send_emit, egress_unistream_on_send_stop};
482
18.8k
        struct st_h2o_http3_egress_unistream_t *stream = h2o_mem_alloc(sizeof(*stream));
483
18.8k
        qs->data = stream;
484
18.8k
        qs->callbacks = &callbacks;
485
18.8k
        stream->quic = qs;
486
18.8k
        stream->bytes_sent = NULL;
487
18.8k
        h2o_buffer_init(&stream->sendbuf, &h2o_socket_buffer_prototype);
488
18.8k
    } else {
489
        /* create ingress unistream */
490
0
        static const quicly_stream_callbacks_t callbacks = {
491
0
            ingress_unistream_on_destroy, NULL, NULL, NULL, ingress_unistream_on_receive, ingress_unistream_on_receive_reset};
492
0
        struct st_h2o_http3_ingress_unistream_t *stream = h2o_mem_alloc(sizeof(*stream));
493
0
        qs->data = stream;
494
0
        qs->callbacks = &callbacks;
495
0
        stream->quic = qs;
496
0
        h2o_buffer_init(&stream->recvbuf, &h2o_socket_buffer_prototype);
497
0
        stream->bytes_received = NULL;
498
0
        stream->handle_input = unknown_type_handle_input;
499
0
    }
500
18.8k
}
501
502
static quicly_error_t open_egress_unistream(h2o_http3_conn_t *conn, struct st_h2o_http3_egress_unistream_t **stream,
503
                                            uint64_t *bytes_sent, h2o_iovec_t initial_bytes)
504
18.8k
{
505
18.8k
    quicly_stream_t *qs;
506
18.8k
    quicly_error_t ret;
507
508
18.8k
    if ((ret = quicly_open_stream(conn->super.quic, &qs, 1)) != 0)
509
0
        return ret;
510
18.8k
    *stream = qs->data;
511
18.8k
    assert((*stream)->quic == qs);
512
18.8k
    (*stream)->bytes_sent = bytes_sent;
513
514
18.8k
    h2o_buffer_append(&(*stream)->sendbuf, initial_bytes.base, initial_bytes.len);
515
18.8k
    return quicly_stream_sync_sendbuf((*stream)->quic, 1);
516
18.8k
}
517
518
static uint8_t *accept_hashkey_flatten_address(uint8_t *p, quicly_address_t *addr)
519
0
{
520
0
    switch (addr->sa.sa_family) {
521
0
    case AF_INET:
522
0
        *p++ = 4;
523
0
        memcpy(p, &addr->sin.sin_addr.s_addr, 4);
524
0
        p += 4;
525
0
        memcpy(p, &addr->sin.sin_port, 2);
526
0
        p += 2;
527
0
        break;
528
0
    case AF_INET6:
529
0
        *p++ = 6;
530
0
        memcpy(p, addr->sin6.sin6_addr.s6_addr, 16);
531
0
        p += 16;
532
0
        memcpy(p, &addr->sin.sin_port, 2);
533
0
        p += 2;
534
0
        break;
535
0
    case AF_UNSPEC:
536
0
        *p++ = 0;
537
0
        break;
538
0
    default:
539
0
        h2o_fatal("unknown protocol family");
540
0
        break;
541
0
    }
542
0
    return p;
543
0
}
544
545
static uint64_t calc_accept_hashkey(quicly_address_t *destaddr, quicly_address_t *srcaddr, ptls_iovec_t src_cid)
546
0
{
547
    /* prepare key */
548
0
    static __thread EVP_CIPHER_CTX *cipher = NULL;
549
0
    if (cipher == NULL) {
550
0
        static uint8_t key[PTLS_AES128_KEY_SIZE];
551
0
        H2O_MULTITHREAD_ONCE({ ptls_openssl_random_bytes(key, sizeof(key)); });
552
0
        cipher = EVP_CIPHER_CTX_new();
553
0
        EVP_EncryptInit_ex(cipher, EVP_aes_128_cbc(), NULL, key, NULL);
554
0
    }
555
556
0
    uint8_t buf[(1 + 16 + 2) * 2 + QUICLY_MAX_CID_LEN_V1 + PTLS_AES_BLOCK_SIZE] = {0};
557
0
    uint8_t *p = buf;
558
559
    /* build plaintext to encrypt */
560
0
    p = accept_hashkey_flatten_address(p, destaddr);
561
0
    p = accept_hashkey_flatten_address(p, srcaddr);
562
0
    memcpy(p, src_cid.base, src_cid.len);
563
0
    p += src_cid.len;
564
0
    assert(p <= buf + sizeof(buf));
565
0
    size_t bytes_to_encrypt = ((p - buf) + PTLS_AES_BLOCK_SIZE - 1) / PTLS_AES_BLOCK_SIZE * PTLS_AES_BLOCK_SIZE;
566
0
    assert(bytes_to_encrypt <= sizeof(buf));
567
568
0
    { /* encrypt */
569
0
        EVP_EncryptInit_ex(cipher, NULL, NULL, NULL, NULL);
570
0
        int bytes_encrypted = 0, ret = EVP_EncryptUpdate(cipher, buf, &bytes_encrypted, buf, (int)bytes_to_encrypt);
571
0
        assert(ret);
572
0
        assert(bytes_encrypted == bytes_to_encrypt);
573
0
    }
574
575
    /* use the last `size_t` bytes of the CBC output as the result */
576
0
    uint64_t result;
577
0
    memcpy(&result, buf + bytes_to_encrypt - sizeof(result), sizeof(result));
578
    /* avoid 0 (used as nonexist) */
579
0
    if (result == 0)
580
0
        result = 1;
581
0
    return result;
582
0
}
583
584
static void drop_from_acceptmap(h2o_quic_ctx_t *ctx, h2o_quic_conn_t *conn)
585
6.28k
{
586
6.28k
    if (conn->_accept_hashkey != 0) {
587
0
        khint_t iter;
588
0
        if ((iter = kh_get_h2o_quic_acceptmap(ctx->conns_accepting, conn->_accept_hashkey)) != kh_end(ctx->conns_accepting))
589
0
            kh_del_h2o_quic_acceptmap(ctx->conns_accepting, iter);
590
0
        conn->_accept_hashkey = 0;
591
0
    }
592
6.28k
}
593
594
static void send_version_negotiation(h2o_quic_ctx_t *ctx, quicly_address_t *destaddr, ptls_iovec_t dest_cid,
595
                                     quicly_address_t *srcaddr, ptls_iovec_t src_cid, const uint32_t *versions)
596
0
{
597
0
    uint8_t payload[QUICLY_MIN_CLIENT_INITIAL_SIZE];
598
0
    size_t payload_size = quicly_send_version_negotiation(ctx->quic, dest_cid, src_cid, versions, payload);
599
0
    assert(payload_size != SIZE_MAX);
600
0
    struct iovec vec = {.iov_base = payload, .iov_len = payload_size};
601
0
    h2o_quic_send_datagrams(ctx, destaddr, srcaddr, &vec, 1, 0);
602
0
    return;
603
0
}
604
605
static void process_packets(h2o_quic_ctx_t *ctx, quicly_address_t *destaddr, quicly_address_t *srcaddr, uint8_t ttl,
606
                            quicly_decoded_packet_t *packets, size_t num_packets)
607
0
{
608
0
    h2o_quic_conn_t *conn = NULL;
609
0
    size_t accepted_packet_index = SIZE_MAX;
610
611
0
    assert(num_packets != 0);
612
613
0
    if (ctx->quic_stats != NULL) {
614
0
        ctx->quic_stats->packet_received += num_packets;
615
0
    }
616
617
#if H2O_USE_DTRACE
618
    if (PTLS_UNLIKELY(H2O_H3_PACKET_RECEIVE_ENABLED())) {
619
        for (size_t i = 0; i != num_packets; ++i)
620
            H2O_H3_PACKET_RECEIVE(&destaddr->sa, &srcaddr->sa, packets[i].octets.base, packets[i].octets.len);
621
    }
622
#endif
623
624
0
    if (packets[0].cid.src.len > QUICLY_MAX_CID_LEN_V1)
625
0
        return;
626
627
    /* find the matching connection, by first looking at the CID (all packets as client, or Handshake, 1-RTT packets as server) */
628
0
    if (packets[0].cid.dest.plaintext.node_id == ctx->next_cid->node_id &&
629
0
        packets[0].cid.dest.plaintext.thread_id == ctx->next_cid->thread_id) {
630
0
        khiter_t iter = kh_get_h2o_quic_idmap(ctx->conns_by_id, packets[0].cid.dest.plaintext.master_id);
631
0
        if (iter != kh_end(ctx->conns_by_id)) {
632
0
            conn = kh_val(ctx->conns_by_id, iter);
633
            /* drop long header packets with different 4-tuple than the original, or if the incoming packet might be the first-
634
             * flight from the client, advance to state lookup using `cons_accepting` */
635
0
            if (!quicly_is_destination(conn->quic, &destaddr->sa, &srcaddr->sa, packets)) {
636
0
                if (!packets[0].cid.dest.might_be_client_generated)
637
0
                    return;
638
0
                conn = NULL;
639
0
            }
640
0
        } else if (!packets[0].cid.dest.might_be_client_generated) {
641
            /* send stateless reset when we could not find a matching connection for a 1 RTT packet */
642
0
            if (packets[0].octets.len >= QUICLY_STATELESS_RESET_PACKET_MIN_LEN) {
643
0
                uint8_t payload[QUICLY_MIN_CLIENT_INITIAL_SIZE];
644
0
                size_t payload_size = quicly_send_stateless_reset(ctx->quic, packets[0].cid.dest.encrypted.base, payload);
645
0
                if (payload_size != SIZE_MAX) {
646
0
                    struct iovec vec = {.iov_base = payload, .iov_len = payload_size};
647
0
                    h2o_quic_send_datagrams(ctx, srcaddr, destaddr, &vec, 1, 0);
648
0
                }
649
0
            }
650
0
            return;
651
0
        }
652
0
    } else if (!packets[0].cid.dest.might_be_client_generated) {
653
        /* forward 1-RTT packets belonging to different nodes, threads */
654
0
        if (ttl == 0)
655
0
            return;
656
0
        uint64_t offending_node_id = packets[0].cid.dest.plaintext.node_id;
657
0
        if (ctx->forward_packets != NULL && ctx->forward_packets(ctx, &offending_node_id, packets[0].cid.dest.plaintext.thread_id,
658
0
                                                                 destaddr, srcaddr, ttl, packets, num_packets))
659
0
            return;
660
        /* non-authenticating 1-RTT packets are potentially stateless resets (FIXME handle them, note that we need to use a hashdos-
661
         * resistant hash map that also meets constant-time comparison requirements) */
662
0
        return;
663
0
    }
664
665
0
    if (conn == NULL) {
666
        /* Initial or 0-RTT packet, use 4-tuple to match the thread and the connection */
667
0
        assert(packets[0].cid.dest.might_be_client_generated);
668
0
        uint64_t accept_hashkey = calc_accept_hashkey(destaddr, srcaddr, packets[0].cid.src);
669
0
        if (ctx->accept_thread_divisor != 0) {
670
0
            uint32_t offending_thread = accept_hashkey % ctx->accept_thread_divisor;
671
0
            if (offending_thread != ctx->next_cid->thread_id) {
672
0
                if (ctx->forward_packets != NULL)
673
0
                    ctx->forward_packets(ctx, NULL, offending_thread, destaddr, srcaddr, ttl, packets, num_packets);
674
0
                return;
675
0
            }
676
0
        }
677
0
        khiter_t iter = kh_get_h2o_quic_acceptmap(ctx->conns_accepting, accept_hashkey);
678
0
        if (iter == kh_end(ctx->conns_accepting)) {
679
            /* a new connection for this thread (at least on this process); accept or delegate to newer process */
680
0
            if (ctx->acceptor != NULL) {
681
0
                if (packets[0].version != 0 && !quicly_is_supported_version(packets[0].version)) {
682
0
                    send_version_negotiation(ctx, srcaddr, packets[0].cid.src, destaddr, packets[0].cid.dest.encrypted,
683
0
                                             quicly_supported_versions);
684
0
                    return;
685
0
                }
686
0
            } else {
687
                /* This is the offending thread but it is not accepting, which means that the process (or the thread) is not acting
688
                 * as a server (likely gracefully shutting down). Let the application process forward the packet to the next
689
                 * generation. */
690
0
                if (ctx->forward_packets != NULL &&
691
0
                    ctx->forward_packets(ctx, NULL, ctx->next_cid->thread_id, destaddr, srcaddr, ttl, packets, num_packets))
692
0
                    return;
693
                /* If not forwarded, send rejection to the peer. A Version Negotiation packet that carries only a greasing version
694
                 * number is used for the purpose, hoping that that signal will trigger immediate downgrade to HTTP/2, across the
695
                 * broad spectrum of the client implementations than if CONNECTION_REFUSED is being used. */
696
0
                if (packets[0].version != 0) {
697
0
                    static const uint32_t no_versions[] = {0};
698
0
                    send_version_negotiation(ctx, srcaddr, packets[0].cid.src, destaddr, packets[0].cid.dest.encrypted,
699
0
                                             no_versions);
700
0
                }
701
0
                return;
702
0
            }
703
            /* try to accept any of the Initial packets being received */
704
0
            size_t i;
705
0
            for (i = 0; i != num_packets; ++i) {
706
0
                if ((packets[i].octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) == QUICLY_PACKET_TYPE_INITIAL &&
707
0
                    (conn = ctx->acceptor(ctx, destaddr, srcaddr, packets + i)) != NULL) {
708
                    /* non-null generally means success, except for H2O_QUIC_ACCEPT_CONN_DECRYPTION_FAILED */
709
0
                    if (conn == &h2o_quic_accept_conn_decryption_failed) {
710
                        /* failed to decrypt Initial packet <=> it could belong to a connection on a different node; forward it to
711
                         * the destination being claimed by the DCID */
712
0
                        uint64_t offending_node_id = packets[i].cid.dest.plaintext.node_id;
713
0
                        uint32_t offending_thread_id = packets[i].cid.dest.plaintext.thread_id;
714
0
                        if (ctx->forward_packets != NULL && ttl > 0 &&
715
0
                            (offending_node_id != ctx->next_cid->node_id || offending_thread_id != ctx->next_cid->thread_id))
716
0
                            ctx->forward_packets(ctx, &offending_node_id, offending_thread_id, destaddr, srcaddr, ttl, packets,
717
0
                                                 num_packets);
718
0
                        return;
719
0
                    }
720
0
                    break;
721
0
                }
722
0
            }
723
0
            if (conn == NULL)
724
0
                return;
725
0
            accepted_packet_index = i;
726
0
            conn->_accept_hashkey = accept_hashkey;
727
0
            int r;
728
0
            iter = kh_put_h2o_quic_acceptmap(conn->ctx->conns_accepting, accept_hashkey, &r);
729
0
            assert(iter != kh_end(conn->ctx->conns_accepting));
730
0
            kh_val(conn->ctx->conns_accepting, iter) = conn;
731
0
        } else {
732
            /* likely have found a connection in `conns_accepting` */
733
0
            conn = kh_val(ctx->conns_accepting, iter);
734
0
            assert(conn != NULL);
735
0
            assert(!quicly_is_client(conn->quic));
736
0
            if (!quicly_is_destination(conn->quic, &destaddr->sa, &srcaddr->sa, packets)) {
737
0
                uint64_t offending_node_id = packets[0].cid.dest.plaintext.node_id;
738
0
                uint32_t offending_thread_id = packets[0].cid.dest.plaintext.thread_id;
739
0
                if (offending_node_id != ctx->next_cid->node_id || offending_thread_id != ctx->next_cid->thread_id) {
740
                    /* accept key matches to a connection being established, but DCID doesn't -- likely a second (or later) Initial
741
                     * that is supposed to be handled by another node. forward it. */
742
0
                    if (ttl == 0)
743
0
                        return;
744
0
                    if (ctx->forward_packets != NULL)
745
0
                        ctx->forward_packets(ctx, &offending_node_id, offending_thread_id, destaddr, srcaddr, ttl, packets,
746
0
                                             num_packets);
747
0
                }
748
                /* regardless of forwarding outcome, we need to drop this packet as it is not for us */
749
0
                return;
750
0
            }
751
0
        }
752
0
    }
753
754
    /* receive packets to the found connection */
755
0
    for (size_t i = 0; i != num_packets; ++i) {
756
0
        if (i != accepted_packet_index) {
757
0
            quicly_error_t ret = quicly_receive(conn->quic, &destaddr->sa, &srcaddr->sa, packets + i);
758
0
            switch (ret) {
759
0
            case QUICLY_ERROR_STATE_EXHAUSTION:
760
0
            case PTLS_ERROR_NO_MEMORY:
761
0
                fprintf(stderr, "%s: `quicly_receive()` returned ret:%" PRId64 "\n", __func__, ret);
762
0
                conn->callbacks->destroy_connection(conn);
763
0
                return;
764
0
            }
765
0
            if (ret != QUICLY_ERROR_PACKET_IGNORED && ret != QUICLY_ERROR_DECRYPTION_FAILED) {
766
0
                if (ctx->quic_stats != NULL) {
767
0
                    ++ctx->quic_stats->packet_processed;
768
0
                }
769
0
            }
770
0
        }
771
0
    }
772
773
0
    h2o_quic_schedule_timer(conn);
774
0
    if (ctx->notify_conn_update != NULL)
775
0
        ctx->notify_conn_update(ctx, conn);
776
0
}
777
778
void h2o_quic_read_socket(h2o_quic_ctx_t *ctx, h2o_socket_t *sock)
779
0
{
780
0
    struct {
781
0
        quicly_address_t destaddr, srcaddr;
782
0
        struct iovec vec;
783
0
        uint8_t ttl;
784
0
        uint8_t ecn;
785
0
        union {
786
0
            struct cmsghdr _align; /* natrually align the contents of controlbuf (which are of type cmsghdr) */
787
0
            char controlbuf[
788
0
#ifdef IPV6_PKTINFO
789
0
                CMSG_SPACE(sizeof(struct in6_pktinfo))
790
#elif defined(IP_PKTINFO)
791
                CMSG_SPACE(sizeof(struct in_pktinfo))
792
#elif defined(IP_RECVDSTADDR)
793
                CMSG_SPACE(sizeof(struct in_addr))
794
#else
795
                CMSG_SPACE(1)
796
#endif
797
0
#if defined(IPV6_TCLASS) || defined(IP_TOS) || defined(IP_RECVTOS)
798
                + CMSG_SPACE(sizeof(int)) /* IPv6 uses int, which is bigger than uint8_t used by IPv4 */
799
0
#endif
800
0
            ];
801
0
        };
802
0
        uint8_t buf[1600];
803
0
    } dgrams[10];
804
0
#ifdef __linux__
805
0
    struct mmsghdr mess[PTLS_ELEMENTSOF(dgrams)];
806
#else
807
    struct {
808
        struct msghdr msg_hdr;
809
    } mess[PTLS_ELEMENTSOF(dgrams)];
810
#endif
811
812
0
#define INIT_DGRAMS(i)                                                                                                             \
813
0
    do {                                                                                                                           \
814
0
        mess[i].msg_hdr = (struct msghdr){                                                                                         \
815
0
            .msg_name = &dgrams[i].srcaddr,                                                                                        \
816
0
            .msg_namelen = sizeof(dgrams[i].srcaddr),                                                                              \
817
0
            .msg_iov = &dgrams[i].vec,                                                                                             \
818
0
            .msg_iovlen = 1,                                                                                                       \
819
0
            .msg_control = &dgrams[i].controlbuf,                                                                                  \
820
0
            .msg_controllen = sizeof(dgrams[i].controlbuf),                                                                        \
821
0
        };                                                                                                                         \
822
0
        memset(&dgrams[i].destaddr, 0, sizeof(dgrams[i].destaddr));                                                                \
823
0
        dgrams[i].vec.iov_base = dgrams[i].buf;                                                                                    \
824
0
        dgrams[i].vec.iov_len = sizeof(dgrams[i].buf);                                                                             \
825
0
    } while (0)
826
827
    /* If the socket is either ctx->sock or ctx->sock_alt_family, the destination port is that of the socket. Otherwise, the
828
     * preprocess_packet callback takes care, therefore the value can be bogus. */
829
0
    in_port_t dst_port = ctx->sock_alt_family.sock == sock ? *ctx->sock_alt_family.port : *ctx->sock.port;
830
831
0
    int fd = h2o_socket_get_fd(sock);
832
0
    size_t dgram_index, num_dgrams;
833
834
    /* Read datagrams. Sender should be provided an ACK every fraction of RTT, otherwise its behavior becomes bursty (assuming that
835
     * pacing is not used), rather than packets being spread across entire round-trip. To minimize the chance of us entering such
836
     * situation, number of datagrams being read at once is limited to `PTLS_ELEMENTSOF(dgrams)`. In other words, one ack is
837
     * generated for no more than every 10 ack-eliciting packets being received, unless the ack-frequency extension is used. */
838
0
#ifdef __linux__
839
0
    {
840
0
        int rret;
841
0
        do {
842
0
            for (dgram_index = 0; dgram_index < PTLS_ELEMENTSOF(dgrams); ++dgram_index)
843
0
                INIT_DGRAMS(dgram_index);
844
0
        } while ((rret = recvmmsg(fd, mess, PTLS_ELEMENTSOF(mess), 0, NULL)) < 0 && errno == EINTR);
845
0
        if (rret <= 0)
846
0
            goto Exit;
847
0
        num_dgrams = (size_t)rret;
848
0
        for (dgram_index = 0; dgram_index < num_dgrams; ++dgram_index)
849
0
            dgrams[dgram_index].vec.iov_len = (size_t)mess[dgram_index].msg_len;
850
0
    }
851
#else
852
    for (dgram_index = 0; dgram_index < PTLS_ELEMENTSOF(dgrams); ++dgram_index) {
853
        ssize_t rret;
854
        do {
855
            INIT_DGRAMS(dgram_index);
856
        } while ((rret = recvmsg(fd, &mess[dgram_index].msg_hdr, 0)) < 0 && errno == EINTR);
857
        if (rret < 0)
858
            break;
859
        dgrams[dgram_index].vec.iov_len = rret;
860
    }
861
    num_dgrams = dgram_index;
862
    if (num_dgrams == 0)
863
        goto Exit;
864
#endif
865
866
    /* normalize and store the obtained data into `dgrams` */
867
0
    for (dgram_index = 0; dgram_index < num_dgrams; ++dgram_index) {
868
0
        dgrams[dgram_index].ecn = 0;
869
0
        dgrams[dgram_index].destaddr.sa.sa_family = AF_UNSPEC;
870
0
        { /* fetch destination address */
871
0
            struct cmsghdr *cmsg;
872
0
            for (cmsg = CMSG_FIRSTHDR(&mess[dgram_index].msg_hdr); cmsg != NULL;
873
0
                 cmsg = CMSG_NXTHDR(&mess[dgram_index].msg_hdr, cmsg)) {
874
0
                switch (cmsg->cmsg_level) {
875
0
                case IPPROTO_IP:
876
0
                    switch (cmsg->cmsg_type) {
877
0
#ifdef IP_PKTINFO
878
0
                    case IP_PKTINFO:
879
0
                        dgrams[dgram_index].destaddr.sin.sin_family = AF_INET;
880
0
                        memcpy(&dgrams[dgram_index].destaddr.sin.sin_addr, CMSG_DATA(cmsg) + offsetof(struct in_pktinfo, ipi_addr),
881
0
                               sizeof(struct in_addr));
882
0
                        dgrams[dgram_index].destaddr.sin.sin_port = dst_port;
883
0
                        break;
884
0
#endif
885
#ifdef IP_RECVDSTADDR
886
                    case IP_RECVDSTADDR:
887
                        dgrams[dgram_index].destaddr.sin.sin_family = AF_INET;
888
                        memcpy(&dgrams[dgram_index].destaddr.sin.sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr));
889
                        dgrams[dgram_index].destaddr.sin.sin_port = dst_port;
890
                        break;
891
#endif
892
0
#ifdef IP_RECVTOS
893
#ifdef __APPLE__
894
                    case IP_RECVTOS:
895
#else
896
0
                    case IP_TOS:
897
0
#endif
898
                        /* draft-ietf-tsvwg-udp-ecn-05 recommends using a byte on all platforms */
899
0
                        dgrams[dgram_index].ecn = *(uint8_t *)CMSG_DATA(cmsg) & IPTOS_ECN_MASK;
900
0
                        break;
901
0
#endif
902
0
                    default:
903
0
                        break;
904
0
                    }
905
0
                    break;
906
0
                case IPPROTO_IPV6:
907
0
                    switch (cmsg->cmsg_type) {
908
0
#ifdef IPV6_PKTINFO
909
0
                    case IPV6_PKTINFO:
910
0
                        dgrams[dgram_index].destaddr.sin6.sin6_family = AF_INET6;
911
0
                        memcpy(&dgrams[dgram_index].destaddr.sin6.sin6_addr,
912
0
                               CMSG_DATA(cmsg) + offsetof(struct in6_pktinfo, ipi6_addr), sizeof(struct in6_addr));
913
0
                        dgrams[dgram_index].destaddr.sin6.sin6_port = dst_port;
914
0
                        break;
915
0
#endif
916
0
#ifdef IPV6_TCLASS
917
0
                    case IPV6_TCLASS: {
918
0
                        int optval;
919
0
                        memcpy(&optval, CMSG_DATA(cmsg), sizeof(optval));
920
0
                        dgrams[dgram_index].ecn = optval & IPTOS_ECN_MASK;
921
0
                    } break;
922
0
#endif
923
0
                    default:
924
0
                        break;
925
0
                    }
926
0
                    break;
927
0
                }
928
0
            }
929
0
        }
930
0
        dgrams[dgram_index].ttl = ctx->default_ttl;
931
        /* preprocess (and drop the packet if it failed) */
932
0
        if (ctx->preprocess_packet != NULL &&
933
0
            !ctx->preprocess_packet(ctx, &mess[dgram_index].msg_hdr, &dgrams[dgram_index].destaddr, &dgrams[dgram_index].srcaddr,
934
0
                                    &dgrams[dgram_index].ttl)) {
935
0
            dgrams[dgram_index].vec.iov_len = 0; /* mark as unused */
936
0
        } else {
937
0
            assert(dgrams[dgram_index].srcaddr.sa.sa_family == AF_INET || dgrams[dgram_index].srcaddr.sa.sa_family == AF_INET6);
938
0
        }
939
0
    }
940
941
    /* convert dgrams to decoded packets and process them in group of (4-tuple, dcid) */
942
0
    quicly_decoded_packet_t packets[64];
943
0
    size_t packet_index = 0;
944
0
    dgram_index = 0;
945
0
    while (dgram_index < num_dgrams) {
946
0
        int has_decoded = 0; /* indicates if a decoded packet belonging to a different connection is stored at
947
                              * `packets[packet_index]` */
948
        /* skip zero-sized datagrams (or the ones for which preprocessing failed) */
949
0
        if (dgrams[dgram_index].vec.iov_len == 0) {
950
0
            ++dgram_index;
951
0
            continue;
952
0
        }
953
        /* dispatch packets in `packets`, if the datagram at dgram_index is from a different path */
954
0
        if (packet_index != 0) {
955
0
            assert(dgram_index != 0);
956
            /* check source address */
957
0
            if (h2o_socket_compare_address(&dgrams[dgram_index - 1].srcaddr.sa, &dgrams[dgram_index].srcaddr.sa, 1) != 0)
958
0
                goto ProcessPackets;
959
            /* check destination address, if available */
960
0
            if (dgrams[dgram_index - 1].destaddr.sa.sa_family == AF_UNSPEC &&
961
0
                dgrams[dgram_index].destaddr.sa.sa_family == AF_UNSPEC) {
962
                /* ok */
963
0
            } else if (h2o_socket_compare_address(&dgrams[dgram_index - 1].destaddr.sa, &dgrams[dgram_index].destaddr.sa, 1) == 0) {
964
                /* ok */
965
0
            } else {
966
0
                goto ProcessPackets;
967
0
            }
968
            /* TTL should be same for dispatched packets */
969
0
            if (dgrams[dgram_index - 1].ttl != dgrams[dgram_index].ttl)
970
0
                goto ProcessPackets;
971
0
        }
972
        /* decode the first packet */
973
0
        size_t payload_off = 0;
974
0
        if (quicly_decode_packet(ctx->quic, packets + packet_index, dgrams[dgram_index].vec.iov_base,
975
0
                                 dgrams[dgram_index].vec.iov_len, &payload_off) == SIZE_MAX) {
976
0
            ++dgram_index;
977
0
            goto ProcessPackets;
978
0
        }
979
0
        packets[packet_index].ecn = dgrams[dgram_index].ecn;
980
        /* dispatch packets in `packets` if the DCID is different, setting the `has_decoded` flag */
981
0
        if (packet_index != 0) {
982
0
            const ptls_iovec_t *prev_dcid = &packets[packet_index - 1].cid.dest.encrypted,
983
0
                               *cur_dcid = &packets[packet_index].cid.dest.encrypted;
984
0
            if (!(prev_dcid->len == cur_dcid->len && memcmp(prev_dcid->base, cur_dcid->base, prev_dcid->len) == 0)) {
985
0
                has_decoded = 1;
986
0
                ++dgram_index;
987
0
                goto ProcessPackets;
988
0
            }
989
0
        }
990
0
        ++packet_index;
991
        /* add rest of the packets */
992
0
        while (payload_off < dgrams[dgram_index].vec.iov_len && packet_index < PTLS_ELEMENTSOF(packets)) {
993
0
            if (quicly_decode_packet(ctx->quic, packets + packet_index, dgrams[dgram_index].vec.iov_base,
994
0
                                     dgrams[dgram_index].vec.iov_len, &payload_off) == SIZE_MAX)
995
0
                break;
996
0
            packets[packet_index].ecn = dgrams[dgram_index].ecn;
997
0
            ++packet_index;
998
0
        }
999
0
        ++dgram_index;
1000
        /* if we have enough room for the next datagram, that is, the expected worst case of 4 packets in a coalesced datagram,
1001
         * continue */
1002
0
        if (packet_index + 4 < PTLS_ELEMENTSOF(packets))
1003
0
            continue;
1004
1005
0
    ProcessPackets:
1006
0
        if (packet_index != 0) {
1007
0
            process_packets(ctx, &dgrams[dgram_index - 1].destaddr, &dgrams[dgram_index - 1].srcaddr, dgrams[dgram_index - 1].ttl,
1008
0
                            packets, packet_index);
1009
0
            if (has_decoded) {
1010
0
                packets[0] = packets[packet_index];
1011
0
                packet_index = 1;
1012
0
            } else {
1013
0
                packet_index = 0;
1014
0
            }
1015
0
        }
1016
0
    }
1017
0
    if (packet_index != 0)
1018
0
        process_packets(ctx, &dgrams[dgram_index - 1].destaddr, &dgrams[dgram_index - 1].srcaddr, dgrams[dgram_index - 1].ttl,
1019
0
                        packets, packet_index);
1020
1021
0
Exit:;
1022
1023
0
#undef INIT_DGRAMS
1024
0
}
1025
1026
static void on_read(h2o_socket_t *sock, const char *err)
1027
0
{
1028
0
    h2o_quic_ctx_t *ctx = sock->data;
1029
0
    h2o_quic_read_socket(ctx, sock);
1030
0
}
1031
1032
static void setup_quic_socket(h2o_quic_ctx_t *ctx, h2o_quic_socket_t *qsock, h2o_socket_t *sock)
1033
0
{
1034
0
    *qsock = (h2o_quic_socket_t){.sock = sock};
1035
0
    h2o_socket_getsockname(qsock->sock, (void *)&qsock->addr);
1036
0
    switch (qsock->addr.ss_family) {
1037
0
    case AF_INET:
1038
0
        qsock->port = &((struct sockaddr_in *)&qsock->addr)->sin_port;
1039
0
        break;
1040
0
    case AF_INET6:
1041
0
        qsock->port = &((struct sockaddr_in6 *)&qsock->addr)->sin6_port;
1042
0
        break;
1043
0
    default:
1044
0
        assert(!"unexpected address family");
1045
0
        break;
1046
0
    }
1047
0
    qsock->sock->data = ctx;
1048
0
    h2o_socket_read_start(qsock->sock, on_read);
1049
0
}
1050
1051
static void on_timeout(h2o_timer_t *timeout)
1052
17.6k
{
1053
17.6k
    h2o_quic_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_quic_conn_t, _timeout, timeout);
1054
17.6k
    h2o_quic_send(conn);
1055
17.6k
}
1056
1057
int h2o_http3_read_frame(h2o_http3_read_frame_t *frame, int is_client, uint64_t stream_type, size_t max_frame_payload_size,
1058
                         const uint8_t **_src, const uint8_t *src_end, const char **err_desc)
1059
22.8k
{
1060
22.8k
    const uint8_t *src = *_src;
1061
1062
22.8k
    if ((frame->type = quicly_decodev(&src, src_end)) == UINT64_MAX)
1063
39
        return H2O_HTTP3_ERROR_INCOMPLETE;
1064
22.7k
    if ((frame->length = quicly_decodev(&src, src_end)) == UINT64_MAX)
1065
99
        return H2O_HTTP3_ERROR_INCOMPLETE;
1066
22.6k
    frame->_header_size = (uint8_t)(src - *_src);
1067
1068
    /* read the content of the frame (unless it's a DATA frame) */
1069
22.6k
    frame->payload = NULL;
1070
22.6k
    if (frame->type != H2O_HTTP3_FRAME_TYPE_DATA) {
1071
7.74k
        if (frame->length > max_frame_payload_size) {
1072
179
            H2O_PROBE(H3_FRAME_RECEIVE, frame->type, NULL, frame->length);
1073
179
            PTLS_LOG(h2o, h3_frame_receive, {
1074
179
                PTLS_LOG_ELEMENT_UNSIGNED(frame_type, frame->type);
1075
179
                PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame->length);
1076
179
            });
1077
179
            *err_desc = h2o_http3_err_frame_too_large;
1078
179
            return H2O_HTTP3_ERROR_GENERAL_PROTOCOL; /* FIXME is this the correct code? */
1079
179
        }
1080
7.56k
        if (src_end - src < frame->length)
1081
46
            return H2O_HTTP3_ERROR_INCOMPLETE;
1082
7.51k
        frame->payload = src;
1083
7.51k
        src += frame->length;
1084
7.51k
    }
1085
1086
22.4k
    H2O_PROBE(H3_FRAME_RECEIVE, frame->type, frame->payload, frame->length);
1087
22.4k
    PTLS_LOG(h2o, h3_frame_receive, {
1088
22.4k
        PTLS_LOG_ELEMENT_UNSIGNED(frame_type, frame->type);
1089
22.4k
        if (frame->payload != NULL) {
1090
22.4k
            PTLS_LOG_APPDATA_ELEMENT_HEXDUMP(payload, frame->payload, frame->length);
1091
22.4k
        } else {
1092
22.4k
            PTLS_LOG_ELEMENT_UNSIGNED(payload_len, frame->length);
1093
22.4k
        }
1094
22.4k
    });
1095
1096
    /* validate frame type */
1097
22.4k
    switch (frame->type) {
1098
0
#define FRAME(id, req_clnt, req_srvr, ctl_clnt, ctl_srvr)                                                                          \
1099
20.8k
    case H2O_HTTP3_FRAME_TYPE_##id:                                                                                                \
1100
20.8k
        switch (stream_type) {                                                                                                     \
1101
20.8k
        case H2O_HTTP3_STREAM_TYPE_REQUEST:                                                                                        \
1102
20.8k
            if (req_clnt && !is_client)                                                                                            \
1103
20.8k
                goto Validation_Success;                                                                                           \
1104
20.8k
            if (req_srvr && is_client)                                                                                             \
1105
12
                goto Validation_Success;                                                                                           \
1106
12
            break;                                                                                                                 \
1107
12
        case H2O_HTTP3_STREAM_TYPE_CONTROL:                                                                                        \
1108
0
            if (ctl_clnt && !is_client)                                                                                            \
1109
0
                goto Validation_Success;                                                                                           \
1110
0
            if (ctl_srvr && is_client)                                                                                             \
1111
0
                goto Validation_Success;                                                                                           \
1112
0
            break;                                                                                                                 \
1113
0
        default:                                                                                                                   \
1114
0
            h2o_fatal("unexpected stream type");                                                                                   \
1115
0
            break;                                                                                                                 \
1116
20.8k
        }                                                                                                                          \
1117
20.8k
        break
1118
        /* clang-format off */
1119
        /*   +-------------------------+-------------+-------------+
1120
         *   |                         | req-stream  | ctrl-stream |
1121
         *   |          frame          +------+------+------+------+
1122
         *   |                         |client|server|client|server|
1123
         *   +-------------------------+------+------+------+------+ */
1124
14.9k
        FRAME( DATA                    ,    1 ,    1 ,    0 ,    0 );
1125
5.87k
        FRAME( HEADERS                 ,    1 ,    1 ,    0 ,    0 );
1126
3
        FRAME( CANCEL_PUSH             ,    0 ,    0 ,    1 ,    1 );
1127
3
        FRAME( SETTINGS                ,    0 ,    0 ,    1 ,    1 );
1128
2
        FRAME( PUSH_PROMISE            ,    0 ,    1 ,    0 ,    0 );
1129
2
        FRAME( GOAWAY                  ,    0 ,    0 ,    1 ,    1 );
1130
1
        FRAME( MAX_PUSH_ID             ,    0 ,    0 ,    1 ,    0 );
1131
2
        FRAME( PRIORITY_UPDATE_REQUEST ,    0 ,    0 ,    1 ,    0 );
1132
2
        FRAME( PRIORITY_UPDATE_PUSH    ,    0 ,    0 ,    1 ,    0 );
1133
        /*   +-------------------------+------+------+------+------+ */
1134
        /* clang-format on */
1135
1
#undef FRAME
1136
1.63k
    default:
1137
        /* ignore extension frames that we do not handle */
1138
1.63k
        goto Validation_Success;
1139
22.4k
    }
1140
12
    return H2O_HTTP3_ERROR_FRAME_UNEXPECTED;
1141
22.4k
Validation_Success:;
1142
1143
22.4k
    *_src = src;
1144
22.4k
    return 0;
1145
22.4k
}
1146
1147
void h2o_quic_init_context(h2o_quic_ctx_t *ctx, h2o_loop_t *loop, h2o_socket_t *sock, h2o_socket_t *sock_alt_family,
1148
                           quicly_context_t *quic, quicly_cid_plaintext_t *next_cid, h2o_quic_accept_cb acceptor,
1149
                           h2o_quic_notify_connection_update_cb notify_conn_update, uint8_t use_gso, h2o_quic_stats_t *quic_stats)
1150
0
{
1151
0
    assert(quic->stream_open != NULL);
1152
1153
0
    *ctx = (h2o_quic_ctx_t){
1154
0
        .loop = loop,
1155
0
        .quic = quic,
1156
0
        .next_cid = next_cid,
1157
0
        .conns_by_id = kh_init_h2o_quic_idmap(),
1158
0
        .conns_accepting = kh_init_h2o_quic_acceptmap(),
1159
0
        .notify_conn_update = notify_conn_update,
1160
0
        .acceptor = acceptor,
1161
0
        .use_gso = use_gso,
1162
0
        .quic_stats = quic_stats,
1163
0
    };
1164
0
    setup_quic_socket(ctx, &ctx->sock, sock);
1165
0
    if (sock_alt_family != NULL) {
1166
0
        setup_quic_socket(ctx, &ctx->sock_alt_family, sock_alt_family);
1167
0
    }
1168
0
}
1169
1170
void h2o_quic_dispose_context(h2o_quic_ctx_t *ctx)
1171
0
{
1172
0
    assert(kh_size(ctx->conns_by_id) == 0);
1173
0
    assert(kh_size(ctx->conns_accepting) == 0);
1174
1175
0
    h2o_socket_close(ctx->sock.sock);
1176
0
    if (ctx->sock_alt_family.sock != NULL)
1177
0
        h2o_socket_close(ctx->sock_alt_family.sock);
1178
0
    kh_destroy_h2o_quic_idmap(ctx->conns_by_id);
1179
0
    kh_destroy_h2o_quic_acceptmap(ctx->conns_accepting);
1180
0
}
1181
1182
void h2o_quic_set_forwarding_context(h2o_quic_ctx_t *ctx, uint32_t accept_thread_divisor, uint8_t ttl,
1183
                                     h2o_quic_forward_packets_cb forward_cb, h2o_quic_preprocess_packet_cb preprocess_cb)
1184
0
{
1185
0
    ctx->accept_thread_divisor = accept_thread_divisor;
1186
0
    ctx->forward_packets = forward_cb;
1187
0
    ctx->default_ttl = ttl;
1188
0
    ctx->preprocess_packet = preprocess_cb;
1189
0
}
1190
1191
void h2o_quic_close_connection(h2o_quic_conn_t *conn, quicly_error_t err, const char *reason_phrase)
1192
4.04k
{
1193
4.04k
    switch (quicly_get_state(conn->quic)) {
1194
0
    case QUICLY_STATE_FIRSTFLIGHT: /* FIXME why is this separate? */
1195
0
        conn->callbacks->destroy_connection(conn);
1196
0
        break;
1197
4.04k
    case QUICLY_STATE_CONNECTED:
1198
4.04k
        quicly_close(conn->quic, err, reason_phrase);
1199
4.04k
        h2o_quic_schedule_timer(conn);
1200
4.04k
        break;
1201
0
    default:
1202
        /* only need to wait for the socket close */
1203
0
        break;
1204
4.04k
    }
1205
4.04k
}
1206
1207
void h2o_quic_close_all_connections(h2o_quic_ctx_t *ctx)
1208
0
{
1209
0
    h2o_quic_conn_t *conn;
1210
1211
0
    kh_foreach_value(ctx->conns_by_id, conn, { h2o_quic_close_connection(conn, 0, NULL); });
1212
    /* closing a connection should also remove an entry from conns_accepting */
1213
0
    assert(kh_size(ctx->conns_accepting) == 0);
1214
0
}
1215
1216
size_t h2o_quic_num_connections(h2o_quic_ctx_t *ctx)
1217
0
{
1218
    /* throughout its lifetime, a connection is always registered to both conns_by_id and conns_accepting,
1219
       thus counting conns_by_id is enough */
1220
0
    return kh_size(ctx->conns_by_id);
1221
0
}
1222
1223
void h2o_quic_init_conn(h2o_quic_conn_t *conn, h2o_quic_ctx_t *ctx, const h2o_quic_conn_callbacks_t *callbacks)
1224
6.28k
{
1225
6.28k
    *conn = (h2o_quic_conn_t){ctx, NULL, callbacks};
1226
6.28k
    h2o_timer_init(&conn->_timeout, on_timeout);
1227
6.28k
}
1228
1229
void h2o_quic_dispose_conn(h2o_quic_conn_t *conn)
1230
6.28k
{
1231
6.28k
    if (conn->quic != NULL) {
1232
6.28k
        khiter_t iter;
1233
        /* unregister from maps */
1234
6.28k
        if ((iter = kh_get_h2o_quic_idmap(conn->ctx->conns_by_id, quicly_get_master_id(conn->quic)->master_id)) !=
1235
6.28k
            kh_end(conn->ctx->conns_by_id))
1236
6.28k
            kh_del_h2o_quic_idmap(conn->ctx->conns_by_id, iter);
1237
6.28k
        drop_from_acceptmap(conn->ctx, conn);
1238
6.28k
        quicly_free(conn->quic);
1239
6.28k
    }
1240
6.28k
    h2o_timer_unlink(&conn->_timeout);
1241
6.28k
}
1242
1243
void h2o_quic_setup(h2o_quic_conn_t *conn, quicly_conn_t *quic)
1244
6.28k
{
1245
    /* Setup relation between `h2o_quic_conn_t` and `quicly_conn_t`. At this point, `conn` will not have `quic` associated, though
1246
     * the back pointer might have alreday been set up (see how we call `quicly_accept`). */
1247
6.28k
    assert(conn->quic == NULL);
1248
6.28k
    void **backptr = quicly_get_data(quic);
1249
6.28k
    if (*backptr == NULL) {
1250
6.28k
        *backptr = conn;
1251
6.28k
    } else {
1252
0
        assert(*backptr == conn);
1253
0
    }
1254
6.28k
    conn->quic = quic;
1255
1256
    /* register to the idmap */
1257
6.28k
    int r;
1258
6.28k
    khiter_t iter = kh_put_h2o_quic_idmap(conn->ctx->conns_by_id, quicly_get_master_id(conn->quic)->master_id, &r);
1259
6.28k
    assert(iter != kh_end(conn->ctx->conns_by_id));
1260
6.28k
    kh_val(conn->ctx->conns_by_id, iter) = conn;
1261
6.28k
}
1262
1263
void h2o_http3_init_conn(h2o_http3_conn_t *conn, h2o_quic_ctx_t *ctx, const h2o_http3_conn_callbacks_t *callbacks,
1264
                         const h2o_http3_qpack_context_t *qpack_ctx, size_t max_frame_payload_size)
1265
6.28k
{
1266
6.28k
    h2o_quic_init_conn(&conn->super, ctx, &callbacks->super);
1267
6.28k
    memset((char *)conn + sizeof(conn->super), 0, sizeof(*conn) - sizeof(conn->super));
1268
6.28k
    conn->qpack.ctx = qpack_ctx;
1269
6.28k
    conn->max_frame_payload_size = max_frame_payload_size;
1270
6.28k
}
1271
1272
void h2o_http3_dispose_conn(h2o_http3_conn_t *conn)
1273
6.28k
{
1274
6.28k
    if (conn->qpack.dec != NULL)
1275
6.28k
        h2o_qpack_destroy_decoder(conn->qpack.dec);
1276
6.28k
    if (conn->qpack.enc != NULL)
1277
0
        h2o_qpack_destroy_encoder(conn->qpack.enc);
1278
6.28k
    h2o_quic_dispose_conn(&conn->super);
1279
6.28k
}
1280
1281
static uint64_t calc_max_blocked_streams(h2o_http3_conn_t *conn)
1282
12.5k
{
1283
12.5k
    if (conn->qpack.ctx->decoder_table_capacity == 0)
1284
12.5k
        return 0;
1285
0
    uint64_t max_blocked = quicly_get_context(conn->super.quic)->transport_params.max_streams_bidi;
1286
0
    assert(max_blocked == 0 || get_callbacks(conn)->qpack_unblock_streams != NULL ||
1287
0
           !"connection enables QPACK blocked-stream support but provides no qpack_unblock_streams callback");
1288
0
    return max_blocked;
1289
0
}
1290
1291
static size_t build_firstflight(h2o_http3_conn_t *conn, uint8_t *bytebuf, size_t capacity)
1292
6.28k
{
1293
6.28k
    ptls_buffer_t buf;
1294
6.28k
    int ret = 0;
1295
6.28k
    uint64_t max_blocked_streams = calc_max_blocked_streams(conn);
1296
1297
6.28k
    ptls_buffer_init(&buf, bytebuf, capacity);
1298
1299
    /* push stream type */
1300
6.28k
    ptls_buffer_push_quicint(&buf, H2O_HTTP3_STREAM_TYPE_CONTROL);
1301
1302
    /* push SETTINGS frame */
1303
6.28k
    ptls_buffer_push_quicint(&buf, H2O_HTTP3_FRAME_TYPE_SETTINGS);
1304
6.28k
    ptls_buffer_push_block(&buf, -1, {
1305
6.28k
        quicly_context_t *qctx = quicly_get_context(conn->super.quic);
1306
6.28k
        if (qctx->transport_params.max_datagram_frame_size != 0) {
1307
            // advertise that we are prepared to receive both RFC and draft-03 datagram formats
1308
6.28k
            ptls_buffer_push_quicint(&buf, H2O_HTTP3_SETTINGS_H3_DATAGRAM);
1309
6.28k
            ptls_buffer_push_quicint(&buf, 1);
1310
6.28k
            ptls_buffer_push_quicint(&buf, H2O_HTTP3_SETTINGS_H3_DATAGRAM_DRAFT03);
1311
6.28k
            ptls_buffer_push_quicint(&buf, 1);
1312
6.28k
        };
1313
6.28k
        if (conn->qpack.ctx->decoder_table_capacity != 0) {
1314
6.28k
            ptls_buffer_push_quicint(&buf, H2O_HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY);
1315
6.28k
            ptls_buffer_push_quicint(&buf, conn->qpack.ctx->decoder_table_capacity);
1316
6.28k
        }
1317
6.28k
        if (max_blocked_streams != 0) {
1318
6.28k
            ptls_buffer_push_quicint(&buf, H2O_HTTP3_SETTINGS_QPACK_BLOCKED_STREAMS);
1319
6.28k
            ptls_buffer_push_quicint(&buf, max_blocked_streams);
1320
6.28k
        }
1321
6.28k
        ptls_buffer_push_quicint(&buf, H2O_HTTP3_SETTINGS_ENABLE_CONNECT_PROTOCOL);
1322
6.28k
        ptls_buffer_push_quicint(&buf, 1);
1323
6.28k
    });
1324
1325
6.28k
    assert(!buf.is_allocated);
1326
6.28k
    return buf.off;
1327
1328
0
Exit:
1329
0
    h2o_fatal("unreachable");
1330
6.28k
}
1331
1332
quicly_error_t h2o_http3_setup(h2o_http3_conn_t *conn, quicly_conn_t *quic)
1333
6.28k
{
1334
6.28k
    quicly_error_t ret;
1335
1336
6.28k
    h2o_quic_setup(&conn->super, quic);
1337
6.28k
    conn->state = H2O_HTTP3_CONN_STATE_OPEN;
1338
1339
    /* setup h3 objects, only when the connection state has been created */
1340
6.28k
    if (quicly_get_state(quic) > QUICLY_STATE_CONNECTED)
1341
0
        goto Exit;
1342
1343
6.28k
    conn->qpack.dec = h2o_qpack_create_decoder(conn->qpack.ctx->decoder_table_capacity, calc_max_blocked_streams(conn));
1344
1345
6.28k
    { /* open control streams, send SETTINGS */
1346
6.28k
        uint8_t firstflight[32];
1347
6.28k
        size_t firstflight_len = build_firstflight(conn, firstflight, sizeof(firstflight));
1348
6.28k
        if ((ret = open_egress_unistream(conn, &conn->_control_streams.egress.control, &conn->stats.bytes_sent.control_stream,
1349
6.28k
                                         h2o_iovec_init(firstflight, firstflight_len))) != 0)
1350
0
            return ret;
1351
6.28k
    }
1352
1353
6.28k
    { /* open QPACK encoder & decoder streams */
1354
6.28k
        static const uint8_t encoder_first_flight[] = {H2O_HTTP3_STREAM_TYPE_QPACK_ENCODER};
1355
6.28k
        static const uint8_t decoder_first_flight[] = {H2O_HTTP3_STREAM_TYPE_QPACK_DECODER};
1356
6.28k
        if ((ret = open_egress_unistream(conn, &conn->_control_streams.egress.qpack_encoder, &conn->stats.bytes_sent.qpack_encoder,
1357
6.28k
                                         h2o_iovec_init(encoder_first_flight, sizeof(encoder_first_flight)))) != 0 ||
1358
6.28k
            (ret = open_egress_unistream(conn, &conn->_control_streams.egress.qpack_decoder, &conn->stats.bytes_sent.qpack_decoder,
1359
6.28k
                                         h2o_iovec_init(decoder_first_flight, sizeof(decoder_first_flight)))) != 0)
1360
0
            return ret;
1361
6.28k
    }
1362
1363
6.28k
Exit:
1364
6.28k
    h2o_quic_schedule_timer(&conn->super);
1365
6.28k
    return 0;
1366
6.28k
}
1367
1368
quicly_error_t h2o_quic_send(h2o_quic_conn_t *conn)
1369
23.9k
{
1370
23.9k
    quicly_address_t dest, src;
1371
23.9k
    struct iovec datagrams[10];
1372
23.9k
    size_t num_datagrams = PTLS_ELEMENTSOF(datagrams);
1373
23.9k
    uint8_t datagram_buf[1500 * PTLS_ELEMENTSOF(datagrams)];
1374
1375
23.9k
    quicly_error_t ret = quicly_send(conn->quic, &dest, &src, datagrams, &num_datagrams, datagram_buf, sizeof(datagram_buf));
1376
23.9k
    switch (ret) {
1377
17.6k
    case 0:
1378
17.6k
        if (num_datagrams != 0 &&
1379
0
            !h2o_quic_send_datagrams(conn->ctx, &dest, &src, datagrams, num_datagrams, quicly_send_get_ecn_bits(conn->quic))) {
1380
            /* FIXME close the connection immediately */
1381
0
            break;
1382
0
        }
1383
17.6k
        break;
1384
17.6k
    case QUICLY_ERROR_STATE_EXHAUSTION:
1385
6.28k
    case QUICLY_ERROR_FREE_CONNECTION:
1386
6.28k
        conn->callbacks->destroy_connection(conn);
1387
6.28k
        return 0;
1388
0
    default:
1389
0
        h2o_fatal("quicly_send returned %" PRId64, ret);
1390
23.9k
    }
1391
1392
17.6k
    h2o_quic_schedule_timer(conn);
1393
1394
17.6k
    return 1;
1395
23.9k
}
1396
1397
void h2o_http3_update_recvbuf(h2o_buffer_t **buf, size_t off, const void *src, size_t len)
1398
6.28k
{
1399
6.28k
    size_t new_size = off + len;
1400
1401
6.28k
    if ((*buf)->size < new_size) {
1402
6.28k
        h2o_buffer_reserve(buf, new_size - (*buf)->size);
1403
6.28k
        (*buf)->size = new_size;
1404
6.28k
    }
1405
6.28k
    memcpy((*buf)->bytes + off, src, len);
1406
6.28k
}
1407
1408
void h2o_quic_schedule_timer(h2o_quic_conn_t *conn)
1409
31.7k
{
1410
31.7k
    int64_t timeout = quicly_get_first_timeout(conn->quic);
1411
31.7k
    if (h2o_timer_is_linked(&conn->_timeout)) {
1412
#if !H2O_USE_LIBUV /* optimization to skip registering a timer specifying the same time */
1413
14.1k
        if (timeout == conn->_timeout.expire_at)
1414
14.0k
            return;
1415
98
#endif
1416
98
        h2o_timer_unlink(&conn->_timeout);
1417
98
    }
1418
17.7k
    uint64_t now = h2o_now(conn->ctx->loop), delay = now < timeout ? timeout - now : 0;
1419
17.7k
    h2o_timer_link(conn->ctx->loop, delay, &conn->_timeout);
1420
17.7k
}
1421
1422
int h2o_http3_handle_settings_frame(h2o_http3_conn_t *conn, const uint8_t *payload, size_t length, const char **err_desc)
1423
0
{
1424
0
    const uint8_t *src = payload, *src_end = src + length;
1425
0
    uint32_t header_table_size = 0;
1426
0
    uint64_t blocked_streams = 0;
1427
1428
0
    assert(!h2o_http3_has_received_settings(conn));
1429
1430
0
    while (src != src_end) {
1431
0
        uint64_t id;
1432
0
        uint64_t value;
1433
0
        if ((id = quicly_decodev(&src, src_end)) == UINT64_MAX)
1434
0
            goto Malformed;
1435
0
        if ((value = quicly_decodev(&src, src_end)) == UINT64_MAX)
1436
0
            goto Malformed;
1437
0
        switch (id) {
1438
0
        case H2O_HTTP3_SETTINGS_MAX_FIELD_SECTION_SIZE:
1439
0
            conn->peer_settings.max_field_section_size = value;
1440
0
            break;
1441
0
        case H2O_HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY:
1442
0
            header_table_size =
1443
0
                value < conn->qpack.ctx->encoder_table_capacity ? (uint32_t)value : conn->qpack.ctx->encoder_table_capacity;
1444
0
            break;
1445
0
        case H2O_HTTP3_SETTINGS_QPACK_BLOCKED_STREAMS:
1446
0
            blocked_streams = value;
1447
0
            break;
1448
0
        case H2O_HTTP3_SETTINGS_H3_DATAGRAM:
1449
0
        case H2O_HTTP3_SETTINGS_H3_DATAGRAM_DRAFT03:
1450
0
            switch (value) {
1451
0
            case 0:
1452
0
                break;
1453
0
            case 1: {
1454
0
                const quicly_transport_parameters_t *remote_tp = quicly_get_remote_transport_parameters(conn->super.quic);
1455
0
                if (remote_tp->max_datagram_frame_size == 0)
1456
0
                    goto Malformed;
1457
0
                conn->peer_settings.h3_datagram = 1;
1458
0
            } break;
1459
0
            default:
1460
0
                goto Malformed;
1461
0
            }
1462
0
            break;
1463
0
        default:
1464
0
            break;
1465
0
        }
1466
0
    }
1467
1468
0
    conn->qpack.enc = h2o_qpack_create_encoder(header_table_size, blocked_streams);
1469
0
    return 0;
1470
0
Malformed:
1471
0
    *err_desc = "malformed SETTINGS frame";
1472
0
    return H2O_HTTP3_ERROR_FRAME;
1473
0
}
1474
1475
void h2o_http3_qpack_cancel_stream(h2o_http3_conn_t *conn, quicly_stream_id_t stream_id)
1476
1.87k
{
1477
1.87k
    struct st_h2o_http3_egress_unistream_t *stream = conn->_control_streams.egress.qpack_decoder;
1478
1479
    /* allocate and write */
1480
1.87k
    h2o_iovec_t buf = h2o_buffer_reserve(&stream->sendbuf, stream->sendbuf->size + H2O_HPACK_ENCODE_INT_MAX_LENGTH);
1481
1.87k
    assert(buf.base != NULL);
1482
1.87k
    stream->sendbuf->size += h2o_qpack_decoder_send_stream_cancel(conn->qpack.dec, (uint8_t *)buf.base, stream_id);
1483
1484
    /* notify the transport */
1485
1.87k
    H2O_HTTP3_CHECK_SUCCESS(quicly_stream_sync_sendbuf(stream->quic, 1) == 0);
1486
1.87k
}
1487
1488
void h2o_http3_send_qpack_header_ack(h2o_http3_conn_t *conn, const void *bytes, size_t len)
1489
0
{
1490
0
    struct st_h2o_http3_egress_unistream_t *stream = conn->_control_streams.egress.qpack_decoder;
1491
1492
0
    assert(stream != NULL);
1493
0
    h2o_buffer_append(&stream->sendbuf, bytes, len);
1494
0
    H2O_HTTP3_CHECK_SUCCESS(quicly_stream_sync_sendbuf(stream->quic, 1) == 0);
1495
0
}
1496
1497
void h2o_http3_send_shutdown_goaway_frame(h2o_http3_conn_t *conn)
1498
0
{
1499
    /* There is a moment where the transport-level close has been initiated while st_h2o_http3_server_conn_t remains.
1500
     * Check QUIC connection state to skip sending GOAWAY in such a case. */
1501
0
    if (conn->state < H2O_HTTP3_CONN_STATE_HALF_CLOSED && quicly_get_state(conn->super.quic) == QUICLY_STATE_CONNECTED) {
1502
        /* advertise the maximum stream ID to indicate that we will no longer accept new requests.
1503
         * HTTP/3 draft section 5.2.8 --
1504
         * "An endpoint that is attempting to gracefully shut down a connection can send a GOAWAY frame with a value set to the
1505
         * maximum possible value (2^62-4 for servers, 2^62-1 for clients). This ensures that the peer stops creating new
1506
         * requests or pushes." */
1507
0
        h2o_http3_send_goaway_frame(conn, (UINT64_C(1) << 62) - 4);
1508
0
    }
1509
0
}
1510
1511
void h2o_http3_send_goaway_frame(h2o_http3_conn_t *conn, uint64_t stream_or_push_id)
1512
0
{
1513
0
    size_t cap = h2o_http3_goaway_frame_capacity(stream_or_push_id);
1514
0
    h2o_iovec_t alloced = h2o_buffer_reserve(&conn->_control_streams.egress.control->sendbuf, cap);
1515
0
    h2o_http3_encode_goaway_frame((uint8_t *)alloced.base, stream_or_push_id);
1516
0
    conn->_control_streams.egress.control->sendbuf->size += cap;
1517
0
    quicly_stream_sync_sendbuf(conn->_control_streams.egress.control->quic, 1);
1518
0
}
1519
1520
void h2o_http3_send_h3_datagrams(h2o_http3_conn_t *conn, uint64_t flow_id, h2o_iovec_t *datagrams, size_t num_datagrams)
1521
0
{
1522
0
    for (size_t i = 0; i < num_datagrams; ++i) {
1523
0
        h2o_iovec_t *src = datagrams + i;
1524
0
        uint8_t buf[quicly_encodev_capacity(flow_id) + src->len], *p = buf;
1525
0
        p = quicly_encodev(p, flow_id);
1526
0
        memcpy(p, src->base, src->len);
1527
0
        p += src->len;
1528
0
        ptls_iovec_t payload = ptls_iovec_init(buf, p - buf);
1529
0
        quicly_send_datagram_frames(conn->super.quic, &payload, 1);
1530
0
    }
1531
1532
0
    h2o_quic_schedule_timer(&conn->super);
1533
0
}
1534
1535
uint64_t h2o_http3_decode_h3_datagram(h2o_iovec_t *payload, const void *_src, size_t len)
1536
0
{
1537
0
    const uint8_t *src = _src, *end = src + len;
1538
0
    uint64_t flow_id;
1539
1540
0
    if ((flow_id = ptls_decode_quicint(&src, end)) != UINT64_MAX)
1541
0
        *payload = h2o_iovec_init(src, end - src);
1542
0
    return flow_id;
1543
0
}