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