src/event/quic/ngx_event_quic_udp.c - nginx-1.31.9 nginx/ @ 2a3a19c6f

Functions defined

Source code


  1. /*
  2. * Copyright (C) Roman Arutyunyan
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_event_quic_connection.h>


  9. static void ngx_quic_close_accepted_connection(ngx_connection_t *c);
  10. static ngx_connection_t *ngx_quic_lookup_connection(ngx_listening_t *ls,
  11.     ngx_str_t *key, struct sockaddr *local_sockaddr, socklen_t local_socklen);


  12. void
  13. ‌ngx_quic_recvmsg(ngx_event_t *ev)
  14. {
  15.     ssize_t             n;
  16.     ngx_str_t           key;
  17.     ngx_buf_t           buf;
  18.     ngx_log_t          *log;
  19.     ngx_err_t           err;
  20.     socklen_t           socklen, local_socklen;
  21.     ngx_event_t        *rev, *wev;
  22.     ngx_socket_t        cfd;
  23.     struct iovec        iov[1];
  24.     struct msghdr       msg;
  25.     ngx_sockaddr_t      sa, lsa;
  26.     struct sockaddr    *sockaddr, *local_sockaddr;
  27.     ngx_listening_t    *ls;
  28.     ngx_event_conf_t   *ecf;
  29.     ngx_connection_t   *c, *lc;
  30.     ngx_quic_socket_t  *qsock;
  31.     static u_char       buffer[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  32. #if (NGX_HAVE_ADDRINFO_CMSG)
  33.     u_char             msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
  34. #endif

  35.     if (ev->timedout) {
  36.         if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
  37.             return;
  38.         }

  39.         ev->timedout = 0;
  40.     }

  41.     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);

  42.     if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
  43.         ev->available = ecf->multi_accept;
  44.     }

  45.     lc = ev->data;
  46.     ls = lc->listening;
  47.     ev->ready = 0;

  48.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  49.                    "quic recvmsg on %V, ready: %d",
  50.                    &ls->addr_text, ev->available);

  51.     do {
  52.         ngx_memzero(&msg, sizeof(struct msghdr));

  53.         iov[0].iov_base = (void *) buffer;
  54.         iov[0].iov_len = sizeof(buffer);

  55.         msg.msg_name = &sa;
  56.         msg.msg_namelen = sizeof(ngx_sockaddr_t);
  57.         msg.msg_iov = iov;
  58.         msg.msg_iovlen = 1;

  59. #if (NGX_HAVE_ADDRINFO_CMSG)
  60.         if (ls->wildcard) {
  61.             msg.msg_control = &msg_control;
  62.             msg.msg_controllen = sizeof(msg_control);

  63.             ngx_memzero(&msg_control, sizeof(msg_control));
  64.         }
  65. #endif

  66.         n = recvmsg(lc->fd, &msg, 0);

  67.         if (n == -1) {
  68.             err = ngx_socket_errno;

  69.             if (err == NGX_EAGAIN) {
  70.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
  71.                                "quic recvmsg() not ready");
  72.                 return;
  73.             }

  74.             ngx_log_error(NGX_LOG_ALERT, ev->log, err, "quic recvmsg() failed");

  75.             return;
  76.         }

  77. #if (NGX_HAVE_ADDRINFO_CMSG)
  78.         if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
  79.             ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
  80.                           "quic recvmsg() truncated data");
  81.             continue;
  82.         }
  83. #endif

  84.         sockaddr = msg.msg_name;
  85.         socklen = msg.msg_namelen;

  86.         if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
  87.             socklen = sizeof(ngx_sockaddr_t);
  88.         }

  89. #if (NGX_HAVE_UNIX_DOMAIN)

  90.         if (sockaddr->sa_family == AF_UNIX) {
  91.             struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr;

  92.             if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)
  93.                 || saun->sun_path[0] == '\0')
  94.             {
  95.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
  96.                                "unbound unix socket");
  97.                 goto next;
  98.             }
  99.         }

  100. #endif

  101.         local_sockaddr = ls->sockaddr;
  102.         local_socklen = ls->socklen;

  103. #if (NGX_HAVE_ADDRINFO_CMSG)

  104.         if (ls->wildcard) {
  105.             struct cmsghdr  *cmsg;

  106.             ngx_memcpy(&lsa, local_sockaddr, local_socklen);
  107.             local_sockaddr = &lsa.sockaddr;

  108.             for (cmsg = CMSG_FIRSTHDR(&msg);
  109.                  cmsg != NULL;
  110.                  cmsg = CMSG_NXTHDR(&msg, cmsg))
  111.             {
  112.                 if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) {
  113.                     break;
  114.                 }
  115.             }
  116.         }

  117. #endif

  118.         if (ngx_quic_get_packet_dcid(ev->log, buffer, n, &key) != NGX_OK) {
  119.             goto next;
  120.         }

  121.         c = ngx_quic_lookup_connection(ls, &key, local_sockaddr, local_socklen);

  122.         if (c) {

  123. #if (NGX_DEBUG)
  124.             if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
  125.                 ngx_log_handler_pt  handler;

  126.                 handler = c->log->handler;
  127.                 c->log->handler = NULL;

  128.                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  129.                                "quic recvmsg: fd:%d n:%z", lc->fd, n);

  130.                 c->log->handler = handler;
  131.             }
  132. #endif

  133.             ngx_memzero(&buf, sizeof(ngx_buf_t));

  134.             buf.pos = buffer;
  135.             buf.last = buffer + n;
  136.             buf.start = buf.pos;
  137.             buf.end = buffer + sizeof(buffer);

  138.             qsock = ngx_quic_get_socket(c);

  139.             ngx_memcpy(&qsock->sockaddr, sockaddr, socklen);
  140.             qsock->socklen = socklen;

  141.             c->udp->buffer = &buf;

  142.             rev = c->read;
  143.             rev->ready = 1;
  144.             rev->active = 0;

  145.             rev->handler(rev);

  146.             if (c->udp) {
  147.                 c->udp->buffer = NULL;
  148.             }

  149.             rev->ready = 0;
  150.             rev->active = 1;

  151.             goto next;
  152.         }

  153. #if (NGX_QUIC_BPF)
  154.         if (lc->read->quic) {
  155.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  156.                            "quic new connection on worker socket, dropped");
  157.             goto next;
  158.         }
  159. #endif

  160. #if (NGX_STAT_STUB)
  161.         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
  162. #endif

  163.         ngx_accept_disabled = ngx_cycle->connection_n / 8
  164.                               - ngx_cycle->free_connection_n;

  165.         cfd = lc->fd;

  166. #if (NGX_QUIC_BPF)
  167.         if (ngx_quic_bpf_get_worker_fd(lc, &cfd) != NGX_OK) {
  168.             return;
  169.         }
  170. #endif

  171.         c = ngx_get_connection(cfd, ev->log);
  172.         if (c == NULL) {
  173.             return;
  174.         }

  175.         c->shared = 1;
  176.         c->type = SOCK_DGRAM;
  177.         c->socklen = socklen;

  178. #if (NGX_STAT_STUB)
  179.         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
  180. #endif

  181.         c->pool = ngx_create_pool(ls->pool_size, ev->log);
  182.         if (c->pool == NULL) {
  183.             ngx_quic_close_accepted_connection(c);
  184.             return;
  185.         }

  186.         c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN);
  187.         if (c->sockaddr == NULL) {
  188.             ngx_quic_close_accepted_connection(c);
  189.             return;
  190.         }

  191.         ngx_memcpy(c->sockaddr, sockaddr, socklen);

  192.         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
  193.         if (log == NULL) {
  194.             ngx_quic_close_accepted_connection(c);
  195.             return;
  196.         }

  197.         *log = ls->log;

  198.         c->log = log;
  199.         c->pool->log = log;
  200.         c->listening = ls;

  201.         if (local_sockaddr == &lsa.sockaddr) {
  202.             local_sockaddr = ngx_palloc(c->pool, local_socklen);
  203.             if (local_sockaddr == NULL) {
  204.                 ngx_quic_close_accepted_connection(c);
  205.                 return;
  206.             }

  207.             ngx_memcpy(local_sockaddr, &lsa, local_socklen);
  208.         }

  209.         c->local_sockaddr = local_sockaddr;
  210.         c->local_socklen = local_socklen;

  211.         c->buffer = ngx_create_temp_buf(c->pool, n);
  212.         if (c->buffer == NULL) {
  213.             ngx_quic_close_accepted_connection(c);
  214.             return;
  215.         }

  216.         c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);

  217.         rev = c->read;
  218.         wev = c->write;

  219.         rev->active = 1;
  220.         wev->ready = 1;

  221.         rev->log = log;
  222.         wev->log = log;

  223.         /*
  224.          * TODO: MT: - ngx_atomic_fetch_add()
  225.          *             or protection by critical section or light mutex
  226.          *
  227.          * TODO: MP: - allocated in a shared memory
  228.          *           - ngx_atomic_fetch_add()
  229.          *             or protection by critical section or light mutex
  230.          */

  231.         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

  232.         c->start_time = ngx_current_msec;

  233. #if (NGX_STAT_STUB)
  234.         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
  235. #endif

  236.         if (ls->addr_ntop) {
  237.             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
  238.             if (c->addr_text.data == NULL) {
  239.                 ngx_quic_close_accepted_connection(c);
  240.                 return;
  241.             }

  242.             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
  243.                                              c->addr_text.data,
  244.                                              ls->addr_text_max_len, 0);
  245.             if (c->addr_text.len == 0) {
  246.                 ngx_quic_close_accepted_connection(c);
  247.                 return;
  248.             }
  249.         }

  250. #if (NGX_DEBUG)
  251.         {
  252.         ngx_str_t  addr;
  253.         u_char     text[NGX_SOCKADDR_STRLEN];

  254.         ngx_debug_accepted_connection(ecf, c);

  255.         if (log->log_level & NGX_LOG_DEBUG_EVENT) {
  256.             addr.data = text;
  257.             addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
  258.                                      NGX_SOCKADDR_STRLEN, 1);

  259.             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
  260.                            "*%uA quic recvmsg: %V fd:%d n:%z",
  261.                            c->number, &addr, lc->fd, n);
  262.         }

  263.         }
  264. #endif

  265.         log->data = NULL;
  266.         log->handler = NULL;

  267.         ls->handler(c);

  268.     next:

  269.         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  270.             ev->available -= n;
  271.         }

  272.     } while (ev->available);
  273. }


  274. static void
  275. ‌ngx_quic_close_accepted_connection(ngx_connection_t *c)
  276. {
  277.     ngx_free_connection(c);

  278.     c->fd = (ngx_socket_t) -1;

  279.     if (c->pool) {
  280.         ngx_destroy_pool(c->pool);
  281.     }

  282. #if (NGX_STAT_STUB)
  283.     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
  284. #endif
  285. }


  286. static ngx_connection_t *
  287. ‌ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key,
  288.     struct sockaddr *local_sockaddr, socklen_t local_socklen)
  289. {
  290.     uint32_t            hash;
  291.     ngx_int_t           rc;
  292.     ngx_connection_t   *c;
  293.     ngx_rbtree_node_t  *node, *sentinel;
  294.     ngx_quic_socket_t  *qsock;

  295.     if (key->len == 0) {
  296.         return NULL;
  297.     }

  298.     node = ls->rbtree.root;
  299.     sentinel = ls->rbtree.sentinel;
  300.     hash = ngx_crc32_long(key->data, key->len);

  301.     while (node != sentinel) {

  302.         if (hash < node->key) {
  303.             node = node->left;
  304.             continue;
  305.         }

  306.         if (hash > node->key) {
  307.             node = node->right;
  308.             continue;
  309.         }

  310.         /* hash == node->key */

  311.         qsock = (ngx_quic_socket_t *) node;

  312.         rc = ngx_memn2cmp(key->data, qsock->sid.id, key->len, qsock->sid.len);

  313.         c = qsock->udp.connection;

  314.         if (rc == 0 && ls->wildcard) {
  315.             rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
  316.                                   c->local_sockaddr, c->local_socklen, 1);
  317.         }

  318.         if (rc == 0) {
  319.             c->udp = &qsock->udp;
  320.             return c;
  321.         }

  322.         node = (rc < 0) ? node->left : node->right;
  323.     }

  324.     return NULL;
  325. }