Nginx Rtmp Learing 之基本數(shù)據(jù)結(jié)構(gòu)ngx_module_t
1. ngx_module_t的基本結(jié)構(gòu)
對(duì)于開發(fā)一個(gè)模塊來(lái)說(shuō)辟汰,我們都需要定義一個(gè)ngx_module_t
類型的變量來(lái)說(shuō)明這個(gè)模塊本身的信息贮竟,從某種意義上來(lái)說(shuō)失尖,這是這個(gè)模塊最重要的一個(gè)信息,它告訴了nginx這個(gè)模塊的一些信息纬朝,配置信息收叶,還有模塊上下文信息,都是通過(guò)這個(gè)結(jié)構(gòu)來(lái)告訴nginx系統(tǒng)的共苛,也就是加載模塊的上層代碼判没,都需要通過(guò)定義的這個(gè)結(jié)構(gòu),來(lái)獲取這些信息隅茎。
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {
// 下面的幾個(gè)成員通常使用宏NGX_MODULE_V1填充
// 每類(http/event)模塊各自的index澄峰, 初始化為-1
ngx_uint_t ctx_index;
// 在ngx_modules數(shù)組里的唯一索引,main()里賦值
// 使用計(jì)數(shù)器變量ngx_max_module
ngx_uint_t index;
// 1.10辟犀,模塊的名字俏竞,標(biāo)識(shí)字符串,默認(rèn)是空指針
// 由腳本生成ngx_module_names數(shù)組堂竟,然后在ngx_preinit_modules里填充
// 動(dòng)態(tài)模塊在ngx_load_module里設(shè)置名字
char *name;
// 兩個(gè)保留字段胞此,1.9之前有4個(gè)
ngx_uint_t spare0;
ngx_uint_t spare1;
// nginx.h:#define nginx_version 1010000
ngx_uint_t version;
// 模塊的二進(jìn)制兼容性簽名,即NGX_MODULE_SIGNATURE
const char *signature;
// 模塊不同含義不同,通常是函數(shù)指針表跃捣,是在配置解析的某個(gè)階段調(diào)用的函數(shù)
// core模塊的ctx
//typedef struct {
// ngx_str_t name;
// void *(*create_conf)(ngx_cycle_t *cycle);
// char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
//} ngx_core_module_t;
void *ctx;
// 模塊支持的指令,數(shù)組形式夺蛇,最后用空對(duì)象表示結(jié)束
ngx_command_t *commands;
// 模塊的類型標(biāo)識(shí)疚漆,相當(dāng)于RTTI,如CORE/HTTP/STRM/MAIL等
ngx_uint_t type;
// 以下7個(gè)函數(shù)會(huì)在進(jìn)程的啟動(dòng)或結(jié)束階段被調(diào)用
// init_master目前nginx不會(huì)調(diào)用
ngx_int_t (*init_master)(ngx_log_t *log);
// 在ngx_init_cycle里被調(diào)用
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
// 在ngx_single_process_cycle/ngx_worker_process_init里調(diào)用
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
// init_thread目前nginx不會(huì)調(diào)用
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
// exit_thread目前nginx不會(huì)調(diào)用
void (*exit_thread)(ngx_cycle_t *cycle);
// 在ngx_worker_process_exit調(diào)用
void (*exit_process)(ngx_cycle_t *cycle);
// 在ngx_master_process_exit(os/unix/ngx_process_cycle.c)里調(diào)用
void (*exit_master)(ngx_cycle_t *cycle);
// 下面8個(gè)成員通常用用NGX_MODULE_V1_PADDING填充
// 暫時(shí)無(wú)任何用處
uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};
2. ngx_modules數(shù)組
2.1 ngx_modules數(shù)組
ngx_modules
數(shù)組是在執(zhí)行configure腳本后自動(dòng)生成的,在objs/ngx_modules.c文件中刁赦。該數(shù)組即當(dāng)前編譯版本中的所有Nginx模塊娶聘。
如果想讓nginx支持Rtmp的話,需要在執(zhí)行configure腳本時(shí)添加第三方庫(kù)nginx-rtmp-module
./configure --add-module=/path/to/nginx-rtmp-module
此時(shí)甚脉,objs/ngx_modules.c的內(nèi)容為:
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
&ngx_rtmp_module,
&ngx_rtmp_core_module,
&ngx_rtmp_cmd_module,
&ngx_rtmp_billing_module,
&ngx_rtmp_codec_module,
&ngx_rtmp_access_module,
&ngx_rtmp_record_module,
&ngx_rtmp_live_module,
&ngx_rtmp_hdl_module,
&ngx_rtmp_hls_delay_module,
&ngx_rtmp_hls_vod_module,
&ngx_rtmp_hls_module,
&ngx_rtmp_play_module,
&ngx_rtmp_flv_module,
&ngx_rtmp_mp4_module,
&ngx_rtmp_netcall_module,
&ngx_rtmp_relay_module,
&ngx_rtmp_exec_module,
&ngx_rtmp_auto_push_module,
&ngx_rtmp_notify_module,
&ngx_rtmp_listener_init_module,
&ngx_rtmp_log_module,
&ngx_rtmp_limit_module,
&ngx_rtmp_dash_module,
&ngx_openssl_module,
&ngx_regex_module,
&ngx_events_module,
&ngx_event_core_module,
&ngx_epoll_module,
&ngx_http_module,
&ngx_http_core_module,
&ngx_http_log_module,
&ngx_http_upstream_module,
&ngx_http_static_module,
&ngx_http_autoindex_module,
&ngx_http_index_module,
&ngx_http_auth_basic_module,
&ngx_http_access_module,
&ngx_http_limit_conn_module,
&ngx_http_limit_req_module,
&ngx_http_geo_module,
&ngx_http_map_module,
&ngx_http_split_clients_module,
&ngx_http_referer_module,
&ngx_http_rewrite_module,
&ngx_http_proxy_module,
&ngx_http_fastcgi_module,
&ngx_http_uwsgi_module,
&ngx_http_scgi_module,
&ngx_http_memcached_module,
&ngx_http_empty_gif_module,
&ngx_http_browser_module,
&ngx_http_upstream_hash_module,
&ngx_http_upstream_ip_hash_module,
&ngx_http_upstream_least_conn_module,
&ngx_http_upstream_keepalive_module,
&ngx_http_upstream_zone_module,
&ngx_rtmp_http_hls_module,
&ngx_rtmp_http_hdl_module,
&ngx_rtmp_stat_module,
&ngx_rtmp_control_module,
&ngx_http_write_filter_module,
&ngx_http_header_filter_module,
&ngx_http_chunked_filter_module,
&ngx_http_range_header_filter_module,
&ngx_http_gzip_filter_module,
&ngx_http_postpone_filter_module,
&ngx_http_ssi_filter_module,
&ngx_http_charset_filter_module,
&ngx_http_userid_filter_module,
&ngx_http_headers_filter_module,
&ngx_http_copy_filter_module,
&ngx_http_range_body_filter_module,
&ngx_http_not_modified_filter_module,
NULL
};
如上所述丸升,ngx_modules
數(shù)組代表了當(dāng)前Nginx中的所有模塊。每一個(gè)Nginx模塊牺氨,即ngx_module_t
類型的變量狡耻,其ctx變量一般為如下幾個(gè)類型之一:
ngx_core_module_t
ngx_event_module_t
ngx_http_module_t
ngx_mail_module_t
所以墩剖,可以對(duì)所有的Nginx模塊按其ctx類型進(jìn)行分類,當(dāng)然并不是所有的nginx模塊都有ctx成員夷狰,例如ngx_conf_module
模塊的ctx成員為NULL,但可以認(rèn)為絕大部分模塊都屬于上述四類模塊之一岭皂。
每一類模塊下的所有模塊,由于其ctx結(jié)構(gòu)是一樣的沼头,因而在程序執(zhí)行邏輯上會(huì)有共同點(diǎn)爷绘。具體來(lái)說(shuō),我們可以遍歷ngx_modules數(shù)組成員进倍,判斷其屬于上述四類的哪一類模塊土至,再調(diào)用其對(duì)應(yīng)的ctx成員中的函數(shù)指針,這樣就會(huì)屏蔽掉具體的模塊名稱猾昆,抽象到框架的層面上陶因。
那么,如何判斷一個(gè)模塊屬于上述四類模塊中的哪一類呢毡庆?這就是模塊變量的type成員的作用了坑赡。
所有的ngx_core_module_t類型的模塊,其type成員為NGX_CORE_MODULE
所有的ngx_event_module_t類型的模塊么抗,其type成員為NGX_EVENT_MODULE
所有的ngx_http_module_t類型的模塊毅否,其type成員為NGX_HTTP_MODULE
所有的ngx_mail_module_t類型的模塊,其type成員為NGX_MAIL_MODULE
所以在遍歷ngx_modules
數(shù)組時(shí)蝇刀,即可根據(jù)每一個(gè)數(shù)組成員的type成員螟加,來(lái)判斷該模塊屬于哪種類型的模塊,進(jìn)而執(zhí)行該模塊對(duì)應(yīng)的鉤子函數(shù)吞琐。
2.2 ngx_module_t的分層模塊結(jié)構(gòu)
Nginx 采用了分層模塊結(jié)構(gòu)設(shè)計(jì)捆探,頂層模塊由 Nginx 自身管理。比如站粟, 在 ngx_init_cycle
有一段代碼為:
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
ngx_uint_t i, n;
// ...
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
// ...
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = cycle->modules[i]->ctx;
if (module->init_conf) {
if (module->init_conf(cycle,
cycle->conf_ctx[cycle->modules[i]->index])
== NGX_CONF_ERROR)
{
environ = senv;
ngx_destroy_cycle_pools(&conf);
return NULL;
}
}
}
// ...
return NULL;
}
類型為 NGX_CORE_MODULE
的模塊的 create_conf
和 init_conf
會(huì)被調(diào)用黍图。 類型為 NGX_CORE_MODULE
的摸塊即屬于 Nginx 中的頂層模塊。 頂層模塊除負(fù)責(zé)像日志打印奴烙、配置解析等核心業(yè)務(wù)外助被,也需要管理二級(jí)模塊的接入。 實(shí)際上切诀,上層模塊負(fù)責(zé)下層模塊的接入揩环,這是一種很自然的設(shè)計(jì)。 假如幅虑,我們自己在 Nginx 中擴(kuò)展了二級(jí)模塊丰滑,而由于業(yè)務(wù)復(fù)雜,我們需要進(jìn)一步進(jìn)行模塊劃分倒庵。 而新劃分出的模塊則屬于三級(jí)模塊褒墨,那這三級(jí)模塊的接入不由我們自己定義的二級(jí)模塊接入又該由誰(shuí)負(fù)責(zé)呢炫刷?
rtmp模塊的類型為 NGX_RTMP_MODULE
,Nginx中與rtmp相關(guān)的模塊有: ngx_rtmp_module
, ngx_rtmp_core_module
, ngx_rmtp_***_module
貌亭。 其中 ngx_rtmp_module
屬于頂層模塊柬唯,但它負(fù)責(zé)二級(jí)事件模塊的接入; ngx_rtmp_core_module
是核心的事件模塊圃庭,它負(fù)責(zé)server,application配置文件的解析和管理锄奢、事件的掛載、初始化listen等剧腻; ngx_rtmp_**_module
是nginx下的其它所有的rtmp模塊拘央。 我們來(lái)ngx_rtmp_module這個(gè)頂層模塊的實(shí)現(xiàn):
2.3 ngx_rtmp_module(ngx_rtmp.c文件)
2.3.1 ngx_rtmp_module
的定義
ngx_module_t ngx_rtmp_module = {
NGX_MODULE_V1,
&ngx_rtmp_module_ctx, /* module context */
ngx_rtmp_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
ngx_rtmp_init_process, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
2.2.2 ngx_rtmp_module的上下文(ngx_rtmp_module_ctx)
// 核心模塊的ctx結(jié)構(gòu),比較簡(jiǎn)單书在,只有創(chuàng)建和初始化配置結(jié)構(gòu)函數(shù) .
// create_conf函數(shù)返回的是void*指針
static ngx_core_module_t ngx_rtmp_module_ctx = {
ngx_string("rtmp"), /*name*/
NULL, /*create_conf*/
NULL /*init_conf*/
};
2.2.3 模塊配置指令(ngx_rtmp_commands)
// 指令結(jié)構(gòu)體灰伟,用于定義nginx指令
static ngx_command_t ngx_rtmp_commands[] = {
{ ngx_string("rtmp"),
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_rtmp_block,
0,
0,
NULL },
ngx_null_command
};
看這個(gè)定義,基本能看出來(lái)一些信息儒旬。例如栏账,我們是定義了一個(gè)配置指令叫rtmp,不接受任何參數(shù)栈源。
接下來(lái)看下ngx_command_t
的定義挡爵,位于src/core/ngx_conf_file.h
中。
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf;
ngx_uint_t offset;
void *post;
};
name: 配置指令的名稱甚垦。
type: 該配置的類型茶鹃,其實(shí)更準(zhǔn)確一點(diǎn)說(shuō),是該配置指令屬性的集合艰亮。
set: 這是一個(gè)函數(shù)指針闭翩,當(dāng)nginx在解析配置的時(shí)候,如果遇到這個(gè)配置指令迄埃,將會(huì)把讀取到的值傳遞給這個(gè)函數(shù)進(jìn)行分解處理疗韵。因?yàn)榫唧w每個(gè)配置指令的值如何處理,只有定義這個(gè)配置指令的人是最清楚的侄非。來(lái)看一下這個(gè)函數(shù)指針要求的函數(shù)原型蕉汪。
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
先看該函數(shù)的返回值,處理成功時(shí)彩库,返回NGX_OK
,否則返回NGX_CONF_ERROR
或者是一個(gè)自定義的錯(cuò)誤信息的字符串先蒋。
再看一下這個(gè)函數(shù)被調(diào)用的時(shí)候骇钦,傳入的三個(gè)參數(shù)。
- cf: 該參數(shù)里面保存從配置文件讀取到的原始字符串以及相關(guān)的一些信息竞漾。特別注意的是這個(gè)參數(shù)的args字段是一個(gè)
ngx_str_t
類型的數(shù)組眯搭,該數(shù)組的首個(gè)元素是這個(gè)配置指令本身窥翩,第二個(gè)元素是指令的第一個(gè)參數(shù),第三個(gè)元素是第二個(gè)參數(shù)鳞仙,依次類推寇蚊。 - cmd: 這個(gè)配置指令對(duì)應(yīng)的
ngx_command_t
結(jié)構(gòu)。 - conf: 就是定義的存儲(chǔ)這個(gè)配置值的結(jié)構(gòu)體棍好。用戶在處理的時(shí)候可以使用類型轉(zhuǎn)換仗岸,轉(zhuǎn)換成自己知道的類型,再進(jìn)行字段的賦值借笙。
// 空指令扒怖,用于在指令數(shù)組的最后當(dāng)做哨兵,結(jié)束數(shù)組业稼,避免指定長(zhǎng)度盗痒,類似NULL的作用
#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }
2.3 ngx_rtmp_block配置解析函數(shù)
這個(gè)函數(shù)可以理解為整個(gè)ngx_rtmp_module
的入口函數(shù):
// 解析rtmp{}配置塊,里面有server{}/application{}等
// 只有出現(xiàn)這個(gè)指令才會(huì)在conf_ctx里創(chuàng)建rtmp配置低散,避免內(nèi)存浪費(fèi)
// 統(tǒng)計(jì)rtmp模塊的數(shù)量,設(shè)置rtmp模塊的ctx_index俯邓,即rtmp模塊自己的序號(hào)
// 調(diào)用每個(gè)rtmp模塊的create_xxx_conf函數(shù),創(chuàng)建配置結(jié)構(gòu)體
// 初始化rtmp處理引擎的階段數(shù)組熔号,調(diào)用ngx_array_init
// 整理所有的rtmp handler模塊稽鞭,填入引擎數(shù)組
// 調(diào)用ngx_create_listening添加到cycle的監(jiān)聽端口數(shù)組,只是添加跨嘉,沒(méi)有其他動(dòng)作
// 設(shè)置有連接發(fā)生時(shí)的回調(diào)函數(shù)ngx_rtmp_init_connection
static char *
ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
ngx_uint_t m, mi, s;
ngx_conf_t pcf;
ngx_rtmp_module_t *module;
ngx_rtmp_conf_ctx_t *ctx;
ngx_rtmp_core_srv_conf_t *cscf, **cscfp;
ngx_rtmp_core_main_conf_t *cmcf;
/* the main rtmp context */
// ngx_rtmp_conf_ctx_t里有三個(gè)void*數(shù)組川慌,存儲(chǔ)三個(gè)層次的模塊配置
// in ngx_rtmp.h
//
// typedef struct {
// void **main_conf;
// void **srv_conf;
// void **loc_conf;
// } ngx_rtmp_conf_ctx_t;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
*(ngx_rtmp_conf_ctx_t **) conf = ctx;
/* count the number of the rtmp modules and set up their indices */
// 統(tǒng)計(jì)rtmp模塊的數(shù)量
// 設(shè)置rtmp模塊的ctx_index,即rtmp模塊自己的序號(hào)
ngx_rtmp_max_module = 0;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
continue;
}
ngx_modules[m]->ctx_index = ngx_rtmp_max_module++;
}
/* the rtmp main_conf context, it is the same in the all rtmp contexts */
// main配置數(shù)組祠乃,所有rtmp模塊只有一個(gè)
ctx->main_conf = ngx_pcalloc(cf->pool,
sizeof(void *) * ngx_rtmp_max_module);
if (ctx->main_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* the rtmp null srv_conf context, it is used to merge
* the server{}s' srv_conf's
*/
// srv配置數(shù)組梦重,在rtmp main層次存儲(chǔ)server基本的配置,用于合并
// 本身并無(wú)實(shí)際意義
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* the rtmp null app_conf context, it is used to merge
* the server{}s' app_conf's
*/
// location配置數(shù)組亮瓷,在rtmp main層次存儲(chǔ)location基本的配置琴拧,用于合并
// 本身并無(wú)實(shí)際意
ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module);
if (ctx->app_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* create the main_conf's, the null srv_conf's, and the null app_conf's
* of the all rtmp modules
*/
// 調(diào)用每個(gè)rtmp模塊的create_xxx_conf函數(shù),創(chuàng)建配置結(jié)構(gòu)體
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
// 創(chuàng)建每個(gè)模塊的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;
}
}
// 創(chuàng)建每個(gè)模塊的srv_conf
if (module->create_srv_conf) {
ctx->srv_conf[mi] = module->create_srv_conf(cf);
if (ctx->srv_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
// 創(chuàng)建每個(gè)模塊的loc_conf
if (module->create_app_conf) {
ctx->app_conf[mi] = module->create_app_conf(cf);
if (ctx->app_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
}
// 初始的解析環(huán)境已經(jīng)準(zhǔn)備好嘱支,下面開始解析rtmp{}配置
// 暫存當(dāng)前的解析上下文
// cf是函數(shù)入口傳遞來(lái)的上下文
pcf = *cf;
// 設(shè)置事件模塊的新解析上下文
// 即ngx_http_conf_ctx_t結(jié)構(gòu)體
cf->ctx = ctx;
// 解析之前蚓胸,調(diào)用preconfiguration,可以添加變量定義
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->preconfiguration) {
if (module->preconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
/* parse inside the rtmp{} block */
// 設(shè)置解析的類型等信息
// NGX_HTTP_MODULE用來(lái)檢查是否是http模塊除师,防止用錯(cuò)了指令
cf->module_type = NGX_RTMP_MODULE;
cf->cmd_type = NGX_RTMP_MAIN_CONF;
// 遞歸解析rtmp模塊
rv = ngx_conf_parse(cf, NULL);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
/* init rtmp{} main_conf's, merge the server{}s' srv_conf's */
// 解析完畢沛膳,檢查rtmp{}里定義的server{}塊
cmcf = ctx->main_conf[ngx_rtmp_core_module.ctx_index];
// 所有server{}定義的配置都保存在core module main conf的serevrs數(shù)組里
cscfp = cmcf->servers.elts;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
/* init rtmp{} main_conf's */
cf->ctx = ctx;
// 初始化main配置
if (module->init_main_conf) {
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
for (s = 0; s < cmcf->servers.nelts; s++) {
/* merge the server{}s' srv_conf's */
cf->ctx = cscfp[s]->ctx;
// 合并srv配置
if (module->merge_srv_conf) {
rv = module->merge_srv_conf(cf,
ctx->srv_conf[mi],
cscfp[s]->ctx->srv_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
if (module->merge_app_conf) {
/* merge the server{}'s app_conf */
/*ctx->app_conf = cscfp[s]->ctx->loc_conf;*/
rv = module->merge_app_conf(cf,
ctx->app_conf[mi],
cscfp[s]->ctx->app_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
/* merge the applications{}' app_conf's */
cscf = cscfp[s]->ctx->srv_conf[ngx_rtmp_core_module.ctx_index];
rv = ngx_rtmp_merge_applications(cf, &cscf->applications,
cscfp[s]->ctx->app_conf,
module, mi);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
}
}
if (ngx_rtmp_init_events(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_RTMP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
// 執(zhí)行每個(gè)rtmp模塊的postconfiguration函數(shù)指針
//** 通常是向phase數(shù)組里添加handler**
if (module->postconfiguration) {
if (module->postconfiguration(cf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
}
// 恢復(fù)之前保存的解析上下文
*cf = pcf;
if (ngx_rtmp_init_event_handlers(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
/* optimize the lists of ports, addresses and server names */
// 類似stream模塊,對(duì)已經(jīng)整理好的監(jiān)聽端口數(shù)組排序
// 調(diào)用ngx_create_listening添加到cycle的監(jiān)聽端口數(shù)組汛聚,只是添加锹安,沒(méi)有其他動(dòng)作
// 設(shè)置有連接發(fā)生時(shí)的回調(diào)函數(shù)ngx_rtmp_init_connection
return ngx_rtmp_optimize_servers(cf, cmcf, &cmcf->ports);
}
參考文章:
https://github.com/chronolaw/annotated_nginx
http://tengine.taobao.org/book/