Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Roman Arutyunyan
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 
0012 
0013 #if !(NGX_WIN32)
0014 
0015 struct ngx_udp_connection_s {
0016     ngx_rbtree_node_t   node;
0017     ngx_connection_t   *connection;
0018     ngx_buf_t          *buffer;
0019 };
0020 
0021 
0022 static void ngx_close_accepted_udp_connection(ngx_connection_t *c);
0023 static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf,
0024     size_t size);
0025 static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c);
0026 static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls,
0027     struct sockaddr *sockaddr, socklen_t socklen,
0028     struct sockaddr *local_sockaddr, socklen_t local_socklen);
0029 
0030 
0031 void
0032 ngx_event_recvmsg(ngx_event_t *ev)
0033 {
0034     ssize_t            n;
0035     ngx_buf_t          buf;
0036     ngx_log_t         *log;
0037     ngx_err_t          err;
0038     socklen_t          socklen, local_socklen;
0039     ngx_event_t       *rev, *wev;
0040     struct iovec       iov[1];
0041     struct msghdr      msg;
0042     ngx_sockaddr_t     sa, lsa;
0043     struct sockaddr   *sockaddr, *local_sockaddr;
0044     ngx_listening_t   *ls;
0045     ngx_event_conf_t  *ecf;
0046     ngx_connection_t  *c, *lc;
0047     static u_char      buffer[65535];
0048 
0049 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0050 
0051 #if (NGX_HAVE_IP_RECVDSTADDR)
0052     u_char             msg_control[CMSG_SPACE(sizeof(struct in_addr))];
0053 #elif (NGX_HAVE_IP_PKTINFO)
0054     u_char             msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
0055 #endif
0056 
0057 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
0058     u_char             msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
0059 #endif
0060 
0061 #endif
0062 
0063     if (ev->timedout) {
0064         if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
0065             return;
0066         }
0067 
0068         ev->timedout = 0;
0069     }
0070 
0071     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
0072 
0073     if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
0074         ev->available = ecf->multi_accept;
0075     }
0076 
0077     lc = ev->data;
0078     ls = lc->listening;
0079     ev->ready = 0;
0080 
0081     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
0082                    "recvmsg on %V, ready: %d", &ls->addr_text, ev->available);
0083 
0084     do {
0085         ngx_memzero(&msg, sizeof(struct msghdr));
0086 
0087         iov[0].iov_base = (void *) buffer;
0088         iov[0].iov_len = sizeof(buffer);
0089 
0090         msg.msg_name = &sa;
0091         msg.msg_namelen = sizeof(ngx_sockaddr_t);
0092         msg.msg_iov = iov;
0093         msg.msg_iovlen = 1;
0094 
0095 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0096 
0097         if (ls->wildcard) {
0098 
0099 #if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO)
0100             if (ls->sockaddr->sa_family == AF_INET) {
0101                 msg.msg_control = &msg_control;
0102                 msg.msg_controllen = sizeof(msg_control);
0103             }
0104 #endif
0105 
0106 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
0107             if (ls->sockaddr->sa_family == AF_INET6) {
0108                 msg.msg_control = &msg_control6;
0109                 msg.msg_controllen = sizeof(msg_control6);
0110             }
0111 #endif
0112         }
0113 
0114 #endif
0115 
0116         n = recvmsg(lc->fd, &msg, 0);
0117 
0118         if (n == -1) {
0119             err = ngx_socket_errno;
0120 
0121             if (err == NGX_EAGAIN) {
0122                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
0123                                "recvmsg() not ready");
0124                 return;
0125             }
0126 
0127             ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed");
0128 
0129             return;
0130         }
0131 
0132 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0133         if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
0134             ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
0135                           "recvmsg() truncated data");
0136             continue;
0137         }
0138 #endif
0139 
0140         sockaddr = msg.msg_name;
0141         socklen = msg.msg_namelen;
0142 
0143         if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
0144             socklen = sizeof(ngx_sockaddr_t);
0145         }
0146 
0147         if (socklen == 0) {
0148 
0149             /*
0150              * on Linux recvmsg() returns zero msg_namelen
0151              * when receiving packets from unbound AF_UNIX sockets
0152              */
0153 
0154             socklen = sizeof(struct sockaddr);
0155             ngx_memzero(&sa, sizeof(struct sockaddr));
0156             sa.sockaddr.sa_family = ls->sockaddr->sa_family;
0157         }
0158 
0159         local_sockaddr = ls->sockaddr;
0160         local_socklen = ls->socklen;
0161 
0162 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0163 
0164         if (ls->wildcard) {
0165             struct cmsghdr  *cmsg;
0166 
0167             ngx_memcpy(&lsa, local_sockaddr, local_socklen);
0168             local_sockaddr = &lsa.sockaddr;
0169 
0170             for (cmsg = CMSG_FIRSTHDR(&msg);
0171                  cmsg != NULL;
0172                  cmsg = CMSG_NXTHDR(&msg, cmsg))
0173             {
0174 
0175 #if (NGX_HAVE_IP_RECVDSTADDR)
0176 
0177                 if (cmsg->cmsg_level == IPPROTO_IP
0178                     && cmsg->cmsg_type == IP_RECVDSTADDR
0179                     && local_sockaddr->sa_family == AF_INET)
0180                 {
0181                     struct in_addr      *addr;
0182                     struct sockaddr_in  *sin;
0183 
0184                     addr = (struct in_addr *) CMSG_DATA(cmsg);
0185                     sin = (struct sockaddr_in *) local_sockaddr;
0186                     sin->sin_addr = *addr;
0187 
0188                     break;
0189                 }
0190 
0191 #elif (NGX_HAVE_IP_PKTINFO)
0192 
0193                 if (cmsg->cmsg_level == IPPROTO_IP
0194                     && cmsg->cmsg_type == IP_PKTINFO
0195                     && local_sockaddr->sa_family == AF_INET)
0196                 {
0197                     struct in_pktinfo   *pkt;
0198                     struct sockaddr_in  *sin;
0199 
0200                     pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
0201                     sin = (struct sockaddr_in *) local_sockaddr;
0202                     sin->sin_addr = pkt->ipi_addr;
0203 
0204                     break;
0205                 }
0206 
0207 #endif
0208 
0209 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
0210 
0211                 if (cmsg->cmsg_level == IPPROTO_IPV6
0212                     && cmsg->cmsg_type == IPV6_PKTINFO
0213                     && local_sockaddr->sa_family == AF_INET6)
0214                 {
0215                     struct in6_pktinfo   *pkt6;
0216                     struct sockaddr_in6  *sin6;
0217 
0218                     pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
0219                     sin6 = (struct sockaddr_in6 *) local_sockaddr;
0220                     sin6->sin6_addr = pkt6->ipi6_addr;
0221 
0222                     break;
0223                 }
0224 
0225 #endif
0226 
0227             }
0228         }
0229 
0230 #endif
0231 
0232         c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr,
0233                                       local_socklen);
0234 
0235         if (c) {
0236 
0237 #if (NGX_DEBUG)
0238             if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
0239                 ngx_log_handler_pt  handler;
0240 
0241                 handler = c->log->handler;
0242                 c->log->handler = NULL;
0243 
0244                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
0245                                "recvmsg: fd:%d n:%z", c->fd, n);
0246 
0247                 c->log->handler = handler;
0248             }
0249 #endif
0250 
0251             ngx_memzero(&buf, sizeof(ngx_buf_t));
0252 
0253             buf.pos = buffer;
0254             buf.last = buffer + n;
0255 
0256             rev = c->read;
0257 
0258             c->udp->buffer = &buf;
0259 
0260             rev->ready = 1;
0261             rev->active = 0;
0262 
0263             rev->handler(rev);
0264 
0265             if (c->udp) {
0266                 c->udp->buffer = NULL;
0267             }
0268 
0269             rev->ready = 0;
0270             rev->active = 1;
0271 
0272             goto next;
0273         }
0274 
0275 #if (NGX_STAT_STUB)
0276         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
0277 #endif
0278 
0279         ngx_accept_disabled = ngx_cycle->connection_n / 8
0280                               - ngx_cycle->free_connection_n;
0281 
0282         c = ngx_get_connection(lc->fd, ev->log);
0283         if (c == NULL) {
0284             return;
0285         }
0286 
0287         c->shared = 1;
0288         c->type = SOCK_DGRAM;
0289         c->socklen = socklen;
0290 
0291 #if (NGX_STAT_STUB)
0292         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
0293 #endif
0294 
0295         c->pool = ngx_create_pool(ls->pool_size, ev->log);
0296         if (c->pool == NULL) {
0297             ngx_close_accepted_udp_connection(c);
0298             return;
0299         }
0300 
0301         c->sockaddr = ngx_palloc(c->pool, socklen);
0302         if (c->sockaddr == NULL) {
0303             ngx_close_accepted_udp_connection(c);
0304             return;
0305         }
0306 
0307         ngx_memcpy(c->sockaddr, sockaddr, socklen);
0308 
0309         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
0310         if (log == NULL) {
0311             ngx_close_accepted_udp_connection(c);
0312             return;
0313         }
0314 
0315         *log = ls->log;
0316 
0317         c->recv = ngx_udp_shared_recv;
0318         c->send = ngx_udp_send;
0319         c->send_chain = ngx_udp_send_chain;
0320 
0321         c->log = log;
0322         c->pool->log = log;
0323         c->listening = ls;
0324 
0325         if (local_sockaddr == &lsa.sockaddr) {
0326             local_sockaddr = ngx_palloc(c->pool, local_socklen);
0327             if (local_sockaddr == NULL) {
0328                 ngx_close_accepted_udp_connection(c);
0329                 return;
0330             }
0331 
0332             ngx_memcpy(local_sockaddr, &lsa, local_socklen);
0333         }
0334 
0335         c->local_sockaddr = local_sockaddr;
0336         c->local_socklen = local_socklen;
0337 
0338         c->buffer = ngx_create_temp_buf(c->pool, n);
0339         if (c->buffer == NULL) {
0340             ngx_close_accepted_udp_connection(c);
0341             return;
0342         }
0343 
0344         c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);
0345 
0346         rev = c->read;
0347         wev = c->write;
0348 
0349         rev->active = 1;
0350         wev->ready = 1;
0351 
0352         rev->log = log;
0353         wev->log = log;
0354 
0355         /*
0356          * TODO: MT: - ngx_atomic_fetch_add()
0357          *             or protection by critical section or light mutex
0358          *
0359          * TODO: MP: - allocated in a shared memory
0360          *           - ngx_atomic_fetch_add()
0361          *             or protection by critical section or light mutex
0362          */
0363 
0364         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
0365 
0366 #if (NGX_STAT_STUB)
0367         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
0368 #endif
0369 
0370         if (ls->addr_ntop) {
0371             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
0372             if (c->addr_text.data == NULL) {
0373                 ngx_close_accepted_udp_connection(c);
0374                 return;
0375             }
0376 
0377             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
0378                                              c->addr_text.data,
0379                                              ls->addr_text_max_len, 0);
0380             if (c->addr_text.len == 0) {
0381                 ngx_close_accepted_udp_connection(c);
0382                 return;
0383             }
0384         }
0385 
0386 #if (NGX_DEBUG)
0387         {
0388         ngx_str_t  addr;
0389         u_char     text[NGX_SOCKADDR_STRLEN];
0390 
0391         ngx_debug_accepted_connection(ecf, c);
0392 
0393         if (log->log_level & NGX_LOG_DEBUG_EVENT) {
0394             addr.data = text;
0395             addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
0396                                      NGX_SOCKADDR_STRLEN, 1);
0397 
0398             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
0399                            "*%uA recvmsg: %V fd:%d n:%z",
0400                            c->number, &addr, c->fd, n);
0401         }
0402 
0403         }
0404 #endif
0405 
0406         if (ngx_insert_udp_connection(c) != NGX_OK) {
0407             ngx_close_accepted_udp_connection(c);
0408             return;
0409         }
0410 
0411         log->data = NULL;
0412         log->handler = NULL;
0413 
0414         ls->handler(c);
0415 
0416     next:
0417 
0418         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
0419             ev->available -= n;
0420         }
0421 
0422     } while (ev->available);
0423 }
0424 
0425 
0426 static void
0427 ngx_close_accepted_udp_connection(ngx_connection_t *c)
0428 {
0429     ngx_free_connection(c);
0430 
0431     c->fd = (ngx_socket_t) -1;
0432 
0433     if (c->pool) {
0434         ngx_destroy_pool(c->pool);
0435     }
0436 
0437 #if (NGX_STAT_STUB)
0438     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
0439 #endif
0440 }
0441 
0442 
0443 static ssize_t
0444 ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size)
0445 {
0446     ssize_t     n;
0447     ngx_buf_t  *b;
0448 
0449     if (c->udp == NULL || c->udp->buffer == NULL) {
0450         return NGX_AGAIN;
0451     }
0452 
0453     b = c->udp->buffer;
0454 
0455     n = ngx_min(b->last - b->pos, (ssize_t) size);
0456 
0457     ngx_memcpy(buf, b->pos, n);
0458 
0459     c->udp->buffer = NULL;
0460 
0461     c->read->ready = 0;
0462     c->read->active = 1;
0463 
0464     return n;
0465 }
0466 
0467 
0468 void
0469 ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp,
0470     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
0471 {
0472     ngx_int_t               rc;
0473     ngx_connection_t       *c, *ct;
0474     ngx_rbtree_node_t     **p;
0475     ngx_udp_connection_t   *udp, *udpt;
0476 
0477     for ( ;; ) {
0478 
0479         if (node->key < temp->key) {
0480 
0481             p = &temp->left;
0482 
0483         } else if (node->key > temp->key) {
0484 
0485             p = &temp->right;
0486 
0487         } else { /* node->key == temp->key */
0488 
0489             udp = (ngx_udp_connection_t *) node;
0490             c = udp->connection;
0491 
0492             udpt = (ngx_udp_connection_t *) temp;
0493             ct = udpt->connection;
0494 
0495             rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen,
0496                                   ct->sockaddr, ct->socklen, 1);
0497 
0498             if (rc == 0 && c->listening->wildcard) {
0499                 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen,
0500                                       ct->local_sockaddr, ct->local_socklen, 1);
0501             }
0502 
0503             p = (rc < 0) ? &temp->left : &temp->right;
0504         }
0505 
0506         if (*p == sentinel) {
0507             break;
0508         }
0509 
0510         temp = *p;
0511     }
0512 
0513     *p = node;
0514     node->parent = temp;
0515     node->left = sentinel;
0516     node->right = sentinel;
0517     ngx_rbt_red(node);
0518 }
0519 
0520 
0521 static ngx_int_t
0522 ngx_insert_udp_connection(ngx_connection_t *c)
0523 {
0524     uint32_t               hash;
0525     ngx_pool_cleanup_t    *cln;
0526     ngx_udp_connection_t  *udp;
0527 
0528     if (c->udp) {
0529         return NGX_OK;
0530     }
0531 
0532     udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t));
0533     if (udp == NULL) {
0534         return NGX_ERROR;
0535     }
0536 
0537     udp->connection = c;
0538 
0539     ngx_crc32_init(hash);
0540     ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen);
0541 
0542     if (c->listening->wildcard) {
0543         ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen);
0544     }
0545 
0546     ngx_crc32_final(hash);
0547 
0548     udp->node.key = hash;
0549 
0550     cln = ngx_pool_cleanup_add(c->pool, 0);
0551     if (cln == NULL) {
0552         return NGX_ERROR;
0553     }
0554 
0555     cln->data = c;
0556     cln->handler = ngx_delete_udp_connection;
0557 
0558     ngx_rbtree_insert(&c->listening->rbtree, &udp->node);
0559 
0560     c->udp = udp;
0561 
0562     return NGX_OK;
0563 }
0564 
0565 
0566 void
0567 ngx_delete_udp_connection(void *data)
0568 {
0569     ngx_connection_t  *c = data;
0570 
0571     if (c->udp == NULL) {
0572         return;
0573     }
0574 
0575     ngx_rbtree_delete(&c->listening->rbtree, &c->udp->node);
0576 
0577     c->udp = NULL;
0578 }
0579 
0580 
0581 static ngx_connection_t *
0582 ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr,
0583     socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen)
0584 {
0585     uint32_t               hash;
0586     ngx_int_t              rc;
0587     ngx_connection_t      *c;
0588     ngx_rbtree_node_t     *node, *sentinel;
0589     ngx_udp_connection_t  *udp;
0590 
0591 #if (NGX_HAVE_UNIX_DOMAIN)
0592 
0593     if (sockaddr->sa_family == AF_UNIX) {
0594         struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr;
0595 
0596         if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)
0597             || saun->sun_path[0] == '\0')
0598         {
0599             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
0600                            "unbound unix socket");
0601             return NULL;
0602         }
0603     }
0604 
0605 #endif
0606 
0607     node = ls->rbtree.root;
0608     sentinel = ls->rbtree.sentinel;
0609 
0610     ngx_crc32_init(hash);
0611     ngx_crc32_update(&hash, (u_char *) sockaddr, socklen);
0612 
0613     if (ls->wildcard) {
0614         ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen);
0615     }
0616 
0617     ngx_crc32_final(hash);
0618 
0619     while (node != sentinel) {
0620 
0621         if (hash < node->key) {
0622             node = node->left;
0623             continue;
0624         }
0625 
0626         if (hash > node->key) {
0627             node = node->right;
0628             continue;
0629         }
0630 
0631         /* hash == node->key */
0632 
0633         udp = (ngx_udp_connection_t *) node;
0634 
0635         c = udp->connection;
0636 
0637         rc = ngx_cmp_sockaddr(sockaddr, socklen,
0638                               c->sockaddr, c->socklen, 1);
0639 
0640         if (rc == 0 && ls->wildcard) {
0641             rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
0642                                   c->local_sockaddr, c->local_socklen, 1);
0643         }
0644 
0645         if (rc == 0) {
0646             return c;
0647         }
0648 
0649         node = (rc < 0) ? node->left : node->right;
0650     }
0651 
0652     return NULL;
0653 }
0654 
0655 #else
0656 
0657 void
0658 ngx_delete_udp_connection(void *data)
0659 {
0660     return;
0661 }
0662 
0663 #endif