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,6 +459,19 @@ ngx_create_udp_connection(ngx_connection_t *c) return NGX_ERROR; } + udp->connection = c; + + ngx_crc32_init(hash); + 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); + } + + ngx_crc32_final(hash); + + udp->node.key = hash; + cln = ngx_pool_cleanup_add(c->pool, 0); if (cln == NULL) { return NGX_ERROR; @@ -514,10 +480,7 @@ ngx_create_udp_connection(ngx_connection_t *c) 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); + ngx_rbtree_insert(&c->listening->rbtree, &udp->node); c->udp = udp; @@ -525,30 +488,6 @@ ngx_create_udp_connection(ngx_connection_t *c) } -void -ngx_insert_udp_connection(ngx_connection_t *c, ngx_udp_connection_t *udp, - ngx_str_t *key) -{ - uint32_t hash; - - ngx_crc32_init(hash); - - ngx_crc32_update(&hash, key->data, key->len); - - if (c->listening->wildcard) { - ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen); - } - - ngx_crc32_final(hash); - - udp->connection = c; - udp->key = *key; - udp->node.key = hash; - - ngx_rbtree_insert(&c->listening->rbtree, &udp->node); -} - - void ngx_delete_udp_connection(void *data) { @@ -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 +#include +#include +#include + + +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;