|  | 
 | #include <ngx_config.h> | 
 | #include <ngx_core.h> | 
 | #include <ngx_event.h> | 
 |  | 
 |  | 
 | ngx_os_io_t  ngx_io; | 
 |  | 
 |  | 
 | ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) | 
 | { | 
 |     ngx_int_t            i; | 
 |     ngx_listening_t     *ls; | 
 |     struct sockaddr_in  *addr_in; | 
 |  | 
 |     ls = cycle->listening.elts; | 
 |     for (i = 0; i < cycle->listening.nelts; i++) { | 
 |  | 
 |         /* AF_INET only */ | 
 |  | 
 |         ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(struct sockaddr_in)); | 
 |         if (ls[i].sockaddr == NULL) { | 
 |             return NGX_ERROR; | 
 |         } | 
 |  | 
 |         ls[i].socklen = sizeof(struct sockaddr_in); | 
 |         if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) { | 
 |             ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, | 
 |                           "getsockname() of the inherited " | 
 |                           "socket #%d failed", ls[i].fd); | 
 |             ls[i].ignore = 1; | 
 |             continue; | 
 |         } | 
 |  | 
 |         addr_in = (struct sockaddr_in *) ls[i].sockaddr; | 
 |  | 
 |         if (addr_in->sin_family != AF_INET) { | 
 |             ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, | 
 |                           "the inherited socket #%d has " | 
 |                           "unsupported family", ls[i].fd); | 
 |             ls[i].ignore = 1; | 
 |             continue; | 
 |         } | 
 |         ls[i].addr_text_max_len = INET_ADDRSTRLEN; | 
 |  | 
 |         ls[i].addr_text.data = ngx_palloc(cycle->pool, ls[i].addr_text_max_len); | 
 |         if (ls[i].addr_text.data == NULL) { | 
 |             return NGX_ERROR; | 
 |         } | 
 |  | 
 |         ls[i].family = addr_in->sin_family; | 
 |         ls[i].addr_text.len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr, | 
 |                                             ls[i].addr_text.data, | 
 |                                             ls[i].addr_text_max_len); | 
 |         if (ls[i].addr_text.len == 0) { | 
 |             return NGX_ERROR; | 
 |         } | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) | 
 | { | 
 |     ngx_int_t         tries, failed, reuseaddr, i; | 
 |     ngx_err_t         err; | 
 |     ngx_log_t        *log; | 
 |     ngx_socket_t      s; | 
 |     ngx_listening_t  *ls; | 
 |  | 
 |     reuseaddr = 1; | 
 | #if (NGX_SUPPRESS_WARN) | 
 |     failed = 0; | 
 | #endif | 
 |  | 
 |     log = cycle->log; | 
 |  | 
 |     /* TODO: tries configurable */ | 
 |  | 
 |     for (tries = 10; tries; tries--) { | 
 |         failed = 0; | 
 |  | 
 |         /* for each listening socket */ | 
 |  | 
 |         ls = cycle->listening.elts; | 
 |         for (i = 0; i < cycle->listening.nelts; i++) { | 
 |  | 
 |             if (ls[i].ignore) { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (ls[i].fd != -1) { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (ls[i].inherited) { | 
 |  | 
 |                 /* TODO: close on exit */ | 
 |                 /* TODO: nonblocking */ | 
 |                 /* TODO: deferred accept */ | 
 |  | 
 |                 continue; | 
 |             } | 
 |  | 
 |             s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, | 
 |                            ls[i].flags); | 
 |  | 
 |             if (s == -1) { | 
 |                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                               ngx_socket_n " %s failed", ls[i].addr_text.data); | 
 |                 return NGX_ERROR; | 
 |             } | 
 |  | 
 | #if (WIN32) | 
 |             /* | 
 |              * Winsock assignes a socket number divisible by 4 | 
 |              * so to find a connection we divide a socket number by 4. | 
 |              */ | 
 |  | 
 |             if (s % 4) { | 
 |                 ngx_log_error(NGX_LOG_EMERG, ls->log, 0, | 
 |                               ngx_socket_n " created socket %d", s); | 
 |                 return NGX_ERROR; | 
 |             } | 
 | #endif | 
 |  | 
 |             if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, | 
 |                            (const void *) &reuseaddr, sizeof(int)) == -1) { | 
 |                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                               "setsockopt(SO_REUSEADDR) %s failed", | 
 |                               ls[i].addr_text.data); | 
 |                 return NGX_ERROR; | 
 |             } | 
 |  | 
 |             /* TODO: close on exit */ | 
 |  | 
 |             if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { | 
 |                 if (ngx_nonblocking(s) == -1) { | 
 |                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                                   ngx_nonblocking_n " %s failed", | 
 |                                   ls[i].addr_text.data); | 
 |                     return NGX_ERROR; | 
 |                 } | 
 |             } | 
 |  | 
 | #if 0 | 
 |             if (ls[i].nonblocking) { | 
 |                 if (ngx_nonblocking(s) == -1) { | 
 |                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                                   ngx_nonblocking_n " %s failed", | 
 |                                   ls[i].addr_text.data); | 
 |                     return NGX_ERROR; | 
 |                 } | 
 |             } | 
 | #endif | 
 |  | 
 |             if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { | 
 |                 err = ngx_socket_errno; | 
 |                 ngx_log_error(NGX_LOG_EMERG, log, err, | 
 |                               "bind() to %s failed", ls[i].addr_text.data); | 
 |  | 
 |                 if (err != NGX_EADDRINUSE) | 
 |                     return NGX_ERROR; | 
 |  | 
 |                 if (ngx_close_socket(s) == -1) | 
 |                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                                   ngx_close_socket_n " %s failed", | 
 |                                   ls[i].addr_text.data); | 
 |  | 
 |                 failed = 1; | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (listen(s, ls[i].backlog) == -1) { | 
 |                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, | 
 |                               "listen() to %s failed", ls[i].addr_text.data); | 
 |                 return NGX_ERROR; | 
 |             } | 
 |  | 
 |             /* TODO: deferred accept */ | 
 |  | 
 |             ls[i].fd = s; | 
 |         } | 
 |  | 
 |         if (!failed) | 
 |             break; | 
 |  | 
 |         /* TODO: delay configurable */ | 
 |  | 
 |         ngx_log_error(NGX_LOG_NOTICE, log, 0, | 
 |                       "try again to bind() after 500ms"); | 
 |         ngx_msleep(500); | 
 |     } | 
 |  | 
 |     if (failed) { | 
 |         ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | void ngx_close_listening_sockets(ngx_cycle_t *cycle) | 
 | { | 
 |     ngx_int_t         i; | 
 |     ngx_socket_t      fd; | 
 |     ngx_listening_t  *ls; | 
 |  | 
 |     if (ngx_event_flags & NGX_USE_IOCP_EVENT) { | 
 |         return; | 
 |     } | 
 |  | 
 |     ls = cycle->listening.elts; | 
 |     for (i = 0; i < cycle->listening.nelts; i++) { | 
 |         fd = ls[i].fd; | 
 |  | 
 | #if (WIN32) | 
 |         /* | 
 |          * Winsock assignes a socket number divisible by 4 | 
 |          * so to find a connection we divide a socket number by 4. | 
 |          */ | 
 |  | 
 |         fd /= 4; | 
 | #endif | 
 |  | 
 |         ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT); | 
 |  | 
 |         if (ngx_close_socket(ls[i].fd) == -1) { | 
 |             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, | 
 |                           ngx_close_socket_n " %s failed", | 
 |                           ls[i].addr_text.data); | 
 |         } | 
 |  | 
 |         cycle->connections[fd].fd = -1; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) | 
 | { | 
 |     ngx_int_t  level; | 
 |  | 
 |     if (err == NGX_ECONNRESET | 
 |         && c->read->log_error == NGX_ERROR_IGNORE_ECONNRESET) | 
 |     { | 
 |         return 0; | 
 |     } | 
 |  | 
 |     if (err == NGX_ECONNRESET || err == NGX_EPIPE || err == NGX_ENOTCONN) { | 
 |  | 
 |         switch (c->read->log_error) { | 
 |  | 
 |         case NGX_ERROR_INFO: | 
 |             level = NGX_LOG_INFO; | 
 |             break; | 
 |  | 
 |         case NGX_ERROR_ERR: | 
 |             level = NGX_LOG_ERR; | 
 |             break; | 
 |  | 
 |         default: | 
 |             level = NGX_LOG_CRIT; | 
 |         } | 
 |  | 
 |     } else { | 
 |         level = NGX_LOG_CRIT; | 
 |     } | 
 |  | 
 |     ngx_log_error(level, c->log, err, text); | 
 |  | 
 |     return NGX_ERROR; | 
 | } |