comparison src/event/quic/ngx_event_quic_udp.c @ 9017:c2f5d79cde64 quic

QUIC: separate UDP framework for QUIC. Previously, QUIC used the existing UDP framework, which was created for UDP in Stream. However the way QUIC connections are created and looked up is different from the way UDP connections in Stream are created and looked up. Now these two implementations are decoupled.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 20 Apr 2022 16:01:17 +0400
parents src/event/ngx_event_udp.c@ce6d9cf0f567
children af5adec171b4
comparison
equal deleted inserted replaced
9016:55b38514729b 9017:c2f5d79cde64
1
2 /*
3 * Copyright (C) Roman Arutyunyan
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_event_quic_connection.h>
12
13
14 static void ngx_quic_close_accepted_connection(ngx_connection_t *c);
15 static ngx_connection_t *ngx_quic_lookup_connection(ngx_listening_t *ls,
16 ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen);
17
18
19 void
20 ngx_quic_recvmsg(ngx_event_t *ev)
21 {
22 ssize_t n;
23 ngx_str_t key;
24 ngx_buf_t buf;
25 ngx_log_t *log;
26 ngx_err_t err;
27 socklen_t socklen, local_socklen;
28 ngx_event_t *rev, *wev;
29 struct iovec iov[1];
30 struct msghdr msg;
31 ngx_sockaddr_t sa, lsa;
32 struct sockaddr *sockaddr, *local_sockaddr;
33 ngx_listening_t *ls;
34 ngx_event_conf_t *ecf;
35 ngx_connection_t *c, *lc;
36 ngx_quic_socket_t *qsock;
37 static u_char buffer[65535];
38
39 #if (NGX_HAVE_ADDRINFO_CMSG)
40 u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
41 #endif
42
43 if (ev->timedout) {
44 if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
45 return;
46 }
47
48 ev->timedout = 0;
49 }
50
51 ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
52
53 if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
54 ev->available = ecf->multi_accept;
55 }
56
57 lc = ev->data;
58 ls = lc->listening;
59 ev->ready = 0;
60
61 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
62 "quic recvmsg on %V, ready: %d",
63 &ls->addr_text, ev->available);
64
65 do {
66 ngx_memzero(&msg, sizeof(struct msghdr));
67
68 iov[0].iov_base = (void *) buffer;
69 iov[0].iov_len = sizeof(buffer);
70
71 msg.msg_name = &sa;
72 msg.msg_namelen = sizeof(ngx_sockaddr_t);
73 msg.msg_iov = iov;
74 msg.msg_iovlen = 1;
75
76 #if (NGX_HAVE_ADDRINFO_CMSG)
77 if (ls->wildcard) {
78 msg.msg_control = &msg_control;
79 msg.msg_controllen = sizeof(msg_control);
80
81 ngx_memzero(&msg_control, sizeof(msg_control));
82 }
83 #endif
84
85 n = recvmsg(lc->fd, &msg, 0);
86
87 if (n == -1) {
88 err = ngx_socket_errno;
89
90 if (err == NGX_EAGAIN) {
91 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
92 "quic recvmsg() not ready");
93 return;
94 }
95
96 ngx_log_error(NGX_LOG_ALERT, ev->log, err, "quic recvmsg() failed");
97
98 return;
99 }
100
101 #if (NGX_HAVE_ADDRINFO_CMSG)
102 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
103 ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
104 "quic recvmsg() truncated data");
105 continue;
106 }
107 #endif
108
109 sockaddr = msg.msg_name;
110 socklen = msg.msg_namelen;
111
112 if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
113 socklen = sizeof(ngx_sockaddr_t);
114 }
115
116 #if (NGX_HAVE_UNIX_DOMAIN)
117
118 if (sockaddr->sa_family == AF_UNIX) {
119 struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr;
120
121 if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)
122 || saun->sun_path[0] == '\0')
123 {
124 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
125 "unbound unix socket");
126 goto next;
127 }
128 }
129
130 #endif
131
132 local_sockaddr = ls->sockaddr;
133 local_socklen = ls->socklen;
134
135 #if (NGX_HAVE_ADDRINFO_CMSG)
136
137 if (ls->wildcard) {
138 struct cmsghdr *cmsg;
139
140 ngx_memcpy(&lsa, local_sockaddr, local_socklen);
141 local_sockaddr = &lsa.sockaddr;
142
143 for (cmsg = CMSG_FIRSTHDR(&msg);
144 cmsg != NULL;
145 cmsg = CMSG_NXTHDR(&msg, cmsg))
146 {
147 if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) {
148 break;
149 }
150 }
151 }
152
153 #endif
154
155 if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) {
156 goto next;
157 }
158
159 c = ngx_quic_lookup_connection(ls, &key, local_sockaddr, local_socklen);
160
161 if (c) {
162
163 #if (NGX_DEBUG)
164 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
165 ngx_log_handler_pt handler;
166
167 handler = c->log->handler;
168 c->log->handler = NULL;
169
170 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
171 "quic recvmsg: fd:%d n:%z", c->fd, n);
172
173 c->log->handler = handler;
174 }
175 #endif
176
177 ngx_memzero(&buf, sizeof(ngx_buf_t));
178
179 buf.pos = buffer;
180 buf.last = buffer + n;
181 buf.start = buf.pos;
182 buf.end = buffer + sizeof(buffer);
183
184 qsock = ngx_quic_get_socket(c);
185
186 ngx_memcpy(&qsock->sockaddr.sockaddr, sockaddr, socklen);
187 qsock->socklen = socklen;
188
189 c->udp->buffer = &buf;
190
191 rev = c->read;
192 rev->ready = 1;
193 rev->active = 0;
194
195 rev->handler(rev);
196
197 if (c->udp) {
198 c->udp->buffer = NULL;
199 }
200
201 rev->ready = 0;
202 rev->active = 1;
203
204 goto next;
205 }
206
207 #if (NGX_STAT_STUB)
208 (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
209 #endif
210
211 ngx_accept_disabled = ngx_cycle->connection_n / 8
212 - ngx_cycle->free_connection_n;
213
214 c = ngx_get_connection(lc->fd, ev->log);
215 if (c == NULL) {
216 return;
217 }
218
219 c->shared = 1;
220 c->type = SOCK_DGRAM;
221 c->socklen = socklen;
222
223 #if (NGX_STAT_STUB)
224 (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
225 #endif
226
227 c->pool = ngx_create_pool(ls->pool_size, ev->log);
228 if (c->pool == NULL) {
229 ngx_quic_close_accepted_connection(c);
230 return;
231 }
232
233 c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN);
234 if (c->sockaddr == NULL) {
235 ngx_quic_close_accepted_connection(c);
236 return;
237 }
238
239 ngx_memcpy(c->sockaddr, sockaddr, socklen);
240
241 log = ngx_palloc(c->pool, sizeof(ngx_log_t));
242 if (log == NULL) {
243 ngx_quic_close_accepted_connection(c);
244 return;
245 }
246
247 *log = ls->log;
248
249 c->log = log;
250 c->pool->log = log;
251 c->listening = ls;
252
253 if (local_sockaddr == &lsa.sockaddr) {
254 local_sockaddr = ngx_palloc(c->pool, local_socklen);
255 if (local_sockaddr == NULL) {
256 ngx_quic_close_accepted_connection(c);
257 return;
258 }
259
260 ngx_memcpy(local_sockaddr, &lsa, local_socklen);
261 }
262
263 c->local_sockaddr = local_sockaddr;
264 c->local_socklen = local_socklen;
265
266 c->buffer = ngx_create_temp_buf(c->pool, n);
267 if (c->buffer == NULL) {
268 ngx_quic_close_accepted_connection(c);
269 return;
270 }
271
272 c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);
273
274 rev = c->read;
275 wev = c->write;
276
277 rev->active = 1;
278 wev->ready = 1;
279
280 rev->log = log;
281 wev->log = log;
282
283 /*
284 * TODO: MT: - ngx_atomic_fetch_add()
285 * or protection by critical section or light mutex
286 *
287 * TODO: MP: - allocated in a shared memory
288 * - ngx_atomic_fetch_add()
289 * or protection by critical section or light mutex
290 */
291
292 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
293
294 c->start_time = ngx_current_msec;
295
296 #if (NGX_STAT_STUB)
297 (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
298 #endif
299
300 if (ls->addr_ntop) {
301 c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
302 if (c->addr_text.data == NULL) {
303 ngx_quic_close_accepted_connection(c);
304 return;
305 }
306
307 c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
308 c->addr_text.data,
309 ls->addr_text_max_len, 0);
310 if (c->addr_text.len == 0) {
311 ngx_quic_close_accepted_connection(c);
312 return;
313 }
314 }
315
316 #if (NGX_DEBUG)
317 {
318 ngx_str_t addr;
319 u_char text[NGX_SOCKADDR_STRLEN];
320
321 ngx_debug_accepted_connection(ecf, c);
322
323 if (log->log_level & NGX_LOG_DEBUG_EVENT) {
324 addr.data = text;
325 addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
326 NGX_SOCKADDR_STRLEN, 1);
327
328 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
329 "*%uA quic recvmsg: %V fd:%d n:%z",
330 c->number, &addr, c->fd, n);
331 }
332
333 }
334 #endif
335
336 log->data = NULL;
337 log->handler = NULL;
338
339 ls->handler(c);
340
341 next:
342
343 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
344 ev->available -= n;
345 }
346
347 } while (ev->available);
348 }
349
350
351 static void
352 ngx_quic_close_accepted_connection(ngx_connection_t *c)
353 {
354 ngx_free_connection(c);
355
356 c->fd = (ngx_socket_t) -1;
357
358 if (c->pool) {
359 ngx_destroy_pool(c->pool);
360 }
361
362 #if (NGX_STAT_STUB)
363 (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
364 #endif
365 }
366
367
368 void
369 ngx_quic_rbtree_insert_value(ngx_rbtree_node_t *temp,
370 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
371 {
372 ngx_int_t rc;
373 ngx_connection_t *c, *ct;
374 ngx_rbtree_node_t **p;
375 ngx_quic_socket_t *qsock, *qsockt;
376
377 for ( ;; ) {
378
379 if (node->key < temp->key) {
380
381 p = &temp->left;
382
383 } else if (node->key > temp->key) {
384
385 p = &temp->right;
386
387 } else { /* node->key == temp->key */
388
389 qsock = (ngx_quic_socket_t *) node;
390 c = qsock->udp.connection;
391
392 qsockt = (ngx_quic_socket_t *) temp;
393 ct = qsockt->udp.connection;
394
395 rc = ngx_memn2cmp(qsock->sid.id, qsockt->sid.id,
396 qsock->sid.len, qsockt->sid.len);
397
398 if (rc == 0 && c->listening->wildcard) {
399 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen,
400 ct->local_sockaddr, ct->local_socklen, 1);
401 }
402
403 p = (rc < 0) ? &temp->left : &temp->right;
404 }
405
406 if (*p == sentinel) {
407 break;
408 }
409
410 temp = *p;
411 }
412
413 *p = node;
414 node->parent = temp;
415 node->left = sentinel;
416 node->right = sentinel;
417 ngx_rbt_red(node);
418 }
419
420
421 static ngx_connection_t *
422 ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key,
423 struct sockaddr *local_sockaddr, socklen_t local_socklen)
424 {
425 uint32_t hash;
426 ngx_int_t rc;
427 ngx_connection_t *c;
428 ngx_rbtree_node_t *node, *sentinel;
429 ngx_quic_socket_t *qsock;
430
431 if (key->len == 0) {
432 return NULL;
433 }
434
435 node = ls->rbtree.root;
436 sentinel = ls->rbtree.sentinel;
437 hash = ngx_crc32_long(key->data, key->len);
438
439 while (node != sentinel) {
440
441 if (hash < node->key) {
442 node = node->left;
443 continue;
444 }
445
446 if (hash > node->key) {
447 node = node->right;
448 continue;
449 }
450
451 /* hash == node->key */
452
453 qsock = (ngx_quic_socket_t *) node;
454
455 rc = ngx_memn2cmp(key->data, qsock->sid.id, key->len, qsock->sid.len);
456
457 c = qsock->udp.connection;
458
459 if (rc == 0 && ls->wildcard) {
460 rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
461 c->local_sockaddr, c->local_socklen, 1);
462 }
463
464 if (rc == 0) {
465 c->udp = &qsock->udp;
466 return c;
467 }
468
469 node = (rc < 0) ? node->left : node->right;
470 }
471
472 return NULL;
473 }