1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 
12 
13 static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
14 static void ngx_close_accepted_connection(ngx_connection_t *c);
15 
16 
17 void
ngx_event_accept(ngx_event_t * ev)18 ngx_event_accept(ngx_event_t *ev)
19 {
20     socklen_t          socklen;
21     ngx_err_t          err;
22     ngx_log_t         *log;
23     ngx_uint_t         level;
24     ngx_socket_t       s;
25     ngx_event_t       *rev, *wev;
26     ngx_sockaddr_t     sa;
27     ngx_listening_t   *ls;
28     ngx_connection_t  *c, *lc;
29     ngx_event_conf_t  *ecf;
30 #if (NGX_HAVE_ACCEPT4)
31     static ngx_uint_t  use_accept4 = 1;
32 #endif
33 
34     if (ev->timedout) {
35         if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
36             return;
37         }
38 
39         ev->timedout = 0;
40     }
41 
42     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
43 
44     if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
45         ev->available = ecf->multi_accept;
46     }
47 
48     lc = ev->data;
49     ls = lc->listening;
50     ev->ready = 0;
51 
52     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
53                    "accept on %V, ready: %d", &ls->addr_text, ev->available);
54 
55     do {
56         socklen = sizeof(ngx_sockaddr_t);
57 
58 #if (NGX_HAVE_ACCEPT4)
59         if (use_accept4) {
60             s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK);
61         } else {
62             s = accept(lc->fd, &sa.sockaddr, &socklen);
63         }
64 #else
65         s = accept(lc->fd, &sa.sockaddr, &socklen);
66 #endif
67 
68         if (s == (ngx_socket_t) -1) {
69             err = ngx_socket_errno;
70 
71             if (err == NGX_EAGAIN) {
72                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
73                                "accept() not ready");
74                 return;
75             }
76 
77             level = NGX_LOG_ALERT;
78 
79             if (err == NGX_ECONNABORTED) {
80                 level = NGX_LOG_ERR;
81 
82             } else if (err == NGX_EMFILE || err == NGX_ENFILE) {
83                 level = NGX_LOG_CRIT;
84             }
85 
86 #if (NGX_HAVE_ACCEPT4)
87             ngx_log_error(level, ev->log, err,
88                           use_accept4 ? "accept4() failed" : "accept() failed");
89 
90             if (use_accept4 && err == NGX_ENOSYS) {
91                 use_accept4 = 0;
92                 ngx_inherited_nonblocking = 0;
93                 continue;
94             }
95 #else
96             ngx_log_error(level, ev->log, err, "accept() failed");
97 #endif
98 
99             if (err == NGX_ECONNABORTED) {
100                 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
101                     ev->available--;
102                 }
103 
104                 if (ev->available) {
105                     continue;
106                 }
107             }
108 
109             if (err == NGX_EMFILE || err == NGX_ENFILE) {
110                 if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
111                     != NGX_OK)
112                 {
113                     return;
114                 }
115 
116                 if (ngx_use_accept_mutex) {
117                     if (ngx_accept_mutex_held) {
118                         ngx_shmtx_unlock(&ngx_accept_mutex);
119                         ngx_accept_mutex_held = 0;
120                     }
121 
122                     ngx_accept_disabled = 1;
123 
124                 } else {
125                     ngx_add_timer(ev, ecf->accept_mutex_delay);
126                 }
127             }
128 
129             return;
130         }
131 
132 #if (NGX_STAT_STUB)
133         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
134 #endif
135 
136         ngx_accept_disabled = ngx_cycle->connection_n / 8
137                               - ngx_cycle->free_connection_n;
138 
139         c = ngx_get_connection(s, ev->log);
140 
141         if (c == NULL) {
142             if (ngx_close_socket(s) == -1) {
143                 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
144                               ngx_close_socket_n " failed");
145             }
146 
147             return;
148         }
149 
150         c->type = SOCK_STREAM;
151 
152 #if (NGX_STAT_STUB)
153         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
154 #endif
155 
156         c->pool = ngx_create_pool(ls->pool_size, ev->log);
157         if (c->pool == NULL) {
158             ngx_close_accepted_connection(c);
159             return;
160         }
161 
162         if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
163             socklen = sizeof(ngx_sockaddr_t);
164         }
165 
166         c->sockaddr = ngx_palloc(c->pool, socklen);
167         if (c->sockaddr == NULL) {
168             ngx_close_accepted_connection(c);
169             return;
170         }
171 
172         ngx_memcpy(c->sockaddr, &sa, socklen);
173 
174         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
175         if (log == NULL) {
176             ngx_close_accepted_connection(c);
177             return;
178         }
179 
180         /* set a blocking mode for iocp and non-blocking mode for others */
181 
182         if (ngx_inherited_nonblocking) {
183             if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
184                 if (ngx_blocking(s) == -1) {
185                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
186                                   ngx_blocking_n " failed");
187                     ngx_close_accepted_connection(c);
188                     return;
189                 }
190             }
191 
192         } else {
193             if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
194                 if (ngx_nonblocking(s) == -1) {
195                     ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
196                                   ngx_nonblocking_n " failed");
197                     ngx_close_accepted_connection(c);
198                     return;
199                 }
200             }
201         }
202 
203         *log = ls->log;
204 
205         c->recv = ngx_recv;
206         c->send = ngx_send;
207         c->recv_chain = ngx_recv_chain;
208         c->send_chain = ngx_send_chain;
209 
210         c->log = log;
211         c->pool->log = log;
212 
213         c->socklen = socklen;
214         c->listening = ls;
215         c->local_sockaddr = ls->sockaddr;
216         c->local_socklen = ls->socklen;
217 
218 #if (NGX_HAVE_UNIX_DOMAIN)
219         if (c->sockaddr->sa_family == AF_UNIX) {
220             c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
221             c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
222 #if (NGX_SOLARIS)
223             /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
224             c->sendfile = 0;
225 #endif
226         }
227 #endif
228 
229         rev = c->read;
230         wev = c->write;
231 
232 #if (NGX_HAVE_FSTACK)
233         rev->belong_to_host = wev->belong_to_host = ev->belong_to_host;
234 #endif
235 
236         wev->ready = 1;
237 
238         if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
239             rev->ready = 1;
240         }
241 
242         if (ev->deferred_accept) {
243             rev->ready = 1;
244 #if (NGX_HAVE_KQUEUE || NGX_HAVE_EPOLLRDHUP) || (NGX_HAVE_FSTACK)
245             rev->available = 1;
246 #endif
247         }
248 
249         rev->log = log;
250         wev->log = log;
251 
252         /*
253          * TODO: MT: - ngx_atomic_fetch_add()
254          *             or protection by critical section or light mutex
255          *
256          * TODO: MP: - allocated in a shared memory
257          *           - ngx_atomic_fetch_add()
258          *             or protection by critical section or light mutex
259          */
260 
261         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
262 
263 #if (NGX_STAT_STUB)
264         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
265 #endif
266 
267         if (ls->addr_ntop) {
268             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
269             if (c->addr_text.data == NULL) {
270                 ngx_close_accepted_connection(c);
271                 return;
272             }
273 
274             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
275                                              c->addr_text.data,
276                                              ls->addr_text_max_len, 0);
277             if (c->addr_text.len == 0) {
278                 ngx_close_accepted_connection(c);
279                 return;
280             }
281         }
282 
283 #if (NGX_DEBUG)
284         {
285         ngx_str_t  addr;
286         u_char     text[NGX_SOCKADDR_STRLEN];
287 
288         ngx_debug_accepted_connection(ecf, c);
289 
290         if (log->log_level & NGX_LOG_DEBUG_EVENT) {
291             addr.data = text;
292             addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
293                                      NGX_SOCKADDR_STRLEN, 1);
294 
295             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
296                            "*%uA accept: %V fd:%d", c->number, &addr, s);
297         }
298 
299         }
300 #endif
301 
302 #if (NGX_HAVE_FSTACK)
303         if (ngx_event_actions.add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
304 #else
305         if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
306 #endif
307             if (ngx_add_conn(c) == NGX_ERROR) {
308                 ngx_close_accepted_connection(c);
309                 return;
310             }
311         }
312 
313         log->data = NULL;
314         log->handler = NULL;
315 
316         ls->handler(c);
317 
318         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
319             ev->available--;
320         }
321 
322     } while (ev->available);
323 }
324 
325 
326 ngx_int_t
327 ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
328 {
329     if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
330 
331         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
332                        "accept mutex locked");
333 
334         if (ngx_accept_mutex_held && ngx_accept_events == 0) {
335             return NGX_OK;
336         }
337 
338         if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
339             ngx_shmtx_unlock(&ngx_accept_mutex);
340             return NGX_ERROR;
341         }
342 
343         ngx_accept_events = 0;
344         ngx_accept_mutex_held = 1;
345 
346         return NGX_OK;
347     }
348 
349     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
350                    "accept mutex lock failed: %ui", ngx_accept_mutex_held);
351 
352     if (ngx_accept_mutex_held) {
353         if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
354             return NGX_ERROR;
355         }
356 
357         ngx_accept_mutex_held = 0;
358     }
359 
360     return NGX_OK;
361 }
362 
363 
364 ngx_int_t
365 ngx_enable_accept_events(ngx_cycle_t *cycle)
366 {
367     ngx_uint_t         i;
368     ngx_listening_t   *ls;
369     ngx_connection_t  *c;
370 
371     ls = cycle->listening.elts;
372     for (i = 0; i < cycle->listening.nelts; i++) {
373 
374         c = ls[i].connection;
375 
376         if (c == NULL || c->read->active) {
377             continue;
378         }
379 
380         if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
381             return NGX_ERROR;
382         }
383     }
384 
385     return NGX_OK;
386 }
387 
388 
389 static ngx_int_t
390 ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all)
391 {
392     ngx_uint_t         i;
393     ngx_listening_t   *ls;
394     ngx_connection_t  *c;
395 
396     ls = cycle->listening.elts;
397     for (i = 0; i < cycle->listening.nelts; i++) {
398 
399         c = ls[i].connection;
400 
401         if (c == NULL || !c->read->active) {
402             continue;
403         }
404 
405 #if (NGX_HAVE_REUSEPORT)
406 
407         /*
408          * do not disable accept on worker's own sockets
409          * when disabling accept events due to accept mutex
410          */
411 
412         if (ls[i].reuseport && !all) {
413             continue;
414         }
415 
416 #endif
417 
418         if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
419             == NGX_ERROR)
420         {
421             return NGX_ERROR;
422         }
423     }
424 
425     return NGX_OK;
426 }
427 
428 
429 static void
430 ngx_close_accepted_connection(ngx_connection_t *c)
431 {
432     ngx_socket_t  fd;
433 
434     ngx_free_connection(c);
435 
436     fd = c->fd;
437     c->fd = (ngx_socket_t) -1;
438 
439     if (ngx_close_socket(fd) == -1) {
440         ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
441                       ngx_close_socket_n " failed");
442     }
443 
444     if (c->pool) {
445         ngx_destroy_pool(c->pool);
446     }
447 
448 #if (NGX_STAT_STUB)
449     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
450 #endif
451 }
452 
453 
454 u_char *
455 ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len)
456 {
457     return ngx_snprintf(buf, len, " while accepting new connection on %V",
458                         log->data);
459 }
460 
461 
462 #if (NGX_DEBUG)
463 
464 void
465 ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c)
466 {
467     struct sockaddr_in   *sin;
468     ngx_cidr_t           *cidr;
469     ngx_uint_t            i;
470 #if (NGX_HAVE_INET6)
471     struct sockaddr_in6  *sin6;
472     ngx_uint_t            n;
473 #endif
474 
475     cidr = ecf->debug_connection.elts;
476     for (i = 0; i < ecf->debug_connection.nelts; i++) {
477         if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) {
478             goto next;
479         }
480 
481         switch (cidr[i].family) {
482 
483 #if (NGX_HAVE_INET6)
484         case AF_INET6:
485             sin6 = (struct sockaddr_in6 *) c->sockaddr;
486             for (n = 0; n < 16; n++) {
487                 if ((sin6->sin6_addr.s6_addr[n]
488                     & cidr[i].u.in6.mask.s6_addr[n])
489                     != cidr[i].u.in6.addr.s6_addr[n])
490                 {
491                     goto next;
492                 }
493             }
494             break;
495 #endif
496 
497 #if (NGX_HAVE_UNIX_DOMAIN)
498         case AF_UNIX:
499             break;
500 #endif
501 
502         default: /* AF_INET */
503             sin = (struct sockaddr_in *) c->sockaddr;
504             if ((sin->sin_addr.s_addr & cidr[i].u.in.mask)
505                 != cidr[i].u.in.addr)
506             {
507                 goto next;
508             }
509             break;
510         }
511 
512         c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL;
513         break;
514 
515     next:
516         continue;
517     }
518 }
519 
520 #endif
521