src/event/quic/ngx_event_quic_udp.c - nginx source code

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.     struct iovec        iov[1];
  23.     struct msghdr       msg;
  24.     ngx_sockaddr_t      sa, lsa;
  25.     struct sockaddr    *sockaddr, *local_sockaddr;
  26.     ngx_listening_t    *ls;
  27.     ngx_event_conf_t   *ecf;
  28.     ngx_connection_t   *c, *lc;
  29.     ngx_quic_socket_t  *qsock;
  30.     static u_char       buffer[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  74.             return;
  75.         }

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

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

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

  88. #if (NGX_HAVE_UNIX_DOMAIN)

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

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

  99. #endif

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

  102. #if (NGX_HAVE_ADDRINFO_CMSG)

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

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

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

  116. #endif

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

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

  121.         if (c) {

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

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

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

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

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

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

  137.             qsock = ngx_quic_get_socket(c);

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

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

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

  144.             rev->handler(rev);

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

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

  150.             goto next;
  151.         }

  152. #if (NGX_STAT_STUB)
  153.         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
  154. #endif

  155.         ngx_accept_disabled = ngx_cycle->connection_n / 8
  156.                               - ngx_cycle->free_connection_n;

  157.         c = ngx_get_connection(lc->fd, ev->log);
  158.         if (c == NULL) {
  159.             return;
  160.         }

  161.         c->shared = 1;
  162.         c->type = SOCK_DGRAM;
  163.         c->socklen = socklen;

  164. #if (NGX_STAT_STUB)
  165.         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
  166. #endif

  167.         c->pool = ngx_create_pool(ls->pool_size, ev->log);
  168.         if (c->pool == NULL) {
  169.             ngx_quic_close_accepted_connection(c);
  170.             return;
  171.         }

  172.         c->sockaddr = ngx_palloc(c->pool, NGX_SOCKADDRLEN);
  173.         if (c->sockaddr == NULL) {
  174.             ngx_quic_close_accepted_connection(c);
  175.             return;
  176.         }

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

  178.         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
  179.         if (log == NULL) {
  180.             ngx_quic_close_accepted_connection(c);
  181.             return;
  182.         }

  183.         *log = ls->log;

  184.         c->log = log;
  185.         c->pool->log = log;
  186.         c->listening = ls;

  187.         if (local_sockaddr == &lsa.sockaddr) {
  188.             local_sockaddr = ngx_palloc(c->pool, local_socklen);
  189.             if (local_sockaddr == NULL) {
  190.                 ngx_quic_close_accepted_connection(c);
  191.                 return;
  192.             }

  193.             ngx_memcpy(local_sockaddr, &lsa, local_socklen);
  194.         }

  195.         c->local_sockaddr = local_sockaddr;
  196.         c->local_socklen = local_socklen;

  197.         c->buffer = ngx_create_temp_buf(c->pool, n);
  198.         if (c->buffer == NULL) {
  199.             ngx_quic_close_accepted_connection(c);
  200.             return;
  201.         }

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

  203.         rev = c->read;
  204.         wev = c->write;

  205.         rev->active = 1;
  206.         wev->ready = 1;

  207.         rev->log = log;
  208.         wev->log = log;

  209.         /*
  210.          * TODO: MT: - ngx_atomic_fetch_add()
  211.          *             or protection by critical section or light mutex
  212.          *
  213.          * TODO: MP: - allocated in a shared memory
  214.          *           - ngx_atomic_fetch_add()
  215.          *             or protection by critical section or light mutex
  216.          */

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

  218.         c->start_time = ngx_current_msec;

  219. #if (NGX_STAT_STUB)
  220.         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
  221. #endif

  222.         if (ls->addr_ntop) {
  223.             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
  224.             if (c->addr_text.data == NULL) {
  225.                 ngx_quic_close_accepted_connection(c);
  226.                 return;
  227.             }

  228.             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
  229.                                              c->addr_text.data,
  230.                                              ls->addr_text_max_len, 0);
  231.             if (c->addr_text.len == 0) {
  232.                 ngx_quic_close_accepted_connection(c);
  233.                 return;
  234.             }
  235.         }

  236. #if (NGX_DEBUG)
  237.         {
  238.         ngx_str_t  addr;
  239.         u_char     text[NGX_SOCKADDR_STRLEN];

  240.         ngx_debug_accepted_connection(ecf, c);

  241.         if (log->log_level & NGX_LOG_DEBUG_EVENT) {
  242.             addr.data = text;
  243.             addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
  244.                                      NGX_SOCKADDR_STRLEN, 1);

  245.             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
  246.                            "*%uA quic recvmsg: %V fd:%d n:%z",
  247.                            c->number, &addr, c->fd, n);
  248.         }

  249.         }
  250. #endif

  251.         log->data = NULL;
  252.         log->handler = NULL;

  253.         ls->handler(c);

  254.     next:

  255.         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  256.             ev->available -= n;
  257.         }

  258.     } while (ev->available);
  259. }


  260. static void
  261. ngx_quic_close_accepted_connection(ngx_connection_t *c)
  262. {
  263.     ngx_free_connection(c);

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

  265.     if (c->pool) {
  266.         ngx_destroy_pool(c->pool);
  267.     }

  268. #if (NGX_STAT_STUB)
  269.     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
  270. #endif
  271. }


  272. static ngx_connection_t *
  273. ngx_quic_lookup_connection(ngx_listening_t *ls, ngx_str_t *key,
  274.     struct sockaddr *local_sockaddr, socklen_t local_socklen)
  275. {
  276.     uint32_t            hash;
  277.     ngx_int_t           rc;
  278.     ngx_connection_t   *c;
  279.     ngx_rbtree_node_t  *node, *sentinel;
  280.     ngx_quic_socket_t  *qsock;

  281.     if (key->len == 0) {
  282.         return NULL;
  283.     }

  284.     node = ls->rbtree.root;
  285.     sentinel = ls->rbtree.sentinel;
  286.     hash = ngx_crc32_long(key->data, key->len);

  287.     while (node != sentinel) {

  288.         if (hash < node->key) {
  289.             node = node->left;
  290.             continue;
  291.         }

  292.         if (hash > node->key) {
  293.             node = node->right;
  294.             continue;
  295.         }

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

  297.         qsock = (ngx_quic_socket_t *) node;

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

  299.         c = qsock->udp.connection;

  300.         if (rc == 0 && ls->wildcard) {
  301.             rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
  302.                                   c->local_sockaddr, c->local_socklen, 1);
  303.         }

  304.         if (rc == 0) {
  305.             c->udp = &qsock->udp;
  306.             return c;
  307.         }

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

  310.     return NULL;
  311. }