Return to ngx_event_accept.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / nginx / src / event |
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: }