diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/cdr.c | 45 | ||||
-rw-r--r-- | main/cel.c | 21 | ||||
-rw-r--r-- | main/config_options.c | 87 | ||||
-rw-r--r-- | main/features_config.c | 22 | ||||
-rw-r--r-- | main/loader.c | 380 | ||||
-rw-r--r-- | main/named_acl.c | 4 | ||||
-rw-r--r-- | main/rtp_engine.c | 19 | ||||
-rw-r--r-- | main/stasis.c | 8 | ||||
-rw-r--r-- | main/udptl.c | 4 |
9 files changed, 384 insertions, 206 deletions
diff --git a/main/cdr.c b/main/cdr.c index 60532fe9f..0b571fe0e 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -241,8 +241,29 @@ static struct aco_type general_option = { .type = ACO_GLOBAL, .name = "general", .item_offset = offsetof(struct module_config, general), - .category = "^general$", - .category_match = ACO_WHITELIST, + .category = "general", + .category_match = ACO_WHITELIST_EXACT, +}; + +/*! Config sections used by existing modules. Do not add to this list. */ +static const char *ignore_categories[] = { + "csv", + "custom", + "manager", + "odbc", + "pgsql", + "radius", + "sqlite", + "tds", + "mysql", + NULL, +}; + +static struct aco_type ignore_option = { + .type = ACO_IGNORE, + .name = "modules", + .category = (const char*)ignore_categories, + .category_match = ACO_WHITELIST_ARRAY, }; static void *module_config_alloc(void); @@ -252,8 +273,7 @@ static void module_config_post_apply(void); /*! \brief The file definition */ static struct aco_file module_file_conf = { .filename = "cdr.conf", - .skip_category = "(^csv$|^custom$|^manager$|^odbc$|^pgsql$|^radius$|^sqlite$|^tds$|^mysql$)", - .types = ACO_TYPES(&general_option), + .types = ACO_TYPES(&general_option, &ignore_option), }; CONFIG_INFO_CORE("cdr", cfg_info, module_configs, module_config_alloc, @@ -2454,12 +2474,12 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr, * \param cand_cdr The \ref cdr_object that is a candidate * */ -static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr) +static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr) { struct cdr_object_snapshot *party_a; struct cdr_object *cand_cdr; - SCOPED_AO2LOCK(lock, base_cand_cdr); + ao2_lock(base_cand_cdr); for (cand_cdr = base_cand_cdr; cand_cdr; cand_cdr = cand_cdr->next) { /* Skip any records that are not in this bridge */ @@ -2471,7 +2491,7 @@ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *b if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name) || (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) { - return 0; + break; } party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a); @@ -2479,7 +2499,7 @@ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *b * Party B */ if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) { bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a); - return 0; + break; } /* We're Party B. Check if we can add ourselves immediately or if we need @@ -2499,9 +2519,11 @@ static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *b */ memset(&cand_cdr->end, 0, sizeof(cand_cdr->end)); } - return 0; + + break; } - return 0; + + ao2_unlock(base_cand_cdr); } /*! @@ -2584,6 +2606,7 @@ static void handle_standard_bridge_enter_message(struct cdr_object *cdr, ao2_lock(cdr); +try_again: for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) { if (it_cdr->fn_table->process_party_a) { CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr, @@ -2636,7 +2659,7 @@ static void handle_standard_bridge_enter_message(struct cdr_object *cdr, /* This is guaranteed to succeed: the new CDR is created in the single state * and will be able to handle the bridge enter message */ - handle_standard_bridge_enter_message(cdr, bridge, channel); + goto try_again; } } ao2_unlock(cdr); diff --git a/main/cel.c b/main/cel.c index 0cdf1be00..d46f185cf 100644 --- a/main/cel.c +++ b/main/cel.c @@ -244,15 +244,28 @@ static struct aco_type general_option = { .type = ACO_GLOBAL, .name = "general", .item_offset = offsetof(struct cel_config, general), - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", +}; + +/*! Config sections used by existing modules. Do not add to this list. */ +static const char *ignore_categories[] = { + "manager", + "radius", + NULL, +}; + +static struct aco_type ignore_option = { + .type = ACO_IGNORE, + .name = "modules", + .category = (const char*)ignore_categories, + .category_match = ACO_WHITELIST_ARRAY, }; /*! \brief The config file to be processed for the module. */ static struct aco_file cel_conf = { .filename = "cel.conf", /*!< The name of the config file */ - .types = ACO_TYPES(&general_option), /*!< The mapping object types to be processed */ - .skip_category = "(^manager$|^radius$)", /*!< Config sections used by existing modules. Do not add to this list. */ + .types = ACO_TYPES(&general_option, &ignore_option), /*!< The mapping object types to be processed */ }; static int cel_pre_apply_config(void); diff --git a/main/config_options.c b/main/config_options.c index f52d3c410..5f6fcbe85 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -133,7 +133,7 @@ static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *va static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj); #ifdef AST_XML_DOCS -static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches); +static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match); static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type); #endif @@ -375,6 +375,8 @@ static int find_option_cb(void *obj, void *arg, int flags) switch (match->match_type) { case ACO_EXACT: return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP; + case ACO_PREFIX: + return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP; case ACO_REGEX: return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP; } @@ -404,6 +406,45 @@ struct ao2_container *aco_option_container_alloc(void) return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp); } +static int internal_aco_type_category_check(struct aco_type *match, const char *category) +{ + const char **categories = (const char **)match->category; + + switch (match->category_match) { + case ACO_WHITELIST: + return regexec(match->internal->regex, category, 0, NULL, 0); + + case ACO_BLACKLIST: + return !regexec(match->internal->regex, category, 0, NULL, 0); + + case ACO_WHITELIST_EXACT: + return strcasecmp(match->category, category); + + case ACO_BLACKLIST_EXACT: + return !strcasecmp(match->category, category); + + case ACO_WHITELIST_ARRAY: + while (*categories) { + if (!strcasecmp(*categories, category)) { + return 0; + } + categories++; + } + return -1; + + case ACO_BLACKLIST_ARRAY: + while (*categories) { + if (!strcasecmp(*categories, category)) { + return -1; + } + categories++; + } + return 0; + } + + return -1; +} + static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category) { size_t x; @@ -412,7 +453,7 @@ static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast for (x = 0, match = file->types[x]; match; match = file->types[++x]) { /* First make sure we are an object that can service this category */ - if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) { + if (internal_aco_type_category_check(match, category)) { continue; } @@ -485,6 +526,10 @@ static int process_category(struct ast_config *cfg, struct aco_info *info, struc return -1; } + if (type->type == ACO_IGNORE) { + return 0; + } + field = info->internal->pending + type->item_offset; if (!*field) { ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat); @@ -633,6 +678,10 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload) for (i = 0, match = file->types[i]; match; match = file->types[++i]) { void **field = info->internal->pending + match->item_offset; + if (match->type == ACO_IGNORE) { + continue; + } + if (match->type != ACO_GLOBAL || !*field) { continue; } @@ -799,9 +848,19 @@ static int internal_type_init(struct aco_type *type) return -1; } - if (!(type->internal->regex = build_regex(type->category))) { - internal_type_destroy(type); - return -1; + switch (type->category_match) { + case ACO_BLACKLIST: + case ACO_WHITELIST: + if (!(type->internal->regex = build_regex(type->category))) { + internal_type_destroy(type); + return -1; + } + break; + case ACO_BLACKLIST_EXACT: + case ACO_WHITELIST_EXACT: + case ACO_BLACKLIST_ARRAY: + case ACO_WHITELIST_ARRAY: + break; } if (!(type->internal->opts = aco_option_container_alloc())) { @@ -830,7 +889,8 @@ int aco_info_init(struct aco_info *info) #ifdef AST_XML_DOCS if (!info->hidden && !type->hidden && - xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) { + type->type != ACO_IGNORE && + xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match)) { goto error; } #endif /* AST_XML_DOCS */ @@ -991,7 +1051,7 @@ static char *complete_config_option(const char *module, const char *option, cons /*! \internal * \brief Update the XML documentation for a config type based on its registration */ -static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches) +static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match) { RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free); RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup); @@ -1030,7 +1090,18 @@ static int xmldoc_update_config_type(const char *module, const char *name, const } ast_xml_set_text(tmp, category); - ast_xml_set_attribute(tmp, "match", matches ? "true" : "false"); + switch (category_match) { + case ACO_WHITELIST: + case ACO_WHITELIST_EXACT: + case ACO_WHITELIST_ARRAY: + ast_xml_set_attribute(tmp, "match", "true"); + break; + case ACO_BLACKLIST: + case ACO_BLACKLIST_EXACT: + case ACO_BLACKLIST_ARRAY: + ast_xml_set_attribute(tmp, "match", "false"); + break; + } if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) { ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module); diff --git a/main/features_config.c b/main/features_config.c index 2689687cc..e2d405740 100644 --- a/main/features_config.c +++ b/main/features_config.c @@ -219,7 +219,7 @@ The <replaceable>DYNAMIC_FEATURES</replaceable> is a <literal>#</literal> separated list of either applicationmap item names or featuregroup names.</para> </description> - <configOption name="^.*$" regex="true"> + <configOption name=""> <synopsis>A custom feature to invoke during a bridged call</synopsis> <description> <para>Each item listed here is a comma-separated list of parameters that determine @@ -272,7 +272,7 @@ DTMF sequence used to invoke an applicationmap item to be overridden with a different sequence.</para> </description> - <configOption name="^.*$" regex="true"> + <configOption name=""> <synopsis>Applicationmap item to place in the feature group</synopsis> <description> <para>Each item here must be a name of an item in the applicationmap. The @@ -578,24 +578,24 @@ struct features_config { static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "globals", - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", .item_offset = offsetof(struct features_config, global), }; static struct aco_type featuremap_option = { .type = ACO_GLOBAL, .name = "featuremap", - .category_match = ACO_WHITELIST, - .category = "^featuremap$", + .category_match = ACO_WHITELIST_EXACT, + .category = "featuremap", .item_offset = offsetof(struct features_config, featuremap), }; static struct aco_type applicationmap_option = { .type = ACO_GLOBAL, .name = "applicationmap", - .category_match = ACO_WHITELIST, - .category = "^applicationmap$", + .category_match = ACO_WHITELIST_EXACT, + .category = "applicationmap", .item_offset = offsetof(struct features_config, applicationmap), }; @@ -1851,13 +1851,13 @@ static int load_config(void) aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options, DEFAULT_FEATUREMAP_AUTOMIXMON, featuremap_handler, 0); - aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options, + aco_option_register_custom(&cfg_info, "", ACO_PREFIX, applicationmap_options, "", applicationmap_handler, 0); - aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options, + aco_option_register_custom(&cfg_info, "", ACO_PREFIX, featuregroup_options, "", featuregroup_handler, 0); - aco_option_register_custom_nodoc(&cfg_info, "^.*$", ACO_REGEX, parkinglot_options, + aco_option_register_custom_nodoc(&cfg_info, "", ACO_PREFIX, parkinglot_options, "", unsupported_handler, 0); if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) { diff --git a/main/loader.c b/main/loader.c index b1a02d542..c18fb379f 100644 --- a/main/loader.c +++ b/main/loader.c @@ -54,7 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/features_config.h" #include "asterisk/dsp.h" #include "asterisk/udptl.h" -#include "asterisk/heap.h" +#include "asterisk/vector.h" #include "asterisk/app.h" #include "asterisk/test.h" #include "asterisk/sounds_index.h" @@ -112,6 +112,8 @@ static const unsigned char expected_key[] = static char buildopt_sum[33] = AST_BUILDOPT_SUM; +AST_VECTOR(module_vector, struct ast_module *); + /*! * \brief Internal flag to indicate all modules have been initially loaded. */ @@ -137,13 +139,34 @@ struct ast_module { /*! This module is being held open until it's time to shutdown. */ unsigned int keepuntilshutdown:1; } flags; - AST_LIST_ENTRY(ast_module) list_entry; AST_DLLIST_ENTRY(ast_module) entry; char resource[0]; }; static AST_DLLIST_HEAD_STATIC(module_list, ast_module); +static int module_vector_strcasecmp(struct ast_module *a, struct ast_module *b) +{ + return strcasecmp(a->resource, b->resource); +} + +static int module_vector_cmp(struct ast_module *a, struct ast_module *b) +{ + /* if load_pri is not set, default is 128. Lower is better */ + int a_pri = ast_test_flag(a->info, AST_MODFLAG_LOAD_ORDER) + ? a->info->load_pri : AST_MODPRI_DEFAULT; + int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER) + ? b->info->load_pri : AST_MODPRI_DEFAULT; + + /* + * Returns comparison values for a vector sorted by priority. + * <0 a_pri < b_pri + * =0 a_pri == b_pri + * >0 a_pri > b_pri + */ + return a_pri - b_pri; +} + const char *ast_module_name(const struct ast_module *mod) { if (!mod || !mod->info) { @@ -171,38 +194,51 @@ static int do_full_reload = 0; static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item); -/* when dynamic modules are being loaded, ast_module_register() will - need to know what filename the module was loaded from while it - is being registered -*/ +/*! + * \internal + * + * This variable is set by load_dynamic_module so ast_module_register + * can know what pointer is being registered. + * + * This is protected by the module_list lock. + */ static struct ast_module *resource_being_loaded; -/* XXX: should we check for duplicate resource names here? */ - +/*! + * \internal + * \brief Used by AST_MODULE_INFO to register with the module loader. + * + * This function is automatically called when each module is opened. + * It must never be used from outside AST_MODULE_INFO. + */ void ast_module_register(const struct ast_module_info *info) { - struct ast_module *mod = resource_being_loaded; + struct ast_module *mod; + + /* + * This lock protects resource_being_loaded as well as the module + * list. Normally we already have a lock on module_list when we + * begin the load but locking again from here prevents corruption + * if an asterisk module is dlopen'ed from outside the module loader. + */ + AST_DLLIST_LOCK(&module_list); + mod = resource_being_loaded; + if (!mod) { + AST_DLLIST_UNLOCK(&module_list); + return; + } ast_debug(5, "Registering module %s\n", info->name); + /* This tells load_dynamic_module that we're registered. */ + resource_being_loaded = NULL; + mod->info = info; #ifdef REF_DEBUG mod->ref_debug = ao2_t_alloc(0, NULL, info->name); #endif AST_LIST_HEAD_INIT(&mod->users); - /* during startup, before the loader has been initialized, - there are no threads, so there is no need to take the lock - on this list to manipulate it. it is also possible that it - might be unsafe to use the list lock at that point... so - let's avoid it altogether - */ - AST_DLLIST_LOCK(&module_list); - /* it is paramount that the new entry be placed at the tail of - the list, otherwise the code that uses dlopen() to load - dynamic modules won't be able to find out if the module it - just opened was registered or failed to load - */ AST_DLLIST_INSERT_TAIL(&module_list, mod, entry); AST_DLLIST_UNLOCK(&module_list); @@ -210,6 +246,15 @@ void ast_module_register(const struct ast_module_info *info) *((struct ast_module **) &(info->self)) = mod; } +static void module_destroy(struct ast_module *mod) +{ + AST_LIST_HEAD_DESTROY(&mod->users); +#ifdef REF_DEBUG + ao2_cleanup(mod->ref_debug); +#endif + ast_free(mod); +} + void ast_module_unregister(const struct ast_module_info *info) { struct ast_module *mod = NULL; @@ -230,11 +275,7 @@ void ast_module_unregister(const struct ast_module_info *info) if (mod) { ast_debug(5, "Unregistering module %s\n", info->name); - AST_LIST_HEAD_DESTROY(&mod->users); -#ifdef REF_DEBUG - ao2_cleanup(mod->ref_debug); -#endif - ast_free(mod); + module_destroy(mod); } } @@ -504,96 +545,93 @@ static void unload_dynamic_module(struct ast_module *mod) #endif } -static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required); - #define MODULE_LOCAL_ONLY (void *)-1 -static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap) +/*! + * \internal + * \brief Attempt to dlopen a module. + * + * \param resource_in The module name to load. + * \param so_ext ".so" or blank if ".so" is already part of resource_in. + * \param filename Passed directly to dlopen. + * \param flags Passed directly to dlopen. + * \param suppress_logging Do not log any error from dlopen. + * + * \return Pointer to opened module, NULL on error. + * + * \warning module_list must be locked before calling this function. + */ +static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext, + const char *filename, int flags, unsigned int suppress_logging) { - char fn[PATH_MAX] = ""; - void *lib = NULL; struct ast_module *mod; - unsigned int wants_global; - int space; /* room needed for the descriptor */ - int missing_so = 0; - - space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1; - if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) { - missing_so = 1; - space += 3; /* room for the extra ".so" */ - } - snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : ""); + ast_assert(!resource_being_loaded); - /* make a first load of the module in 'quiet' mode... don't try to resolve - any symbols, and don't export any symbols. this will allow us to peek into - the module's info block (if available) to see what flags it has set */ - - resource_being_loaded = ast_calloc(1, space); - if (!resource_being_loaded) + mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1); + if (!mod) { return NULL; - strcpy(resource_being_loaded->resource, resource_in); - if (missing_so) - strcat(resource_being_loaded->resource, ".so"); + } + + sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */ - if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) { - if (!suppress_logging) { + resource_being_loaded = mod; + mod->lib = dlopen(filename, flags); + if (resource_being_loaded) { + resource_being_loaded = NULL; + if (mod->lib) { + ast_log(LOG_ERROR, "Module '%s' did not register itself during load\n", resource_in); + logged_dlclose(resource_in, mod->lib); + } else if (!suppress_logging) { ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); } - ast_free(resource_being_loaded); - return NULL; - } + ast_free(mod); - /* the dlopen() succeeded, let's find out if the module - registered itself */ - /* note that this will only work properly as long as - ast_module_register() (which is called by the module's - constructor) places the new module at the tail of the - module_list - */ - if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) { - ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); - /* no, it did not, so close it and return */ - logged_dlclose(resource_in, lib); - /* note that the module's destructor will call ast_module_unregister(), - which will free the structure we allocated in resource_being_loaded */ return NULL; } - wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); + return mod; +} - /* if we are being asked only to load modules that provide global symbols, - and this one does not, then close it and return */ - if (global_symbols_only && !wants_global) { - logged_dlclose(resource_in, lib); - return MODULE_LOCAL_ONLY; +static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging) +{ + char fn[PATH_MAX]; + struct ast_module *mod; + size_t resource_in_len = strlen(resource_in); + int exports_globals; + const char *so_ext = ""; + + if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3, ".so")) { + so_ext = ".so"; } - logged_dlclose(resource_in, lib); - resource_being_loaded = NULL; + snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext); - /* start the load process again */ - resource_being_loaded = ast_calloc(1, space); - if (!resource_being_loaded) - return NULL; - strcpy(resource_being_loaded->resource, resource_in); - if (missing_so) - strcat(resource_being_loaded->resource, ".so"); + /* Try loading in quiet mode first with flags to export global symbols. + * If the module does not want to export globals we will close and reopen. */ + mod = load_dlopen(resource_in, so_ext, fn, + global_symbols_only ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL, + suppress_logging); - if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { - ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); - ast_free(resource_being_loaded); + if (!mod) { return NULL; } - /* since the module was successfully opened, and it registered itself - the previous time we did that, we're going to assume it worked this - time too :) */ + exports_globals = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); + if ((global_symbols_only && exports_globals) || (!global_symbols_only && !exports_globals)) { + /* The first dlopen had the correct flags. */ + return mod; + } - AST_DLLIST_LAST(&module_list)->lib = lib; - resource_being_loaded = NULL; + /* Close the module so we can reopen with correct flags. */ + logged_dlclose(resource_in, mod->lib); + if (global_symbols_only) { + return MODULE_LOCAL_ONLY; + } - return AST_DLLIST_LAST(&module_list); + return load_dlopen(resource_in, so_ext, fn, + exports_globals ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL, + 0); } int modules_shutdown(void) @@ -627,11 +665,7 @@ int modules_shutdown(void) ast_verb(1, "Unloading %s\n", mod->resource); mod->info->unload(); } - AST_LIST_HEAD_DESTROY(&mod->users); -#ifdef REF_DEBUG - ao2_cleanup(mod->ref_debug); -#endif - free(mod); + module_destroy(mod); somethingchanged = 1; } AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END; @@ -1128,13 +1162,13 @@ static enum ast_module_load_result start_resource(struct ast_module *mod) /*! loads a resource based upon resource_name. If global_symbols_only is set * only modules with global symbols will be loaded. * - * If the ast_heap is provided (not NULL) the module is found and added to the - * heap without running the module's load() function. By doing this, modules - * added to the resource_heap can be initialized later in order by priority. + * If the module_vector is provided (not NULL) the module is found and added to the + * vector without running the module's load() function. By doing this, modules + * can be initialized later in order by priority and dependencies. * - * If the ast_heap is not provided, the module's load function will be executed + * If the module_vector is not provided, the module's load function will be executed * immediately */ -static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required) +static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct module_vector *resource_heap, int required) { struct ast_module *mod; enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; @@ -1147,7 +1181,7 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) return AST_MODULE_LOAD_SKIP; } else { - mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging, resource_heap); + mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging); if (mod == MODULE_LOCAL_ONLY) { return AST_MODULE_LOAD_SKIP; } @@ -1160,21 +1194,26 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi } if (inspect_module(mod)) { - ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); - unload_dynamic_module(mod); - return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; + goto prestart_error; } mod->flags.declined = 0; if (resource_heap) { - ast_heap_push(resource_heap, mod); + if (AST_VECTOR_ADD_SORTED(resource_heap, mod, module_vector_cmp)) { + goto prestart_error; + } res = AST_MODULE_LOAD_PRIORITY; } else { res = start_resource(mod); } return res; + +prestart_error: + ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); + unload_dynamic_module(mod); + return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE; } int ast_load_resource(const char *resource_name) @@ -1222,23 +1261,6 @@ static struct load_order_entry *add_to_load_order(const char *resource, struct l return order; } -static int mod_load_cmp(void *a, void *b) -{ - struct ast_module *a_mod = (struct ast_module *) a; - struct ast_module *b_mod = (struct ast_module *) b; - /* if load_pri is not set, default is 128. Lower is better */ - int a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128; - int b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128; - - /* - * Returns comparison values for a min-heap - * <0 a_pri > b_pri - * =0 a_pri == b_pri - * >0 a_pri < b_pri - */ - return b_pri - a_pri; -} - AST_LIST_HEAD_NOLOCK(load_retries, load_order_entry); /*! loads modules in order by load_pri, updates mod_count @@ -1246,9 +1268,8 @@ AST_LIST_HEAD_NOLOCK(load_retries, load_order_entry); */ static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count) { - struct ast_heap *resource_heap; + struct module_vector resource_heap; struct load_order_entry *order; - struct ast_module *mod; struct load_retries load_retries; int count = 0; int res = 0; @@ -1257,7 +1278,9 @@ static int load_resource_list(struct load_order *load_order, unsigned int global AST_LIST_HEAD_INIT_NOLOCK(&load_retries); - if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) { + if (AST_VECTOR_INIT(&resource_heap, 500)) { + ast_log(LOG_ERROR, "Failed to initialize module loader.\n"); + return -1; } @@ -1266,7 +1289,7 @@ static int load_resource_list(struct load_order *load_order, unsigned int global enum ast_module_load_result lres; /* Suppress log messages unless this is the last pass */ - lres = load_resource(order->resource, global_symbols, 1, resource_heap, order->required); + lres = load_resource(order->resource, global_symbols, 1, &resource_heap, order->required); ast_debug(3, "PASS 0: %-46s %d %d\n", order->resource, lres, global_symbols); switch (lres) { case AST_MODULE_LOAD_SUCCESS: @@ -1290,7 +1313,7 @@ static int load_resource_list(struct load_order *load_order, unsigned int global */ break; case AST_MODULE_LOAD_PRIORITY: - /* load_resource worked and the module was added to the priority heap */ + /* load_resource worked and the module was added to the priority vector */ AST_LIST_REMOVE_CURRENT(entry); ast_free(order->resource); ast_free(order); @@ -1305,7 +1328,7 @@ static int load_resource_list(struct load_order *load_order, unsigned int global enum ast_module_load_result lres; /* Suppress log messages unless this is the last pass */ - lres = load_resource(order->resource, global_symbols, (i < LOAD_RETRIES - 1), resource_heap, order->required); + lres = load_resource(order->resource, global_symbols, (i < LOAD_RETRIES - 1), &resource_heap, order->required); ast_debug(3, "PASS %d %-46s %d %d\n", i + 1, order->resource, lres, global_symbols); switch (lres) { /* These are all retryable. */ @@ -1343,7 +1366,8 @@ static int load_resource_list(struct load_order *load_order, unsigned int global } /* second remove modules from heap sorted by priority */ - while ((mod = ast_heap_pop(resource_heap))) { + for (i = 0; i < AST_VECTOR_SIZE(&resource_heap); i++) { + struct ast_module *mod = AST_VECTOR_GET(&resource_heap, i); enum ast_module_load_result lres; lres = start_resource(mod); @@ -1373,7 +1397,7 @@ done: if (mod_count) { *mod_count += count; } - ast_heap_destroy(resource_heap); + AST_VECTOR_FREE(&resource_heap); return res; } @@ -1511,33 +1535,57 @@ void ast_update_use_count(void) AST_LIST_UNLOCK(&updaters); } +/*! + * \internal + * \brief Build an alpha sorted list of modules. + * + * \param alpha_module_list Pointer to uninitialized module_vector. + * + * This function always initializes alpha_module_list. + * + * \pre module_list must be locked. + */ +static int alpha_module_list_create(struct module_vector *alpha_module_list) +{ + struct ast_module *cur; + + if (AST_VECTOR_INIT(alpha_module_list, 32)) { + return -1; + } + + AST_DLLIST_TRAVERSE(&module_list, cur, entry) { + if (AST_VECTOR_ADD_SORTED(alpha_module_list, cur, module_vector_strcasecmp)) { + return -1; + } + } + + return 0; +} + int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level), const char *like) { - struct ast_module *cur; - int unlock = -1; int total_mod_loaded = 0; - AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + struct module_vector alpha_module_list; - if (AST_DLLIST_TRYLOCK(&module_list)) { - unlock = 0; - } + AST_DLLIST_LOCK(&module_list); - AST_DLLIST_TRAVERSE(&module_list, cur, entry) { - AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource); - } + if (!alpha_module_list_create(&alpha_module_list)) { + int idx; - while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) { - total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, - cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level); - } + for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) { + struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx); - if (unlock) { - AST_DLLIST_UNLOCK(&module_list); + total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, + cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level); + } } + AST_DLLIST_UNLOCK(&module_list); + AST_VECTOR_FREE(&alpha_module_list); + return total_mod_loaded; } @@ -1547,22 +1595,24 @@ int ast_update_module_list_data(int (*modentry)(const char *module, const char * void *data), const char *like, void *data) { - struct ast_module *cur; int total_mod_loaded = 0; - AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + struct module_vector alpha_module_list; AST_DLLIST_LOCK(&module_list); - AST_DLLIST_TRAVERSE(&module_list, cur, entry) { - AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource); - } + if (!alpha_module_list_create(&alpha_module_list)) { + int idx; - while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) { - total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, - cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data); + for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) { + struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx); + + total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, + cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data); + } } AST_DLLIST_UNLOCK(&module_list); + AST_VECTOR_FREE(&alpha_module_list); return total_mod_loaded; } @@ -1574,23 +1624,25 @@ int ast_update_module_list_condition(int (*modentry)(const char *module, const c void *data, const char *condition), const char *like, void *data, const char *condition) { - struct ast_module *cur; int conditions_met = 0; - AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + struct module_vector alpha_module_list; AST_DLLIST_LOCK(&module_list); - AST_DLLIST_TRAVERSE(&module_list, cur, entry) { - AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource); - } + if (!alpha_module_list_create(&alpha_module_list)) { + int idx; - while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) { - conditions_met += modentry(cur->resource, cur->info->description, cur->usecount, - cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data, - condition); + for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) { + struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx); + + conditions_met += modentry(cur->resource, cur->info->description, cur->usecount, + cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data, + condition); + } } AST_DLLIST_UNLOCK(&module_list); + AST_VECTOR_FREE(&alpha_module_list); return conditions_met; } diff --git a/main/named_acl.c b/main/named_acl.c index 3b81c8c38..47787e921 100644 --- a/main/named_acl.c +++ b/main/named_acl.c @@ -82,8 +82,8 @@ static void *named_acl_find(struct ao2_container *container, const char *cat); static struct aco_type named_acl_type = { .type = ACO_ITEM, /*!< named_acls are items stored in containers, not individual global objects */ .name = "named_acl", - .category_match = ACO_BLACKLIST, - .category = "^general$", /*!< Match everything but "general" */ + .category_match = ACO_BLACKLIST_EXACT, + .category = "general", /*!< Match everything but "general" */ .item_alloc = named_acl_alloc, /*!< A callback to allocate a new named_acl based on category */ .item_find = named_acl_find, /*!< A callback to find a named_acl in some container of named_acls */ .item_offset = offsetof(struct named_acl_config, named_acl_list), /*!< Could leave this out since 0 */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index e7032724b..b12761bc4 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -887,6 +887,25 @@ void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp ast_rwlock_unlock(&codecs->codecs_lock); } +enum ast_media_type ast_rtp_codecs_get_stream_type(struct ast_rtp_codecs *codecs) +{ + enum ast_media_type stream_type = AST_MEDIA_TYPE_UNKNOWN; + int payload; + struct ast_rtp_payload_type *type; + + ast_rwlock_rdlock(&codecs->codecs_lock); + for (payload = 0; payload < AST_VECTOR_SIZE(&codecs->payloads); ++payload) { + type = AST_VECTOR_GET(&codecs->payloads, payload); + if (type && type->asterisk_format) { + stream_type = ast_format_get_type(type->format); + break; + } + } + ast_rwlock_unlock(&codecs->codecs_lock); + + return stream_type; +} + struct ast_rtp_payload_type *ast_rtp_codecs_get_payload(struct ast_rtp_codecs *codecs, int payload) { struct ast_rtp_payload_type *type = NULL; diff --git a/main/stasis.c b/main/stasis.c index 63d17dfaf..d9785ce73 100644 --- a/main/stasis.c +++ b/main/stasis.c @@ -1436,8 +1436,8 @@ static struct aco_type threadpool_option = { .type = ACO_GLOBAL, .name = "threadpool", .item_offset = offsetof(struct stasis_config, threadpool_options), - .category = "^threadpool$", - .category_match = ACO_WHITELIST, + .category = "threadpool", + .category_match = ACO_WHITELIST_EXACT, }; static struct aco_type *threadpool_options[] = ACO_TYPES(&threadpool_option); @@ -1447,8 +1447,8 @@ static struct aco_type declined_option = { .type = ACO_GLOBAL, .name = "declined_message_types", .item_offset = offsetof(struct stasis_config, declined_message_types), - .category_match = ACO_WHITELIST, - .category = "^declined_message_types$", + .category_match = ACO_WHITELIST_EXACT, + .category = "declined_message_types", }; struct aco_type *declined_options[] = ACO_TYPES(&declined_option); diff --git a/main/udptl.c b/main/udptl.c index 44e9eb9bb..83989f738 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -239,9 +239,9 @@ static int udptl_pre_apply_config(void); static struct aco_type general_option = { .type = ACO_GLOBAL, .name = "global", - .category_match = ACO_WHITELIST, + .category_match = ACO_WHITELIST_EXACT, .item_offset = offsetof(struct udptl_config, general), - .category = "^general$", + .category = "general", }; static struct aco_type *general_options[] = ACO_TYPES(&general_option); |