• Nginx-HTTP之listen指令解析


    1. ngx_http_core_listen

    static char *
    ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        /* conf 即为该 listen 所在的配置信息结构体 */
        ngx_http_core_srv_conf_t *cscf = conf;
    
        ngx_str_t              *value, size;
        ngx_url_t               u;
        ngx_uint_t              n;
        ngx_http_listen_opt_t   lsopt;
    
        cscf->listen = 1;
        
        /* 假设当前 listen 指令为: "listen 80;" */
    
        /* value = "listen" */
        value = cf->args->elts;
    
        ngx_memzero(&u, sizeof(ngx_url_t));
    
        /* u.url = "80" */
        u.url = value[1];
        /* 标志位,为 1 表示当前端口有效 */
        u.listen = 1;
        /* 若 listen 没有指定端口,则会使用默认端口 */
        u.default_port = 80;
    
        /* 解析 listen 的参数 */
        if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
            if (u.err) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "%s in "%V" of the "listen" directive",
                                   u.err, &u.url);
            }
    
            return NGX_CONF_ERROR;
        }
    
        ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
    
        ngx_memcpy(&lsopt.sockaddr.sockaddr, &u.sockaddr, u.socklen);
    
        lsopt.socklen = u.socklen;
        /* TCP 实现监听时的 backlog 队列,它表示允许正在通过三次握手建立 TCP
         * 连接但没有任何进程开始处理的连接最大个数,linux 下设为 511 */
        lsopt.backlog = NGX_LISTEN_BACKLOG;
        lsopt.rcvbuf = -1;
        lsopt.sndbuf = -1;
    #if (NGX_HAVE_SETFIB)
        lsopt.setfib = -1;
    #endif
    #if (NGX_HAVE_TCP_FASTOPEN)
        lsopt.fastopen = -1;
    #endif
        lsopt.wildcard = u.wildcard;
    #if (NGX_HAVE_INET6)
        lsopt.ipv6only = 1;
    #endif
    
        /* 将 */
        (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen, lsopt.addr,
                             NGX_SOCKADDR_STRLEN, 1);
    
        /* 若当前 listen 指令不止一个参数 */
        for (n = 2; n < cf->args->nelts; n++) {
    
            /* 若第二个参数为 "default_server" */
            if (ngx_strcmp(value[n].data, "default_server") == 0
                || ngx_strcmp(value[n].data, "default") == 0)
            {
                /* 表示使用默认的服务器 */
                lsopt.default_server = 1;
                continue;
            }
    
            /* 若listen指定有 bind 参数,则表示需要绑定该端口 */
            if (ngx_strcmp(value[n].data, "bind") == 0) {
                lsopt.set = 1;
                lsopt.bind = 1;
                continue;
            }
    
    #if (NGX_HAVE_SETFIB)
            if (ngx_strncmp(value[n].data, "setfib=", 7) == 0) {
                lsopt.setfib = ngx_atoi(value[n].data + 7, value[n].len - 7);
                lsopt.set = 1;
                lsopt.bind = 1;
    
                if (lsopt.setfib == NGX_ERROR) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "invalid setfib "%V"", &value[n]);
                    return NGX_CONF_ERROR;
                }
    
                continue;
            }
    #endif
    
    #if (NGX_HAVE_TCP_FASTOPEN)
            if (ngx_strncmp(value[n].data, "fastopen=", 9) == 0) {
                lsopt.fastopen = ngx_atoi(value[n].data + 9, value[n].len - 9);
                lsopt.set = 1;
                lsopt.bind = 1;
    
                if (lsopt.fastopen == NGX_ERROR) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "invalid fastopen "%V"", &value[n]);
                    return NGX_CONF_ERROR;
                }
    
                continue;
            }
    #endif
    
            if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
                lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
                lsopt.set = 1;
                lsopt.bind = 1;
    
                if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "invalid backlog "%V"", &value[n]);
                    return NGX_CONF_ERROR;
                }
    
                continue;
            }
    
            if (ngx_strncmp(value[n].data, "rcvbuf=", 7) == 0) {
                size.len = value[n].len - 7;
                size.data = value[n].data + 7;
    
                lsopt.rcvbuf = ngx_parse_size(&size);
                lsopt.set = 1;
                lsopt.bind = 1;
    
                if (lsopt.rcvbuf == NGX_ERROR) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "invalid rcvbuf "%V"", &value[n]);
                    return NGX_CONF_ERROR;
                }
    
                continue;
            }
    
            if (ngx_strncmp(value[n].data, "sndbuf=", 7) == 0) {
                size.len = value[n].len - 7;
                size.data = value[n].data + 7;
    
                lsopt.sndbuf = ngx_parse_size(&size);
                lsopt.set = 1;
                lsopt.bind = 1;
    
                if (lsopt.sndbuf == NGX_ERROR) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "invalid sndbuf "%V"", &value[n]);
                    return NGX_CONF_ERROR;
                }
    
                continue;
            }
    
            if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) {
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
                lsopt.accept_filter = (char *) &value[n].data[14];
                lsopt.set = 1;
                lsopt.bind = 1;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "accept filters "%V" are not supported "
                                   "on this platform, ignored",
                                   &value[n]);
    #endif
                continue;
            }
    
            if (ngx_strcmp(value[n].data, "deferred") == 0) {
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
                lsopt.deferred_accept = 1;
                lsopt.set = 1;
                lsopt.bind = 1;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "the deferred accept is not supported "
                                   "on this platform, ignored");
    #endif
                continue;
            }
    
            if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) {
    #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
                struct sockaddr  *sa;
    
                sa = &lsopt.sockaddr.sockaddr;
    
                if (sa->sa_family == AF_INET6) {
    
                    if (ngx_strcmp(&value[n].data[10], "n") == 0) {
                        lsopt.ipv6only = 1;
    
                    } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) {
                        lsopt.ipv6only = 0;
    
                    } else {
                        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                           "invalid ipv6only flags "%s"",
                                           &value[n].data[9]);
                        return NGX_CONF_ERROR;
                    }
    
                    lsopt.set = 1;
                    lsopt.bind = 1;
    
                } else {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "ipv6only is not supported "
                                       "on addr "%s", ignored", lsopt.addr);
                }
    
                continue;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "ipv6only is not supported "
                                   "on this platform");
                return NGX_CONF_ERROR;
    #endif
            }
    
            if (ngx_strcmp(value[n].data, "reuseport") == 0) {
    #if (NGX_HAVE_REUSEPORT)
                lsopt.reuseport = 1;
                lsopt.set = 1;
                lsopt.bind = 1;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "reuseport is not supported "
                                   "on this platform, ignored");
    #endif
                continue;
            }
    
            if (ngx_strcmp(value[n].data, "ssl") == 0) {
    #if (NGX_HTTP_SSL)
                lsopt.ssl = 1;
                continue;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "the "ssl" parameter requires "
                                   "ngx_http_ssl_module");
                return NGX_CONF_ERROR;
    #endif
            }
    
            if (ngx_strcmp(value[n].data, "http2") == 0) {
    #if (NGX_HTTP_V2)
                lsopt.http2 = 1;
                continue;
    #else
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "the "http2" parameter requires "
                                   "ngx_http_v2_module");
                return NGX_CONF_ERROR;
    #endif
            }
    
            if (ngx_strcmp(value[n].data, "spdy") == 0) {
                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                                   "invalid parameter "spdy": "
                                   "ngx_http_spdy_module was superseded "
                                   "by ngx_http_v2_module");
                continue;
            }
    
            if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) {
    
                if (ngx_strcmp(&value[n].data[13], "on") == 0) {
                    lsopt.so_keepalive = 1;
    
                } else if (ngx_strcmp(&value[n].data[13], "off") == 0) {
                    lsopt.so_keepalive = 2;
    
                } else {
    
    #if (NGX_HAVE_KEEPALIVE_TUNABLE)
                    u_char     *p, *end;
                    ngx_str_t   s;
    
                    end = value[n].data + value[n].len;
                    s.data = value[n].data + 13;
    
                    p = ngx_strlchr(s.data, end, ':');
                    if (p == NULL) {
                        p = end;
                    }
    
                    if (p > s.data) {
                        s.len = p - s.data;
    
                        lsopt.tcp_keepidle = ngx_parse_time(&s, 1);
                        if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) {
                            goto invalid_so_keepalive;
                        }
                    }
    
                    s.data = (p < end) ? (p + 1) : end;
    
                    p = ngx_strlchr(s.data, end, ':');
                    if (p == NULL) {
                        p = end;
                    }
    
                    if (p > s.data) {
                        s.len = p - s.data;
    
                        lsopt.tcp_keepintvl = ngx_parse_time(&s, 1);
                        if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) {
                            goto invalid_so_keepalive;
                        }
                    }
    
                    s.data = (p < end) ? (p + 1) : end;
    
                    if (s.data < end) {
                        s.len = end - s.data;
    
                        lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);
                        if (lsopt.tcp_keepcnt == NGX_ERROR) {
                            goto invalid_so_keepalive;
                        }
                    }
    
                    if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0
                        && lsopt.tcp_keepcnt == 0)
                    {
                        goto invalid_so_keepalive;
                    }
    
                    lsopt.so_keepalive = 1;
    
    #else
    
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "the "so_keepalive" parameter accepts "
                                       "only "on" or "off" on this platform");
                    return NGX_CONF_ERROR;
    
    #endif
                }
    
                lsopt.set = 1;
                lsopt.bind = 1;
    
                continue;
    
    #if (NGX_HAVE_KEEPALIVE_TUNABLE)
            invalid_so_keepalive:
    
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid so_keepalive value: "%s"",
                                   &value[n].data[13]);
                return NGX_CONF_ERROR;
    #endif
            }
    
            if (ngx_strcmp(value[n].data, "proxy_protocol") == 0) {
                lsopt.proxy_protocol = 1;
                continue;
            }
    
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid parameter "%V"", &value[n]);
            return NGX_CONF_ERROR;
        }
    
        /* 将已经初始化好的 lsopt 结构体添加到 */
        if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {
            return NGX_CONF_OK;
        }
    
        return NGX_CONF_ERROR;
    }
    

    2. ngx_parse_url

    解析 lisetn 指令的参数。

    ngx_int_t
    ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
    {
        u_char  *p;
        size_t   len;
    
        p = u->url.data;
        len = u->url.len;
    
        /* 检测是否为 unix 域 */
        if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
            return ngx_parse_unix_domain_url(pool, u);
        }
    
        /* 检测是否为 ip6  */
        if (len && p[0] == '[') {
            return ngx_parse_inet6_url(pool, u);
        }
    
        /* 否则调用该函数 */
        return ngx_parse_inet_url(pool, u);
    }
    

    2.1 ngx_parse_inet_url

    static ngx_int_t
    ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
    {
        u_char               *p, *host, *port, *last, *uri, *args;
        size_t                len;
        ngx_int_t             n;
        struct sockaddr_in   *sin;
    #if (NGX_HAVE_INET6)
        struct sockaddr_in6  *sin6;
    #endif
    
        u->socklen = sizeof(struct sockaddr_in);
        sin = (struct sockaddr_in *) &u->sockaddr;
        /* 初始化地址组为 AF_INET,即为 ipv4 类型的 */
        sin->sin_family = AF_INET;
    
        u->family = AF_INET;
    
        /* 若当前 listen 指令的配置为: listen 80; */
    
        host = u->url.data;
    
        last = host + u->url.len;
    
        port = ngx_strlchr(host, last, ':');
    
        uri = ngx_strlchr(host, last, '/');
    
        args = ngx_strlchr(host, last, '?');
    
        if (args) {
            if (uri == NULL || args < uri) {
                uri = args;
            }
        }
    
        if (uri) {
            if (u->listen || !u->uri_part) {
                u->err = "invalid host";
                return NGX_ERROR;
            }
    
            u->uri.len = last - uri;
            u->uri.data = uri;
    
            last = uri;
    
            if (uri < port) {
                port = NULL;
            }
        }
    
        if (port) {
            port++;
    
            len = last - port;
    
            n = ngx_atoi(port, len);
    
            if (n < 1 || n > 65535) {
                u->err = "invalid port";
                return NGX_ERROR;
            }
    
            u->port = (in_port_t) n;
            sin->sin_port = htons((in_port_t) n);
    
            u->port_text.len = len;
            u->port_text.data = port;
    
            last = port - 1;
    
        } else {
            if (uri == NULL) {
    
                if (u->listen) {
    
                    /* test value as port only */
    
                    n = ngx_atoi(host, last - host);
    
                    if (n != NGX_ERROR) {
    
                        if (n < 1 || n > 65535) {
                            u->err = "invalid port";
                            return NGX_ERROR;
                        }
    
                        /* 当前 listen 指令的参数仅为要监听的端口 */
                        u->port = (in_port_t) n;
                        /* 将该端口转换为网络字节序 */
                        sin->sin_port = htons((in_port_t) n);
    
                        u->port_text.len = last - host;
                        /* 将该端口以字符串形式保存在该变量中 */
                        u->port_text.data = host;
    
                        u->wildcard = 1;
    
                        /* 仅为端口的情况下,这里直接返回了 */
                        return NGX_OK;
                    }
                }
            }
    
            /* no_port 标志位,为 1 表示当前 listen 的参数中没有指定端口 */
            u->no_port = 1;
            /* 因此使用默认端口 80 */
            u->port = u->default_port;
            /* 将主机字节序转换为网络字节序 */
            sin->sin_port = htons(u->default_port);
        }
    
        len = last - host;
    
        if (len == 0) {
            u->err = "no host";
            return NGX_ERROR;
        }
    
        u->host.len = len;
        u->host.data = host;
    
        if (u->listen && len == 1 && *host == '*') {
            sin->sin_addr.s_addr = INADDR_ANY;
            u->wildcard = 1;
            return NGX_OK;
        }
    
        sin->sin_addr.s_addr = ngx_inet_addr(host, len);
    
        if (sin->sin_addr.s_addr != INADDR_NONE) {
    
            if (sin->sin_addr.s_addr == INADDR_ANY) {
                u->wildcard = 1;
            }
    
            u->naddrs = 1;
    
            u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
            if (u->addrs == NULL) {
                return NGX_ERROR;
            }
    
            sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
            if (sin == NULL) {
                return NGX_ERROR;
            }
    
            ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in));
    
            u->addrs[0].sockaddr = (struct sockaddr *) sin;
            u->addrs[0].socklen = sizeof(struct sockaddr_in);
    
            p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
            if (p == NULL) {
                return NGX_ERROR;
            }
    
            u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
                                               &u->host, u->port) - p;
            u->addrs[0].name.data = p;
    
            return NGX_OK;
        }
    
        if (u->no_resolve) {
            return NGX_OK;
        }
    
        if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
            return NGX_ERROR;
        }
    
        u->family = u->addrs[0].sockaddr->sa_family;
        u->socklen = u->addrs[0].socklen;
        ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
    
        switch (u->family) {
    
    #if (NGX_HAVE_INET6)
        case AF_INET6:
            sin6 = (struct sockaddr_in6 *) &u->sockaddr;
    
            if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
                u->wildcard = 1;
            }
    
            break;
    #endif
    
        default: /* AF_INET */
            sin = (struct sockaddr_in *) &u->sockaddr;
    
            if (sin->sin_addr.s_addr == INADDR_ANY) {
                u->wildcard = 1;
            }
    
            break;
        }
    
        return NGX_OK;
    }
    

    3. ngx_http_add_listen

    /* 每监听一个TCP端口,都将使用一个独立的ngx_http_conf_port_t结构体表示。
     * 这个保存着监听端口的ngx_http_conf_port_t将由全局的ngx_http_core_main_conf_t
     * 结构体保存 */
    typedef struct {
        /* socket地址家族 */
        ngx_int_t                       family;
        /* 监听端口 */
        in_port_t                       port;
        /* 监听端口下对应着的所有ngx_http_conf_addr_t地址 */
        ngx_array_t                     addrs; /* array of ngx_http_conf_addr_t */
    }ngx_http_conf_port_t;
    
    ngx_int_t
    ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
        ngx_http_listen_opt_t *lsopt)
    {
        in_port_t                   p;
        ngx_uint_t                  i;
        struct sockaddr            *sa;
        ngx_http_conf_port_t       *port;
        ngx_http_core_main_conf_t  *cmcf;
    
        cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
    
        /* 若 ports 数组为空 */
        if (cmcf->ports == NULL) {
            /* posts 存放着该http{}配置块下监听的所有ngx_http_conf_port_t端口 */
            cmcf->ports = ngx_array_create(cf->temp_pool, 2,
                                           sizeof(ngx_http_conf_port_t));
            if (cmcf->ports == NULL) {
                return NGX_ERROR;
            }
        }
    
        sa = &lsopt->sockaddr.sockaddr;
        /* 获取当前监听的端口,返回值为主机字节序 */
        p = ngx_inet_get_port(sa);
    
        port = cmcf->ports->elts;
        /* 检测当前所要监听的端口是否已经存在 ports 数组中 */
        for (i = 0; i < cmcf->ports->nelts; i++) {
    
            if (p != port[i].port || sa->sa_family != port[i].family) {
                continue;
            }
    
            /* a port is already in the port list */
    
            return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);
        }
    
        /* add a port to the port list */
        
        /* 若当前所要监听的端口不存在 ports 数组中,则
         * 将该端口添加到 ports 数组中 */
        port = ngx_array_push(cmcf->ports);
        if (port == NULL) {
            return NGX_ERROR;
        }
        
        /* 端口的地址族 */
        port->family = sa->sa_family;
        /* 监听的端口 */
        port->port = p;
        port->addrs.elts = NULL;
    
        /* 为该端口添加地址 */
        return ngx_http_add_address(cf, cscf, port, lsopt);
    }
    

    对ngx_http_conf_port_t的addrs动态数组的理解:

    • 在nginx.conf配置文件中,对于同一个端口8000,我们可以同时监听127.0.0.1:8000、192.168.1.82:8000这两个地址,当一台物理主机具备多个IP地址时这是很有用的。具体到HTTP框架的实现上,Nginx是使用ngx_http_conf_addr_t结构体来表示一个对应着具体地址的监听端口的,因此,一个ngx_http_conf_port_t将会对应多个ngx_http_conf_addr_t,而ngx_http_conf_addr_t就是以动态数组的形式保存在addrs成员中的.

    3.1 ngx_http_add_address

    typedef struct {
        /* 监听套接字的各种属性 */
        ngx_http_listen_opt_t           opt;
    
        /* 以下3个散列表用于加速寻找对应监听端口上的新连接,确定到底使用哪个server{}
         * 虚拟主机下的配置来处理它。所以,散列表的值就是ngx_http_core_srv_conf_t
         * 结构体的地址 */
    
        /* 完全匹配server name的散列表 */
        ngx_hash_t                      hash;
        /* 通配符前置的散列表 */
        ngx_hash_wildcard_t            *wc_head;
        /* 通配符后置的散列表 */
        ngx_hash_wildcard_t            *wc_tail;
    
    #if (NGX_PCRE)
        /* 下面的regex数组中元素的个数 */
        ngx_uint_t                      nregex;
        /* regex指向静态数组,其数组成员就是ngx_http_server_name_t结构体,
         * 表示正则表达式及其匹配的server{}虚拟主机 */
        ngx_http_server_name_t         *regex;
    #endif
    
        /* 该监听端口下对应的默认server{}虚拟主机 */
        /* the default server configuration for this address:port */
        ngx_http_core_srv_conf_t       *default_server;
        /* servers动态数组中的成员将指向ngx_http_core_srv_conf_t结构体 */
        ngx_array_t                     servers; /* array of ngx_http_core_srv_conf_t */
    }ngx_http_conf_addr_t;
    
    /*
     * add the server address, the server names and the server core module
     * configurations to the port list.
     */
    static ngx_int_t
    ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
        ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
    {
        ngx_http_conf_addr_t  *addr;
    
        /* 一个端口可能对应几个主机地址,具体看当前主机有多少个 ip 地址 */
        if (port->addrs.elts == NULL) {
            if (ngx_array_init(&port->addrs, cf->temp_pool, 4,
                               sizeof(ngx_http_conf_addr_t))
                != NGX_OK)
            {
                return NGX_ERROR;
            }
        }
    
    #if (NGX_HTTP_V2 && NGX_HTTP_SSL                                              
         && !defined TLSEXT_TYPE_application_layer_protocol_negotiation           
         && !defined TLSEXT_TYPE_next_proto_neg)
    
        if (lsopt->http2 && lsopt->ssl) {
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "nginx was built with OpenSSL that lacks ALPN "
                               "and NPN support, HTTP/2 is not enabled for %s",
                               lsopt->addr);
        }
    
    #endif
    
        /* 向该 port->addrs 数组中添加一个地址 */
        addr = ngx_array_push(&port->addrs);
        if (addr == NULL) {
            return NGX_ERROR;
        }
    
        addr->opt = *lsopt;
        addr->hash.buckets = NULL;
        addr->hash.size = 0;
        addr->wc_head = NULL;
        addr->wc_tail = NULL;
    #if (NGX_PCRE)
        addr->nregex = 0;
        addr->regex = NULL;
    #endif
        addr->default_server = cscf;
        addr->servers.elts = NULL;
    
        return ngx_http_add_server(cf, cscf, addr);
    }
    

    3.2 ngx_http_add_server

    /* 
     * add the server core module configuration to the address:port 
     */
    static ngx_int_t
    ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
        ngx_http_conf_addr_t *addr)
    {
        ngx_uint_t                  i;
        ngx_http_core_srv_conf_t  **server;
    
        /* servers动态数组中的成员将指向ngx_http_core_srv_conf_t结构体 */
        if (addr->servers.elts == NULL) {
            if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
                               sizeof(ngx_http_core_srv_conf_t *))
                != NGX_OK)
            {
                return NGX_ERROR;
            }
    
        } else {
            server = addr->servers.elts;
            for (i = 0; i < addr->servers.nelts; i++) {
                if (server[i] == cscf) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "a duplicate listen %s", addr->opt.addr);
                    return NGX_ERROR;
                }
            }
        }
    
        /* 向该数组中添加一个 ngx_http_core_srv_conf_t 结构体 */
        server = ngx_array_push(&addr->servers);
        if (server == NULL) {
            return NGX_ERROR;
        }
    
        /* 将当前 listen 指令所在的 server{} 下 srv 相关配置项的
         * ngx_http_core_srv_conf_t 添加到 servers 数组中 */
        *server = cscf;
    
        return NGX_OK;
    }
    
  • 相关阅读:
    TTL电平和CMOS电平总结
    掩码
    关于Autosar中DCM(14229UDS)模块的理解
    Diagnostic Trouble Code诊断故障码
    eclipse搭建android开发环境
    在ubuntu下安装zookeeper
    redis的windows版本下载地址及windows的客户端工具
    最简单的启动并连接一个redis的docker容器
    转:Redis介绍及常用命令大全
    redis常用命令
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9206749.html
Copyright © 2020-2023  润新知