Nginx (二) Mail模块中的配置信息解析
因为http模块比较复杂,我选择读mail模块,也涉及到stmp协议。
从ngx_mail_block()函数开始。
原型如下:
static char * ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_conf_t *cf 实际上来自于ngx_init_cycle()函数中定义的conf对象,经由ngx_conf_param() -> ngx_conf_parse() -> ngx_conf_handler()一路传下来的。
ngx_command_t *cmd 实际上是mail模块中的command对象;
void *conf 是mail模块的configure上下文。由ngx_conf_handler()中取得模块的上下文指针传给ngx_mail_block()。
ngx_mail_block() 一开始就创建为自己的配置信息上下文申请空间。下面的代码比较有意思。
*(ngx_mail_conf_ctx_t **) conf = ctx;
conf当成了指向ngx_mail_conf_ctx结构体指针的指针。
接着为所有mail模块计数并建立索引。
分别为main_conf和srv_conf配置上下文申请空间。注意下面代码中可看出,这是两张表每个mail模块都可以根据索引找到自己的main_conf和srv_conf。
ctx->main_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
然后,再循环一次,调用每个mail模块中的create_main_conf()和create_srv_conf()钩子。这两个钩子的主要作用是模块依自己所需的结构体大小申请空间。成功后,将所申请空间的地址存入main_conf与srv_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;
}
}
接着就是mail{}块中配置参数的解析。
/* parse inside the mail{} block */
pcf = *cf;
cf->ctx = ctx;
cf->module_type = NGX_MAIL_MODULE;
cf->cmd_type = NGX_MAIL_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
再次调用ngx_conf_parse()之前,对cf的module_type和cmd_type进行了设定。调用了ngx_conf_parse()之后,cf中包含从配置文件中指令传过来的参数。
再次循环,调用每个模块中init_main_conf()和merge_srv_conf()钩子。调用merge_srv_conf()钩子时,将ngx_mail_core_main_conf_t结构中servers数组中的所有元素和全局的srv_conf数组中的所有元素传入merge_srv_conf()函数中。
注意:在配置参数的解析之前有下面一句:
pcf = *cf;
到merge结束后又有下面的一句:
*cf = pcf;
别外在init_main_conf()和merge_srv_conf()钩子调用失败时,也有*cf = pcf;表示维持原有的cf不变。也就是说,每个mail模块的init_main_conf()和merge_srv_conf()钩子调用不会影响到其他模块对cf的调用。失败也是一样。
创建一个ports数组,4个成员,将监听着的端口存入ports数组,并且保证端口号没有重复。每个端口可以有两个地址。参考ngx_mail_add_ports()函数的代码即可,不难看懂。
最后以ngx_mail_optimize_servers(cf, &ports);调用结束。