diff options
-rw-r--r-- | CHANGES | 5 | ||||
-rw-r--r-- | channels/chan_pjsip.c | 46 | ||||
-rw-r--r-- | channels/chan_sip.c | 1 | ||||
-rw-r--r-- | include/asterisk/module.h | 2 | ||||
-rw-r--r-- | main/cdr.c | 17 | ||||
-rw-r--r-- | main/loader.c | 374 |
6 files changed, 267 insertions, 178 deletions
@@ -21,6 +21,11 @@ Core Asterisk is compiled with the LOW_MEMORY compile time option enabled because the cache code does not exist. +chan_sip +------------------ + * Calls to invalid extensions are now reported as an ACL failure security event + "no_extension_match". + res_rtp_asterisk ------------------ * The X.509 certificate used for DTLS negotation can now be automatically diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 69bcc187f..10f45a4cc 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2381,7 +2381,7 @@ static int request(void *obj) struct request_data *req_data = obj; struct ast_sip_session *session = NULL; char *tmp = ast_strdupa(req_data->dest), *endpoint_name = NULL, *request_user = NULL; - RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + struct ast_sip_endpoint *endpoint; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(endpoint); @@ -2406,10 +2406,18 @@ static int request(void *obj) } if (ast_strlen_zero(endpoint_name)) { - ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + if (request_user) { + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name: %s@<endpoint-name>\n", + request_user); + } else { + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + } req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; return -1; - } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + } + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + endpoint_name); + if (!endpoint) { ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name); req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; return -1; @@ -2421,23 +2429,38 @@ static int request(void *obj) ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; return -1; - } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + } + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + endpoint_name); + if (!endpoint) { /* It seems it's not a multi-domain endpoint or single endpoint exact match, * it's possible that it's a SIP trunk with a specified user (user@trunkname), * so extract the user before @ sign. */ - if ((endpoint_name = strchr(args.endpoint, '@'))) { - request_user = args.endpoint; - *endpoint_name++ = '\0'; + endpoint_name = strchr(args.endpoint, '@'); + if (!endpoint_name) { + /* + * Couldn't find an '@' so it had to be an endpoint + * name that doesn't exist. + */ + ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", + args.endpoint); + req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; + return -1; } + request_user = args.endpoint; + *endpoint_name++ = '\0'; if (ast_strlen_zero(endpoint_name)) { - ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name\n"); + ast_log(LOG_ERROR, "Unable to create PJSIP channel with empty endpoint name: %s@<endpoint-name>\n", + request_user); req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE; return -1; } - if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + endpoint_name); + if (!endpoint) { ast_log(LOG_ERROR, "Unable to create PJSIP channel - endpoint '%s' was not found\n", endpoint_name); req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; return -1; @@ -2445,7 +2468,10 @@ static int request(void *obj) } } - if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->topology))) { + session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, + req_data->topology); + ao2_ref(endpoint, -1); + if (!session) { ast_log(LOG_ERROR, "Failed to create outgoing session to endpoint '%s'\n", endpoint_name); req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION; return -1; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4bae39da0..b0573002b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -26460,6 +26460,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str ast_log(LOG_NOTICE, "Call from '%s' (%s) to extension" " '%s' rejected because extension not found in context '%s'.\n", S_OR(p->username, p->peername), ast_sockaddr_stringify(&p->recv), decoded_exten, p->context); + sip_report_failed_acl(p, "no_extension_match"); } break; case SIP_GET_DEST_REFUSED: diff --git a/include/asterisk/module.h b/include/asterisk/module.h index 6c60429c9..3df924c59 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -69,7 +69,7 @@ enum ast_module_load_result { AST_MODULE_LOAD_SUCCESS = 0, /*!< Module loaded and configured */ AST_MODULE_LOAD_DECLINE = 1, /*!< Module is not configured */ AST_MODULE_LOAD_SKIP = 2, /*!< Module was skipped for some reason (For loader.c use only. Should never be returned by modules)*/ - AST_MODULE_LOAD_PRIORITY = 3, /*!< Module is not loaded yet, but is added to prioity heap */ + AST_MODULE_LOAD_PRIORITY = 3, /*!< Module is not loaded yet, but is added to priority list */ AST_MODULE_LOAD_FAILURE = -1, /*!< Module could not be loaded properly */ }; diff --git a/main/cdr.c b/main/cdr.c index 3681cdc6b..0e0366836 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -2457,12 +2457,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 */ @@ -2474,7 +2474,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); @@ -2482,7 +2482,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 @@ -2502,9 +2502,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); } /*! @@ -2587,6 +2589,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, @@ -2639,7 +2642,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/loader.c b/main/loader.c index 23a29d994..2a203c6a7 100644 --- a/main/loader.c +++ b/main/loader.c @@ -52,7 +52,7 @@ #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" @@ -110,6 +110,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. */ @@ -133,13 +135,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) { @@ -167,38 +190,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; if (ast_opt_ref_debug) { mod->ref_debug = ao2_t_alloc(0, NULL, info->name); } 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); @@ -206,6 +242,13 @@ 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); + ao2_cleanup(mod->ref_debug); + ast_free(mod); +} + void ast_module_unregister(const struct ast_module_info *info) { struct ast_module *mod = NULL; @@ -226,9 +269,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); - ao2_cleanup(mod->ref_debug); - ast_free(mod); + module_destroy(mod); } } @@ -498,96 +539,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" : ""); - /* 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 */ + ast_assert(!resource_being_loaded); - 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"); + } - if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) { - if (!suppress_logging) { + sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */ + + 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) @@ -621,9 +659,7 @@ int modules_shutdown(void) ast_verb(1, "Unloading %s\n", mod->resource); mod->info->unload(); } - AST_LIST_HEAD_DESTROY(&mod->users); - ao2_cleanup(mod->ref_debug); - ast_free(mod); + module_destroy(mod); somethingchanged = 1; } AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END; @@ -1120,13 +1156,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; @@ -1139,7 +1175,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; } @@ -1152,21 +1188,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) @@ -1214,23 +1255,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 @@ -1238,9 +1262,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; @@ -1249,7 +1272,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; } @@ -1258,7 +1283,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: @@ -1282,7 +1307,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); @@ -1297,7 +1322,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. */ @@ -1335,7 +1360,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); @@ -1365,7 +1391,7 @@ done: if (mod_count) { *mod_count += count; } - ast_heap_destroy(resource_heap); + AST_VECTOR_FREE(&resource_heap); return res; } @@ -1503,33 +1529,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; } @@ -1539,22 +1589,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; + + for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) { + struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, 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); + 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; } @@ -1566,23 +1618,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; + + for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) { + struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, 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); + 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; } |