Mercurial > hg > nginx
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 } |