• Nginx-HTTP之框架的初始化


    http 框架的初始化与 nginx-rtmp 框架的初始化类似: Nginx-rtmp之配置项的管理

    1. ngx_http_module_t

    ngx_http_module 核心模块定义了新的模块类型 NGX_HTTP_MODULE。这样的 HTTP 模块对于 ctx 上下文使用了不同于核心模块、事件模块的新接口 ngx_http_module_t。对于每一个 HTTMP 模块,都必须实现 ngx_http_module_t 接口。

    typedef struct {
        /* 
         * 在解析 http{} 内的配置项前调用 
         */
        ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
        /* 
         * 解析完 http{} 内的所有配置后回调
         */
        ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
    
        /* 
         * 创建用于存储 HTTP 全局配置项的结构体,该结构体中的成员将保存直属于
         * http{} 块的配置项参数,它会在解析 main 配置项前调用 
         */
        void       *(*create_main_conf)(ngx_conf_t *cf);
        /* 
         * 解析完 main 配置项后回调 
         */
        char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
        
        /* 
         * 创建用于存储可同时出现在 main、srv 级别配置项的结构体,该结构体中的成员
         * 与 server 配置是相关联的 
         */
        void       *(*create_srv_conf)(ngx_conf_t *cf);
        /* 
         * create_srv_conf 产生的结构体所要解析的配置项,可能同时出现在 main、srv 级别中,
         * merge_srv_conf 方法可以把出现在 main 级别中的配置项合并到 srv 级别配置项中 
         */
        char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
    
        /*
         * 创建可用于存储可同时出现在 main、srv、loc 级别配置项的结构体,该结构体中的成员与 
         * location 配置是相关联的 
         */
        void       *(*create_loc_conf)(ngx_conf_t *cf);
        /*
         * create_loc_conf 产生的结构体所要解析的配置项,可能同时出现在 main、srv、loc 级别中,
         * merge_loc_conf 方法可以分别把出现在 main、serv 级别中的配置项值合并到 loc 级别的
         * 配置项中
         */
        char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
    } ngx_http_module_t;
    

    2. ngx_http_conf_ctx_t

    typedef struct {
        /*
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_main_conf 
         * 方法创建的存放全局配置项的结构体,它们存放着解析直属于 http{} 块内的 main
         * 级别的配置项参数.
         */
        void        **main_conf;
        /*
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_srv_conf
         * 方法创建的与 server 相关的结构体,它们或存放 main 级别的配置项,或存放
         * srv 级别的配置项,这与当前 ngx_http_conf_t 是在解析 http{} 或者 server{}
         * 块时创建的有关
         */
        void        **srv_conf;
        /*
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_loc_conf 
         * 方法创建的与 location 相关的结构体,它们可能存放着 main、srv、loc 级别的
         * 配置项,这与当前的 ngx_http_conf_ctx_t 是在解析 http{}、server{} 或者
         * location{} 块时创建有关的
         */
        void        **loc_conf;
    } ngx_http_conf_ctx_t;
    

    在核心结构体 ngx_cycle_t 的 conf_ctx 成员指向的指针数组中,第 8 个指针由 ngx_http_module 模块使用(假设当前没有添加任何第三方模块,且使用默认配置时,则 ngx_http_module 模块的 index 序号为 7,由于从 0 开始,所以它在 ngx_modules 数组中排行第 8。在存放全局配置结构体的 conf_ctx 数组中,第 8 个成员指向 ngx_http_module 模块),这个指针设置为指向解析 http{} 块时生成的 ngx_http_conf_ctx_t 结构体,而 ngx_http_conf_ctx_t 的 3 个成员则分别指向新分配的 3 个指针数组新的指针数组中成员的意义由每个 HTTP 模块的 ctx_index 序号指定(ctx_index 在 HTTP 模块中表明它处于 HTTP 模块间的序号)。

    在 ngx_cycle_t 核心结构体找到 main 级别的配置结构体的方法如下:

    #define ngx_http_cycle_get_module_main_conf(cycle, module)                    
        (cycle->conf_ctx[ngx_http_module.index] ?                                 
            ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index])      
                ->main_conf[module.ctx_index]:                                    
            NULL)
    

    3. ngx_http_block

    static char *
    ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        char                        *rv;
        ngx_uint_t                   mi, m, s;
        ngx_conf_t                   pcf;
        ngx_http_module_t           *module;
        ngx_http_conf_ctx_t         *ctx;
        ngx_http_core_loc_conf_t    *clcf;
        ngx_http_core_srv_conf_t   **cscfp;
        ngx_http_core_main_conf_t   *cmcf;
    
        /* ngx_http_conf_ctx_t 结构体必须在解析 http{} 时分配 */
        if (*(ngx_http_conf_ctx_t **) conf) {
            return "is duplicate";
        }
    
        /* the main http context */
    
        /* 为 ngx_http_conf_ctx_t 结构体分配内存,该结构体管理着解析 http{} 
         * 时所有 HTTP 模块的配置项 */
        ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
        if (ctx == NULL) {
            return NGX_CONF_ERROR;
        }
    
        /* 传入的 conf 指针为核心结构体 ngx_cycle_t 中成员 conf_ctx 指针数组
         * 中的第 8 号元素,即序号为 7 的元素,该 conf_ctx[7] 元素是给 
         * 核心模块 ngx_http_module 使用的 */
        *(ngx_http_conf_ctx_t **) conf = ctx;
    
    
        /* count the number of the http modules and set up their indices */
    
        ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);
    
    
        /* the http main_conf context, it is the same in the all http contexts */
    
        /*
         * main_conf:
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_main_conf 
         * 方法创建的存放全局配置项的结构体,它们存放着解析直属于 http{} 块内的 main
         * 级别的配置项参数.
         */
        ctx->main_conf = ngx_pcalloc(cf->pool,
                                     sizeof(void *) * ngx_http_max_module);
        if (ctx->main_conf == NULL) {
            return NGX_CONF_ERROR;
        }
    
    
        /*
         * the http null srv_conf context, it is used to merge
         * the server{}s' srv_conf's
         */
    
        /*
         * srv_conf:
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_srv_conf
         * 方法创建的与 server 相关的结构体,它们或存放 main 级别的配置项,或存放
         * srv 级别的配置项,这与当前 ngx_http_conf_t 是在解析 http{} 或者 server{}
         * 块时创建的有关
         */
        ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
        if (ctx->srv_conf == NULL) {
            return NGX_CONF_ERROR;
        }
    
    
        /*
         * the http null loc_conf context, it is used to merge
         * the server{}s' loc_conf's
         */
    
        /*
         * loc_conf:
         * 指向一个指针数组,数组中的每个成员都是由所有 HTTP 模块的 create_loc_conf 
         * 方法创建的与 location 相关的结构体,它们可能存放着 main、srv、loc 级别的
         * 配置项,这与当前的 ngx_http_conf_ctx_t 是在解析 http{}、server{} 或者
         * location{} 块时创建有关的
         */
        ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
        if (ctx->loc_conf == NULL) {
            return NGX_CONF_ERROR;
        }
    
    
        /*
         * create the main_conf's, the null srv_conf's, and the null loc_conf's
         * of the all http modules
         */
    
        /* 在开始解析 http{} 的 main 级别的配置项前,调用所有 HTTP 模块的
         * create_main_conf、create_srv_conf 以及 create_loc_conf 方法,
         * 分别创建用于存放于 main、srv、location 相关的配置项结构体,
         * 这三个方法返回的配置项结构体分别存放在 ngx_http_conf_ctx_t 
         * 的成员 main_conf、srv_conf 以及 loc_conf 这个三个指针数组
         * 中该模块的 ctx_index 对应的下标处 */
    
        /* 遍历所有的 HTTP 模块 */
        for (m = 0; cf->cycle->modules[m]; m++) {
            if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            /* 获取该模块的上下文结构体 */
            module = cf->cycle->modules[m]->ctx;
            /* 该模块在 HTTP 模块中的序号 */
            mi = cf->cycle->modules[m]->ctx_index;
    
            /* 调用该 HTTP 模块的 create_main_conf 方法,创建存放全局
             * 配置项的结构体 */
            if (module->create_main_conf) {
                ctx->main_conf[mi] = module->create_main_conf(cf);
                if (ctx->main_conf[mi] == NULL) {
                    return NGX_CONF_ERROR;
                }
            }
    
            /* 调用该模块的 create_srv_conf,创建存放与 server{} 相关的
             * 配置项结构体,该结构体可能存放着 main 或 server 级别的
             * 配置项 */
            if (module->create_srv_conf) {
                ctx->srv_conf[mi] = module->create_srv_conf(cf);
                if (ctx->srv_conf[mi] == NULL) {
                    return NGX_CONF_ERROR;
                }
            }
    
            /* 调用该模块的 create_loc_conf,创建存放于 location 相关的
             * 配置项结构体,该结构体可能存放 main、server 或 location
             * 级别的配置项 */
            if (module->create_loc_conf) {
                ctx->loc_conf[mi] = module->create_loc_conf(cf);
                if (ctx->loc_conf[mi] == NULL) {
                    return NGX_CONF_ERROR;
                }
            }
        }
    
        /* 临时缓存 cf 和 ctx 变量 */
        pcf = *cf;
        cf->ctx = ctx;
    
        /* 在解析配置项前调用所有模块的 precofiguration 函数,
         * 该函数主要是将一些 variable 添加到 ngx_http_core_main_conf_t
         * 结构体中的 variables_keys 哈希数组中,主要有以下几个 http 模块
         * 实现了该函数:
         * ngx_http_core_module
         * ngx_http_upstream
         * ngx_http_proxy_module 等等,还有很多 */
        for (m = 0; cf->cycle->modules[m]; m++) {
            if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = cf->cycle->modules[m]->ctx;
    
            if (module->preconfiguration) {
                if (module->preconfiguration(cf) != NGX_OK) {
                    return NGX_CONF_ERROR;
                }
            }
        }
    
        /* parse inside the http{} block */
    
        /* 设置当前解析的模块类型为 HTTP 模块 */
        cf->module_type = NGX_HTTP_MODULE;
        /* 设置当前解析配置项为 main 级别的 */
        cf->cmd_type = NGX_HTTP_MAIN_CONF;
        /* 开始解析 http{} 中的配置项 */
        rv = ngx_conf_parse(cf, NULL);
    
        if (rv != NGX_CONF_OK) {
            goto failed;
        }
    
        /*
         * init http{} main_conf's, merge the server{}s' srv_conf's
         * and its location{}s' loc_conf's
         */
    
        /* cmcf是ngx_http_core_module在http下的全局配置结构体,它的servers成员
         * 是一个动态数组,保存着所有ngx_http_core_srv_conf_t的指针,从而关联了
         * 所有的server块 */
        cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
        cscfp = cmcf->servers.elts;
    
        for (m = 0; cf->cycle->modules[m]; m++) {
            if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = cf->cycle->modules[m]->ctx;
            mi = cf->cycle->modules[m]->ctx_index;
    
            /* init http{} main_conf's */
    
            /* 解析配置项完成后,调用所有模块的 init_main_conf 方法,
             * 初始化所有模块与 main 相关的配置项结构体中各成员的值 */
            if (module->init_main_conf) {
                rv = module->init_main_conf(cf, ctx->main_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
    
            /* 合并配置项值 */
            rv = ngx_http_merge_servers(cf, cmcf, module, mi);
            if (rv != NGX_CONF_OK) {
                goto failed;
            }
        }
    
    
        /* create location trees */
    
        for (s = 0; s < cmcf->servers.nelts; s++) {
            
            /* clcf是server块下ngx_http_core_loc_conf_t结构体,
             * 它的locations成员以双向链表关联着隶属于这个server块的
             * 所有location块对应的ngx_http_core_loc_conf_t结构体 */
            clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
    
            /* 将ngx_http_core_loc_conf_t组成的双向链表按照location匹配字符串
             * 进行排序。注意,这个操作是递归进行的,如果某个location块下还具
             * 有其他location,那么它的locations链表也会被排序 */
            if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        
            /* 根据已经按照locations字符串排序过的双向链表,快速地构建
             * 静态的二叉查找树。与ngx_http_init_locations方法类似,
             * 这个操作也是递归进行的 */
            if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    
        /*
         * 为 cmcf->phases 数组分配内存,该数组的每一个元素都为 ngx_http_phase_t 类型的结构体,
         * phases 数组是用于在 HTTP 框架初始化时帮助各个 HTTP 模块在任意阶段中添加 HTTP 处理方
         * 法,它是一个有 11 个成员的 ngx_http_phase_t 数组,其中每一个 ngx_http_phase_t 结构体
         * 对应一个 HTTP 阶段。在 HTTP 框架初始化完毕后,运行过程中的 phases 数组是无用的.
         */
        if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        /* 将一些常用的 HTTP 头部字段及其处理方法存放到一个散列表中 */
        if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
    
        /* postconfiguration 主要做的事情有:
         * 1. 向 cmcf->phases 数组中插入该 HTTP 模块对某个阶段的处理方法 
         * 2. 向 ngx_http_top_header_filter、ngx_http_top_body_filter、
         *    ngx_http_top_request_body_filter 这三个单链表中添加自己的处理方法
         * 3. 有些特殊模块仅是检测当前的配置是否合理,如 charset 模块等 */
        for (m = 0; cf->cycle->modules[m]; m++) {
            if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = cf->cycle->modules[m]->ctx;
    
            if (module->postconfiguration) {
                if (module->postconfiguration(cf) != NGX_OK) {
                    return NGX_CONF_ERROR;
                }
            }
        }
    
        /* 初始化 http variables,并将其保存到 hash 表中 */
        if (ngx_http_variables_init_vars(cf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        /*
         * http{}'s cf->ctx was needed while the configuration merging
         * and in postconfiguration process
         */
    
        *cf = pcf;
    
        /* 初始化各个阶段所有 HTTP 模块介入的处理方法 */
        if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
    
        /* optimize the lists of ports, addresses and server names */
    
        if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        return NGX_CONF_OK;
    
    failed:
    
        *cf = pcf;
    
        return rv;
    }
    

    4. ngx_http_core_server

    当解析到 http{} 中的 server{} 时,回调该函数进行解析。

    static char *
    ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
    {
        char                        *rv;
        void                        *mconf;
        ngx_uint_t                   i;
        ngx_conf_t                   pcf;
        ngx_http_module_t           *module;
        struct sockaddr_in          *sin;
        ngx_http_conf_ctx_t         *ctx, *http_ctx;
        ngx_http_listen_opt_t        lsopt;
        ngx_http_core_srv_conf_t    *cscf, **cscfp;
        ngx_http_core_main_conf_t   *cmcf;
    
        /* 当开始解析 server{} 时,创建一个属于该 server{} 下的
         * ngx_http_conf_ctx_t 结构体,该结构体中有三个指针数组,
         * 分别为 main_conf、srv_conf、loc_conf */
        ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
        if (ctx == NULL) {
            return NGX_CONF_ERROR;
        }
    
        /* 传入的 cf->ctx 上下文结构体指向当前 server{} 所属的 http{}
         * 解析 main 级别时创建的 ngx_http_conf_ctx_t 结构体 */
        http_ctx = cf->ctx;
        /* 将当前 server{} 所属的 ngx_http_conf_ctx_t 的 main_conf 指针
         * 指向 http{} 下解析 main{} 级别时创建的 ngx_http_conf_ctx_t 
         * 结构体的 main_conf 成员 */
        ctx->main_conf = http_ctx->main_conf;
    
        /* 下面调用所有 http 模块的 create_srv_conf 和 create_loc_conf 
         * 方法,为所有的 http 模块创建该模块与 server{} 和 location{}
         * 相关的配置项结构体 */
        /* the server{}'s srv_conf */
    
        ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
        if (ctx->srv_conf == NULL) {
            return NGX_CONF_ERROR;
        }
    
        /* the server{}'s loc_conf */
    
        ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
        if (ctx->loc_conf == NULL) {
            return NGX_CONF_ERROR;
        }
    
        for (i = 0; cf->cycle->modules[i]; i++) {
            if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
                continue;
            }
    
            module = cf->cycle->modules[i]->ctx;
    
            if (module->create_srv_conf) {
                mconf = module->create_srv_conf(cf);
                if (mconf == NULL) {
                    return NGX_CONF_ERROR;
                }
    
                ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;
            }
    
            if (module->create_loc_conf) {
                mconf = module->create_loc_conf(cf);
                if (mconf == NULL) {
                    return NGX_CONF_ERROR;
                }
    
                ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
            }
        }
    
    
        /* the server configuration context */
    
        /* 获取该 server{} 下与 srv 级别相关的第一个模块的配置结构体 */
        cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
        /* 指向当前 server{} 所属的 ngx_http_conf_ctx_t 结构体 */
        cscf->ctx = ctx;
    
        cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
    
        /* 从 servers 数组中取出一个空闲的元素,servers 数组中的每一项
         * 元素的类型都为 ngx_http_core_srv_conf_t 结构体类型,保存着
         * http{} 下每一个 server{} 所属的 ngx_http_conf_ctx_t 结构体中
         * srv_conf 指针数组的第一个元素,即 srv_conf[0],实际上该元素
         * 指向该 server{} 下与 srv 级别相关的第一个模块即
         * ngx_http_core_module 模块的配置项结构体 */
        cscfp = ngx_array_push(&cmcf->servers);
        if (cscfp == NULL) {
            return NGX_CONF_ERROR;
        }
    
        /* 将该结构体存到 servers 数组中 */
        *cscfp = cscf;
    
    
        /* parse inside server{} */
    
        /* 临时缓存变量 */
        pcf = *cf;
        /* 此时开始解析 server{},因此需要更新当前所属的上下文为
         * server{} 所属的 ngx_http_conf_ctx_t 结构体 */
        cf->ctx = ctx;
        /* 设置当前指令的类型为 srv 级别 */
        cf->cmd_type = NGX_HTTP_SRV_CONF;
    
        /* 开始解析 server{} 下的配置项 */
        rv = ngx_conf_parse(cf, NULL);
    
        /* 重新恢复之前的缓存的值 */
        *cf = pcf;
    
        /* 若解析 server{} 成功且 server{} 下没有解析到 listen 指令,
         * 则下面默认监听一个端口 */
        if (rv == NGX_CONF_OK && !cscf->listen) {
            ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
    
            sin = &lsopt.sockaddr.sockaddr_in;
    
            sin->sin_family = AF_INET;
    #if (NGX_WIN32)
            sin->sin_port = htons(80);
    #else
            sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
    #endif
            sin->sin_addr.s_addr = INADDR_ANY;
    
            lsopt.socklen = sizeof(struct sockaddr_in);
    
            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 = 1;
    
            (void) ngx_sock_ntop(&lsopt.sockaddr.sockaddr, lsopt.socklen,
                                 lsopt.addr, NGX_SOCKADDR_STRLEN, 1);
    
            if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    
        return rv;
    }
    

    5. ngx_http_merge_servers

    static char *
    ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
        ngx_http_module_t *module, ngx_uint_t ctx_index)
    {
        char                        *rv;
        ngx_uint_t                   s;
        ngx_http_conf_ctx_t         *ctx, saved;
        ngx_http_core_loc_conf_t    *clcf;
        ngx_http_core_srv_conf_t   **cscfp;
    
        /* cmcf是ngx_http_core_module在http下的全局配置结构体,它的servers成员
         * 是一个动态数组,保存着所有ngx_http_core_srv_conf_t的指针,从而关联了
         * 所有的server块 */
        cscfp = cmcf->servers.elts;
        /* 将 ctx 指向 http{} 下解析 main 级别时创建的全局配置项上下文结构体 */
        ctx = (ngx_http_conf_ctx_t *) cf->ctx;
        saved = *ctx;
        rv = NGX_CONF_OK;
    
        /* 遍历 http{} 下所有的 server{}  */
        for (s = 0; s < cmcf->servers.nelts; s++) {
    
            /* merge the server{}s' srv_conf's */
    
            /* 将 ctx->srv_conf 指向 当前 server{} 所属的上下文结构体
             * ngx_http_conf_ctx_t 中的 srv_conf 指针数组 */
            ctx->srv_conf = cscfp[s]->ctx->srv_conf;
    
            /* 调用该模块的 merge_srv_conf 函数,将同时出现在 main
             * 级别下的配置项合并到 srv 级别下(前提是该配置项没有出现在
             * srv级别下,若出现了,则不需要合并,直接以 srv 级别下的为主)*/
            if (module->merge_srv_conf) {
                rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
                                            cscfp[s]->ctx->srv_conf[ctx_index]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
    
            if (module->merge_loc_conf) {
    
                /* merge the server{}'s loc_conf */
    
                /* 将 ctx->loc_conf 指向当前 server{} 下的
                 * loc_conf 指针数组 */
                ctx->loc_conf = cscfp[s]->ctx->loc_conf;
    
                /* 将 mian、srv 级别下的配置项合并到 loc 级别下 */
                rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
                                            cscfp[s]->ctx->loc_conf[ctx_index]);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
    
                /* merge the locations{}' loc_conf's */
    
                /* clcf是server块下ngx_http_core_module模块使用create_loc_conf方法产生的
                 * ngx_http_core_loc_conf_t结构体,它的locations成员将以双向链表的形式关联
                 * 到所有当前server{}块下的location块 */
                clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
    
                /* 调用ngx_http_merge_locations方法,将server{}块与其所包含的location{}块下
                 * 的结构体进行合并 */
                rv = ngx_http_merge_locations(cf, clcf->locations,
                                              cscfp[s]->ctx->loc_conf,
                                              module, ctx_index);
                if (rv != NGX_CONF_OK) {
                    goto failed;
                }
            }
        }
    
    failed:
    
        *ctx = saved;
    
        return rv;
    }
    

    6. ngx_http_merge_locations

    static char *
    ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
        void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
    {
        char                       *rv;
        ngx_queue_t                *q;
        ngx_http_conf_ctx_t        *ctx, saved;
        ngx_http_core_loc_conf_t   *clcf;
        ngx_http_location_queue_t  *lq;
        
        /* 如果locations链表为空,也就是说,当前server下没有location块,
         * 则立即返回 */
        if (locations == NULL) {
            return NGX_CONF_OK;
        }
    
        ctx = (ngx_http_conf_ctx_t *) cf->ctx;
        saved = *ctx;
    
        /* 遍历locations双向链表 */
        for (q = ngx_queue_head(locations);
             q != ngx_queue_sentinel(locations);
             q = ngx_queue_next(q))
        {
            lq = (ngx_http_location_queue_t *) q;
            
            /* 如果locations后的匹配字符串不依靠Nginx自定义的通配符就可以完全匹配的话,
             * 则exact指向当前locations对应的ngx_http_core_loc_conf_t结构体,否则使用
             * inclusive指向该结构体,且exact的优先级高于inclusive */
            clcf = lq->exact ? lq->exact : lq->inclusive;
            /* clcf->loc_conf这个指针数组里保存着当前location下所有HTTP模块使用
             * create_loc_conf方法生成的结构体的指针 */
            ctx->loc_conf = clcf->loc_conf;
    
            /* 调用merge_loc_conf方法合并srv、loc级别配置项 */
            rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
                                        clcf->loc_conf[ctx_index]);
            if (rv != NGX_CONF_OK) {
                return rv;
            }
    
            /* 注意,因为location{}中可以嵌套location{}配置块,
             * 所以是可以继续合并的。 */
            rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
                                          module, ctx_index);
            if (rv != NGX_CONF_OK) {
                return rv;
            }
        }
    
        *ctx = saved;
    
        return NGX_CONF_OK;
    }
    

    7. ngx_http_init_headers_in_hash

    将 HTTP 的一些常用的头部字段以及该字段对应的处理方法添加到 hash 表中,便于后续处理 HTTP 数据时可以快速找到该字段,并进行处理。

    static ngx_int_t
    ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
    {
        ngx_array_t         headers_in;
        ngx_hash_key_t     *hk;
        ngx_hash_init_t     hash;
        ngx_http_header_t  *header;
    
        if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
            != NGX_OK)
        {
            return NGX_ERROR;
        }
    
        for (header = ngx_http_headers_in; header->name.len; header++) {
            hk = ngx_array_push(&headers_in);
            if (hk == NULL) {
                return NGX_ERROR;
            }
    
            /* 元素关键字为该头部字段名称 */
            hk->key = header->name;
            /* 以头部字段为关键字,通过散列方法 ngx_hash_key_lc 算出来的
             * 关键码保存在 key_hash 中 */
            hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
            /* value 指向用户自定义的数据结构 */
            hk->value = header;
        }
    
        /* 指向普通的完全匹配散列表 */
        hash.hash = &cmcf->headers_in_hash;
        /* 用于初始化添加元素的散列方法 */
        hash.key = ngx_hash_key_lc;
        /* 散列表中槽的最大数目 */
        hash.max_size = 512;
        /* 散列表中一个槽的空间大小,它限制了每个散列表元素关键字的最大长度 */
        hash.bucket_size = ngx_align(64, ngx_cacheline_size);
        /* 散列表的名称 */
        hash.name = "headers_in_hash";
        /* 内存池,它分配散列表(最多3个,包括 1 个普通散列表、1个前置通配符
         * 散列表、1个后置通配符散列表)中的所有槽 */
        hash.pool = cf->pool;
        /* 临时内存池,它仅存在于初始化散列表之前。它主要用于分配一些临时的动态数组,
         * 带通配符的元素在初始化时需要用到这些数组 */
        hash.temp_pool = NULL;
    
        /* 初始化一个基本的散列表 */
        if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
            return NGX_ERROR;
        }
    
        return NGX_OK;
    }
    

    8. ngx_http_init_phase_handlers

    typedef struct ngx_http_phase_handler_s  ngx_http_phase_handler_t;
    
    /*
     * 一个 HTTP 处理阶段的 checker 检查方法,仅可以由 HTTP 框架实现,
     * 以此控制 HTTP 请求的处理流程
     */
    typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r,
        ngx_http_phase_handler_t *ph);
    
    /*
     * 该结构体仅表示处理阶段中的一个处理方法
     */
    struct ngx_http_phase_handler_s {
        /*
         * 在处理某一个 HTTP 阶段时,HTTP 框架将会在 checker 方法已实现的前提下
         * 首先调用 checker 方法来处理请求,而不会直接调用任何阶段中的 handler 
         * 方法,只有在 checker 方法中才会去调用 handler 方法。因此,事实上所有
         * 的 checker 方法都是由框架中的 ngx_http_core_module 模块实现的,且普通
         * 的 HTTP 模块无法重定义 checker 方法
         */
        ngx_http_phase_handler_pt  checker;
        /*
         * 除 ngx_http_core_module 模块以外的 HTTP 模块,只能通过定义 handler 
         * 方法才能介入某一个 HTTP 处理阶段以处理请求.
         */
        ngx_http_handler_pt        handler;
        /*
         * 将要执行的下一个 HTTP 处理阶段的序号.
         * next 的设计使得处理阶段不必按顺序依次执行,即可以向后跳跃数个阶段继续
         * 执行,也可以跳跃到之前曾经执行过的某个阶段重新执行。通常,next 表示
         * 下一个处理阶段中的第 1 个 ngx_http_phase_handler_t 处理方法
         */
        ngx_uint_t                 next;
    };
    
    typedef enum {
        /* 
         * 在接收到完整的HTTP头部后处理的HTTP阶段 
         */
        NGX_HTTP_POST_READ_PHASE = 0,
    
        /* 
         * 在将请求的 URI 与 location 表达式匹配前,修改请求的 URI 
         * (所谓的重定向)是一个独立的HTTP阶段 
         */
        NGX_HTTP_SERVER_REWRITE_PHASE,
    
        /*
         * 根据请求的 URI 寻找匹配的 location 表达式,这个阶段只能由
         * ngx_http_core_module 模块实现,不建议其他 HTTP 模块重新
         * 定义这一阶段的行为.
         */
        NGX_HTTP_FIND_CONFIG_PHASE,
        /*
         * 在 NGX_HTTP_FIND_CONFIG_PHASE 阶段寻找到匹配的 location
         * 之后再修改请求的 URI.
         */
        NGX_HTTP_REWRITE_PHASE,
        /*
         * 这一阶段是用于在 rewrite 重写 URL 后,防止错误的 nginx.conf 
         * 配置导致死循环(递归地修改 URI),因此,这一阶段仅由
         * ngx_http_core_module 模块处理。目前,控制死循环的方式很简单,
         * 首先检查 rewrite 的次数,如果一个请求超过 10 次重定向,就认为
         * 进入了 rewrite 死循环,这时在 NGX_HTTP_POST_REWRITE_PHASE 阶段
         * 就会向用户返回 500,表示服务器内部错误.
         */
        NGX_HTTP_POST_REWRITE_PHASE,
    
        /*
         * 表示在处理 NGX_HTTP_ACCESS_PHASE 阶段决定请求的访问权限前,
         * HTTP 模块可以介入的处理阶段.
         */
        NGX_HTTP_PREACCESS_PHASE,
    
        /*
         * 这个阶段用于让 HTTP 模块判断是否允许这个请求访问服务器.
         */
        NGX_HTTP_ACCESS_PHASE,
        /*
         * 在 NGX_HTTP_ACCESS_PHASE 阶段中,当 HTTP 模块的 handler 处理
         * 函数返回不允许访问的错误码时(实际就是 NGX_HTTP_FORBIDDEN 或
         * NGX_HTTP_UNAUTHORIZED),这里将负责向用户发送拒绝服务的错误
         * 响应。因此,这个阶段实际上用于给 NGX_HTTP_ACCESS_PHASE 阶段
         * 收尾.
         */
        NGX_HTTP_POST_ACCESS_PHASE,
    
        /*
         * 这个阶段完全是 try_files 配置项而设计的,当 HTTP 请求访问静态
         * 文件资源时,try_files 配置项可以使这个请求顺序地访问多个静态
         * 文件资源,如果某一次访问失败,则继续访问 try_files 中指定的
         * 下一个静态资源。这个功能完全是在 NGX_HTTP_TRY_FILES_PHASE 阶段
         * 实现的.
         */
        NGX_HTTP_TRY_FILES_PHASE,
        /*
         * 用于处理 HTTP 请求内容的阶段,这是大部分 HTTP 模块最愿意介入
         * 阶段
         */
        NGX_HTTP_CONTENT_PHASE,
    
        /*
         * 处理完请求后记录日志的阶段。如,ngx_http_log_module 模块就在
         * 这个阶段中加入了一个 handler 处理方法,使得每个 HTTP 请求
         * 处理完毕后会记录 access_log 访问日志.
         */
        NGX_HTTP_LOG_PHASE
    } ngx_http_phases;
    
    typedef struct {
        /* 
         * handlers 是由 ngx_http_phase_handler_t 构成的数组首地址,它表示
         * 一个请求可能经历的所有 ngx_http_handle_pt 处理方法
         */
        ngx_http_phase_handler_t  *handlers;
        /*
         * 表示 NGX_HTTP_SERVER_REWRITE_PAHSE 阶段第 1 个 ngx_http_phase_handler_t
         * 处理方法在 handlers 数组中的序号,用于在执行 HTTP 请求的任何阶段中快速
         * 跳转到 NGX_HTTP_SERVER_REWRITE_PHASE 阶段处理请求.
         */
        ngx_uint_t                 server_rewrite_index;
        /*
         * 表示 NGX_HTTP_REWRITE_PHASE 阶段第 1 个 ngx_http_phase_handler_t 处理
         * 方法在 handlers 数组中的序号,用于在执行 HTTP 请求的任何阶段中快速跳转
         * 到 NGX_HTTP_REWRITE_PHASE 阶段处理请求.
         */
        ngx_uint_t                 location_rewrite_index;
    } ngx_http_phase_engine_t;
    
    static ngx_int_t
    ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
    {
        ngx_int_t                   j;
        ngx_uint_t                  i, n;
        ngx_uint_t                  find_config_index, use_rewrite, use_access;
        ngx_http_handler_pt        *h;
        ngx_http_phase_handler_t   *ph;
        ngx_http_phase_handler_pt   checker;
    
        cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
        cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
        find_config_index = 0;
        /* 检测当前是否有 HTTP 模块介入到 NGX_HTTP_REWRITE_PHASE 阶段 */
        use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
        /* 检测当前是否有 HTTP 模块介入到 NGX_HTTP_ACCESS_PHASE 阶段 */
        use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
    
        n = 1                  /* find config phase */
            + use_rewrite      /* post rewrite phase */
            + use_access       /* post access phase */
            + cmcf->try_files;
    
        /* 统计phases数组中每个阶段的的 handlers 之和 */
        for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
            n += cmcf->phases[i].handlers.nelts;
        }
    
        ph = ngx_pcalloc(cf->pool,
                         n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
        if (ph == NULL) {
            return NGX_ERROR;
        }
    
    
        /* handlers 是由 ngx_http_phase_handler_t 构成的数组首地址,它表示
         * 一个请求可能经历的所有 ngx_http_handle_pt 处理方法
         */
        cmcf->phase_engine.handlers = ph;
        n = 0;
    
        for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
            h = cmcf->phases[i].handlers.elts;
    
            switch (i) {
    
            /* 
             * 在将请求的 URI 与 location 表达式匹配前,修改请求的 URI 
             * (所谓的重定向)是一个独立的 HTTP 阶段 
             */
            case NGX_HTTP_SERVER_REWRITE_PHASE:
                if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
                    
                    /* 表示 NGX_HTTP_SERVER_REWRITE_PAHSE 阶段第 1 个 ngx_http_phase_handler_t
                     * 处理方法在 handlers 数组中的序号,用于在执行 HTTP 请求的任何阶段中快速
                     * 跳转到 NGX_HTTP_SERVER_REWRITE_PHASE 阶段处理请求.
                     */
                    cmcf->phase_engine.server_rewrite_index = n;
                }
                checker = ngx_http_core_rewrite_phase;
    
                break;
    
            /*
             * 根据请求的 URI 寻找匹配的 location 表达式,这个阶段只能由
             * ngx_http_core_module 模块实现,不建议其他 HTTP 模块重新
             * 定义这一阶段的行为.
             */
            case NGX_HTTP_FIND_CONFIG_PHASE:
                find_config_index = n;
    
                /*
                 * 在处理某一个 HTTP 阶段时,HTTP 框架将会在 checker 方法已实现的前提下
                 * 首先调用 checker 方法来处理请求,而不会直接调用任何阶段中的 handler 
                 * 方法,只有在 checker 方法中才会去调用 handler 方法。因此,事实上所有
                 * 的 checker 方法都是由框架中的 ngx_http_core_module 模块实现的,且普通
                 * 的 HTTP 模块无法重定义 checker 方法
                 */
                ph->checker = ngx_http_core_find_config_phase;
                n++;
                ph++;
    
                continue;
    
            /*
             * 在 NGX_HTTP_FIND_CONFIG_PHASE 阶段寻找到匹配的 location
             * 之后再修改请求的 URI.
             */
            case NGX_HTTP_REWRITE_PHASE:
                if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) { 
                    /*
                     * 表示 NGX_HTTP_REWRITE_PHASE 阶段第 1 个 ngx_http_phase_handler_t 处理
                     * 方法在 handlers 数组中的序号,用于在执行 HTTP 请求的任何阶段中快速跳转
                     * 到 NGX_HTTP_REWRITE_PHASE 阶段处理请求.
                     */
                    cmcf->phase_engine.location_rewrite_index = n;
                }
                checker = ngx_http_core_rewrite_phase;
    
                break;
    
            /* 这一阶段是用于在rewrite重写URL后,防止错误的nginx.conf配置导致死循环(递归地修改URI),
             * 因此,这一阶段仅由ngx_http_core_module模块处理。目前,控制死循环的方式很简单,首先
             * 检查 rewrite 的次数,如果一个请求超过10次重定向,就认为进入了rewrite死循环,这时在
             * NGX_HTTP_POST_REWRITE_PHASE阶段就会向用户返回500,表示服务器内部错误 */
            case NGX_HTTP_POST_REWRITE_PHASE:
                if (use_rewrite) {
                    ph->checker = ngx_http_core_post_rewrite_phase;
                    /* 将要执行的下一个HTTP处理阶段的序号.
                     * next的设计使得处理阶段不必按顺序依次执行,既可以向后跳跃数个阶段继续执行,
                     * 也可以跳跃到之前曾经执行过的某个阶段重新执行。通常,next表示下一个处理阶
                     * 段中的第1个 ngx_http_phase_handler_t 处理方法 */
                    ph->next = find_config_index;
                    n++;
                    ph++;
                }
    
                continue;
    
            /* 这个阶段用于让HTTP模块判断是否允许这个请求访问Nginx服务器 */
            case NGX_HTTP_ACCESS_PHASE:
                checker = ngx_http_core_access_phase;
                n++;
                break;
    
            /* 在NGX_HTTP_ACCESS_PHASE阶段中,当HTTP模块的handler处理函数返回不允许
             * 访问的错误码时(实际就是NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUTHORIZED),
             * 这里将负责向用户发送拒绝服务的错误响应。因此,这个阶段实际上用于给
             * NGX_HTTP_ACCESS_PHASE阶段收尾 */
            case NGX_HTTP_POST_ACCESS_PHASE:
                if (use_access) {
                    ph->checker = ngx_http_core_post_access_phase;
                    ph->next = n;
                    ph++;
                }
    
                continue;
    
            /* 这个阶段完全是为 try_files 配置项而设立的,当 HTTP 请求访问静态文件资源时,
             * try_files 配置项可以使这个请求顺序地访问多个静态文件资源,如果某一次访
             * 问失败,则继续访问 try_files 中指定的下一个静态资源。这个功能完全是在
             * NGX_HTTP_TRY_FILES_PHASE 阶段实现的 */
            case NGX_HTTP_TRY_FILES_PHASE:
                if (cmcf->try_files) {
                    ph->checker = ngx_http_core_try_files_phase;
                    n++;
                    ph++;
                }
    
                continue;
    
            /* 用于处理HTTP请求内容的阶段,这是大部分HTTP模块最愿意介入的阶段 */
            case NGX_HTTP_CONTENT_PHASE:
                checker = ngx_http_core_content_phase;
                break;
    
            /* 对于 NGX_HTTP_POST_READ_PHASE、NGX_HTTP_PREACCESS_PHASE 以及
             * NGX_HTTP_LOG_PHASE 这三个阶段,统一使用同一个 checket 方法 */
            default:
                checker = ngx_http_core_generic_phase;
            }
    
            n += cmcf->phases[i].handlers.nelts;
    
            /* 仅在当前阶段有 HTTP 模块介入自己的处理方法才会执行下面的语句 */
            for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
                ph->checker = checker;
                ph->handler = h[j];
                ph->next = n;
                ph++;
            }
        }
    
        return NGX_OK;
    }
    

    9. ngx_http_optimize_servers

    /*
     * 每监听一个 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;
    
    static ngx_int_t
    ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
        ngx_array_t *ports)
    {
        ngx_uint_t             p, a;
        ngx_http_conf_port_t  *port;
        ngx_http_conf_addr_t  *addr;
    
        if (ports == NULL) {
            return NGX_OK;
        }
    
        port = ports->elts;
        /* 遍历所有监听端口 */
        for (p = 0; p < ports->nelts; p++) {
    
            ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
                     sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);
    
            /*
             * check whether all name-based servers have the same
             * configuration as a default server for given address:port
             */
    
            addr = port[p].addrs.elts;
            for (a = 0; a < port[p].addrs.nelts; a++) {
    
                if (addr[a].servers.nelts > 1
    #if (NGX_PCRE)
                    || addr[a].default_server->captures
    #endif
                   )
                {
                    if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
                        return NGX_ERROR;
                    }
                }
            }
    
            /* 初始化监听端口 */
            if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
                return NGX_ERROR;
            }
        }
    
        return NGX_OK;
    }
    

    9.1 ngx_http_init_listening

    static ngx_int_t
    ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
    {
        ngx_uint_t                 i, last, bind_wildcard;
        ngx_listening_t           *ls;
        ngx_http_port_t           *hport;
        ngx_http_conf_addr_t      *addr;
    
        addr = port->addrs.elts;
        last = port->addrs.nelts;
    
        /*
         * If there is a binding to an "*:port" then we need to bind() to
         * the "*:port" only and ignore other implicit bindings.  The bindings
         * have been already sorted: explicit bindings are on the start, then
         * implicit bindings go, and wildcard binding is in the end.
         */
    
        if (addr[last - 1].opt.wildcard) {
            addr[last - 1].opt.bind = 1;
            bind_wildcard = 1;
    
        } else {
            bind_wildcard = 0;
        }
    
        i = 0;
    
        while (i < last) {
    
            if (bind_wildcard && !addr[i].opt.bind) {
                i++;
                continue;
            }
    
            ls = ngx_http_add_listening(cf, &addr[i]);
            if (ls == NULL) {
                return NGX_ERROR;
            }
    
            hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
            if (hport == NULL) {
                return NGX_ERROR;
            }
    
            ls->servers = hport;
    
            hport->naddrs = i + 1;
    
            switch (ls->sockaddr->sa_family) {
    
    #if (NGX_HAVE_INET6)
            case AF_INET6:
                if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) {
                    return NGX_ERROR;
                }
                break;
    #endif
            default: /* AF_INET */
                if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
                    return NGX_ERROR;
                }
                break;
            }
    
            if (ngx_clone_listening(cf, ls) != NGX_OK) {
                return NGX_ERROR;
            }
    
            addr++;
            last--;
        }
    
        return NGX_OK;
    }
    

    9.2 ngx_http_add_listening

    static ngx_listening_t *
    ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
    {
        ngx_listening_t           *ls;
        ngx_http_core_loc_conf_t  *clcf;
        ngx_http_core_srv_conf_t  *cscf;
    
        /* 分配并初始化一个 ngx_listening_t 结构体,该结构体代表了
         * 一个具体监听的端口 */
        ls = ngx_create_listening(cf, &addr->opt.sockaddr.sockaddr,
                                  addr->opt.socklen);
        if (ls == NULL) {
            return NULL;
        }
    
        /* 标志位,为 1 表示将网络地址转换为字符串形式的地址 */
        ls->addr_ntop = 1;
    
        /* 当新的 TCP 连接成功建立后的处理方法,即 accept 返回后调用的
         * 处理方法 */
        ls->handler = ngx_http_init_connection;
    
        /* 该监听端口下对应的默认 server{} 虚拟主机 */
        cscf = addr->default_server;
        /* 
         * 如果为新的 TCP 连接创建内存池,则内存池的初始大小应该是 pool_size,
         * 若配置文件中没有指定 tcp 连接时创建的内存池大小,则使用默认的大小
         * 为 256 字节 */
        ls->pool_size = cscf->connection_pool_size;
        /* 
         * TCP_DEFER_ACCEPT 选项将在建立 TCP 连接成功且接收到用户的请求数据后,
         * 才向对监听套接字感兴趣的进程发送事件通知,而连接建立成功后,如果 
         * post_accept_timeout 秒后仍然没有收到用户数据,则内核直接丢弃连接 */
        ls->post_accept_timeout = cscf->client_header_timeout;
    
        clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
    
        ls->logp = clcf->error_log;
        ls->log.data = &ls->addr_text;
        ls->log.handler = ngx_accept_log_error;
    
    #if (NGX_WIN32)
        {
        ngx_iocp_conf_t  *iocpcf = NULL;
    
        if (ngx_get_conf(cf->cycle->conf_ctx, ngx_events_module)) {
            iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
        }
        if (iocpcf && iocpcf->acceptex_read) {
            ls->post_accept_buffer_size = cscf->client_header_buffer_size;
        }
        }
    #endif
    
        ls->backlog = addr->opt.backlog;
        ls->rcvbuf = addr->opt.rcvbuf;
        ls->sndbuf = addr->opt.sndbuf;
    
        ls->keepalive = addr->opt.so_keepalive;
    #if (NGX_HAVE_KEEPALIVE_TUNABLE)
        ls->keepidle = addr->opt.tcp_keepidle;
        ls->keepintvl = addr->opt.tcp_keepintvl;
        ls->keepcnt = addr->opt.tcp_keepcnt;
    #endif
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
        ls->accept_filter = addr->opt.accept_filter;
    #endif
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
        ls->deferred_accept = addr->opt.deferred_accept;
    #endif
    
    #if (NGX_HAVE_INET6)
        ls->ipv6only = addr->opt.ipv6only;
    #endif
    
    #if (NGX_HAVE_SETFIB)
        ls->setfib = addr->opt.setfib;
    #endif
    
    #if (NGX_HAVE_TCP_FASTOPEN)
        ls->fastopen = addr->opt.fastopen;
    #endif
    
    #if (NGX_HAVE_REUSEPORT)
        ls->reuseport = addr->opt.reuseport;
    #endif
    
        return ls;
    }
    

    9.3 ngx_create_listening

    该函数是构造一个 ngx_listening_t 结构体,每一个该结构体代表一个监听端口.

    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];
    
        /* listening 是动态数组,每个数组元素存储着 ngx_listening_t 成员,
         * 表示监听端口及相关的参数 */
        ls = ngx_array_push(&cf->cycle->listening);
        if (ls == NULL) {
            return NULL;
        }
    
        ngx_memzero(ls, sizeof(ngx_listening_t));
    
        sa = ngx_palloc(cf->pool, socklen);
        if (sa == NULL) {
            return NULL;
        }
    
        ngx_memcpy(sa, sockaddr, socklen);
        /* 监听 sockaddr 地址 */
        ls->sockaddr = sa;
        ls->socklen = socklen;
    
        /* 这里是将ip地址转换为点分十进制格式的字符串(若有端口,则加上端口:address:port)
         * 假设当前 listen 的配置为 listen 80; 则此时返回的 text 为 "0.0.0.0:80" */
        len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
        ls->addr_text.len = len;
    
        /* 根据协议族,确定该 ip 对应的字符串的最大长度 */
        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;
        }
    
        /* 将字符串形式的 ip跟端口拷贝到 addr_text 中 */
        ngx_memcpy(ls->addr_text.data, text, len);
    
        ls->fd = (ngx_socket_t) -1;
        ls->type = SOCK_STREAM;
    
        /* TCP实现监听时的backlog队列,它表示允许正在通过三次握手
         * 建立TCP连接但还没有任何进程开始处理的连接最大个数 */
        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;
    }
    
  • 相关阅读:
    hdu 5170 GTY's math problem(水,,数学,,)
    hdu 5178 pairs(BC第一题,,方法不止一种,,我用lower_bound那种。。。)
    hdu 5179 beautiful number(构造,,,,)
    cf12E Start of the season(构造,,,)
    cf12D Ball(MAP,排序,贪心思想)
    cf 12C Fruits(贪心【简单数学】)
    cf 12B Correct Solution?(贪心)
    hdu 5171 GTY's birthday gift(数学,矩阵快速幂)
    hdu 5172 GTY's gay friends(线段树最值)
    cf 11D A Simple Task(状压DP)
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9207036.html
Copyright © 2020-2023  润新知