blob: b7cffc9d23673072c0f0a08eb4193e08d7ab2d40 [file] [log] [blame]
Frédéric Lécaille70da8892020-11-06 15:49:49 +01001/*
2 * QUIC socket management.
3 *
Willy Tarreau3dfb7da2022-03-02 22:33:39 +01004 * Copyright 2020 HAProxy Technologies, Frederic Lecaille <flecaille@haproxy.com>
Frédéric Lécaille70da8892020-11-06 15:49:49 +01005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14
15#include <sys/socket.h>
16#include <sys/types.h>
17
18#include <haproxy/connection.h>
19#include <haproxy/listener.h>
Frédéric Lécaille6492e662022-05-17 17:23:16 +020020#include <haproxy/proto_quic.h>
Amaury Denoyelle4d295042022-01-19 16:18:44 +010021#include <haproxy/quic_sock.h>
Amaury Denoyelleeb01f592021-10-07 16:44:05 +020022#include <haproxy/session.h>
Amaury Denoyelle777969c2022-03-24 16:06:26 +010023#include <haproxy/tools.h>
Frédéric Lécaille026a7922020-11-23 15:46:36 +010024#include <haproxy/xprt_quic.h>
25
26/* This function is called from the protocol layer accept() in order to
27 * instantiate a new session on behalf of a given listener and frontend. It
28 * returns a positive value upon success, 0 if the connection can be ignored,
29 * or a negative value upon critical failure. The accepted connection is
30 * closed if we return <= 0. If no handshake is needed, it immediately tries
31 * to instantiate a new stream. The connection must already have been filled
32 * with the incoming connection handle (a fd), a target (the listener) and a
33 * source address.
34 */
35int quic_session_accept(struct connection *cli_conn)
36{
37 struct listener *l = __objt_listener(cli_conn->target);
38 struct proxy *p = l->bind_conf->frontend;
39 struct session *sess;
40
41 cli_conn->proxy_netns = l->rx.settings->netns;
Frédéric Lécaille026a7922020-11-23 15:46:36 +010042 /* This flag is ordinarily set by conn_ctrl_init() which cannot
43 * be called for now.
44 */
45 cli_conn->flags |= CO_FL_CTRL_READY;
46
47 /* wait for a PROXY protocol header */
48 if (l->options & LI_O_ACC_PROXY)
49 cli_conn->flags |= CO_FL_ACCEPT_PROXY;
50
51 /* wait for a NetScaler client IP insertion protocol header */
52 if (l->options & LI_O_ACC_CIP)
53 cli_conn->flags |= CO_FL_ACCEPT_CIP;
54
Frédéric Lécaille026a7922020-11-23 15:46:36 +010055 /* Add the handshake pseudo-XPRT */
56 if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
57 if (xprt_add_hs(cli_conn) != 0)
58 goto out_free_conn;
59 }
Olivier Houchard1b3c9312021-03-05 23:37:48 +010060
Frédéric Lécaille026a7922020-11-23 15:46:36 +010061 sess = session_new(p, l, &cli_conn->obj_type);
62 if (!sess)
63 goto out_free_conn;
64
65 conn_set_owner(cli_conn, sess, NULL);
66
Frédéric Lécailleecb58722021-05-27 17:12:36 +020067 if (conn_complete_session(cli_conn) < 0)
68 goto out_free_sess;
69
Amaury Denoyelle622ec412022-04-13 16:58:26 +020070 if (conn_xprt_start(cli_conn) < 0) {
71 /* conn_complete_session has succeeded : conn is the owner of
72 * the session and the MUX is initialized.
73 * Let the MUX free all resources on error.
74 */
75 cli_conn->mux->destroy(cli_conn->ctx);
76 return -1;
77 }
78
79 return 1;
Frédéric Lécaille27faba72021-03-03 16:21:00 +010080
Frédéric Lécaille026a7922020-11-23 15:46:36 +010081 out_free_sess:
82 /* prevent call to listener_release during session_free. It will be
83 * done below, for all errors. */
84 sess->listener = NULL;
85 session_free(sess);
86 out_free_conn:
Willy Tarreau784b8682022-04-11 14:18:10 +020087 cli_conn->handle.qc->conn = NULL;
Frédéric Lécaille026a7922020-11-23 15:46:36 +010088 conn_stop_tracking(cli_conn);
89 conn_xprt_close(cli_conn);
90 conn_free(cli_conn);
91 out:
92
Frédéric Lécaillee8139f32021-03-11 17:06:30 +010093 return -1;
Frédéric Lécaille026a7922020-11-23 15:46:36 +010094}
95
Willy Tarreaucdf7c8e2022-04-11 16:20:00 +020096/* Retrieve a connection's source address. Returns -1 on failure. */
97int quic_sock_get_src(struct connection *conn, struct sockaddr *addr, socklen_t len)
98{
99 struct quic_conn *qc;
100
Willy Tarreau784b8682022-04-11 14:18:10 +0200101 if (!conn || !conn->handle.qc)
Willy Tarreaucdf7c8e2022-04-11 16:20:00 +0200102 return -1;
103
Willy Tarreau784b8682022-04-11 14:18:10 +0200104 qc = conn->handle.qc;
Willy Tarreaucdf7c8e2022-04-11 16:20:00 +0200105 if (conn_is_back(conn)) {
106 /* no source address defined for outgoing connections for now */
107 return -1;
108 } else {
109 /* front connection, return the peer's address */
110 if (len > sizeof(qc->peer_addr))
111 len = sizeof(qc->peer_addr);
112 memcpy(addr, &qc->peer_addr, len);
113 return 0;
114 }
115}
116
117/* Retrieve a connection's destination address. Returns -1 on failure. */
118int quic_sock_get_dst(struct connection *conn, struct sockaddr *addr, socklen_t len)
119{
120 struct quic_conn *qc;
121
Willy Tarreau784b8682022-04-11 14:18:10 +0200122 if (!conn || !conn->handle.qc)
Willy Tarreaucdf7c8e2022-04-11 16:20:00 +0200123 return -1;
124
Willy Tarreau784b8682022-04-11 14:18:10 +0200125 qc = conn->handle.qc;
Willy Tarreaucdf7c8e2022-04-11 16:20:00 +0200126 if (conn_is_back(conn)) {
127 /* back connection, return the peer's address */
128 if (len > sizeof(qc->peer_addr))
129 len = sizeof(qc->peer_addr);
130 memcpy(addr, &qc->peer_addr, len);
131 } else {
132 /* FIXME: front connection, no local address for now, we'll
133 * return the listener's address instead.
134 */
135 BUG_ON(!qc->li);
136
137 if (len > sizeof(qc->li->rx.addr))
138 len = sizeof(qc->li->rx.addr);
139 memcpy(addr, &qc->li->rx.addr, len);
140 }
141 return 0;
142}
143
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100144/*
145 * Inspired from session_accept_fd().
146 * Instantiate a new connection (connection struct) to be attached to <qc>
147 * QUIC connection of <l> listener.
148 * Returns 1 if succeeded, 0 if not.
149 */
150static int new_quic_cli_conn(struct quic_conn *qc, struct listener *l,
151 struct sockaddr_storage *saddr)
152{
153 struct connection *cli_conn;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100154
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100155 if (unlikely((cli_conn = conn_new(&l->obj_type)) == NULL))
156 goto out;
157
Willy Tarreau9cc88c32022-04-08 14:34:31 +0200158 if (!sockaddr_alloc(&cli_conn->src, saddr, sizeof *saddr))
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100159 goto out_free_conn;
160
Willy Tarreau030b3e62022-05-02 17:47:46 +0200161 cli_conn->flags |= CO_FL_FDLESS;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100162 qc->conn = cli_conn;
Willy Tarreau784b8682022-04-11 14:18:10 +0200163 cli_conn->handle.qc = qc;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100164
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100165 cli_conn->target = &l->obj_type;
166
Frédéric Lécaille01ab6612021-06-14 10:31:43 +0200167 /* We need the xprt context before accepting (->accept()) the connection:
168 * we may receive packet before this connection acception.
169 */
170 if (conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt) < 0)
171 goto out_free_conn;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100172
173 return 1;
174
175 out_free_conn:
Frédéric Lécaille01ab6612021-06-14 10:31:43 +0200176 qc->conn = NULL;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100177 conn_stop_tracking(cli_conn);
178 conn_xprt_close(cli_conn);
179 conn_free(cli_conn);
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100180 out:
181
182 return 0;
183}
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100184
185/* Tests if the receiver supports accepting connections. Returns positive on
186 * success, 0 if not possible
187 */
188int quic_sock_accepting_conn(const struct receiver *rx)
189{
190 return 1;
191}
192
193/* Accept an incoming connection from listener <l>, and return it, as well as
194 * a CO_AC_* status code into <status> if not null. Null is returned on error.
195 * <l> must be a valid listener with a valid frontend.
196 */
197struct connection *quic_sock_accept_conn(struct listener *l, int *status)
198{
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100199 struct quic_conn *qc;
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100200 struct li_per_thread *lthr = &l->per_thr[tid];
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100201
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100202 qc = MT_LIST_POP(&lthr->quic_accept.conns, struct quic_conn *, accept_list);
203 if (!qc)
204 goto done;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100205
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100206 if (!new_quic_cli_conn(qc, l, &qc->peer_addr))
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100207 goto err;
208
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100209 done:
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100210 *status = CO_AC_DONE;
Frédéric Lécaille026a7922020-11-23 15:46:36 +0100211 return qc ? qc->conn : NULL;
212
213 err:
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100214 /* in case of error reinsert the element to process it later. */
215 MT_LIST_INSERT(&lthr->quic_accept.conns, &qc->accept_list);
216
217 *status = CO_AC_PAUSE;
218 return NULL;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100219}
220
Frédéric Lécaille6492e662022-05-17 17:23:16 +0200221/* Retrieve the DCID from the datagram found in <buf> and deliver it to the
222 * correct datagram handler.
223 * Return 1 if a correct datagram could be found, 0 if not.
224 */
225static int quic_lstnr_dgram_dispatch(unsigned char *buf, size_t len, void *owner,
226 struct sockaddr_storage *saddr,
227 struct quic_dgram *new_dgram, struct list *dgrams)
228{
229 struct quic_dgram *dgram;
230 unsigned char *dcid;
231 size_t dcid_len;
232 int cid_tid;
233
234 if (!len || !quic_get_dgram_dcid(buf, buf + len, &dcid, &dcid_len))
235 goto err;
236
237 dgram = new_dgram ? new_dgram : pool_alloc(pool_head_quic_dgram);
238 if (!dgram)
239 goto err;
240
241 cid_tid = quic_get_cid_tid(dcid);
242
243 /* All the members must be initialized! */
244 dgram->owner = owner;
245 dgram->buf = buf;
246 dgram->len = len;
247 dgram->dcid = dcid;
248 dgram->dcid_len = dcid_len;
249 dgram->saddr = *saddr;
250 dgram->qc = NULL;
251 LIST_APPEND(dgrams, &dgram->list);
252 MT_LIST_APPEND(&quic_dghdlrs[cid_tid].dgrams, &dgram->mt_list);
253
Willy Tarreauf9d4a7d2022-08-05 08:45:56 +0200254 /* typically quic_lstnr_dghdlr() */
Frédéric Lécaille6492e662022-05-17 17:23:16 +0200255 tasklet_wakeup(quic_dghdlrs[cid_tid].task);
256
257 return 1;
258
259 err:
260 return 0;
261}
262
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100263/* Function called on a read event from a listening socket. It tries
264 * to handle as many connections as possible.
265 */
266void quic_sock_fd_iocb(int fd)
267{
268 ssize_t ret;
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100269 struct rxbuf *rxbuf;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100270 struct buffer *buf;
271 struct listener *l = objt_listener(fdtab[fd].owner);
Frédéric Lécaillec4becf52021-11-08 11:23:17 +0100272 struct quic_transport_params *params;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100273 /* Source address */
274 struct sockaddr_storage saddr = {0};
Frédéric Lécaille320744b2022-01-27 12:19:28 +0100275 size_t max_sz, cspace;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100276 socklen_t saddrlen;
Frédéric Lécaille2bed1f12022-06-23 21:05:05 +0200277 struct quic_dgram *new_dgram;
Frédéric Lécaillef6f75202022-02-02 09:44:22 +0100278 unsigned char *dgram_buf;
Frédéric Lécaille1b0707f2022-06-30 11:28:56 +0200279 int max_dgrams;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100280
Tim Duesterhus16554242021-09-15 13:58:49 +0200281 BUG_ON(!l);
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100282
Frédéric Lécaille19ef6362022-06-23 18:00:37 +0200283 new_dgram = NULL;
Frédéric Lécaillec4becf52021-11-08 11:23:17 +0100284 if (!l)
285 return;
286
Willy Tarreauf5090652021-04-06 17:23:40 +0200287 if (!(fdtab[fd].state & FD_POLL_IN) || !fd_recv_ready(fd))
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100288 return;
289
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100290 rxbuf = MT_LIST_POP(&l->rx.rxbuf_list, typeof(rxbuf), mt_list);
Amaury Denoyelleee72a432021-11-19 15:49:29 +0100291 if (!rxbuf)
Frédéric Lécaillec4becf52021-11-08 11:23:17 +0100292 goto out;
Frédéric Lécaille37ae5052022-01-27 11:31:50 +0100293
Amaury Denoyelleee72a432021-11-19 15:49:29 +0100294 buf = &rxbuf->buf;
Frédéric Lécaillec4becf52021-11-08 11:23:17 +0100295
Frédéric Lécaille1b0707f2022-06-30 11:28:56 +0200296 max_dgrams = global.tune.maxpollevents;
297 start:
Ilya Shipitsin3b64a282022-07-29 22:26:53 +0500298 /* Try to reuse an existing dgram. Note that there is always at
Frédéric Lécaille2bed1f12022-06-23 21:05:05 +0200299 * least one datagram to pick, except the first time we enter
300 * this function for this <rxbuf> buffer.
301 */
302 if (!LIST_ISEMPTY(&rxbuf->dgrams)) {
303 struct quic_dgram *dg =
304 LIST_ELEM(rxbuf->dgrams.n, struct quic_dgram *, list);
Frédéric Lécaille37ae5052022-01-27 11:31:50 +0100305
Frédéric Lécaille2bed1f12022-06-23 21:05:05 +0200306 if (!dg->buf) {
307 LIST_DELETE(&dg->list);
308 b_del(buf, dg->len);
309 new_dgram = dg;
310 }
Frédéric Lécaille37ae5052022-01-27 11:31:50 +0100311 }
312
Frédéric Lécaillec4becf52021-11-08 11:23:17 +0100313 params = &l->bind_conf->quic_params;
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100314 max_sz = params->max_udp_payload_size;
Frédéric Lécaille320744b2022-01-27 12:19:28 +0100315 cspace = b_contig_space(buf);
316 if (cspace < max_sz) {
Frédéric Lécaille1712b1d2022-01-28 13:10:24 +0100317 struct quic_dgram *dgram;
318
Frédéric Lécaille0c535682022-06-23 17:47:10 +0200319 /* Do no mark <buf> as full, and do not try to consume it
320 * if the contiguous remmaining space is not at the end
321 */
322 if (b_tail(buf) + cspace < b_wrap(buf))
323 goto out;
324
Frédéric Lécaille1712b1d2022-01-28 13:10:24 +0100325 /* Allocate a fake datagram, without data to locate
326 * the end of the RX buffer (required during purging).
327 */
328 dgram = pool_zalloc(pool_head_quic_dgram);
329 if (!dgram)
330 goto out;
331
332 dgram->len = cspace;
333 LIST_APPEND(&rxbuf->dgrams, &dgram->list);
Frédéric Lécaille0c535682022-06-23 17:47:10 +0200334
Frédéric Lécaille320744b2022-01-27 12:19:28 +0100335 /* Consume the remaining space */
336 b_add(buf, cspace);
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100337 if (b_contig_space(buf) < max_sz)
338 goto out;
339 }
340
Frédéric Lécaillef6f75202022-02-02 09:44:22 +0100341 dgram_buf = (unsigned char *)b_tail(buf);
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100342 saddrlen = sizeof saddr;
343 do {
Frédéric Lécaillef6f75202022-02-02 09:44:22 +0100344 ret = recvfrom(fd, dgram_buf, max_sz, 0,
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100345 (struct sockaddr *)&saddr, &saddrlen);
Willy Tarreauacef5e22022-04-25 20:32:15 +0200346 if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
Frédéric Lécaille439c4642022-02-02 14:33:10 +0100347 fd_cant_recv(fd);
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100348 goto out;
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100349 }
Frédéric Lécaille439c4642022-02-02 14:33:10 +0100350 } while (ret < 0 && errno == EINTR);
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100351
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100352 b_add(buf, ret);
Frédéric Lécaillef6f75202022-02-02 09:44:22 +0100353 if (!quic_lstnr_dgram_dispatch(dgram_buf, ret, l, &saddr,
354 new_dgram, &rxbuf->dgrams)) {
Frédéric Lécaille37ae5052022-01-27 11:31:50 +0100355 /* If wrong, consume this datagram */
356 b_del(buf, ret);
357 }
Frédéric Lécaille19ef6362022-06-23 18:00:37 +0200358 new_dgram = NULL;
Frédéric Lécaille1b0707f2022-06-30 11:28:56 +0200359 if (--max_dgrams > 0)
360 goto start;
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100361 out:
Frédéric Lécaille19ef6362022-06-23 18:00:37 +0200362 pool_free(pool_head_quic_dgram, new_dgram);
Frédéric Lécaille324ecda2021-11-02 10:14:44 +0100363 MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->mt_list);
Frédéric Lécaille70da8892020-11-06 15:49:49 +0100364}
Amaury Denoyelle2ce99fe2022-01-19 15:46:11 +0100365
Frédéric Lécaille48bb8752022-08-03 20:52:20 +0200366/* Send a datagram stored into <buf> buffer with <sz> as size.
367 * The caller must ensure there is at least <sz> bytes in this buffer.
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200368 *
369 * Returns 0 on success else non-zero.
370 *
Frédéric Lécaille48bb8752022-08-03 20:52:20 +0200371 * TODO standardize this function for a generic UDP sendto wrapper. This can be
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100372 * done by removing the <qc> arg and replace it with address/port.
373 */
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200374int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
375 int flags)
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100376{
377 ssize_t ret;
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100378
Frédéric Lécaille48bb8752022-08-03 20:52:20 +0200379 do {
380 ret = sendto(qc->li->rx.fd, b_peek(buf, b_head_ofs(buf)), sz,
381 MSG_DONTWAIT | MSG_NOSIGNAL,
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100382 (struct sockaddr *)&qc->peer_addr, get_addr_len(&qc->peer_addr));
Frédéric Lécaille48bb8752022-08-03 20:52:20 +0200383 } while (ret < 0 && errno == EINTR);
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100384
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200385 if (ret < 0 || ret != sz) {
386 /* TODO adjust errno for UDP context. */
387 if (errno == EAGAIN || errno == EWOULDBLOCK ||
388 errno == ENOTCONN || errno == EINPROGRESS || errno == EBADF) {
389 struct proxy *prx = qc->li->bind_conf->frontend;
390 struct quic_counters *prx_counters =
391 EXTRA_COUNTERS_GET(prx->extra_counters_fe,
392 &quic_stats_module);
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100393
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200394 if (errno == EAGAIN || errno == EWOULDBLOCK)
395 HA_ATOMIC_INC(&prx_counters->socket_full);
396 else
397 HA_ATOMIC_INC(&prx_counters->sendto_err);
398 }
399 else if (errno) {
Ilya Shipitsin3b64a282022-07-29 22:26:53 +0500400 /* TODO unlisted errno : handle it explicitly. */
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200401 ABORT_NOW();
402 }
403
404 return 1;
Frédéric Lécaille48bb8752022-08-03 20:52:20 +0200405 }
406
Amaury Denoyelle6715cbf2022-08-05 11:56:36 +0200407 /* we count the total bytes sent, and the send rate for 32-byte blocks.
408 * The reason for the latter is that freq_ctr are limited to 4GB and
409 * that it's not enough per second.
410 */
411 _HA_ATOMIC_ADD(&global.out_bytes, ret);
412 update_freq_ctr(&global.out_32bps, (ret + 16) / 32);
413
414 return 0;
Amaury Denoyelle58a77042022-02-09 15:43:07 +0100415}
416
Amaury Denoyelle2ce99fe2022-01-19 15:46:11 +0100417
418/*********************** QUIC accept queue management ***********************/
419/* per-thread accept queues */
420struct quic_accept_queue *quic_accept_queues;
421
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100422/* Install <qc> on the queue ready to be accepted. The queue task is then woken
Frédéric Lécaille91f083a2022-01-28 21:43:48 +0100423 * up. If <qc> accept is already scheduled or done, nothing is done.
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100424 */
425void quic_accept_push_qc(struct quic_conn *qc)
426{
427 struct quic_accept_queue *queue = &quic_accept_queues[qc->tid];
428 struct li_per_thread *lthr = &qc->li->per_thr[qc->tid];
429
Frédéric Lécaille91f083a2022-01-28 21:43:48 +0100430 /* early return if accept is already in progress/done for this
431 * connection
432 */
Frédéric Lécaillefc790062022-03-28 17:10:31 +0200433 if (qc->flags & QUIC_FL_CONN_ACCEPT_REGISTERED)
Frédéric Lécaille91f083a2022-01-28 21:43:48 +0100434 return;
435
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100436 BUG_ON(MT_LIST_INLIST(&qc->accept_list));
437
Frédéric Lécaillefc790062022-03-28 17:10:31 +0200438 qc->flags |= QUIC_FL_CONN_ACCEPT_REGISTERED;
Amaury Denoyellecfa2d562022-01-19 16:01:05 +0100439 /* 1. insert the listener in the accept queue
440 *
441 * Use TRY_APPEND as there is a possible race even with INLIST if
442 * multiple threads try to add the same listener instance from several
443 * quic_conn.
444 */
445 if (!MT_LIST_INLIST(&(lthr->quic_accept.list)))
446 MT_LIST_TRY_APPEND(&queue->listeners, &(lthr->quic_accept.list));
447
448 /* 2. insert the quic_conn in the listener per-thread queue. */
449 MT_LIST_APPEND(&lthr->quic_accept.conns, &qc->accept_list);
450
451 /* 3. wake up the queue tasklet */
452 tasklet_wakeup(quic_accept_queues[qc->tid].tasklet);
453}
454
Amaury Denoyelle2ce99fe2022-01-19 15:46:11 +0100455/* Tasklet handler to accept QUIC connections. Call listener_accept on every
456 * listener instances registered in the accept queue.
457 */
458static struct task *quic_accept_run(struct task *t, void *ctx, unsigned int i)
459{
460 struct li_per_thread *lthr;
461 struct mt_list *elt1, elt2;
462 struct quic_accept_queue *queue = &quic_accept_queues[tid];
463
464 mt_list_for_each_entry_safe(lthr, &queue->listeners, quic_accept.list, elt1, elt2) {
465 listener_accept(lthr->li);
466 MT_LIST_DELETE_SAFE(elt1);
467 }
468
469 return NULL;
470}
471
472static int quic_alloc_accept_queues(void)
473{
474 int i;
475
Tim Duesterhus9fb57e82022-06-01 21:58:37 +0200476 quic_accept_queues = calloc(global.nbthread,
477 sizeof(*quic_accept_queues));
Amaury Denoyelle2ce99fe2022-01-19 15:46:11 +0100478 if (!quic_accept_queues) {
479 ha_alert("Failed to allocate the quic accept queues.\n");
480 return 0;
481 }
482
483 for (i = 0; i < global.nbthread; ++i) {
484 struct tasklet *task;
485 if (!(task = tasklet_new())) {
486 ha_alert("Failed to allocate the quic accept queue on thread %d.\n", i);
487 return 0;
488 }
489
490 tasklet_set_tid(task, i);
491 task->process = quic_accept_run;
492 quic_accept_queues[i].tasklet = task;
493
494 MT_LIST_INIT(&quic_accept_queues[i].listeners);
495 }
496
497 return 1;
498}
499REGISTER_POST_CHECK(quic_alloc_accept_queues);
500
501static int quic_deallocate_accept_queues(void)
502{
503 int i;
504
505 if (quic_accept_queues) {
506 for (i = 0; i < global.nbthread; ++i)
507 tasklet_free(quic_accept_queues[i].tasklet);
508 free(quic_accept_queues);
509 }
510
511 return 1;
512}
513REGISTER_POST_DEINIT(quic_deallocate_accept_queues);