Mercurial > hg > nginx
comparison src/event/ngx_event_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 | ce6d9cf0f567 |
children | af5adec171b4 |
comparison
equal
deleted
inserted
replaced
9016:55b38514729b | 9017:c2f5d79cde64 |
---|---|
13 #if !(NGX_WIN32) | 13 #if !(NGX_WIN32) |
14 | 14 |
15 static void ngx_close_accepted_udp_connection(ngx_connection_t *c); | 15 static void ngx_close_accepted_udp_connection(ngx_connection_t *c); |
16 static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, | 16 static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, |
17 size_t size); | 17 size_t size); |
18 static ngx_int_t ngx_create_udp_connection(ngx_connection_t *c); | 18 static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); |
19 static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, | 19 static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, |
20 ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); | 20 struct sockaddr *sockaddr, socklen_t socklen, |
21 struct sockaddr *local_sockaddr, socklen_t local_socklen); | |
21 | 22 |
22 | 23 |
23 void | 24 void |
24 ngx_event_recvmsg(ngx_event_t *ev) | 25 ngx_event_recvmsg(ngx_event_t *ev) |
25 { | 26 { |
26 size_t len; | |
27 ssize_t n; | 27 ssize_t n; |
28 ngx_str_t key; | |
29 ngx_buf_t buf; | 28 ngx_buf_t buf; |
30 ngx_log_t *log; | 29 ngx_log_t *log; |
31 ngx_err_t err; | 30 ngx_err_t err; |
32 socklen_t local_socklen; | 31 socklen_t socklen, local_socklen; |
33 ngx_event_t *rev, *wev; | 32 ngx_event_t *rev, *wev; |
34 struct iovec iov[1]; | 33 struct iovec iov[1]; |
35 struct msghdr msg; | 34 struct msghdr msg; |
36 ngx_sockaddr_t sa, lsa; | 35 ngx_sockaddr_t sa, lsa; |
37 ngx_udp_dgram_t dgram; | 36 struct sockaddr *sockaddr, *local_sockaddr; |
38 struct sockaddr *local_sockaddr; | |
39 ngx_listening_t *ls; | 37 ngx_listening_t *ls; |
40 ngx_event_conf_t *ecf; | 38 ngx_event_conf_t *ecf; |
41 ngx_connection_t *c, *lc; | 39 ngx_connection_t *c, *lc; |
42 static u_char buffer[65535]; | 40 static u_char buffer[65535]; |
43 | 41 |
108 "recvmsg() truncated data"); | 106 "recvmsg() truncated data"); |
109 continue; | 107 continue; |
110 } | 108 } |
111 #endif | 109 #endif |
112 | 110 |
113 dgram.sockaddr = msg.msg_name; | 111 sockaddr = msg.msg_name; |
114 dgram.socklen = msg.msg_namelen; | 112 socklen = msg.msg_namelen; |
115 | 113 |
116 if (dgram.socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { | 114 if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { |
117 dgram.socklen = sizeof(ngx_sockaddr_t); | 115 socklen = sizeof(ngx_sockaddr_t); |
118 } | 116 } |
119 | 117 |
120 if (dgram.socklen == 0) { | 118 if (socklen == 0) { |
121 | 119 |
122 /* | 120 /* |
123 * on Linux recvmsg() returns zero msg_namelen | 121 * on Linux recvmsg() returns zero msg_namelen |
124 * when receiving packets from unbound AF_UNIX sockets | 122 * when receiving packets from unbound AF_UNIX sockets |
125 */ | 123 */ |
126 | 124 |
127 dgram.socklen = sizeof(struct sockaddr); | 125 socklen = sizeof(struct sockaddr); |
128 ngx_memzero(&sa, sizeof(struct sockaddr)); | 126 ngx_memzero(&sa, sizeof(struct sockaddr)); |
129 sa.sockaddr.sa_family = ls->sockaddr->sa_family; | 127 sa.sockaddr.sa_family = ls->sockaddr->sa_family; |
130 } | 128 } |
131 | 129 |
132 local_sockaddr = ls->sockaddr; | 130 local_sockaddr = ls->sockaddr; |
150 } | 148 } |
151 } | 149 } |
152 | 150 |
153 #endif | 151 #endif |
154 | 152 |
155 key.data = (u_char *) dgram.sockaddr; | 153 c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, |
156 key.len = dgram.socklen; | 154 local_socklen); |
157 | |
158 #if (NGX_HAVE_UNIX_DOMAIN) | |
159 | |
160 if (dgram.sockaddr->sa_family == AF_UNIX) { | |
161 struct sockaddr_un *saun = (struct sockaddr_un *) dgram.sockaddr; | |
162 | |
163 if (dgram.socklen <= (socklen_t) offsetof(struct sockaddr_un, | |
164 sun_path) | |
165 || saun->sun_path[0] == '\0') | |
166 { | |
167 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | |
168 "unbound unix socket"); | |
169 key.len = 0; | |
170 } | |
171 } | |
172 | |
173 #endif | |
174 | |
175 #if (NGX_QUIC) | |
176 if (ls->quic) { | |
177 if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { | |
178 goto next; | |
179 } | |
180 } | |
181 #endif | |
182 | |
183 c = ngx_lookup_udp_connection(ls, &key, local_sockaddr, local_socklen); | |
184 | 155 |
185 if (c) { | 156 if (c) { |
186 | 157 |
187 #if (NGX_DEBUG) | 158 #if (NGX_DEBUG) |
188 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { | 159 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { |
200 | 171 |
201 ngx_memzero(&buf, sizeof(ngx_buf_t)); | 172 ngx_memzero(&buf, sizeof(ngx_buf_t)); |
202 | 173 |
203 buf.pos = buffer; | 174 buf.pos = buffer; |
204 buf.last = buffer + n; | 175 buf.last = buffer + n; |
205 buf.start = buf.pos; | |
206 buf.end = buffer + sizeof(buffer); | |
207 | 176 |
208 rev = c->read; | 177 rev = c->read; |
209 | 178 |
210 dgram.buffer = &buf; | 179 c->udp->buffer = &buf; |
211 | |
212 c->udp->dgram = &dgram; | |
213 | 180 |
214 rev->ready = 1; | 181 rev->ready = 1; |
215 rev->active = 0; | 182 rev->active = 0; |
216 | 183 |
217 rev->handler(rev); | 184 rev->handler(rev); |
218 | 185 |
219 if (c->udp) { | 186 if (c->udp) { |
220 c->udp->dgram = NULL; | 187 c->udp->buffer = NULL; |
221 } | 188 } |
222 | 189 |
223 rev->ready = 0; | 190 rev->ready = 0; |
224 rev->active = 1; | 191 rev->active = 1; |
225 | 192 |
238 return; | 205 return; |
239 } | 206 } |
240 | 207 |
241 c->shared = 1; | 208 c->shared = 1; |
242 c->type = SOCK_DGRAM; | 209 c->type = SOCK_DGRAM; |
243 c->socklen = dgram.socklen; | 210 c->socklen = socklen; |
244 | 211 |
245 #if (NGX_STAT_STUB) | 212 #if (NGX_STAT_STUB) |
246 (void) ngx_atomic_fetch_add(ngx_stat_active, 1); | 213 (void) ngx_atomic_fetch_add(ngx_stat_active, 1); |
247 #endif | 214 #endif |
248 | 215 |
250 if (c->pool == NULL) { | 217 if (c->pool == NULL) { |
251 ngx_close_accepted_udp_connection(c); | 218 ngx_close_accepted_udp_connection(c); |
252 return; | 219 return; |
253 } | 220 } |
254 | 221 |
255 len = dgram.socklen; | 222 c->sockaddr = ngx_palloc(c->pool, socklen); |
256 | |
257 #if (NGX_QUIC) | |
258 if (ls->quic) { | |
259 len = NGX_SOCKADDRLEN; | |
260 } | |
261 #endif | |
262 | |
263 c->sockaddr = ngx_palloc(c->pool, len); | |
264 if (c->sockaddr == NULL) { | 223 if (c->sockaddr == NULL) { |
265 ngx_close_accepted_udp_connection(c); | 224 ngx_close_accepted_udp_connection(c); |
266 return; | 225 return; |
267 } | 226 } |
268 | 227 |
269 ngx_memcpy(c->sockaddr, dgram.sockaddr, dgram.socklen); | 228 ngx_memcpy(c->sockaddr, sockaddr, socklen); |
270 | 229 |
271 log = ngx_palloc(c->pool, sizeof(ngx_log_t)); | 230 log = ngx_palloc(c->pool, sizeof(ngx_log_t)); |
272 if (log == NULL) { | 231 if (log == NULL) { |
273 ngx_close_accepted_udp_connection(c); | 232 ngx_close_accepted_udp_connection(c); |
274 return; | 233 return; |
367 } | 326 } |
368 | 327 |
369 } | 328 } |
370 #endif | 329 #endif |
371 | 330 |
372 if (ngx_create_udp_connection(c) != NGX_OK) { | 331 if (ngx_insert_udp_connection(c) != NGX_OK) { |
373 ngx_close_accepted_udp_connection(c); | 332 ngx_close_accepted_udp_connection(c); |
374 return; | 333 return; |
375 } | 334 } |
376 | 335 |
377 log->data = NULL; | 336 log->data = NULL; |
410 ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size) | 369 ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size) |
411 { | 370 { |
412 ssize_t n; | 371 ssize_t n; |
413 ngx_buf_t *b; | 372 ngx_buf_t *b; |
414 | 373 |
415 if (c->udp == NULL || c->udp->dgram == NULL) { | 374 if (c->udp == NULL || c->udp->buffer == NULL) { |
416 return NGX_AGAIN; | 375 return NGX_AGAIN; |
417 } | 376 } |
418 | 377 |
419 b = c->udp->dgram->buffer; | 378 b = c->udp->buffer; |
420 | 379 |
421 n = ngx_min(b->last - b->pos, (ssize_t) size); | 380 n = ngx_min(b->last - b->pos, (ssize_t) size); |
422 | 381 |
423 ngx_memcpy(buf, b->pos, n); | 382 ngx_memcpy(buf, b->pos, n); |
424 | 383 |
425 c->udp->dgram = NULL; | 384 c->udp->buffer = NULL; |
426 | 385 |
427 c->read->ready = 0; | 386 c->read->ready = 0; |
428 c->read->active = 1; | 387 c->read->active = 1; |
429 | 388 |
430 return n; | 389 return n; |
456 c = udp->connection; | 415 c = udp->connection; |
457 | 416 |
458 udpt = (ngx_udp_connection_t *) temp; | 417 udpt = (ngx_udp_connection_t *) temp; |
459 ct = udpt->connection; | 418 ct = udpt->connection; |
460 | 419 |
461 rc = ngx_memn2cmp(udp->key.data, udpt->key.data, | 420 rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, |
462 udp->key.len, udpt->key.len); | 421 ct->sockaddr, ct->socklen, 1); |
463 | 422 |
464 if (rc == 0 && c->listening->wildcard) { | 423 if (rc == 0 && c->listening->wildcard) { |
465 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, | 424 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, |
466 ct->local_sockaddr, ct->local_socklen, 1); | 425 ct->local_sockaddr, ct->local_socklen, 1); |
467 } | 426 } |
483 ngx_rbt_red(node); | 442 ngx_rbt_red(node); |
484 } | 443 } |
485 | 444 |
486 | 445 |
487 static ngx_int_t | 446 static ngx_int_t |
488 ngx_create_udp_connection(ngx_connection_t *c) | 447 ngx_insert_udp_connection(ngx_connection_t *c) |
489 { | 448 { |
490 ngx_str_t key; | 449 uint32_t hash; |
491 ngx_pool_cleanup_t *cln; | 450 ngx_pool_cleanup_t *cln; |
492 ngx_udp_connection_t *udp; | 451 ngx_udp_connection_t *udp; |
493 | |
494 #if (NGX_QUIC) | |
495 if (c->listening->quic) { | |
496 return NGX_OK; | |
497 } | |
498 #endif | |
499 | 452 |
500 if (c->udp) { | 453 if (c->udp) { |
501 return NGX_OK; | 454 return NGX_OK; |
502 } | 455 } |
503 | 456 |
504 udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t)); | 457 udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t)); |
505 if (udp == NULL) { | 458 if (udp == NULL) { |
506 return NGX_ERROR; | 459 return NGX_ERROR; |
507 } | 460 } |
508 | 461 |
462 udp->connection = c; | |
463 | |
464 ngx_crc32_init(hash); | |
465 ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen); | |
466 | |
467 if (c->listening->wildcard) { | |
468 ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); | |
469 } | |
470 | |
471 ngx_crc32_final(hash); | |
472 | |
473 udp->node.key = hash; | |
474 | |
509 cln = ngx_pool_cleanup_add(c->pool, 0); | 475 cln = ngx_pool_cleanup_add(c->pool, 0); |
510 if (cln == NULL) { | 476 if (cln == NULL) { |
511 return NGX_ERROR; | 477 return NGX_ERROR; |
512 } | 478 } |
513 | 479 |
514 cln->data = c; | 480 cln->data = c; |
515 cln->handler = ngx_delete_udp_connection; | 481 cln->handler = ngx_delete_udp_connection; |
516 | 482 |
517 key.data = (u_char *) c->sockaddr; | 483 ngx_rbtree_insert(&c->listening->rbtree, &udp->node); |
518 key.len = c->socklen; | |
519 | |
520 ngx_insert_udp_connection(c, udp, &key); | |
521 | 484 |
522 c->udp = udp; | 485 c->udp = udp; |
523 | 486 |
524 return NGX_OK; | 487 return NGX_OK; |
525 } | |
526 | |
527 | |
528 void | |
529 ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, | |
530 ngx_str_t *key) | |
531 { | |
532 uint32_t hash; | |
533 | |
534 ngx_crc32_init(hash); | |
535 | |
536 ngx_crc32_update(&hash, key->data, key->len); | |
537 | |
538 if (c->listening->wildcard) { | |
539 ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); | |
540 } | |
541 | |
542 ngx_crc32_final(hash); | |
543 | |
544 udp->connection = c; | |
545 udp->key = *key; | |
546 udp->node.key = hash; | |
547 | |
548 ngx_rbtree_insert(&c->listening->rbtree, &udp->node); | |
549 } | 488 } |
550 | 489 |
551 | 490 |
552 void | 491 void |
553 ngx_delete_udp_connection(void *data) | 492 ngx_delete_udp_connection(void *data) |
563 c->udp = NULL; | 502 c->udp = NULL; |
564 } | 503 } |
565 | 504 |
566 | 505 |
567 static ngx_connection_t * | 506 static ngx_connection_t * |
568 ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, | 507 ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, |
569 struct sockaddr *local_sockaddr, socklen_t local_socklen) | 508 socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen) |
570 { | 509 { |
571 uint32_t hash; | 510 uint32_t hash; |
572 ngx_int_t rc; | 511 ngx_int_t rc; |
573 ngx_connection_t *c; | 512 ngx_connection_t *c; |
574 ngx_rbtree_node_t *node, *sentinel; | 513 ngx_rbtree_node_t *node, *sentinel; |
575 ngx_udp_connection_t *udp; | 514 ngx_udp_connection_t *udp; |
576 | 515 |
577 if (key->len == 0) { | 516 #if (NGX_HAVE_UNIX_DOMAIN) |
578 return NULL; | 517 |
579 } | 518 if (sockaddr->sa_family == AF_UNIX) { |
519 struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; | |
520 | |
521 if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) | |
522 || saun->sun_path[0] == '\0') | |
523 { | |
524 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | |
525 "unbound unix socket"); | |
526 return NULL; | |
527 } | |
528 } | |
529 | |
530 #endif | |
580 | 531 |
581 node = ls->rbtree.root; | 532 node = ls->rbtree.root; |
582 sentinel = ls->rbtree.sentinel; | 533 sentinel = ls->rbtree.sentinel; |
583 | 534 |
584 ngx_crc32_init(hash); | 535 ngx_crc32_init(hash); |
585 ngx_crc32_update(&hash, key->data, key->len); | 536 ngx_crc32_update(&hash, (u_char *) sockaddr, socklen); |
586 | 537 |
587 if (ls->wildcard) { | 538 if (ls->wildcard) { |
588 ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); | 539 ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); |
589 } | 540 } |
590 | 541 |
606 | 557 |
607 udp = (ngx_udp_connection_t *) node; | 558 udp = (ngx_udp_connection_t *) node; |
608 | 559 |
609 c = udp->connection; | 560 c = udp->connection; |
610 | 561 |
611 rc = ngx_memn2cmp(key->data, udp->key.data, key->len, udp->key.len); | 562 rc = ngx_cmp_sockaddr(sockaddr, socklen, |
563 c->sockaddr, c->socklen, 1); | |
612 | 564 |
613 if (rc == 0 && ls->wildcard) { | 565 if (rc == 0 && ls->wildcard) { |
614 rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, | 566 rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, |
615 c->local_sockaddr, c->local_socklen, 1); | 567 c->local_sockaddr, c->local_socklen, 1); |
616 } | 568 } |
617 | 569 |
618 if (rc == 0) { | 570 if (rc == 0) { |
619 | |
620 #if (NGX_QUIC) | |
621 if (ls->quic && c->udp != udp) { | |
622 c->udp = udp; | |
623 } | |
624 #endif | |
625 | |
626 return c; | 571 return c; |
627 } | 572 } |
628 | 573 |
629 node = (rc < 0) ? node->left : node->right; | 574 node = (rc < 0) ? node->left : node->right; |
630 } | 575 } |