src/event/ngx_event_accept.c - nginx

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


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


  8. static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
  9. #if (NGX_HAVE_EPOLLEXCLUSIVE)
  10. static void ngx_reorder_accept_events(ngx_listening_t *ls);
  11. #endif
  12. static void ngx_close_accepted_connection(ngx_connection_t *c);


  13. void
  14. ngx_event_accept(ngx_event_t *ev)
  15. {
  16.     socklen_t          socklen;
  17.     ngx_err_t          err;
  18.     ngx_log_t         *log;
  19.     ngx_uint_t         level;
  20.     ngx_socket_t       s;
  21.     ngx_event_t       *rev, *wev;
  22.     ngx_sockaddr_t     sa;
  23.     ngx_listening_t   *ls;
  24.     ngx_connection_t  *c, *lc;
  25.     ngx_event_conf_t  *ecf;
  26. #if (NGX_HAVE_ACCEPT4)
  27.     static ngx_uint_t  use_accept4 = 1;
  28. #endif

  29.     if (ev->timedout) {
  30.         if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
  31.             return;
  32.         }

  33.         ev->timedout = 0;
  34.     }

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

  36.     if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
  37.         ev->available = ecf->multi_accept;
  38.     }

  39.     lc = ev->data;
  40.     ls = lc->listening;
  41.     ev->ready = 0;

  42.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
  43.                    "accept on %V, ready: %d", &ls->addr_text, ev->available);

  44.     do {
  45.         socklen = sizeof(ngx_sockaddr_t);

  46. #if (NGX_HAVE_ACCEPT4)
  47.         if (use_accept4) {
  48.             s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK);
  49.         } else {
  50.             s = accept(lc->fd, &sa.sockaddr, &socklen);
  51.         }
  52. #else
  53.         s = accept(lc->fd, &sa.sockaddr, &socklen);
  54. #endif

  55.         if (s == (ngx_socket_t) -1) {
  56.             err = ngx_socket_errno;

  57.             if (err == NGX_EAGAIN) {
  58.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
  59.                                "accept() not ready");
  60.                 return;
  61.             }

  62.             level = NGX_LOG_ALERT;

  63.             if (err == NGX_ECONNABORTED) {
  64.                 level = NGX_LOG_ERR;

  65.             } else if (err == NGX_EMFILE || err == NGX_ENFILE) {
  66.                 level = NGX_LOG_CRIT;
  67.             }

  68. #if (NGX_HAVE_ACCEPT4)
  69.             ngx_log_error(level, ev->log, err,
  70.                           use_accept4 ? "accept4() failed" : "accept() failed");

  71.             if (use_accept4 && err == NGX_ENOSYS) {
  72.                 use_accept4 = 0;
  73.                 ngx_inherited_nonblocking = 0;
  74.                 continue;
  75.             }
  76. #else
  77.             ngx_log_error(level, ev->log, err, "accept() failed");
  78. #endif

  79.             if (err == NGX_ECONNABORTED) {
  80.                 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  81.                     ev->available--;
  82.                 }

  83.                 if (ev->available) {
  84.                     continue;
  85.                 }
  86.             }

  87.             if (err == NGX_EMFILE || err == NGX_ENFILE) {
  88.                 if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
  89.                     != NGX_OK)
  90.                 {
  91.                     return;
  92.                 }

  93.                 if (ngx_use_accept_mutex) {
  94.                     if (ngx_accept_mutex_held) {
  95.                         ngx_shmtx_unlock(&ngx_accept_mutex);
  96.                         ngx_accept_mutex_held = 0;
  97.                     }

  98.                     ngx_accept_disabled = 1;

  99.                 } else {
  100.                     ngx_add_timer(ev, ecf->accept_mutex_delay);
  101.                 }
  102.             }

  103.             return;
  104.         }

  105. #if (NGX_STAT_STUB)
  106.         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
  107. #endif

  108.         ngx_accept_disabled = ngx_cycle->connection_n / 8
  109.                               - ngx_cycle->free_connection_n;

  110.         c = ngx_get_connection(s, ev->log);

  111.         if (c == NULL) {
  112.             if (ngx_close_socket(s) == -1) {
  113.                 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
  114.                               ngx_close_socket_n " failed");
  115.             }

  116.             return;
  117.         }

  118.         c->type = SOCK_STREAM;

  119. #if (NGX_STAT_STUB)
  120.         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
  121. #endif

  122.         c->pool = ngx_create_pool(ls->pool_size, ev->log);
  123.         if (c->pool == NULL) {
  124.             ngx_close_accepted_connection(c);
  125.             return;
  126.         }

  127.         if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
  128.             socklen = sizeof(ngx_sockaddr_t);
  129.         }

  130.         c->sockaddr = ngx_palloc(c->pool, socklen);
  131.         if (c->sockaddr == NULL) {
  132.             ngx_close_accepted_connection(c);
  133.             return;
  134.         }

  135.         ngx_memcpy(c->sockaddr, &sa, socklen);

  136.         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
  137.         if (log == NULL) {
  138.             ngx_close_accepted_connection(c);
  139.             return;
  140.         }

  141.         /* set a blocking mode for iocp and non-blocking mode for others */

  142.         if (ngx_inherited_nonblocking) {
  143.             if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
  144.                 if (ngx_blocking(s) == -1) {
  145.                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
  146.                                   ngx_blocking_n " failed");
  147.                     ngx_close_accepted_connection(c);
  148.                     return;
  149.                 }
  150.             }

  151.         } else {
  152.             if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
  153.                 if (ngx_nonblocking(s) == -1) {
  154.                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
  155.                                   ngx_nonblocking_n " failed");
  156.                     ngx_close_accepted_connection(c);
  157.                     return;
  158.                 }
  159.             }
  160.         }

  161. #if (NGX_HAVE_KEEPALIVE_TUNABLE && NGX_DARWIN)

  162.         /* Darwin doesn't inherit TCP_KEEPALIVE from a listening socket */

  163.         if (ls->keepidle) {
  164.             if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
  165.                            (const void *) &ls->keepidle, sizeof(int))
  166.                 == -1)
  167.             {
  168.                 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
  169.                               "setsockopt(TCP_KEEPALIVE, %d) failed, ignored",
  170.                               ls->keepidle);
  171.             }
  172.         }

  173. #endif

  174.         *log = ls->log;

  175.         c->recv = ngx_recv;
  176.         c->send = ngx_send;
  177.         c->recv_chain = ngx_recv_chain;
  178.         c->send_chain = ngx_send_chain;

  179.         c->log = log;
  180.         c->pool->log = log;

  181.         c->socklen = socklen;
  182.         c->listening = ls;
  183.         c->local_sockaddr = ls->sockaddr;
  184.         c->local_socklen = ls->socklen;

  185. #if (NGX_HAVE_UNIX_DOMAIN)
  186.         if (c->sockaddr->sa_family == AF_UNIX) {
  187.             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
  188.             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
  189. #if (NGX_SOLARIS)
  190.             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
  191.             c->sendfile = 0;
  192. #endif
  193.         }
  194. #endif

  195.         rev = c->read;
  196.         wev = c->write;

  197.         wev->ready = 1;

  198.         if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
  199.             rev->ready = 1;
  200.         }

  201.         if (ev->deferred_accept) {
  202.             rev->ready = 1;
  203. #if (NGX_HAVE_KQUEUE || NGX_HAVE_EPOLLRDHUP)
  204.             rev->available = 1;
  205. #endif
  206.         }

  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_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_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_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
  246.                            "*%uA accept: %V fd:%d", c->number, &addr, s);
  247.         }

  248.         }
  249. #endif

  250.         if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
  251.             if (ngx_add_conn(c) == NGX_ERROR) {
  252.                 ngx_close_accepted_connection(c);
  253.                 return;
  254.             }
  255.         }

  256.         log->data = NULL;
  257.         log->handler = NULL;

  258.         ls->handler(c);

  259.         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  260.             ev->available--;
  261.         }

  262.     } while (ev->available);

  263. #if (NGX_HAVE_EPOLLEXCLUSIVE)
  264.     ngx_reorder_accept_events(ls);
  265. #endif
  266. }


  267. ngx_int_t
  268. ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
  269. {
  270.     if (ngx_shmtx_trylock(&ngx_accept_mutex)) {

  271.         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  272.                        "accept mutex locked");

  273.         if (ngx_accept_mutex_held && ngx_accept_events == 0) {
  274.             return NGX_OK;
  275.         }

  276.         if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
  277.             ngx_shmtx_unlock(&ngx_accept_mutex);
  278.             return NGX_ERROR;
  279.         }

  280.         ngx_accept_events = 0;
  281.         ngx_accept_mutex_held = 1;

  282.         return NGX_OK;
  283.     }

  284.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
  285.                    "accept mutex lock failed: %ui", ngx_accept_mutex_held);

  286.     if (ngx_accept_mutex_held) {
  287.         if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
  288.             return NGX_ERROR;
  289.         }

  290.         ngx_accept_mutex_held = 0;
  291.     }

  292.     return NGX_OK;
  293. }


  294. ngx_int_t
  295. ngx_enable_accept_events(ngx_cycle_t *cycle)
  296. {
  297.     ngx_uint_t         i;
  298.     ngx_listening_t   *ls;
  299.     ngx_connection_t  *c;

  300.     ls = cycle->listening.elts;
  301.     for (i = 0; i < cycle->listening.nelts; i++) {

  302.         c = ls[i].connection;

  303.         if (c == NULL || c->read->active) {
  304.             continue;
  305.         }

  306.         if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
  307.             return NGX_ERROR;
  308.         }
  309.     }

  310.     return NGX_OK;
  311. }


  312. static ngx_int_t
  313. ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all)
  314. {
  315.     ngx_uint_t         i;
  316.     ngx_listening_t   *ls;
  317.     ngx_connection_t  *c;

  318.     ls = cycle->listening.elts;
  319.     for (i = 0; i < cycle->listening.nelts; i++) {

  320.         c = ls[i].connection;

  321.         if (c == NULL || !c->read->active) {
  322.             continue;
  323.         }

  324. #if (NGX_HAVE_REUSEPORT)

  325.         /*
  326.          * do not disable accept on worker's own sockets
  327.          * when disabling accept events due to accept mutex
  328.          */

  329.         if (ls[i].reuseport && !all) {
  330.             continue;
  331.         }

  332. #endif

  333.         if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
  334.             == NGX_ERROR)
  335.         {
  336.             return NGX_ERROR;
  337.         }
  338.     }

  339.     return NGX_OK;
  340. }


  341. #if (NGX_HAVE_EPOLLEXCLUSIVE)

  342. static void
  343. ngx_reorder_accept_events(ngx_listening_t *ls)
  344. {
  345.     ngx_connection_t  *c;

  346.     /*
  347.      * Linux with EPOLLEXCLUSIVE usually notifies only the process which
  348.      * was first to add the listening socket to the epoll instance.  As
  349.      * a result most of the connections are handled by the first worker
  350.      * process.  To fix this, we re-add the socket periodically, so other
  351.      * workers will get a chance to accept connections.
  352.      */

  353.     if (!ngx_use_exclusive_accept) {
  354.         return;
  355.     }

  356. #if (NGX_HAVE_REUSEPORT)

  357.     if (ls->reuseport) {
  358.         return;
  359.     }

  360. #endif

  361.     c = ls->connection;

  362.     if (c->requests++ % 16 != 0
  363.         && ngx_accept_disabled <= 0)
  364.     {
  365.         return;
  366.     }

  367.     if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
  368.         == NGX_ERROR)
  369.     {
  370.         return;
  371.     }

  372.     if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
  373.         == NGX_ERROR)
  374.     {
  375.         return;
  376.     }
  377. }

  378. #endif


  379. static void
  380. ngx_close_accepted_connection(ngx_connection_t *c)
  381. {
  382.     ngx_socket_t  fd;

  383.     ngx_free_connection(c);

  384.     fd = c->fd;
  385.     c->fd = (ngx_socket_t) -1;

  386.     if (ngx_close_socket(fd) == -1) {
  387.         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
  388.                       ngx_close_socket_n " failed");
  389.     }

  390.     if (c->pool) {
  391.         ngx_destroy_pool(c->pool);
  392.     }

  393. #if (NGX_STAT_STUB)
  394.     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
  395. #endif
  396. }


  397. u_char *
  398. ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len)
  399. {
  400.     return ngx_snprintf(buf, len, " while accepting new connection on %V",
  401.                         log->data);
  402. }


  403. #if (NGX_DEBUG)

  404. void
  405. ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c)
  406. {
  407.     struct sockaddr_in   *sin;
  408.     ngx_cidr_t           *cidr;
  409.     ngx_uint_t            i;
  410. #if (NGX_HAVE_INET6)
  411.     struct sockaddr_in6  *sin6;
  412.     ngx_uint_t            n;
  413. #endif

  414.     cidr = ecf->debug_connection.elts;
  415.     for (i = 0; i < ecf->debug_connection.nelts; i++) {
  416.         if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) {
  417.             goto next;
  418.         }

  419.         switch (cidr[i].family) {

  420. #if (NGX_HAVE_INET6)
  421.         case AF_INET6:
  422.             sin6 = (struct sockaddr_in6 *) c->sockaddr;
  423.             for (n = 0; n < 16; n++) {
  424.                 if ((sin6->sin6_addr.s6_addr[n]
  425.                     & cidr[i].u.in6.mask.s6_addr[n])
  426.                     != cidr[i].u.in6.addr.s6_addr[n])
  427.                 {
  428.                     goto next;
  429.                 }
  430.             }
  431.             break;
  432. #endif

  433. #if (NGX_HAVE_UNIX_DOMAIN)
  434.         case AF_UNIX:
  435.             break;
  436. #endif

  437.         default: /* AF_INET */
  438.             sin = (struct sockaddr_in *) c->sockaddr;
  439.             if ((sin->sin_addr.s_addr & cidr[i].u.in.mask)
  440.                 != cidr[i].u.in.addr)
  441.             {
  442.                 goto next;
  443.             }
  444.             break;
  445.         }

  446.         c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL;
  447.         break;

  448.     next:
  449.         continue;
  450.     }
  451. }

  452. #endif