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