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