static char * ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #if (NGX_HAVE_DLOPEN) void *handle; char **names, **order; ngx_str_t *value, file; ngx_uint_t i; ngx_module_t *module, **modules; ngx_pool_cleanup_t *cln; if (cf->cycle->modules_used) { return "is specified too late"; } value = cf->args->elts; file = value[1]; if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) { return NGX_CONF_ERROR; } cln = ngx_pool_cleanup_add(cf->cycle->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } handle = ngx_dlopen(file.data); if (handle == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlopen_n " \"%s\" failed (%s)", file.data, ngx_dlerror()); return NGX_CONF_ERROR; } cln->handler = ngx_unload_module; cln->data = handle; modules = ngx_dlsym(handle, "ngx_modules"); if (modules == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", &value[1], "ngx_modules", ngx_dlerror()); return NGX_CONF_ERROR; } names = ngx_dlsym(handle, "ngx_module_names"); if (names == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", &value[1], "ngx_module_names", ngx_dlerror()); return NGX_CONF_ERROR; } order = ngx_dlsym(handle, "ngx_module_order"); for (i = 0; modules[i]; i++) { module = modules[i]; module->name = names[i]; if (ngx_add_module(cf, &file, module, order) != NGX_OK) { return NGX_CONF_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%ui", module->name, module->index); } return NGX_CONF_OK; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"load_module\" is not supported " "on this platform"); return NGX_CONF_ERROR; #endif }
// 打开动态库文件 // 设置内存池销毁时的清理动作,关闭动态库 // 使用"ngx_modules"取动态库里的模块数组 // 使用"ngx_module_names"取动态库里的模块名字数组 // 使用"ngx_module_order"取动态库里的模块顺序数组 // 模块顺序只对http filter模块有意义 // 所以可以没有,不需要检查 // 遍历动态库里的模块数组 // 流程类似ngx_preinit_modules // 调用ngx_add_module添加模块 static char * ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #if (NGX_HAVE_DLOPEN) void *handle; char **names, **order; ngx_str_t *value, file; ngx_uint_t i; ngx_module_t *module, **modules; ngx_pool_cleanup_t *cln; // 标志位,cycle已经完成模块的初始化,不能再添加模块 if (cf->cycle->modules_used) { return "is specified too late"; } // 取配置参数 value = cf->args->elts; // 第一个参数是动态库文件名 file = value[1]; if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) { return NGX_CONF_ERROR; } // 当cycle内存池销毁时的清理动作 cln = ngx_pool_cleanup_add(cf->cycle->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } // 打开动态库文件 handle = ngx_dlopen(file.data); if (handle == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlopen_n " \"%s\" failed (%s)", file.data, ngx_dlerror()); return NGX_CONF_ERROR; } // 设置内存池销毁时的清理动作,关闭动态库 cln->handler = ngx_unload_module; cln->data = handle; // 使用"ngx_modules"取动态库里的模块数组 modules = ngx_dlsym(handle, "ngx_modules"); if (modules == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", &value[1], "ngx_modules", ngx_dlerror()); return NGX_CONF_ERROR; } // 使用"ngx_module_names"取动态库里的模块名字数组 names = ngx_dlsym(handle, "ngx_module_names"); if (names == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_dlsym_n " \"%V\", \"%s\" failed (%s)", &value[1], "ngx_module_names", ngx_dlerror()); return NGX_CONF_ERROR; } // 使用"ngx_module_order"取动态库里的模块顺序数组 // 模块顺序只对http filter模块有意义 // 所以可以没有,不需要检查 order = ngx_dlsym(handle, "ngx_module_order"); // 遍历动态库里的模块数组 // 流程类似ngx_preinit_modules // 调用ngx_add_module添加模块 for (i = 0; modules[i]; i++) { module = modules[i]; // 在这里为动态模块设置名字 module->name = names[i]; // cycle->modules_n是模块计数器 如果超过最大数量则报错 // 使用模块里的各种信息进行检查,只有正确的才能加载 // 首先是版本号,必须一致,例如1.10的不能给1.9使用 // 比较签名字符串,里面是二进制兼容信息 // 看cycle里的模块数组里是否有重名的 也就是说每个模块的名字都不能相同 // 模块还没有加载,那么就给一个全局序号,不是ctx_index // 把动态模块的指针加入cycle的模块数组 // 最后完成了一个动态模块的加载,放到了cycle模块数组里的合适位置 if (ngx_add_module(cf, &file, module, order) != NGX_OK) { return NGX_CONF_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%ui", module->name, module->index); } return NGX_CONF_OK; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"load_module\" is not supported " "on this platform"); return NGX_CONF_ERROR; #endif }