nginx http模块开发(3) - ngx_http_core_server

2018-07-20 12:31:01

在上一节的 ngx_http_block 函数里在遍历调用完每个http模块的 create_xxx_conf 后,就会调用如下开始继续解析配置命令。

// 递归解析http{}块里 http模块配置
rv = ngx_conf_parse(cf, NULL);

当解析到 server{} 块指令时,根据 ngx_http_core_module 模块的配置

static ngx_command_t  ngx_http_core_commands[] = {
    ...

    // server{}块
    { ngx_string("server"),
      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_http_core_server,
      0,
      0,
      NULL },

    ngx_null_command
};

就会调用 ngx_http_core_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;

    // ctx是本server的配置结构体数组
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    // 保存http{}的配置上下文
    // 也就是http{}里的ngx_http_conf_ctx_t
    http_ctx = cf->ctx;

    // main_conf指针直接指向上层http_ctx
    ctx->main_conf = http_ctx->main_conf;

    // 重新分配srv配置数组,存储本server基本的配置
    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 */

    // 重新分配location配置数组,在server{}层次存储location基本的配置,用于合并
    // 本身并无实际意义
    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }

    // 调用每个http模块的create_xxx_conf函数,创建配置结构体
    for (i = 0; cf->cycle->modules[i]; i++) {
        if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = cf->cycle->modules[i]->ctx;

        // 创建每个模块的srv_conf
        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;
        }

        // 创建每个模块的loc_conf
        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配置,它记录了本server的核心参数
    cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];

    // ctx保存了本server{}的配置数组
    // 以后通过它就可以获取本server{}的全部模块配置
    cscf->ctx = ctx;


    // 获取本server{}里main配置,实际存储在http_ctx里
    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];

    // cmcf->servers存储了所有的server{}模块信息
    cscfp = ngx_array_push(&cmcf->servers);
    if (cscfp == NULL) {
        return NGX_CONF_ERROR;
    }

    // 把本server{}的配置信息,也就是本server{}里http core模块的srv配置加入数组
    // 以后再用cscf->ctx即可获取本server{}的全部模块配置
    *cscfp = cscf;

指针图大致如下

下面是 ngx_http_core_server 函数的剩余代码

// server{}的解析环境已经准备好,下面开始解析server{}配置

    // 暂存当前的解析上下文
    pcf = *cf;

    // 设置事件模块的新解析上下文
    // 即本server{}的ngx_http_conf_ctx_t结构体
    cf->ctx = ctx;

    // 设置解析的信息,类型在之前的http解析已经设置为NGX_HTTP_MODULE
    cf->cmd_type = NGX_HTTP_SRV_CONF;

    // 递归解析http模块
    rv = ngx_conf_parse(cf, NULL);

    // 恢复之前保存的解析上下文
    // 可以解析下一个server{}
    *cf = pcf;

    // 检查是否设置了listen,如果没有就默认80
    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;
}

下一节讲解 ngx_http_core_module 模块的 location{} 指令的解析。


 备注

1.测试环境centos7 64位,nginx版本为 1.14.0。
2..原文地址http://www.freecls.com/a/2712/cc


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。