代码拉取完成,页面将自动刷新
// annotated by chrono since 2016
//
// * ngx_create_listening
// * ngx_open_listening_sockets
// * ngx_configure_listening_sockets
// * ngx_get_connection
// * ngx_close_connection
// * ngx_close_listening_sockets
// * ngx_connection_local_sockaddr
//
// 1.10增加对reuseport的支持
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
// os/unix/ngx_os.h
// 操作系统提供的底层数据收发接口
// ngx_posix_init.c里初始化为linux的底层接口
// 在epoll模块的ngx_epoll_init里设置
//
// typedef struct {
// ngx_recv_pt recv;
// ngx_recv_chain_pt recv_chain;
// ngx_recv_pt udp_recv;
// ngx_send_pt send;
// ngx_send_chain_pt send_chain;
// ngx_uint_t flags;
// } ngx_os_io_t;
ngx_os_io_t ngx_io;
// 检查最多32个在可复用连接队列里的元素
// 设置为连接关闭c->close = 1;
// 调用事件的处理函数,里面会检查c->close
// 这样就会调用ngx_http_close_connection
// 释放连接,加入空闲链表,可以再次使用
// 早期函数参数是void,1.12改成cycle
static void ngx_drain_connections(ngx_cycle_t *cycle);
// http/ngx_http.c:ngx_http_add_listening()里调用
// 添加到cycle的监听端口数组,只是添加,没有其他动作
// 添加后需要用ngx_open_listening_sockets()才能打开端口监听
ngx_listening_t *
ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
socklen_t socklen)
{
size_t len;
ngx_listening_t *ls;
struct sockaddr *sa;
u_char text[NGX_SOCKADDR_STRLEN];
// 添加到cycle的监听端口数组
ls = ngx_array_push(&cf->cycle->listening);
if (ls == NULL) {
return NULL;
}
// 内存清零,这样ls->worker就是0
ngx_memzero(ls, sizeof(ngx_listening_t));
// 根据socklen分配sockaddr的内存空间
sa = ngx_palloc(cf->pool, socklen);
if (sa == NULL) {
return NULL;
}
ngx_memcpy(sa, sockaddr, socklen);
ls->sockaddr = sa;
ls->socklen = socklen;
// 准备addr的字符串形式
len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
ls->addr_text.len = len;
switch (ls->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
case AF_UNIX:
ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
len++;
break;
#endif
case AF_INET:
ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
break;
default:
ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
break;
}
ls->addr_text.data = ngx_pnalloc(cf->pool, len);
if (ls->addr_text.data == NULL) {
return NULL;
}
// 拷贝addr的字符串形式
ngx_memcpy(ls->addr_text.data, text, len);
// 1.15.0 新增,管理本端口的udp客户端连接
// 保持udp连接,支持客户端发多包
// 但对于tcp连接来说浪费了点空间
#if !(NGX_WIN32)
ngx_rbtree_init(&ls->rbtree, &ls->sentinel, ngx_udp_rbtree_insert_value);
#endif
ls->fd = (ngx_socket_t) -1;
ls->type = SOCK_STREAM;
// os/unix/ngx_linux_config.h:#define NGX_LISTEN_BACKLOG 511
ls->backlog = NGX_LISTEN_BACKLOG;
ls->rcvbuf = -1;
ls->sndbuf = -1;
#if (NGX_HAVE_SETFIB)
ls->setfib = -1;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
ls->fastopen = -1;
#endif
return ls;
}
// 1.10新函数,专为reuseport使用
// 拷贝了worker数量个的监听结构体
// 在ngx_stream_optimize_servers等函数创建端口时调用
ngx_int_t
ngx_clone_listening(ngx_cycle_t *cycle, ngx_listening_t *ls)
{
// configure脚本可以检测系统是否支持reuseport
// 使用宏来控制条件编译
#if (NGX_HAVE_REUSEPORT)
ngx_int_t n;
ngx_core_conf_t *ccf;
ngx_listening_t ols;
// 监听指令需要配置了reuseport
if (!ls->reuseport || ls->worker != 0) {
return NGX_OK;
}
// ls在之前已经正确设置了若干参数
// 例如type/handler/backlog等等
ols = *ls;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
// ccf->worker_processes是nginx的worker进程数
// 拷贝了worker数量个的监听结构体
//
// 注意从1开始,这样拷贝后总数就是worker数量个
// 最开始的一个就是被克隆的ls监听结构体
for (n = 1; n < ccf->worker_processes; n++) {
/* create a socket for each worker process */
ls = ngx_array_push(&cycle->listening);
if (ls == NULL) {
return NGX_ERROR;
}
// 完全拷贝结构体
*ls = ols;
// 设置worker的序号
// 被克隆的对象的worker是0
//
// worker的使用是在ngx_event.c:ngx_event_process_init
// 只有worker id是本worker的listen才会enable
ls->worker = n;
}
#endif
return NGX_OK;
}
// 根据传递过来的socket描述符,使用系统调用获取之前设置的参数
// 填入ngx_listeing_t结构体
ngx_int_t
ngx_set_inherited_sockets(ngx_cycle_t *cycle)
{
size_t len;
ngx_uint_t i;
ngx_listening_t *ls;
socklen_t olen;
#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN)
ngx_err_t err;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
int timeout;
#endif
#if (NGX_HAVE_REUSEPORT)
int reuseport;
#endif
// 遍历监听端口数组,里面应该有之前传递过来的socket
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
// 监听端口的实际地址,先分配内存
ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t));
if (ls[i].sockaddr == NULL) {
return NGX_ERROR;
}
// 地址内存的长度
ls[i].socklen = sizeof(ngx_sockaddr_t);
// 系统调用,获取socket的地址
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;
}
// 调整为正确的长度
if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
ls[i].socklen = sizeof(ngx_sockaddr_t);
}
// 接下来计算地址的文本形式
switch (ls[i].sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
case AF_UNIX:
ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
len = NGX_UNIX_ADDRSTRLEN;
break;
#endif
case AF_INET:
ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
break;
default:
ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
"the inherited socket #%d has "
"an unsupported protocol family", ls[i].fd);
ls[i].ignore = 1;
continue;
}
// 分配文本的内存
ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
if (ls[i].addr_text.data == NULL) {
return NGX_ERROR;
}
// socket地址转换为字符串
len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen,
ls[i].addr_text.data, len, 1);
if (len == 0) {
return NGX_ERROR;
}
ls[i].addr_text.len = len;
ls[i].backlog = NGX_LISTEN_BACKLOG;
// 逐个获取socket的各个参数
olen = sizeof(int);
// type,即tcp或udp
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type,
&olen)
== -1)
{
ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
"getsockopt(SO_TYPE) %V failed", &ls[i].addr_text);
ls[i].ignore = 1;
continue;
}
olen = sizeof(int);
// rcvbuf
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
&olen)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"getsockopt(SO_RCVBUF) %V failed, ignored",
&ls[i].addr_text);
ls[i].rcvbuf = -1;
}
olen = sizeof(int);
// sndbuf
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
&olen)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"getsockopt(SO_SNDBUF) %V failed, ignored",
&ls[i].addr_text);
ls[i].sndbuf = -1;
}
#if 0
/* SO_SETFIB is currently a set only option */
#if (NGX_HAVE_SETFIB)
olen = sizeof(int);
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
(void *) &ls[i].setfib, &olen)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"getsockopt(SO_SETFIB) %V failed, ignored",
&ls[i].addr_text);
ls[i].setfib = -1;
}
#endif
#endif
#if (NGX_HAVE_REUSEPORT)
reuseport = 0;
olen = sizeof(int);
// SO_REUSEPORT_LB目前仅在FreeBSD里有效
#ifdef SO_REUSEPORT_LB
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB,
(void *) &reuseport, &olen)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"getsockopt(SO_REUSEPORT_LB) %V failed, ignored",
&ls[i].addr_text);
} else {
ls[i].reuseport = reuseport ? 1 : 0;
}
#else
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
(void *) &reuseport, &olen)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"getsockopt(SO_REUSEPORT) %V failed, ignored",
&ls[i].addr_text);
} else {
ls[i].reuseport = reuseport ? 1 : 0;
}
#endif
#endif
// udp不检查下面的fastopen等参数
if (ls[i].type != SOCK_STREAM) {
continue;
}
#if (NGX_HAVE_TCP_FASTOPEN)
olen = sizeof(int);
// tcp专用的fastopen
if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
(void *) &ls[i].fastopen, &olen)
== -1)
{
err = ngx_socket_errno;
if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT
&& err != NGX_EINVAL)
{
ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
"getsockopt(TCP_FASTOPEN) %V failed, ignored",
&ls[i].addr_text);
}
ls[i].fastopen = -1;
}
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
// tcp专用的defered accept
ngx_memzero(&af, sizeof(struct accept_filter_arg));
olen = sizeof(struct accept_filter_arg);
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
== -1)
{
err = ngx_socket_errno;
if (err == NGX_EINVAL) {
continue;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
"getsockopt(SO_ACCEPTFILTER) for %V failed, ignored",
&ls[i].addr_text);
continue;
}
if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
continue;
}
ls[i].accept_filter = ngx_palloc(cycle->pool, 16);
if (ls[i].accept_filter == NULL) {
return NGX_ERROR;
}
(void) ngx_cpystrn((u_char *) ls[i].accept_filter,
(u_char *) af.af_name, 16);
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
timeout = 0;
olen = sizeof(int);
if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
== -1)
{
err = ngx_socket_errno;
if (err == NGX_EOPNOTSUPP) {
continue;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
"getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
&ls[i].addr_text);
continue;
}
if (olen < sizeof(int) || timeout == 0) {
continue;
}
ls[i].deferred_accept = 1;
#endif
}
return NGX_OK;
}
// ngx_cycle.c : init_cycle()里被调用
// 创建socket, bind/listen
// 之后会调用ngx_configure_listening_sockets()
// 配置监听端口的rcvbuf/sndbuf等参数,调用setsockopt()
ngx_int_t
ngx_open_listening_sockets(ngx_cycle_t *cycle)
{
int reuseaddr;
ngx_uint_t i, tries, failed;
ngx_err_t err;
ngx_log_t *log;
ngx_socket_t s;
ngx_listening_t *ls;
// 默认使用reuseaddr选项
reuseaddr = 1;
#if (NGX_SUPPRESS_WARN)
failed = 0;
#endif
log = cycle->log;
/* TODO: configurable try number */
for (tries = 5; tries; tries--) {
failed = 0;
/* for each listening socket */
// 遍历监听端口链表
// 如果设置了reuseport,那么一个端口会有worker个克隆的结构体
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
if (ls[i].ignore) {
continue;
}
#if (NGX_HAVE_REUSEPORT)
// 检查是否已经设置的标志位,只是用在inherited的时候,见注释
// 在init_cycle里设置
if (ls[i].add_reuseport) {
/*
* to allow transition from a socket without SO_REUSEPORT
* to multiple sockets with SO_REUSEPORT, we have to set
* SO_REUSEPORT on the old socket before opening new ones
*/
int reuseport = 1;
// SO_REUSEPORT_LB目前仅在FreeBSD里有效
#ifdef SO_REUSEPORT_LB
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB,
(const void *) &reuseport, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_REUSEPORT_LB) %V failed, "
"ignored",
&ls[i].addr_text);
}
#else
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
(const void *) &reuseport, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_REUSEPORT) %V failed, ignored",
&ls[i].addr_text);
}
#endif
// 标志位清零
ls[i].add_reuseport = 0;
}
#endif
// 已经打开的端口不再处理
if (ls[i].fd != (ngx_socket_t) -1) {
continue;
}
// 从前一个nginx进程继承过来的
// 已经打开,所以也不需要再处理
// 在ngx_set_inherited_sockets里操作
if (ls[i].inherited) {
/* TODO: close on exit */
/* TODO: nonblocking */
/* TODO: deferred accept */
continue;
}
// 创建socket
s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
if (s == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_socket_n " %V failed", &ls[i].addr_text);
return NGX_ERROR;
}
// 设置SO_REUSEADDR选项
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) %V failed",
&ls[i].addr_text);
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
return NGX_ERROR;
}
// 设置SO_REUSEPORT选项
// 这样多个进程可以打开相同的端口,由内核负责负载均衡
#if (NGX_HAVE_REUSEPORT)
if (ls[i].reuseport && !ngx_test_config) {
int reuseport;
reuseport = 1;
// SO_REUSEPORT_LB目前仅在FreeBSD里有效
#ifdef SO_REUSEPORT_LB
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT_LB,
(const void *) &reuseport, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
"setsockopt(SO_REUSEPORT_LB) %V failed",
&ls[i].addr_text);
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
return NGX_ERROR;
}
#else
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
(const void *) &reuseport, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
"setsockopt(SO_REUSEPORT) %V failed",
&ls[i].addr_text);
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
return NGX_ERROR;
}
#endif
}
#endif
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
if (ls[i].sockaddr->sa_family == AF_INET6) {
int ipv6only;
ipv6only = ls[i].ipv6only;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(const void *) &ipv6only, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
"setsockopt(IPV6_V6ONLY) %V failed, ignored",
&ls[i].addr_text);
}
}
#endif
/* TODO: close on exit */
if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
// 设置为nonblocking,使用FIONBIO
if (ngx_nonblocking(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_nonblocking_n " %V failed",
&ls[i].addr_text);
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
return NGX_ERROR;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
"bind() %V #%d ", &ls[i].addr_text, s);
//绑定地址
if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
err = ngx_socket_errno;
if (err != NGX_EADDRINUSE || !ngx_test_config) {
ngx_log_error(NGX_LOG_EMERG, log, err,
"bind() to %V failed", &ls[i].addr_text);
}
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
if (err != NGX_EADDRINUSE) {
return NGX_ERROR;
}
if (!ngx_test_config) {
failed = 1;
}
continue;
}
#if (NGX_HAVE_UNIX_DOMAIN)
if (ls[i].sockaddr->sa_family == AF_UNIX) {
mode_t mode;
u_char *name;
name = ls[i].addr_text.data + sizeof("unix:") - 1;
mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if (chmod((char *) name, mode) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"chmod() \"%s\" failed", name);
}
if (ngx_test_config) {
if (ngx_delete_file(name) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
ngx_delete_file_n " %s failed", name);
}
}
}
#endif
// 检查是否是tcp,即SOCK_STREAM
if (ls[i].type != SOCK_STREAM) {
// 如果不是tcp,即udp,那么无需监听
ls[i].fd = s;
// 继续处理下一个监听结构体
continue;
}
// 开始监听,设置backlog
if (listen(s, ls[i].backlog) == -1) {
err = ngx_socket_errno;
/*
* on OpenVZ after suspend/resume EADDRINUSE
* may be returned by listen() instead of bind(), see
* https://bugzilla.openvz.org/show_bug.cgi?id=2470
*/
if (err != NGX_EADDRINUSE || !ngx_test_config) {
ngx_log_error(NGX_LOG_EMERG, log, err,
"listen() to %V, backlog %d failed",
&ls[i].addr_text, ls[i].backlog);
}
if (ngx_close_socket(s) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[i].addr_text);
}
if (err != NGX_EADDRINUSE) {
return NGX_ERROR;
}
if (!ngx_test_config) {
failed = 1;
}
continue;
}
// 设置已经监听标志
ls[i].listen = 1;
// 设置socket描述符
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 could not bind()");
return NGX_ERROR;
}
return NGX_OK;
}
// ngx_init_cycle()里调用,在ngx_open_listening_sockets()之后
// 配置监听端口的rcvbuf/sndbuf等参数,调用setsockopt()
void
ngx_configure_listening_sockets(ngx_cycle_t *cycle)
{
int value;
ngx_uint_t i;
ngx_listening_t *ls;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
// 遍历监听端口链表
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
ls[i].log = *ls[i].logp;
// rcvbuf
if (ls[i].rcvbuf != -1) {
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
(const void *) &ls[i].rcvbuf, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_RCVBUF, %d) %V failed, ignored",
ls[i].rcvbuf, &ls[i].addr_text);
}
}
// sndbuf
if (ls[i].sndbuf != -1) {
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF,
(const void *) &ls[i].sndbuf, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_SNDBUF, %d) %V failed, ignored",
ls[i].sndbuf, &ls[i].addr_text);
}
}
// keepalive
if (ls[i].keepalive) {
value = (ls[i].keepalive == 1) ? 1 : 0;
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_KEEPALIVE, %d) %V failed, ignored",
value, &ls[i].addr_text);
}
}
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
if (ls[i].keepidle) {
value = ls[i].keepidle;
#if (NGX_KEEPALIVE_FACTOR)
value *= NGX_KEEPALIVE_FACTOR;
#endif
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
value, &ls[i].addr_text);
}
}
if (ls[i].keepintvl) {
value = ls[i].keepintvl;
#if (NGX_KEEPALIVE_FACTOR)
value *= NGX_KEEPALIVE_FACTOR;
#endif
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored",
value, &ls[i].addr_text);
}
}
if (ls[i].keepcnt) {
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPCNT,
(const void *) &ls[i].keepcnt, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_KEEPCNT, %d) %V failed, ignored",
ls[i].keepcnt, &ls[i].addr_text);
}
}
#endif
#if (NGX_HAVE_SETFIB)
if (ls[i].setfib != -1) {
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
(const void *) &ls[i].setfib, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_SETFIB, %d) %V failed, ignored",
ls[i].setfib, &ls[i].addr_text);
}
}
#endif
// tcp fast open, 可以优化tcp三次握手的延迟,提高响应速度
#if (NGX_HAVE_TCP_FASTOPEN)
if (ls[i].fastopen != -1) {
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
(const void *) &ls[i].fastopen, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_FASTOPEN, %d) %V failed, ignored",
ls[i].fastopen, &ls[i].addr_text);
}
}
#endif
#if 0
if (1) {
int tcp_nodelay = 1;
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_NODELAY,
(const void *) &tcp_nodelay, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_NODELAY) %V failed, ignored",
&ls[i].addr_text);
}
}
#endif
// 已经监听标志, backlog
if (ls[i].listen) {
/* change backlog via listen() */
// 修改了tcp选项,重新监听
if (listen(ls[i].fd, ls[i].backlog) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"listen() to %V, backlog %d failed, ignored",
&ls[i].addr_text, ls[i].backlog);
}
}
/*
* setting deferred mode should be last operation on socket,
* because code may prematurely continue cycle on failure
*/
#if (NGX_HAVE_DEFERRED_ACCEPT)
// 这个是freebsd的设置
#ifdef SO_ACCEPTFILTER
if (ls[i].delete_deferred) {
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_ACCEPTFILTER, NULL) "
"for %V failed, ignored",
&ls[i].addr_text);
if (ls[i].accept_filter) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"could not change the accept filter "
"to \"%s\" for %V, ignored",
ls[i].accept_filter, &ls[i].addr_text);
}
continue;
}
ls[i].deferred_accept = 0;
}
if (ls[i].add_deferred) {
ngx_memzero(&af, sizeof(struct accept_filter_arg));
(void) ngx_cpystrn((u_char *) af.af_name,
(u_char *) ls[i].accept_filter, 16);
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER,
&af, sizeof(struct accept_filter_arg))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_ACCEPTFILTER, \"%s\") "
"for %V failed, ignored",
ls[i].accept_filter, &ls[i].addr_text);
continue;
}
ls[i].deferred_accept = 1;
}
#endif
// 这个是linux的设置
#ifdef TCP_DEFER_ACCEPT
// deferred,只有socket上有数据可读才接受连接
// 由内核检查客户端连接的数据发送情况
// 减少了epoll的调用次数,可以提高性能
if (ls[i].add_deferred || ls[i].delete_deferred) {
if (ls[i].add_deferred) {
/*
* There is no way to find out how long a connection was
* in queue (and a connection may bypass deferred queue at all
* if syncookies were used), hence we use 1 second timeout
* here.
*/
value = 1;
} else {
value = 0;
}
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
&value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
"ignored",
value, &ls[i].addr_text);
continue;
}
}
if (ls[i].add_deferred) {
ls[i].deferred_accept = 1;
}
#endif
#endif /* NGX_HAVE_DEFERRED_ACCEPT */
#if (NGX_HAVE_IP_RECVDSTADDR)
if (ls[i].wildcard
&& ls[i].type == SOCK_DGRAM
&& ls[i].sockaddr->sa_family == AF_INET)
{
value = 1;
if (setsockopt(ls[i].fd, IPPROTO_IP, IP_RECVDSTADDR,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(IP_RECVDSTADDR) "
"for %V failed, ignored",
&ls[i].addr_text);
}
}
#elif (NGX_HAVE_IP_PKTINFO)
if (ls[i].wildcard
&& ls[i].type == SOCK_DGRAM
&& ls[i].sockaddr->sa_family == AF_INET)
{
value = 1;
if (setsockopt(ls[i].fd, IPPROTO_IP, IP_PKTINFO,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(IP_PKTINFO) "
"for %V failed, ignored",
&ls[i].addr_text);
}
}
#endif
#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
if (ls[i].wildcard
&& ls[i].type == SOCK_DGRAM
&& ls[i].sockaddr->sa_family == AF_INET6)
{
value = 1;
if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
(const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(IPV6_RECVPKTINFO) "
"for %V failed, ignored",
&ls[i].addr_text);
}
}
#endif
}
// 此句貌似多余,应该删除?
return;
}
// 在ngx_master_process_exit里被调用(os/unix/ngx_process_cycle.c)
// 遍历监听端口列表,逐个删除监听事件
void
ngx_close_listening_sockets(ngx_cycle_t *cycle)
{
ngx_uint_t i;
ngx_listening_t *ls;
ngx_connection_t *c;
if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
return;
}
ngx_accept_mutex_held = 0;
ngx_use_accept_mutex = 0;
// 遍历监听端口链表
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
c = ls[i].connection;
if (c) {
if (c->read->active) {
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
/*
* it seems that Linux-2.6.x OpenVZ sends events
* for closed shared listening sockets unless
* the events was explicitly deleted
*/
ngx_del_event(c->read, NGX_READ_EVENT, 0);
} else {
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
}
}
// 释放连接,加入空闲链表
ngx_free_connection(c);
c->fd = (ngx_socket_t) -1;
}
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
"close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
if (ngx_close_socket(ls[i].fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_close_socket_n " %V failed", &ls[i].addr_text);
}
#if (NGX_HAVE_UNIX_DOMAIN)
// 对于domain socket需要删除文件
if (ls[i].sockaddr->sa_family == AF_UNIX
&& ngx_process <= NGX_PROCESS_MASTER
&& ngx_new_binary == 0
&& (!ls[i].inherited || ngx_getppid() != ngx_parent))
{
// 去掉前面的unix:前缀
u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
// 删除文件
if (ngx_delete_file(name) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_delete_file_n " %s failed", name);
}
}
#endif
ls[i].fd = (ngx_socket_t) -1;
}
cycle->listening.nelts = 0;
}
// 从全局变量ngx_cycle里获取空闲链接,即free_connections链表
// 如果没有空闲连接,调用ngx_drain_connections释放一些可复用的连接
ngx_connection_t *
ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
{
ngx_uint_t instance;
ngx_event_t *rev, *wev;
ngx_connection_t *c;
/* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
// 如果使用epoll,那么files指针通常是null,即不会使用
if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"the new socket has number %d, "
"but only %ui files are available",
s, ngx_cycle->files_n);
return NULL;
}
// 从全局变量ngx_cycle里获取空闲链接,即free_connections链表
// free_connections是空闲链表头指针
// 检查最多32个在可复用连接队列里的元素
// 设置为连接关闭c->close = 1;
// 调用事件的处理函数,里面会检查c->close
// 这样就会调用ngx_http_close_connection
// 释放连接,加入空闲链表,可以再次使用
ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
// 此时应该有了一些空闲连接
// 再次获取
c = ngx_cycle->free_connections;
// 如果还没有获取到连接,那么就报错
if (c == NULL) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"%ui worker_connections are not enough",
ngx_cycle->connection_n);
return NULL;
}
// 此时已经拿到了空闲连接
// 调整空闲链表的指针,复用data成员
// 空闲链表头指针指向链表里的下一个节点
ngx_cycle->free_connections = c->data;
// 空闲连接计数器减少
ngx_cycle->free_connection_n--;
// 如果使用epoll,那么files指针通常是null,即不会使用
if (ngx_cycle->files && ngx_cycle->files[s] == NULL) {
ngx_cycle->files[s] = c;
}
// 暂时保存读写事件对象
rev = c->read;
wev = c->write;
// 清空连接对象
// 注意这时fd、sent、type等字段、计数器、标志都变成了0
ngx_memzero(c, sizeof(ngx_connection_t));
// 恢复读写事件对象
c->read = rev;
c->write = wev;
// 设置连接的socket
c->fd = s;
c->log = log;
// 置instance标志,用于检查连接是否失效
instance = rev->instance;
ngx_memzero(rev, sizeof(ngx_event_t));
ngx_memzero(wev, sizeof(ngx_event_t));
// 置instance标志,用于检查连接是否失效
rev->instance = !instance;
wev->instance = !instance;
rev->index = NGX_INVALID_INDEX;
wev->index = NGX_INVALID_INDEX;
// 读写事件对象的data保存了连接对象
rev->data = c;
wev->data = c;
// 设置写事件的标志
// 用于区分读写事件
wev->write = 1;
return c;
}
// 释放一个连接,加入空闲链表
void
ngx_free_connection(ngx_connection_t *c)
{
// 调整空闲链表的指针,复用data成员
// free_connections是空闲链表头指针
c->data = ngx_cycle->free_connections;
// 空闲链表头指针指向连接对象
ngx_cycle->free_connections = c;
// 空闲连接数量增加
ngx_cycle->free_connection_n++;
// 如果使用epoll,那么files指针通常是null,即不会使用
if (ngx_cycle->files && ngx_cycle->files[c->fd] == c) {
ngx_cycle->files[c->fd] = NULL;
}
}
// 关闭连接,删除epoll里的读写事件
// 释放连接,加入空闲链表,可以再次使用
void
ngx_close_connection(ngx_connection_t *c)
{
ngx_err_t err;
ngx_uint_t log_error, level;
ngx_socket_t fd;
if (c->fd == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
return;
}
// 读事件在定时器里,需要删除
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
// 写事件在定时器里,需要删除
if (c->write->timer_set) {
ngx_del_timer(c->write);
}
if (!c->shared) {
// in event/ngx_event.h
// 宏,实际上是ngx_event_actions.del_conn
if (ngx_del_conn) {
ngx_del_conn(c, NGX_CLOSE_EVENT);
} else {
if (c->read->active || c->read->disabled) {
// 宏,实际上是ngx_event_actions.del
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
}
if (c->write->active || c->write->disabled) {
// 宏,实际上是ngx_event_actions.del
ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
}
}
}
if (c->read->posted) {
ngx_delete_posted_event(c->read);
}
if (c->write->posted) {
ngx_delete_posted_event(c->write);
}
c->read->closed = 1;
c->write->closed = 1;
// 连接加入cycle的复用队列ngx_cycle->reusable_connections_queue
ngx_reusable_connection(c, 0);
log_error = c->log_error;
// 释放连接,加入空闲链表
ngx_free_connection(c);
fd = c->fd;
c->fd = (ngx_socket_t) -1;
if (c->shared) {
return;
}
// 关闭socket
if (ngx_close_socket(fd) == -1) {
err = ngx_socket_errno;
if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {
switch (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, ngx_close_socket_n " %d failed", fd);
}
}
// 连接加入cycle的复用队列ngx_cycle->reusable_connections_queue
// 参数reusable表示是否可以复用,即加入队列
void
ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
{
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
"reusable connection: %ui", reusable);
// 连接已经加入了队列,需要移出
if (c->reusable) {
ngx_queue_remove(&c->queue);
ngx_cycle->reusable_connections_n--;
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
#endif
}
// 设置标志位,是否已经加入队列
c->reusable = reusable;
// 要求加入队列,插入队列头
if (reusable) {
/* need cast as ngx_cycle is volatile */
ngx_queue_insert_head(
(ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);
ngx_cycle->reusable_connections_n++;
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
#endif
}
}
// 检查最多32个在可复用连接队列里的元素
// 设置为连接关闭c->close = 1;
// 调用事件的处理函数,里面会检查c->close
// 这样就会调用ngx_http_close_connection
// 释放连接,加入空闲链表,可以再次使用
static void
ngx_drain_connections(ngx_cycle_t *cycle)
{
ngx_uint_t i, n;
ngx_queue_t *q;
ngx_connection_t *c;
// 从全局变量ngx_cycle里获取空闲链接,即free_connections链表
// free_connections是空闲链表头指针
// 早期的nginx只检查32次,避免过多消耗时间
// 1.12改变了这个固定值
if (cycle->free_connection_n > cycle->connection_n / 16
|| cycle->reusable_connections_n == 0)
{
return;
}
if (cycle->connections_reuse_time != ngx_time()) {
cycle->connections_reuse_time = ngx_time();
ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
"%ui worker_connections are not enough, "
"reusing connections",
cycle->connection_n);
}
c = NULL;
n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1);
for (i = 0; i < n; i++) {
// 如果队列是空的那么直接退出
if (ngx_queue_empty(&cycle->reusable_connections_queue)) {
break;
}
// 取出队列末尾的连接对象,必定是c->reusable == true
q = ngx_queue_last(&cycle->reusable_connections_queue);
c = ngx_queue_data(q, ngx_connection_t, queue);
ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
"reusing connection");
// 注意!设置为连接关闭
c->close = 1;
// 调用事件的处理函数,里面会检查c->close
// 这样就会调用ngx_http_close_connection
// 释放连接,加入空闲链表,可以再次使用
// 例如ngx_http_wait_request_handler
c->read->handler(c->read);
}
if (cycle->free_connection_n == 0 && c && c->reusable) {
/*
* if no connections were freed, try to reuse the last
* connection again: this should free it as long as
* previous reuse moved it to lingering close
*/
ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
"reusing connection again");
c->close = 1;
c->read->handler(c->read);
}
}
// 检查cycle里的连接数组,如果连接空闲则设置close标志位,关闭
void
ngx_close_idle_connections(ngx_cycle_t *cycle)
{
ngx_uint_t i;
ngx_connection_t *c;
c = cycle->connections;
// 检查cycle里的连接数组
for (i = 0; i < cycle->connection_n; i++) {
/* THREAD: lock */
// 如果连接空闲则设置close标志位,关闭
if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) {
c[i].close = 1;
c[i].read->handler(c[i].read);
}
}
}
// 获取服务器的ip地址信息
ngx_int_t
ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
ngx_uint_t port)
{
socklen_t len;
ngx_uint_t addr;
ngx_sockaddr_t sa;
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
ngx_uint_t i;
struct sockaddr_in6 *sin6;
#endif
addr = 0;
// 先检查c->local_socklen
// 即ls->sock_addr,监听端口的地址
if (c->local_socklen) {
switch (c->local_sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
for (i = 0; addr == 0 && i < 16; i++) {
addr |= sin6->sin6_addr.s6_addr[i];
}
break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
case AF_UNIX:
addr = 1;
break;
#endif
// ipv4,转换为sockaddr_in
default: /* AF_INET */
sin = (struct sockaddr_in *) c->local_sockaddr;
addr = sin->sin_addr.s_addr;
break;
}
}
// 地址为0,可能是未明确配置监听的ip
if (addr == 0) {
len = sizeof(ngx_sockaddr_t);
// 系统调用获取本地地址
if (getsockname(c->fd, &sa.sockaddr, &len) == -1) {
ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
return NGX_ERROR;
}
// 分配内存
c->local_sockaddr = ngx_palloc(c->pool, len);
if (c->local_sockaddr == NULL) {
return NGX_ERROR;
}
// 拷贝真正的服务器地址
ngx_memcpy(c->local_sockaddr, &sa, len);
c->local_socklen = len;
}
// 不传入字符串则直接结束,节约计算
if (s == NULL) {
return NGX_OK;
}
// 格式化地址字符串
s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen,
s->data, s->len, port);
return NGX_OK;
}
ngx_int_t
ngx_tcp_nodelay(ngx_connection_t *c)
{
int tcp_nodelay;
if (c->tcp_nodelay != NGX_TCP_NODELAY_UNSET) {
return NGX_OK;
}
ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, "tcp_nodelay");
tcp_nodelay = 1;
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
(const void *) &tcp_nodelay, sizeof(int))
== -1)
{
#if (NGX_SOLARIS)
if (c->log_error == NGX_ERROR_INFO) {
/* Solaris returns EINVAL if a socket has been shut down */
c->log_error = NGX_ERROR_IGNORE_EINVAL;
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
c->log_error = NGX_ERROR_INFO;
return NGX_ERROR;
}
#endif
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
return NGX_ERROR;
}
c->tcp_nodelay = NGX_TCP_NODELAY_SET;
return NGX_OK;
}
ngx_int_t
ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
{
ngx_uint_t level;
/* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */
if ((err == NGX_ECONNRESET
#if (NGX_WIN32)
|| err == NGX_ECONNABORTED
#endif
) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET)
{
return 0;
}
#if (NGX_SOLARIS)
if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) {
return 0;
}
#endif
if (err == 0
|| err == NGX_ECONNRESET
#if (NGX_WIN32)
|| err == NGX_ECONNABORTED
#else
|| err == NGX_EPIPE
#endif
|| err == NGX_ENOTCONN
|| err == NGX_ETIMEDOUT
|| err == NGX_ECONNREFUSED
|| err == NGX_ENETDOWN
|| err == NGX_ENETUNREACH
|| err == NGX_EHOSTDOWN
|| err == NGX_EHOSTUNREACH)
{
switch (c->log_error) {
case NGX_ERROR_IGNORE_EINVAL:
case NGX_ERROR_IGNORE_ECONNRESET:
case NGX_ERROR_INFO:
level = NGX_LOG_INFO;
break;
default:
level = NGX_LOG_ERR;
}
} else {
level = NGX_LOG_ALERT;
}
ngx_log_error(level, c->log, err, text);
return NGX_ERROR;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。