|  | 
 | /* | 
 |  * Copyright (C) Igor Sysoev | 
 |  * Copyright (C) Maxim Dounin | 
 |  * Copyright (C) Nginx, Inc. | 
 |  */ | 
 |  | 
 |  | 
 | #include <ngx_config.h> | 
 | #include <ngx_core.h> | 
 |  | 
 |  | 
 | #define NGX_MAX_DYNAMIC_MODULES  128 | 
 |  | 
 |  | 
 | static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle); | 
 | static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, | 
 |     ngx_uint_t index); | 
 |  | 
 |  | 
 | ngx_uint_t         ngx_max_module; | 
 | static ngx_uint_t  ngx_modules_n; | 
 |  | 
 |  | 
 | ngx_int_t | 
 | ngx_preinit_modules(void) | 
 | { | 
 |     ngx_uint_t  i; | 
 |  | 
 |     for (i = 0; ngx_modules[i]; i++) { | 
 |         ngx_modules[i]->index = i; | 
 |         ngx_modules[i]->name = ngx_module_names[i]; | 
 |     } | 
 |  | 
 |     ngx_modules_n = i; | 
 |     ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t | 
 | ngx_cycle_modules(ngx_cycle_t *cycle) | 
 | { | 
 |     /* | 
 |      * create a list of modules to be used for this cycle, | 
 |      * copy static modules to it | 
 |      */ | 
 |  | 
 |     cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1) | 
 |                                               * sizeof(ngx_module_t *)); | 
 |     if (cycle->modules == NULL) { | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     ngx_memcpy(cycle->modules, ngx_modules, | 
 |                ngx_modules_n * sizeof(ngx_module_t *)); | 
 |  | 
 |     cycle->modules_n = ngx_modules_n; | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t | 
 | ngx_init_modules(ngx_cycle_t *cycle) | 
 | { | 
 |     ngx_uint_t  i; | 
 |  | 
 |     for (i = 0; cycle->modules[i]; i++) { | 
 |         if (cycle->modules[i]->init_module) { | 
 |             if (cycle->modules[i]->init_module(cycle) != NGX_OK) { | 
 |                 return NGX_ERROR; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t | 
 | ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type) | 
 | { | 
 |     ngx_uint_t     i, next, max; | 
 |     ngx_module_t  *module; | 
 |  | 
 |     next = 0; | 
 |     max = 0; | 
 |  | 
 |     /* count appropriate modules, set up their indices */ | 
 |  | 
 |     for (i = 0; cycle->modules[i]; i++) { | 
 |         module = cycle->modules[i]; | 
 |  | 
 |         if (module->type != type) { | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (module->ctx_index != NGX_MODULE_UNSET_INDEX) { | 
 |  | 
 |             /* if ctx_index was assigned, preserve it */ | 
 |  | 
 |             if (module->ctx_index > max) { | 
 |                 max = module->ctx_index; | 
 |             } | 
 |  | 
 |             if (module->ctx_index == next) { | 
 |                 next++; | 
 |             } | 
 |  | 
 |             continue; | 
 |         } | 
 |  | 
 |         /* search for some free index */ | 
 |  | 
 |         module->ctx_index = ngx_module_ctx_index(cycle, type, next); | 
 |  | 
 |         if (module->ctx_index > max) { | 
 |             max = module->ctx_index; | 
 |         } | 
 |  | 
 |         next = module->ctx_index + 1; | 
 |     } | 
 |  | 
 |     /* | 
 |      * make sure the number returned is big enough for previous | 
 |      * cycle as well, else there will be problems if the number | 
 |      * will be stored in a global variable (as it's used to be) | 
 |      * and we'll have to roll back to the previous cycle | 
 |      */ | 
 |  | 
 |     if (cycle->old_cycle && cycle->old_cycle->modules) { | 
 |  | 
 |         for (i = 0; cycle->old_cycle->modules[i]; i++) { | 
 |             module = cycle->old_cycle->modules[i]; | 
 |  | 
 |             if (module->type != type) { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (module->ctx_index > max) { | 
 |                 max = module->ctx_index; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /* prevent loading of additional modules */ | 
 |  | 
 |     cycle->modules_used = 1; | 
 |  | 
 |     return max + 1; | 
 | } | 
 |  | 
 |  | 
 | ngx_int_t | 
 | ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module, | 
 |     char **order) | 
 | { | 
 |     void               *rv; | 
 |     ngx_uint_t          i, m, before; | 
 |     ngx_core_module_t  *core_module; | 
 |  | 
 |     if (cf->cycle->modules_n >= ngx_max_module) { | 
 |         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 
 |                            "too many modules loaded"); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     if (module->version != nginx_version) { | 
 |         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 
 |                            "module \"%V\" version %ui instead of %ui", | 
 |                            file, module->version, (ngx_uint_t) nginx_version); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) { | 
 |         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 
 |                            "module \"%V\" is not binary compatible", | 
 |                            file); | 
 |         return NGX_ERROR; | 
 |     } | 
 |  | 
 |     for (m = 0; cf->cycle->modules[m]; m++) { | 
 |         if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) { | 
 |             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 
 |                                "module \"%s\" is already loaded", | 
 |                                module->name); | 
 |             return NGX_ERROR; | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * if the module wasn't previously loaded, assign an index | 
 |      */ | 
 |  | 
 |     if (module->index == NGX_MODULE_UNSET_INDEX) { | 
 |         module->index = ngx_module_index(cf->cycle); | 
 |  | 
 |         if (module->index >= ngx_max_module) { | 
 |             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 
 |                                "too many modules loaded"); | 
 |             return NGX_ERROR; | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * put the module into the cycle->modules array | 
 |      */ | 
 |  | 
 |     before = cf->cycle->modules_n; | 
 |  | 
 |     if (order) { | 
 |         for (i = 0; order[i]; i++) { | 
 |             if (ngx_strcmp(order[i], module->name) == 0) { | 
 |                 i++; | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         for ( /* void */ ; order[i]; i++) { | 
 |  | 
 | #if 0 | 
 |             ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, | 
 |                            "module: %s before %s", | 
 |                            module->name, order[i]); | 
 | #endif | 
 |  | 
 |             for (m = 0; m < before; m++) { | 
 |                 if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) { | 
 |  | 
 |                     ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0, | 
 |                                    "module: %s before %s:%i", | 
 |                                    module->name, order[i], m); | 
 |  | 
 |                     before = m; | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /* put the module before modules[before] */ | 
 |  | 
 |     if (before != cf->cycle->modules_n) { | 
 |         ngx_memmove(&cf->cycle->modules[before + 1], | 
 |                     &cf->cycle->modules[before], | 
 |                     (cf->cycle->modules_n - before) * sizeof(ngx_module_t *)); | 
 |     } | 
 |  | 
 |     cf->cycle->modules[before] = module; | 
 |     cf->cycle->modules_n++; | 
 |  | 
 |     if (module->type == NGX_CORE_MODULE) { | 
 |  | 
 |         /* | 
 |          * we are smart enough to initialize core modules; | 
 |          * other modules are expected to be loaded before | 
 |          * initialization - e.g., http modules must be loaded | 
 |          * before http{} block | 
 |          */ | 
 |  | 
 |         core_module = module->ctx; | 
 |  | 
 |         if (core_module->create_conf) { | 
 |             rv = core_module->create_conf(cf->cycle); | 
 |             if (rv == NULL) { | 
 |                 return NGX_ERROR; | 
 |             } | 
 |  | 
 |             cf->cycle->conf_ctx[module->index] = rv; | 
 |         } | 
 |     } | 
 |  | 
 |     return NGX_OK; | 
 | } | 
 |  | 
 |  | 
 | static ngx_uint_t | 
 | ngx_module_index(ngx_cycle_t *cycle) | 
 | { | 
 |     ngx_uint_t     i, index; | 
 |     ngx_module_t  *module; | 
 |  | 
 |     index = 0; | 
 |  | 
 | again: | 
 |  | 
 |     /* find an unused index */ | 
 |  | 
 |     for (i = 0; cycle->modules[i]; i++) { | 
 |         module = cycle->modules[i]; | 
 |  | 
 |         if (module->index == index) { | 
 |             index++; | 
 |             goto again; | 
 |         } | 
 |     } | 
 |  | 
 |     /* check previous cycle */ | 
 |  | 
 |     if (cycle->old_cycle && cycle->old_cycle->modules) { | 
 |  | 
 |         for (i = 0; cycle->old_cycle->modules[i]; i++) { | 
 |             module = cycle->old_cycle->modules[i]; | 
 |  | 
 |             if (module->index == index) { | 
 |                 index++; | 
 |                 goto again; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return index; | 
 | } | 
 |  | 
 |  | 
 | static ngx_uint_t | 
 | ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index) | 
 | { | 
 |     ngx_uint_t     i; | 
 |     ngx_module_t  *module; | 
 |  | 
 | again: | 
 |  | 
 |     /* find an unused ctx_index */ | 
 |  | 
 |     for (i = 0; cycle->modules[i]; i++) { | 
 |         module = cycle->modules[i]; | 
 |  | 
 |         if (module->type != type) { | 
 |             continue; | 
 |         } | 
 |  | 
 |         if (module->ctx_index == index) { | 
 |             index++; | 
 |             goto again; | 
 |         } | 
 |     } | 
 |  | 
 |     /* check previous cycle */ | 
 |  | 
 |     if (cycle->old_cycle && cycle->old_cycle->modules) { | 
 |  | 
 |         for (i = 0; cycle->old_cycle->modules[i]; i++) { | 
 |             module = cycle->old_cycle->modules[i]; | 
 |  | 
 |             if (module->type != type) { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             if (module->ctx_index == index) { | 
 |                 index++; | 
 |                 goto again; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return index; | 
 | } |