diff options
author | Roman Arutyunyan <arut@nginx.com> | 2022-04-20 16:01:17 +0400 |
---|---|---|
committer | Roman Arutyunyan <arut@nginx.com> | 2022-04-20 16:01:17 +0400 |
commit | 9d81ef744cdaacf1e52bcaec4224d375af5ba59b (patch) | |
tree | db3f8a9fc1381a2c848d934fd1c7f9bbaf1a9dca | |
parent | c24c27bb074b571fc9e9d75e19be31b83c69c253 (diff) | |
download | nginx-9d81ef744cdaacf1e52bcaec4224d375af5ba59b.tar.gz nginx-9d81ef744cdaacf1e52bcaec4224d375af5ba59b.zip |
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.
-rw-r--r-- | auto/modules | 1 | ||||
-rw-r--r-- | src/core/ngx_connection.c | 4 | ||||
-rw-r--r-- | src/event/ngx_event.c | 12 | ||||
-rw-r--r-- | src/event/ngx_event_udp.c | 173 | ||||
-rw-r--r-- | src/event/ngx_event_udp.h | 17 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic.c | 8 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic.h | 3 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic_connection.h | 2 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic_migration.c | 7 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic_socket.c | 5 | ||||
-rw-r--r-- | src/event/quic/ngx_event_quic_udp.c | 473 | ||||
-rw-r--r-- | src/http/ngx_http.c | 7 | ||||
-rw-r--r-- | src/stream/ngx_stream.c | 15 |
13 files changed, 585 insertions, 142 deletions
diff --git a/auto/modules b/auto/modules index 19967fa40..575fff0b7 100644 --- a/auto/modules +++ b/auto/modules @@ -1344,6 +1344,7 @@ if [ $USE_OPENSSL_QUIC = YES ]; then src/event/quic/ngx_event_quic_output.h \ src/event/quic/ngx_event_quic_socket.h" ngx_module_srcs="src/event/quic/ngx_event_quic.c \ + src/event/quic/ngx_event_quic_udp.c \ src/event/quic/ngx_event_quic_transport.c \ src/event/quic/ngx_event_quic_protection.c \ src/event/quic/ngx_event_quic_frames.c \ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 4a7d2fe79..cbd5803be 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -72,10 +72,6 @@ ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr, ngx_memcpy(ls->addr_text.data, text, len); -#if !(NGX_WIN32) - ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ngx_udp_rbtree_insert_value); -#endif - ls->fd = (ngx_socket_t) -1; ls->type = SOCK_STREAM; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index aebc4541d..284aafbe6 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -886,8 +886,16 @@ ngx_event_process_init(ngx_cycle_t *cycle) #else - rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept - : ngx_event_recvmsg; + if (c->type == SOCK_STREAM) { + rev->handler = ngx_event_accept; + +#if (NGX_QUIC) + } else if (ls[i].quic) { + rev->handler = ngx_quic_recvmsg; +#endif + } else { + rev->handler = ngx_event_recvmsg; + } #if (NGX_HAVE_REUSEPORT) diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index 1053fa0ac..a7fa38aa8 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -15,27 +15,25 @@ static void ngx_close_accepted_udp_connection(ngx_connection_t *c); static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size); -static ngx_int_t ngx_create_udp_connection(ngx_connection_t *c); +static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, - ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); + struct sockaddr *sockaddr, socklen_t socklen, + struct sockaddr *local_sockaddr, socklen_t local_socklen); void ngx_event_recvmsg(ngx_event_t *ev) { - size_t len; ssize_t n; - ngx_str_t key; ngx_buf_t buf; ngx_log_t *log; ngx_err_t err; - socklen_t local_socklen; + socklen_t socklen, local_socklen; ngx_event_t *rev, *wev; struct iovec iov[1]; struct msghdr msg; ngx_sockaddr_t sa, lsa; - ngx_udp_dgram_t dgram; - struct sockaddr *local_sockaddr; + struct sockaddr *sockaddr, *local_sockaddr; ngx_listening_t *ls; ngx_event_conf_t *ecf; ngx_connection_t *c, *lc; @@ -110,21 +108,21 @@ ngx_event_recvmsg(ngx_event_t *ev) } #endif - dgram.sockaddr = msg.msg_name; - dgram.socklen = msg.msg_namelen; + sockaddr = msg.msg_name; + socklen = msg.msg_namelen; - if (dgram.socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { - dgram.socklen = sizeof(ngx_sockaddr_t); + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); } - if (dgram.socklen == 0) { + if (socklen == 0) { /* * on Linux recvmsg() returns zero msg_namelen * when receiving packets from unbound AF_UNIX sockets */ - dgram.socklen = sizeof(struct sockaddr); + socklen = sizeof(struct sockaddr); ngx_memzero(&sa, sizeof(struct sockaddr)); sa.sockaddr.sa_family = ls->sockaddr->sa_family; } @@ -152,35 +150,8 @@ ngx_event_recvmsg(ngx_event_t *ev) #endif - key.data = (u_char *) dgram.sockaddr; - key.len = dgram.socklen; - -#if (NGX_HAVE_UNIX_DOMAIN) - - if (dgram.sockaddr->sa_family == AF_UNIX) { - struct sockaddr_un *saun = (struct sockaddr_un *) dgram.sockaddr; - - if (dgram.socklen <= (socklen_t) offsetof(struct sockaddr_un, - sun_path) - || saun->sun_path[0] == '\0') - { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "unbound unix socket"); - key.len = 0; - } - } - -#endif - -#if (NGX_QUIC) - if (ls->quic) { - if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { - goto next; - } - } -#endif - - c = ngx_lookup_udp_connection(ls, &key, local_sockaddr, local_socklen); + c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr, + local_socklen); if (c) { @@ -202,14 +173,10 @@ ngx_event_recvmsg(ngx_event_t *ev) buf.pos = buffer; buf.last = buffer + n; - buf.start = buf.pos; - buf.end = buffer + sizeof(buffer); rev = c->read; - dgram.buffer = &buf; - - c->udp->dgram = &dgram; + c->udp->buffer = &buf; rev->ready = 1; rev->active = 0; @@ -217,7 +184,7 @@ ngx_event_recvmsg(ngx_event_t *ev) rev->handler(rev); if (c->udp) { - c->udp->dgram = NULL; + c->udp->buffer = NULL; } rev->ready = 0; @@ -240,7 +207,7 @@ ngx_event_recvmsg(ngx_event_t *ev) c->shared = 1; c->type = SOCK_DGRAM; - c->socklen = dgram.socklen; + c->socklen = socklen; #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); @@ -252,21 +219,13 @@ ngx_event_recvmsg(ngx_event_t *ev) return; } - len = dgram.socklen; - -#if (NGX_QUIC) - if (ls->quic) { - len = NGX_SOCKADDRLEN; - } -#endif - - c->sockaddr = ngx_palloc(c->pool, len); + c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_udp_connection(c); return; } - ngx_memcpy(c->sockaddr, dgram.sockaddr, dgram.socklen); + ngx_memcpy(c->sockaddr, sockaddr, socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { @@ -369,7 +328,7 @@ ngx_event_recvmsg(ngx_event_t *ev) } #endif - if (ngx_create_udp_connection(c) != NGX_OK) { + if (ngx_insert_udp_connection(c) != NGX_OK) { ngx_close_accepted_udp_connection(c); return; } @@ -412,17 +371,17 @@ ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size) ssize_t n; ngx_buf_t *b; - if (c->udp == NULL || c->udp->dgram == NULL) { + if (c->udp == NULL || c->udp->buffer == NULL) { return NGX_AGAIN; } - b = c->udp->dgram->buffer; + b = c->udp->buffer; n = ngx_min(b->last - b->pos, (ssize_t) size); ngx_memcpy(buf, b->pos, n); - c->udp->dgram = NULL; + c->udp->buffer = NULL; c->read->ready = 0; c->read->active = 1; @@ -458,8 +417,8 @@ ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, udpt = (ngx_udp_connection_t *) temp; ct = udpt->connection; - rc = ngx_memn2cmp(udp->key.data, udpt->key.data, - udp->key.len, udpt->key.len); + rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen, + ct->sockaddr, ct->socklen, 1); if (rc == 0 && c->listening->wildcard) { rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, @@ -485,18 +444,12 @@ ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, static ngx_int_t -ngx_create_udp_connection(ngx_connection_t *c) +ngx_insert_udp_connection(ngx_connection_t *c) { - ngx_str_t key; + uint32_t hash; ngx_pool_cleanup_t *cln; ngx_udp_connection_t *udp; -#if (NGX_QUIC) - if (c->listening->quic) { - return NGX_OK; - } -#endif - if (c->udp) { return NGX_OK; } @@ -506,34 +459,10 @@ ngx_create_udp_connection(ngx_connection_t *c) return NGX_ERROR; } - cln = ngx_pool_cleanup_add(c->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->data = c; - cln->handler = ngx_delete_udp_connection; - - key.data = (u_char *) c->sockaddr; - key.len = c->socklen; - - ngx_insert_udp_connection(c, udp, &key); - - c->udp = udp; - - return NGX_OK; -} - - -void -ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, - ngx_str_t *key) -{ - uint32_t hash; + udp->connection = c; ngx_crc32_init(hash); - - ngx_crc32_update(&hash, key->data, key->len); + ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen); if (c->listening->wildcard) { ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); @@ -541,11 +470,21 @@ ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, ngx_crc32_final(hash); - udp->connection = c; - udp->key = *key; udp->node.key = hash; + cln = ngx_pool_cleanup_add(c->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = c; + cln->handler = ngx_delete_udp_connection; + ngx_rbtree_insert(&c->listening->rbtree, &udp->node); + + c->udp = udp; + + return NGX_OK; } @@ -565,8 +504,8 @@ ngx_delete_udp_connection(void *data) static ngx_connection_t * -ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, - struct sockaddr *local_sockaddr, socklen_t local_socklen) +ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, + socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen) { uint32_t hash; ngx_int_t rc; @@ -574,15 +513,27 @@ ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, ngx_rbtree_node_t *node, *sentinel; ngx_udp_connection_t *udp; - if (key->len == 0) { - return NULL; +#if (NGX_HAVE_UNIX_DOMAIN) + + if (sockaddr->sa_family == AF_UNIX) { + struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) + || saun->sun_path[0] == '\0') + { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "unbound unix socket"); + return NULL; + } } +#endif + node = ls->rbtree.root; sentinel = ls->rbtree.sentinel; ngx_crc32_init(hash); - ngx_crc32_update(&hash, key->data, key->len); + ngx_crc32_update(&hash, (u_char *) sockaddr, socklen); if (ls->wildcard) { ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen); @@ -608,7 +559,8 @@ ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, c = udp->connection; - rc = ngx_memn2cmp(key->data, udp->key.data, key->len, udp->key.len); + rc = ngx_cmp_sockaddr(sockaddr, socklen, + c->sockaddr, c->socklen, 1); if (rc == 0 && ls->wildcard) { rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, @@ -616,13 +568,6 @@ ngx_lookup_udp_connection(ngx_listening_t *ls, ngx_str_t *key, } if (rc == 0) { - -#if (NGX_QUIC) - if (ls->quic && c->udp != udp) { - c->udp = udp; - } -#endif - return c; } diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h index b5ceeca3f..d7a64ee03 100644 --- a/src/event/ngx_event_udp.h +++ b/src/event/ngx_event_udp.h @@ -23,18 +23,10 @@ #endif -typedef struct { - ngx_buf_t *buffer; - struct sockaddr *sockaddr; - socklen_t socklen; -} ngx_udp_dgram_t; - - struct ngx_udp_connection_s { - ngx_rbtree_node_t node; - ngx_connection_t *connection; - ngx_str_t key; - ngx_udp_dgram_t *dgram; + ngx_rbtree_node_t node; + ngx_connection_t *connection; + ngx_buf_t *buffer; }; @@ -65,9 +57,6 @@ void ngx_event_recvmsg(ngx_event_t *ev); ssize_t ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags); void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); -void ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, - ngx_str_t *key); - #endif void ngx_delete_udp_connection(void *data); diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c index 96884cd44..834e7935f 100644 --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -430,7 +430,7 @@ ngx_quic_input_handler(ngx_event_t *rev) return; } - b = c->udp->dgram->buffer; + b = c->udp->buffer; rc = ngx_quic_handle_datagram(c, b, NULL); @@ -758,6 +758,7 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf, ngx_quic_header_t *pkt) { ngx_int_t rc; + ngx_quic_socket_t *qsock; ngx_quic_connection_t *qc; c->log->action = "parsing quic packet"; @@ -809,8 +810,9 @@ ngx_quic_handle_packet(ngx_connection_t *c, ngx_quic_conf_t *conf, } if (pkt->first) { - if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr, - c->udp->dgram->socklen, + qsock = ngx_quic_get_socket(c); + + if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, qc->path->sockaddr, qc->path->socklen, 1) != NGX_OK) { diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h index 903b690b9..92c9ecae0 100644 --- a/src/event/quic/ngx_event_quic.h +++ b/src/event/quic/ngx_event_quic.h @@ -102,6 +102,9 @@ struct ngx_quic_stream_s { }; +void ngx_quic_recvmsg(ngx_event_t *ev); +void ngx_quic_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); void ngx_quic_run(ngx_connection_t *c, ngx_quic_conf_t *conf); ngx_connection_t *ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi); void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h index 377b26bd6..2b198ac6f 100644 --- a/src/event/quic/ngx_event_quic_connection.h +++ b/src/event/quic/ngx_event_quic_connection.h @@ -107,6 +107,8 @@ struct ngx_quic_socket_s { ngx_quic_connection_t *quic; ngx_queue_t queue; ngx_quic_server_id_t sid; + ngx_sockaddr_t sockaddr; + socklen_t socklen; ngx_uint_t used; /* unsigned used:1; */ }; diff --git a/src/event/quic/ngx_event_quic_migration.c b/src/event/quic/ngx_event_quic_migration.c index e07c53250..36a2af73c 100644 --- a/src/event/quic/ngx_event_quic_migration.c +++ b/src/event/quic/ngx_event_quic_migration.c @@ -264,7 +264,7 @@ ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt) len = pkt->raw->last - pkt->raw->start; - if (c->udp->dgram == NULL) { + if (c->udp->buffer == NULL) { /* first ever packet in connection, path already exists */ path = qc->path; goto update; @@ -278,7 +278,7 @@ ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt) { path = ngx_queue_data(q, ngx_quic_path_t, queue); - if (ngx_cmp_sockaddr(c->udp->dgram->sockaddr, c->udp->dgram->socklen, + if (ngx_cmp_sockaddr(&qsock->sockaddr.sockaddr, qsock->socklen, path->sockaddr, path->socklen, 1) == NGX_OK) { @@ -315,8 +315,7 @@ ngx_quic_set_path(ngx_connection_t *c, ngx_quic_header_t *pkt) return NGX_DONE; } - path = ngx_quic_new_path(c, c->udp->dgram->sockaddr, - c->udp->dgram->socklen, cid); + path = ngx_quic_new_path(c, &qsock->sockaddr.sockaddr, qsock->socklen, cid); if (path == NULL) { return NGX_ERROR; } diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c index c9e1b603c..6813fcd0a 100644 --- a/src/event/quic/ngx_event_quic_socket.c +++ b/src/event/quic/ngx_event_quic_socket.c @@ -177,7 +177,10 @@ ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc, id.data = sid->id; id.len = sid->len; - ngx_insert_udp_connection(c, &qsock->udp, &id); + qsock->udp.connection = c; + qsock->udp.node.key = ngx_crc32_long(id.data, id.len); + + ngx_rbtree_insert(&c->listening->rbtree, &qsock->udp.node); ngx_queue_insert_tail(&qc->sockets, &qsock->queue); diff --git a/src/event/quic/ngx_event_quic_udp.c b/src/event/quic/ngx_event_quic_udp.c new file mode 100644 index 000000000..db6377371 --- /dev/null +++ b/src/event/quic/ngx_event_quic_udp.c @@ -0,0 +1,473 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_event_quic_connection.h> + + +static void ngx_quic_close_accepted_connection(ngx_connection_t *c); +static ngx_connection_t *ngx_quic_lookup_connection(ngx_listening_t *ls, + ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen); + + +void +ngx_quic_recvmsg(ngx_event_t *ev) +{ + ssize_t n; + ngx_str_t key; + ngx_buf_t buf; + ngx_log_t *log; + ngx_err_t err; + socklen_t socklen, local_socklen; + ngx_event_t *rev, *wev; + struct iovec iov[1]; + struct msghdr msg; + ngx_sockaddr_t sa, lsa; + struct sockaddr *sockaddr, *local_sockaddr; + ngx_listening_t *ls; + ngx_event_conf_t *ecf; + ngx_connection_t *c, *lc; + ngx_quic_socket_t *qsock; + static u_char buffer[65535]; + +#if (NGX_HAVE_ADDRINFO_CMSG) + u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; +#endif + + if (ev->timedout) { + if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { + return; + } + + ev->timedout = 0; + } + + ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); + + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + ev->available = ecf->multi_accept; + } + + lc = ev->data; + ls = lc->listening; + ev->ready = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "quic recvmsg on %V, ready: %d", + &ls->addr_text, ev->available); + + do { + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov[0].iov_base = (void *) buffer; + iov[0].iov_len = sizeof(buffer); + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(ngx_sockaddr_t); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (ls->wildcard) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); + + ngx_memzero(&msg_control, sizeof(msg_control)); + } +#endif + + n = recvmsg(lc->fd, &msg, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, + "quic recvmsg() not ready"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "quic recvmsg() failed"); + + return; + } + +#if (NGX_HAVE_ADDRINFO_CMSG) + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "quic recvmsg() truncated data"); + continue; + } +#endif + + sockaddr = msg.msg_name; + socklen = msg.msg_namelen; + + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (sockaddr->sa_family == AF_UNIX) { + struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr; + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path) + || saun->sun_path[0] == '\0') + { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, + "unbound unix socket"); + goto next; + } + } + +#endif + + local_sockaddr = ls->sockaddr; + local_socklen = ls->socklen; + +#if (NGX_HAVE_ADDRINFO_CMSG) + + if (ls->wildcard) { + struct cmsghdr *cmsg; + + ngx_memcpy(&lsa, local_sockaddr, local_socklen); + local_sockaddr = &lsa.sockaddr; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) { + break; + } + } + } + +#endif + + if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) { + goto next; + } + + c = ngx_quic_lookup_connection(ls, &key, local_sockaddr, local_socklen); + + if (c) { + +#if (NGX_DEBUG) + if (c->log->log_level & NGX_LOG_DEBUG_EVENT) { + ngx_log_handler_pt handler; + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic recvmsg: fd:%d n:%z", c->fd, n); + + c->log->handler = handler; + } +#endif + + ngx_memzero(&buf, sizeof(ngx_buf_t)); + + buf.pos = buffer; + buf.last = buffer + n; + buf.start = buf.pos; + buf.end = buffer + sizeof(buffer); + + qsock = ngx_quic_get_socket(c); + + ngx_memcpy(&qsock->sockaddr.sockaddr, sockaddr, socklen); + qsock->socklen = socklen; + + c->udp->buffer = &buf; + + rev = c->read; + rev->ready = 1; + rev->active = 0; + + rev->handler(rev); + + if (c->udp) { + c->udp->buffer = NULL; + } + + rev->ready = 0; + rev->active = 1; + + goto next; + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); +#endif + + ngx_accept_disabled = ngx_cycle->connection_n / 8 + - ngx_cycle->free_connection_n; + + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; + } + + c->shared = 1; + c->type = SOCK_DGRAM; + c->socklen = socklen; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN); + if (c->sockaddr == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, sockaddr, socklen); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + *log = ls->log; + + c->log = log; + c->pool->log = log; + c->listening = ls; + + if (local_sockaddr == &lsa.sockaddr) { + local_sockaddr = ngx_palloc(c->pool, local_socklen); + if (local_sockaddr == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + ngx_memcpy(local_sockaddr, &lsa, local_socklen); + } + + c->local_sockaddr = local_sockaddr; + c->local_socklen = local_socklen; + + c->buffer = ngx_create_temp_buf(c->pool, n); + if (c->buffer == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); + + rev = c->read; + wev = c->write; + + rev->active = 1; + wev->ready = 1; + + rev->log = log; + wev->log = log; + + /* + * TODO: MT: - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + * + * TODO: MP: - allocated in a shared memory + * - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + */ + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + + c->start_time = ngx_current_msec; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); +#endif + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { + ngx_quic_close_accepted_connection(c); + return; + } + + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + ls->addr_text_max_len, 0); + if (c->addr_text.len == 0) { + ngx_quic_close_accepted_connection(c); + return; + } + } + +#if (NGX_DEBUG) + { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA quic recvmsg: %V fd:%d n:%z", + c->number, &addr, c->fd, n); + } + + } +#endif + + log->data = NULL; + log->handler = NULL; + + ls->handler(c); + + next: + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ev->available -= n; + } + + } while (ev->available); +} + + +static void +ngx_quic_close_accepted_connection(ngx_connection_t *c) +{ + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; + + if (c->pool) { + ngx_destroy_pool(c->pool); + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif +} + + +void +ngx_quic_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_int_t rc; + ngx_connection_t *c, *ct; + ngx_rbtree_node_t **p; + ngx_quic_socket_t *qsock, *qsockt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + qsock = (ngx_quic_socket_t *) node; + c = qsock->udp.connection; + + qsockt = (ngx_quic_socket_t *) temp; + ct = qsockt->udp.connection; + + rc = ngx_memn2cmp(qsock->sid.id, qsockt->sid.id, + qsock->sid.len, qsockt->sid.len); + + if (rc == 0 && c->listening->wildcard) { + rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen, + ct->local_sockaddr, ct->local_socklen, 1); + } + + p = (rc < 0) ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static ngx_connection_t * +ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key, + struct sockaddr *local_sockaddr, socklen_t local_socklen) +{ + uint32_t hash; + ngx_int_t rc; + ngx_connection_t *c; + ngx_rbtree_node_t *node, *sentinel; + ngx_quic_socket_t *qsock; + + if (key->len == 0) { + return NULL; + } + + node = ls->rbtree.root; + sentinel = ls->rbtree.sentinel; + hash = ngx_crc32_long(key->data, key->len); + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + qsock = (ngx_quic_socket_t *) node; + + rc = ngx_memn2cmp(key->data, qsock->sid.id, key->len, qsock->sid.len); + + c = qsock->udp.connection; + + if (rc == 0 && ls->wildcard) { + rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen, + c->local_sockaddr, c->local_socklen, 1); + } + + if (rc == 0) { + c->udp = &qsock->udp; + return c; + } + + node = (rc < 0) ? node->left : node->right; + } + + return NULL; +} diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 082a849a2..134eed944 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1822,7 +1822,14 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->wildcard = addr->opt.wildcard; #if (NGX_HTTP_V3) + ls->quic = addr->opt.http3; + + if (ls->quic) { + ngx_rbtree_init(&ls->rbtree, &ls->sentinel, + ngx_quic_rbtree_insert_value); + } + #endif return ls; diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index a1a82f95a..4c41af173 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -519,8 +519,23 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) #endif #if (NGX_STREAM_QUIC) + ls->quic = addr[i].opt.quic; + + if (ls->quic) { + ngx_rbtree_init(&ls->rbtree, &ls->sentinel, + ngx_quic_rbtree_insert_value); + } + #endif + +#if !(NGX_WIN32) + if (!ls->quic) { + ngx_rbtree_init(&ls->rbtree, &ls->sentinel, + ngx_udp_rbtree_insert_value); + } +#endif + stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t)); if (stport == NULL) { return NGX_CONF_ERROR; |