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 }