comparison src/event/ngx_event_udp.c @ 8628:45db1b5c1706 quic

QUIC: connection multiplexing per port. Also, connection migration within a single worker is implemented.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 11 Nov 2020 11:57:50 +0000
parents 6d4bc025c5a7
children d62a16fff3a4
comparison
equal deleted inserted replaced
8627:405b6e8eb523 8628:45db1b5c1706
10 #include <ngx_event.h> 10 #include <ngx_event.h>
11 11
12 12
13 #if !(NGX_WIN32) 13 #if !(NGX_WIN32)
14 14
15 struct ngx_udp_connection_s {
16 ngx_rbtree_node_t node;
17 ngx_connection_t *connection;
18 ngx_buf_t *buffer;
19 };
20
21
22 static void ngx_close_accepted_udp_connection(ngx_connection_t *c); 15 static void ngx_close_accepted_udp_connection(ngx_connection_t *c);
23 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,
24 size_t size); 17 size_t size);
25 static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); 18 static ngx_int_t ngx_create_udp_connection(ngx_connection_t *c);
26 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,
27 struct sockaddr *sockaddr, socklen_t socklen, 20 ngx_str_t *key, struct sockaddr *sockaddr, socklen_t socklen,
28 struct sockaddr *local_sockaddr, socklen_t local_socklen); 21 struct sockaddr *local_sockaddr, socklen_t local_socklen);
29 22
30 23
31 void 24 void
32 ngx_event_recvmsg(ngx_event_t *ev) 25 ngx_event_recvmsg(ngx_event_t *ev)
33 { 26 {
34 ssize_t n; 27 ssize_t n;
28 ngx_str_t key;
35 ngx_buf_t buf; 29 ngx_buf_t buf;
36 ngx_log_t *log; 30 ngx_log_t *log;
37 ngx_err_t err; 31 ngx_err_t err;
38 socklen_t socklen, local_socklen; 32 socklen_t socklen, local_socklen;
39 ngx_event_t *rev, *wev; 33 ngx_event_t *rev, *wev;
227 } 221 }
228 } 222 }
229 223
230 #endif 224 #endif
231 225
232 c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, 226 ngx_str_null(&key);
233 local_socklen); 227
228 #if (NGX_QUIC)
229 if (ls->quic) {
230 if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) {
231 goto next;
232 }
233 }
234 #endif
235
236 c = ngx_lookup_udp_connection(ls, &key, sockaddr, socklen,
237 local_sockaddr, local_socklen);
234 238
235 if (c) { 239 if (c) {
236 240
237 #if (NGX_DEBUG) 241 #if (NGX_DEBUG)
238 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { 242 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
401 } 405 }
402 406
403 } 407 }
404 #endif 408 #endif
405 409
406 if (ngx_insert_udp_connection(c) != NGX_OK) { 410 if (ngx_create_udp_connection(c) != NGX_OK) {
407 ngx_close_accepted_udp_connection(c); 411 ngx_close_accepted_udp_connection(c);
408 return; 412 return;
409 } 413 }
410 414
411 log->data = NULL; 415 log->data = NULL;
490 c = udp->connection; 494 c = udp->connection;
491 495
492 udpt = (ngx_udp_connection_t *) temp; 496 udpt = (ngx_udp_connection_t *) temp;
493 ct = udpt->connection; 497 ct = udpt->connection;
494 498
495 rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, 499 rc = ngx_memn2cmp(udp->key.data, udpt->key.data,
496 ct->sockaddr, ct->socklen, 1); 500 udp->key.len, udpt->key.len);
501
502 if (rc == 0 && udp->key.len == 0) {
503 rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen,
504 ct->sockaddr, ct->socklen, 1);
505 }
497 506
498 if (rc == 0 && c->listening->wildcard) { 507 if (rc == 0 && c->listening->wildcard) {
499 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, 508 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen,
500 ct->local_sockaddr, ct->local_socklen, 1); 509 ct->local_sockaddr, ct->local_socklen, 1);
501 } 510 }
517 ngx_rbt_red(node); 526 ngx_rbt_red(node);
518 } 527 }
519 528
520 529
521 static ngx_int_t 530 static ngx_int_t
522 ngx_insert_udp_connection(ngx_connection_t *c) 531 ngx_create_udp_connection(ngx_connection_t *c)
523 { 532 {
524 uint32_t hash; 533 ngx_str_t key;
525 ngx_pool_cleanup_t *cln; 534 ngx_pool_cleanup_t *cln;
526 ngx_udp_connection_t *udp; 535 ngx_udp_connection_t *udp;
536
537 #if (NGX_QUIC)
538 if (c->listening->quic) {
539 return NGX_OK;
540 }
541 #endif
527 542
528 if (c->udp) { 543 if (c->udp) {
529 return NGX_OK; 544 return NGX_OK;
530 } 545 }
531 546
532 udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t)); 547 udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t));
533 if (udp == NULL) { 548 if (udp == NULL) {
534 return NGX_ERROR; 549 return NGX_ERROR;
535 } 550 }
536 551
537 udp->connection = c;
538
539 ngx_crc32_init(hash);
540 ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen);
541
542 if (c->listening->wildcard) {
543 ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen);
544 }
545
546 ngx_crc32_final(hash);
547
548 udp->node.key = hash;
549
550 cln = ngx_pool_cleanup_add(c->pool, 0); 552 cln = ngx_pool_cleanup_add(c->pool, 0);
551 if (cln == NULL) { 553 if (cln == NULL) {
552 return NGX_ERROR; 554 return NGX_ERROR;
553 } 555 }
554 556
555 cln->data = c; 557 cln->data = c;
556 cln->handler = ngx_delete_udp_connection; 558 cln->handler = ngx_delete_udp_connection;
557 559
560 key.len = 0;
561
562 ngx_insert_udp_connection(c, udp, &key);
563
564 c->udp = udp;
565
566 return NGX_OK;
567 }
568
569
570 void
571 ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp,
572 ngx_str_t *key)
573 {
574 uint32_t hash;
575
576 ngx_crc32_init(hash);
577
578 ngx_crc32_update(&hash, key->data, key->len);
579
580 if (key->len == 0) {
581 ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen);
582 }
583
584 if (c->listening->wildcard) {
585 ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen);
586 }
587
588 ngx_crc32_final(hash);
589
590 udp->connection = c;
591 udp->key = *key;
592 udp->node.key = hash;
593
558 ngx_rbtree_insert(&c->listening->rbtree, &udp->node); 594 ngx_rbtree_insert(&c->listening->rbtree, &udp->node);
559
560 c->udp = udp;
561
562 return NGX_OK;
563 } 595 }
564 596
565 597
566 void 598 void
567 ngx_delete_udp_connection(void *data) 599 ngx_delete_udp_connection(void *data)
577 c->udp = NULL; 609 c->udp = NULL;
578 } 610 }
579 611
580 612
581 static ngx_connection_t * 613 static ngx_connection_t *
582 ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, 614 ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key,
583 socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen) 615 struct sockaddr *sockaddr, socklen_t socklen,
616 struct sockaddr *local_sockaddr, socklen_t local_socklen)
584 { 617 {
585 uint32_t hash; 618 uint32_t hash;
586 ngx_int_t rc; 619 ngx_int_t rc;
587 ngx_connection_t *c; 620 ngx_connection_t *c;
588 ngx_rbtree_node_t *node, *sentinel; 621 ngx_rbtree_node_t *node, *sentinel;
606 639
607 node = ls->rbtree.root; 640 node = ls->rbtree.root;
608 sentinel = ls->rbtree.sentinel; 641 sentinel = ls->rbtree.sentinel;
609 642
610 ngx_crc32_init(hash); 643 ngx_crc32_init(hash);
611 ngx_crc32_update(&hash, (u_char *) sockaddr, socklen); 644
645 ngx_crc32_update(&hash, key->data, key->len);
646
647 if (key->len == 0) {
648 ngx_crc32_update(&hash, (u_char *) sockaddr, socklen);
649 }
612 650
613 if (ls->wildcard) { 651 if (ls->wildcard) {
614 ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); 652 ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen);
615 } 653 }
616 654
632 670
633 udp = (ngx_udp_connection_t *) node; 671 udp = (ngx_udp_connection_t *) node;
634 672
635 c = udp->connection; 673 c = udp->connection;
636 674
637 rc = ngx_cmp_sockaddr(sockaddr, socklen, 675 rc = ngx_memn2cmp(key->data, udp->key.data, key->len, udp->key.len);
638 c->sockaddr, c->socklen, 1); 676
677 if (rc == 0 && key->len == 0) {
678 rc = ngx_cmp_sockaddr(sockaddr, socklen,
679 c->sockaddr, c->socklen, 1);
680 }
639 681
640 if (rc == 0 && ls->wildcard) { 682 if (rc == 0 && ls->wildcard) {
641 rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, 683 rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
642 c->local_sockaddr, c->local_socklen, 1); 684 c->local_sockaddr, c->local_socklen, 1);
643 } 685 }
644 686
645 if (rc == 0) { 687 if (rc == 0) {
688 if (key->len) {
689 rc = ngx_cmp_sockaddr(sockaddr, socklen,
690 c->sockaddr, c->socklen, 1);
691
692 if (rc) {
693 #if (NGX_DEBUG)
694 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
695 ngx_str_t addr;
696 u_char text[NGX_SOCKADDR_STRLEN];
697
698 addr.data = text;
699 addr.len = ngx_sock_ntop(sockaddr, socklen, text,
700 NGX_SOCKADDR_STRLEN, 1);
701
702 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
703 "client migrated to %V", &addr);
704 }
705 #endif
706
707 if (c->socklen < socklen) {
708 c->sockaddr = ngx_palloc(c->pool, socklen);
709 if (c->sockaddr == NULL) {
710 return c;
711 }
712 }
713
714 ngx_memcpy(c->sockaddr, sockaddr, socklen);
715 c->socklen = socklen;
716 }
717 }
718
646 return c; 719 return c;
647 } 720 }
648 721
649 node = (rc < 0) ? node->left : node->right; 722 node = (rc < 0) ? node->left : node->right;
650 } 723 }