]> git.kaiwu.me - nginx.git/commitdiff
QUIC: separate UDP framework for QUIC.
authorRoman Arutyunyan <arut@nginx.com>
Wed, 20 Apr 2022 12:01:17 +0000 (16:01 +0400)
committerRoman Arutyunyan <arut@nginx.com>
Wed, 20 Apr 2022 12:01:17 +0000 (16:01 +0400)
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.

13 files changed:
auto/modules
src/core/ngx_connection.c
src/event/ngx_event.c
src/event/ngx_event_udp.c
src/event/ngx_event_udp.h
src/event/quic/ngx_event_quic.c
src/event/quic/ngx_event_quic.h
src/event/quic/ngx_event_quic_connection.h
src/event/quic/ngx_event_quic_migration.c
src/event/quic/ngx_event_quic_socket.c
src/event/quic/ngx_event_quic_udp.c [new file with mode: 0644]
src/http/ngx_http.c
src/stream/ngx_stream.c

index 19967fa408048d024851bf7ba183da4b96e2bc83..575fff0b757741ef9cc48c53505b8b1cf62b8449 100644 (file)
@@ -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 \
index 4a7d2fe79656646c227884b98ca266a7763502fb..cbd5803be119221c2bbfb9e9ec05a98a4a2bf2dd 100644 (file)
@@ -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;
 
index aebc4541dc1a605d0fd55f73f3faffebdf5a3863..284aafbe6663076a5de67fb35258a61c010fa01c 100644 (file)
@@ -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)
 
index 1053fa0acfd34beaa11fb375615a63f74ae2e0aa..a7fa38aa898487c520974efc2d723cfebba4c924 100644 (file)
 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;
         }
 
index b5ceeca3fb47f0c34894da07f835edfa6530d450..d7a64ee03dace46a708a6c73dbe64dfd05b97a05 100644 (file)
 #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);
index 96884cd44f749d1fad069f0e444ddc26fcc90275..834e7935f9f9e75328b20deb53f84b48bd1bf357 100644 (file)
@@ -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)
                 {
index 903b690b953fc3e23906f981c7428f4621796bcd..92c9ecae03dfa1062ae3289226360cdca618b065 100644 (file)
@@ -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,
index 377b26bd6a0cc456297f18f1103538951ed5abec..2b198ac6f40286667a91f8be40f555a690a2dccd 100644 (file)
@@ -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; */
 };
 
index e07c532509616968b9884d8d4eabdcc2fdec0288..36a2af73c1273ddf4787ba0f626c75ac09f662bf 100644 (file)
@@ -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;
     }
index c9e1b603c677f098b0351c0f77c5a0929c555294..6813fcd0a0adfa578abfa0a33bde4b398b2efabd 100644 (file)
@@ -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 (file)
index 0000000..db63773
--- /dev/null
@@ -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;
+}
index 082a849a254e0d47dfe53fcdf4da988bc08eb128..134eed944089c8855753327933155fd8233e2d66 100644 (file)
@@ -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;
index a1a82f95a2388453fd937fbc81604580b5d843f6..4c41af1735cc9efa23b54059566f1e7a19a992c1 100644 (file)
@@ -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;