#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <dirent.h>
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/cdr.h"
#include "asterisk/enum.h"
#include "asterisk/rtp.h"
#include "asterisk/http.h"
#include "asterisk/lock.h"
#include "asterisk/features.h"
#include "asterisk/dsp.h"
#include "asterisk/udptl.h"
#include <dlfcn.h>
#include "asterisk/md5.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | ast_module |
struct | ast_module_user |
struct | load_order |
struct | load_order_entry |
struct | loadupdate |
struct | module_list |
struct | module_user_list |
struct | reload_classes |
struct | updaters |
Defines | |
#define | RTLD_LOCAL 0 |
#define | RTLD_NOW 0 |
Functions | |
ast_module_user * | __ast_module_user_add (struct ast_module *mod, struct ast_channel *chan) |
void | __ast_module_user_hangup_all (struct ast_module *mod) |
void | __ast_module_user_remove (struct ast_module *mod, struct ast_module_user *u) |
static struct load_order_entry * | add_to_load_order (const char *resource, struct load_order *load_order) |
int | ast_load_resource (const char *resource_name) |
Load a module. | |
int | ast_loader_register (int(*v)(void)) |
Add a procedure to be run when modules have been updated. | |
int | ast_loader_unregister (int(*v)(void)) |
Remove a procedure to be run when modules are updated. | |
int | ast_module_check (const char *name) |
Check if module with the name given is loaded. | |
char * | ast_module_helper (const char *line, const char *word, int pos, int state, int rpos, int needsreload) |
Match modules names for the Asterisk cli. | |
ast_module * | ast_module_ref (struct ast_module *mod) |
void | ast_module_register (const struct ast_module_info *info) |
int | ast_module_reload (const char *name) |
Reload asterisk modules. | |
void | ast_module_shutdown (void) |
Run the unload() callback for all loaded modules. | |
void | ast_module_unref (struct ast_module *mod) |
void | ast_module_unregister (const struct ast_module_info *info) |
int | ast_unload_resource (const char *resource_name, enum ast_module_unload_mode force) |
Unload a module. | |
int | ast_update_module_list (int(*modentry)(const char *module, const char *description, int usecnt, const char *like), const char *like) |
Ask for a list of modules, descriptions, and use counts. | |
void | ast_update_use_count (void) |
Notify when usecount has been changed. | |
static struct ast_module * | find_resource (const char *resource, int do_lock) |
static unsigned int | inspect_module (const struct ast_module *mod) |
static int | key_matches (const unsigned char *key1, const unsigned char *key2) |
static struct ast_module * | load_dynamic_module (const char *resource_in, unsigned int global_symbols_only) |
int | load_modules (unsigned int preload_only) |
static enum ast_module_load_result | load_resource (const char *resource_name, unsigned int global_symbols_only) |
static int | printdigest (const unsigned char *d) |
static int | resource_name_match (const char *name1_in, const char *name2_in) |
static void | unload_dynamic_module (struct ast_module *mod) |
static int | verify_key (const unsigned char *key) |
Variables | |
static char | buildopt_sum [33] = AST_BUILDOPT_SUM |
static struct module_list | embedded_module_list |
static unsigned int | embedding = 1 |
static unsigned char | expected_key [] |
static ast_mutex_t | reloadlock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) |
ast_module * | resource_being_loaded |
Kevin P. Fleming <kpfleming@digium.com>
Luigi Rizzo <rizzo@icir.org>
Definition in file loader.c.
#define RTLD_LOCAL 0 |
#define RTLD_NOW 0 |
struct ast_module_user* __ast_module_user_add | ( | struct ast_module * | mod, | |
struct ast_channel * | chan | |||
) |
Definition at line 185 of file loader.c.
References ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::chan, ast_module_user::entry, ast_module::usecount, and ast_module::users.
Referenced by ast_func_read(), ast_func_write(), and pbx_exec().
00187 { 00188 struct ast_module_user *u = ast_calloc(1, sizeof(*u)); 00189 00190 if (!u) 00191 return NULL; 00192 00193 u->chan = chan; 00194 00195 AST_LIST_LOCK(&mod->users); 00196 AST_LIST_INSERT_HEAD(&mod->users, u, entry); 00197 AST_LIST_UNLOCK(&mod->users); 00198 00199 ast_atomic_fetchadd_int(&mod->usecount, +1); 00200 00201 ast_update_use_count(); 00202 00203 return u; 00204 }
void __ast_module_user_hangup_all | ( | struct ast_module * | mod | ) |
Definition at line 217 of file loader.c.
References ast_atomic_fetchadd_int(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_update_use_count(), ast_module_user::chan, ast_module_user::entry, ast_module::usecount, and ast_module::users.
Referenced by ast_unload_resource().
00218 { 00219 struct ast_module_user *u; 00220 00221 AST_LIST_LOCK(&mod->users); 00222 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) { 00223 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD); 00224 ast_atomic_fetchadd_int(&mod->usecount, -1); 00225 ast_free(u); 00226 } 00227 AST_LIST_UNLOCK(&mod->users); 00228 00229 ast_update_use_count(); 00230 }
void __ast_module_user_remove | ( | struct ast_module * | mod, | |
struct ast_module_user * | u | |||
) |
Definition at line 206 of file loader.c.
References ast_atomic_fetchadd_int(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::entry, ast_module::usecount, and ast_module::users.
Referenced by ast_func_read(), ast_func_write(), and pbx_exec().
00207 { 00208 AST_LIST_LOCK(&mod->users); 00209 AST_LIST_REMOVE(&mod->users, u, entry); 00210 AST_LIST_UNLOCK(&mod->users); 00211 ast_atomic_fetchadd_int(&mod->usecount, -1); 00212 ast_free(u); 00213 00214 ast_update_use_count(); 00215 }
static struct load_order_entry* add_to_load_order | ( | const char * | resource, | |
struct load_order * | load_order | |||
) | [static] |
Definition at line 727 of file loader.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strdup, ast_module_user::entry, load_order_entry::resource, and resource_name_match().
Referenced by load_modules().
00728 { 00729 struct load_order_entry *order; 00730 00731 AST_LIST_TRAVERSE(load_order, order, entry) { 00732 if (!resource_name_match(order->resource, resource)) 00733 return NULL; 00734 } 00735 00736 if (!(order = ast_calloc(1, sizeof(*order)))) 00737 return NULL; 00738 00739 order->resource = ast_strdup(resource); 00740 AST_LIST_INSERT_TAIL(load_order, order, entry); 00741 00742 return order; 00743 }
int ast_load_resource | ( | const char * | resource_name | ) |
Load a module.
resource_name | The name of the module to load. |
Definition at line 710 of file loader.c.
References AST_LIST_LOCK, AST_LIST_UNLOCK, and load_resource().
Referenced by file_ok_sel(), handle_load(), load_module(), manager_moduleload(), and reload().
00711 { 00712 int res; 00713 AST_LIST_LOCK(&module_list); 00714 res = load_resource(resource_name, 0); 00715 AST_LIST_UNLOCK(&module_list); 00716 00717 return res; 00718 }
int ast_loader_register | ( | int(*)(void) | updater | ) |
Add a procedure to be run when modules have been updated.
updater | The function to run when modules have been updated. |
0 | on success | |
-1 | on failure. |
Definition at line 964 of file loader.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and ast_malloc.
Referenced by show_console().
00965 { 00966 struct loadupdate *tmp; 00967 00968 if (!(tmp = ast_malloc(sizeof(*tmp)))) 00969 return -1; 00970 00971 tmp->updater = v; 00972 AST_LIST_LOCK(&updaters); 00973 AST_LIST_INSERT_HEAD(&updaters, tmp, entry); 00974 AST_LIST_UNLOCK(&updaters); 00975 00976 return 0; 00977 }
int ast_loader_unregister | ( | int(*)(void) | updater | ) |
Remove a procedure to be run when modules are updated.
updater | The updater function to unregister. |
0 | on success | |
-1 | on failure. |
Definition at line 979 of file loader.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, and loadupdate::updater.
Referenced by exit_now().
00980 { 00981 struct loadupdate *cur; 00982 00983 AST_LIST_LOCK(&updaters); 00984 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) { 00985 if (cur->updater == v) { 00986 AST_LIST_REMOVE_CURRENT(entry); 00987 break; 00988 } 00989 } 00990 AST_LIST_TRAVERSE_SAFE_END; 00991 AST_LIST_UNLOCK(&updaters); 00992 00993 return cur ? 0 : -1; 00994 }
int ast_module_check | ( | const char * | name | ) |
Check if module with the name given is loaded.
name | Module name, like "chan_sip.so" |
1 | if true | |
0 | if false |
Definition at line 951 of file loader.c.
References ast_strlen_zero(), and find_resource().
Referenced by ifmodule_read(), load_module(), manager_modulecheck(), and unload_module().
00952 { 00953 struct ast_module *cur; 00954 00955 if (ast_strlen_zero(name)) 00956 return 0; /* FALSE */ 00957 00958 cur = find_resource(name, 1); 00959 00960 return (cur != NULL); 00961 }
char* ast_module_helper | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state, | |||
int | rpos, | |||
int | needsreload | |||
) |
Match modules names for the Asterisk cli.
line | Unused by this function, but this should be the line we are matching. | |
word | The partial name to match. | |
pos | The position the word we are completing is in. | |
state | The possible match to return. | |
rpos | The position we should be matching. This should be the same as pos. | |
needsreload | This should be 1 if we need to reload this module and 0 otherwise. This function will only return modules that are reloadble if this is 1. |
A | possible completion of the partial match. | |
NULL | if no matches were found. |
Definition at line 518 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_module_user::entry, ast_module::info, name, ast_module_info::reload, and ast_module::resource.
Referenced by handle_modlist(), handle_reload(), handle_unload(), and load_module().
00519 { 00520 struct ast_module *cur; 00521 int i, which=0, l = strlen(word); 00522 char *ret = NULL; 00523 00524 if (pos != rpos) 00525 return NULL; 00526 00527 AST_LIST_LOCK(&module_list); 00528 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00529 if (!strncasecmp(word, cur->resource, l) && 00530 (cur->info->reload || !needsreload) && 00531 ++which > state) { 00532 ret = ast_strdup(cur->resource); 00533 break; 00534 } 00535 } 00536 AST_LIST_UNLOCK(&module_list); 00537 00538 if (!ret) { 00539 for (i=0; !ret && reload_classes[i].name; i++) { 00540 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) 00541 ret = ast_strdup(reload_classes[i].name); 00542 } 00543 } 00544 00545 return ret; 00546 }
struct ast_module* ast_module_ref | ( | struct ast_module * | mod | ) |
Definition at line 996 of file loader.c.
References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.
Referenced by __oh323_new(), agi_handle_command(), alsa_new(), ast_agi_register(), ast_iax2_new(), ast_timer_open(), dahdi_new(), fn_wrapper(), gtalk_new(), handle_cli_file_convert(), handle_orig(), mgcp_new(), newpvt(), oss_new(), phone_check_exception(), phone_new(), sip_new(), skinny_new(), and usbradio_new().
00997 { 00998 ast_atomic_fetchadd_int(&mod->usecount, +1); 00999 ast_update_use_count(); 01000 01001 return mod; 01002 }
void ast_module_register | ( | const struct ast_module_info * | info | ) |
Definition at line 123 of file loader.c.
References ast_calloc, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, embedding, ast_module_user::entry, ast_module::info, resource_being_loaded, and ast_module::users.
00124 { 00125 struct ast_module *mod; 00126 00127 if (embedding) { 00128 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) 00129 return; 00130 strcpy(mod->resource, info->name); 00131 } else { 00132 mod = resource_being_loaded; 00133 } 00134 00135 mod->info = info; 00136 AST_LIST_HEAD_INIT(&mod->users); 00137 00138 /* during startup, before the loader has been initialized, 00139 there are no threads, so there is no need to take the lock 00140 on this list to manipulate it. it is also possible that it 00141 might be unsafe to use the list lock at that point... so 00142 let's avoid it altogether 00143 */ 00144 if (embedding) { 00145 AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry); 00146 } else { 00147 AST_LIST_LOCK(&module_list); 00148 /* it is paramount that the new entry be placed at the tail of 00149 the list, otherwise the code that uses dlopen() to load 00150 dynamic modules won't be able to find out if the module it 00151 just opened was registered or failed to load 00152 */ 00153 AST_LIST_INSERT_TAIL(&module_list, mod, entry); 00154 AST_LIST_UNLOCK(&module_list); 00155 } 00156 00157 /* give the module a copy of its own handle, for later use in registrations and the like */ 00158 *((struct ast_module **) &(info->self)) = mod; 00159 }
int ast_module_reload | ( | const char * | name | ) |
Reload asterisk modules.
name | the name of the module to reload |
1 | if the module was found but cannot be reloaded. | |
-1 | if a reload operation is already in progress. | |
2 | if the specfied module was found and reloaded. |
Definition at line 548 of file loader.c.
References ast_lastreloadtime, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_tvnow(), ast_verb, ast_verbose, ast_module::declined, ast_module_info::description, ast_module_user::entry, ast_module::flags, ast_module::info, LOG_NOTICE, ast_module_info::reload, reloadlock, ast_module::resource, resource_name_match(), and ast_module::running.
Referenced by action_reload(), action_updateconfig(), handle_reload(), manager_moduleload(), and monitor_sig_flags().
00549 { 00550 struct ast_module *cur; 00551 int res = 0; /* return value. 0 = not found, others, see below */ 00552 int i; 00553 00554 if (ast_mutex_trylock(&reloadlock)) { 00555 ast_verbose("The previous reload command didn't finish yet\n"); 00556 return -1; /* reload already in progress */ 00557 } 00558 ast_lastreloadtime = ast_tvnow(); 00559 00560 /* Call "predefined" reload here first */ 00561 for (i = 0; reload_classes[i].name; i++) { 00562 if (!name || !strcasecmp(name, reload_classes[i].name)) { 00563 reload_classes[i].reload_fn(); /* XXX should check error ? */ 00564 res = 2; /* found and reloaded */ 00565 } 00566 } 00567 00568 if (name && res) { 00569 ast_mutex_unlock(&reloadlock); 00570 return res; 00571 } 00572 00573 AST_LIST_LOCK(&module_list); 00574 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00575 const struct ast_module_info *info = cur->info; 00576 00577 if (name && resource_name_match(name, cur->resource)) 00578 continue; 00579 00580 if (!cur->flags.running || cur->flags.declined) { 00581 if (!name) 00582 continue; 00583 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. " 00584 "Before reloading the module, you must run \"module load %s\" " 00585 "and fix whatever is preventing the module from being initialized.\n", 00586 name, name); 00587 res = 2; /* Don't report that the module was not found */ 00588 break; 00589 } 00590 00591 if (!info->reload) { /* cannot be reloaded */ 00592 if (res < 1) /* store result if possible */ 00593 res = 1; /* 1 = no reload() method */ 00594 continue; 00595 } 00596 00597 res = 2; 00598 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description); 00599 info->reload(); 00600 } 00601 AST_LIST_UNLOCK(&module_list); 00602 00603 ast_mutex_unlock(&reloadlock); 00604 00605 return res; 00606 }
void ast_module_shutdown | ( | void | ) |
Run the unload() callback for all loaded modules.
This function should be called when Asterisk is shutting down gracefully.
Definition at line 433 of file loader.c.
References AST_LIST_HEAD_DESTROY, AST_LIST_HEAD_NOLOCK_STATIC, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_module_user::entry, free, ast_module::info, ast_module_info::unload, and ast_module::users.
Referenced by quit_handler().
00434 { 00435 struct ast_module *mod; 00436 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module); 00437 00438 /* We have to call the unload() callbacks in reverse order that the modules 00439 * exist in the module list so it is the reverse order of how they were 00440 * loaded. */ 00441 00442 AST_LIST_LOCK(&module_list); 00443 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry))) 00444 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry); 00445 AST_LIST_UNLOCK(&module_list); 00446 00447 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) { 00448 if (mod->info->unload) 00449 mod->info->unload(); 00450 /* Since this should only be called when shutting down "gracefully", 00451 * all channels should be down before we get to this point, meaning 00452 * there will be no module users left. */ 00453 AST_LIST_HEAD_DESTROY(&mod->users); 00454 free(mod); 00455 } 00456 }
void ast_module_unref | ( | struct ast_module * | mod | ) |
Definition at line 1004 of file loader.c.
References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.
Referenced by agi_handle_command(), alsa_hangup(), ast_agi_unregister(), ast_smdi_interface_destroy(), ast_timer_close(), dahdi_destroy_channel_bynum(), dahdi_hangup(), destroy(), filestream_destructor(), gtalk_hangup(), handle_cli_file_convert(), handle_orig(), iax2_predestroy(), mgcp_hangup(), oh323_hangup(), oss_hangup(), phone_check_exception(), phone_hangup(), sip_hangup(), and usbradio_hangup().
01005 { 01006 ast_atomic_fetchadd_int(&mod->usecount, -1); 01007 ast_update_use_count(); 01008 }
void ast_module_unregister | ( | const struct ast_module_info * | info | ) |
Definition at line 161 of file loader.c.
References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_module_user::entry, ast_module::info, and ast_module::users.
00162 { 00163 struct ast_module *mod = NULL; 00164 00165 /* it is assumed that the users list in the module structure 00166 will already be empty, or we cannot have gotten to this 00167 point 00168 */ 00169 AST_LIST_LOCK(&module_list); 00170 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) { 00171 if (mod->info == info) { 00172 AST_LIST_REMOVE_CURRENT(entry); 00173 break; 00174 } 00175 } 00176 AST_LIST_TRAVERSE_SAFE_END; 00177 AST_LIST_UNLOCK(&module_list); 00178 00179 if (mod) { 00180 AST_LIST_HEAD_DESTROY(&mod->users); 00181 ast_free(mod); 00182 } 00183 }
int ast_unload_resource | ( | const char * | resource_name, | |
enum | ast_module_unload_mode | |||
) |
Unload a module.
resource_name | The name of the module to unload. | |
ast_module_unload_mode | The force flag. This should be set using one of the AST_FORCE flags. |
0 | on success. | |
-1 | on error. |
Definition at line 458 of file loader.c.
References __ast_module_user_hangup_all(), AST_FORCE_FIRM, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_update_use_count(), ast_module::declined, find_resource(), ast_module::flags, ast_module::info, ast_module::lib, LOG_WARNING, ast_module_info::restore_globals, ast_module::running, unload_dynamic_module(), and ast_module::usecount.
Referenced by exit_now(), handle_unload(), manager_moduleload(), reload(), and remove_module().
00459 { 00460 struct ast_module *mod; 00461 int res = -1; 00462 int error = 0; 00463 00464 AST_LIST_LOCK(&module_list); 00465 00466 if (!(mod = find_resource(resource_name, 0))) { 00467 AST_LIST_UNLOCK(&module_list); 00468 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name); 00469 return 0; 00470 } 00471 00472 if (!(mod->flags.running || mod->flags.declined)) 00473 error = 1; 00474 00475 if (!error && (mod->usecount > 0)) { 00476 if (force) 00477 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", 00478 resource_name, mod->usecount); 00479 else { 00480 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, 00481 mod->usecount); 00482 error = 1; 00483 } 00484 } 00485 00486 if (!error) { 00487 __ast_module_user_hangup_all(mod); 00488 res = mod->info->unload(); 00489 00490 if (res) { 00491 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00492 if (force <= AST_FORCE_FIRM) 00493 error = 1; 00494 else 00495 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00496 } 00497 } 00498 00499 if (!error) 00500 mod->flags.running = mod->flags.declined = 0; 00501 00502 AST_LIST_UNLOCK(&module_list); 00503 00504 if (!error && !mod->lib && mod->info && mod->info->restore_globals) 00505 mod->info->restore_globals(); 00506 00507 #ifdef LOADABLE_MODULES 00508 if (!error) 00509 unload_dynamic_module(mod); 00510 #endif 00511 00512 if (!error) 00513 ast_update_use_count(); 00514 00515 return res; 00516 }
int ast_update_module_list | ( | int(*)(const char *module, const char *description, int usecnt, const char *like) | modentry, | |
const char * | like | |||
) |
Ask for a list of modules, descriptions, and use counts.
modentry | A callback to an updater function. | |
like | For each of the modules loaded, modentry will be executed with the resource, description, and usecount values of each particular module. |
Definition at line 930 of file loader.c.
References AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_module_info::description, ast_module::info, ast_module::resource, and ast_module::usecount.
Referenced by handle_modlist(), and mod_update().
00932 { 00933 struct ast_module *cur; 00934 int unlock = -1; 00935 int total_mod_loaded = 0; 00936 00937 if (AST_LIST_TRYLOCK(&module_list)) 00938 unlock = 0; 00939 00940 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00941 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like); 00942 } 00943 00944 if (unlock) 00945 AST_LIST_UNLOCK(&module_list); 00946 00947 return total_mod_loaded; 00948 }
void ast_update_use_count | ( | void | ) |
Notify when usecount has been changed.
This function calulates use counts and notifies anyone trying to keep track of them. It should be called whenever your module's usecount changes.
Definition at line 918 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and loadupdate::updater.
Referenced by __ast_module_user_add(), __ast_module_user_hangup_all(), __ast_module_user_remove(), ast_module_ref(), ast_module_unref(), ast_unload_resource(), exit_now(), handle_request_do(), load_module(), load_resource(), oh323_request(), sip_request_call(), and unistim_new().
00919 { 00920 /* Notify any module monitors that the use count for a 00921 resource has changed */ 00922 struct loadupdate *m; 00923 00924 AST_LIST_LOCK(&updaters); 00925 AST_LIST_TRAVERSE(&updaters, m, entry) 00926 m->updater(); 00927 AST_LIST_UNLOCK(&updaters); 00928 }
static struct ast_module* find_resource | ( | const char * | resource, | |
int | do_lock | |||
) | [static] |
Definition at line 315 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module_user::entry, ast_module::resource, and resource_name_match().
Referenced by ast_module_check(), ast_unload_resource(), and load_resource().
00316 { 00317 struct ast_module *cur; 00318 00319 if (do_lock) 00320 AST_LIST_LOCK(&module_list); 00321 00322 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00323 if (!resource_name_match(resource, cur->resource)) 00324 break; 00325 } 00326 00327 if (do_lock) 00328 AST_LIST_UNLOCK(&module_list); 00329 00330 return cur; 00331 }
static unsigned int inspect_module | ( | const struct ast_module * | mod | ) | [static] |
Definition at line 608 of file loader.c.
References ast_log(), ast_strlen_zero(), buildopt_sum, ast_module_info::buildopt_sum, ast_module_info::description, ast_module::info, ast_module_info::key, LOG_WARNING, ast_module::resource, and verify_key().
Referenced by load_resource().
00609 { 00610 if (!mod->info->description) { 00611 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource); 00612 return 1; 00613 } 00614 00615 if (!mod->info->key) { 00616 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource); 00617 return 1; 00618 } 00619 00620 if (verify_key((unsigned char *) mod->info->key)) { 00621 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource); 00622 return 1; 00623 } 00624 00625 if (!ast_strlen_zero(mod->info->buildopt_sum) && 00626 strcmp(buildopt_sum, mod->info->buildopt_sum)) { 00627 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource); 00628 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource); 00629 return 1; 00630 } 00631 00632 return 0; 00633 }
static int key_matches | ( | const unsigned char * | key1, | |
const unsigned char * | key2 | |||
) | [static] |
Definition at line 268 of file loader.c.
Referenced by verify_key().
00269 { 00270 int x; 00271 00272 for (x = 0; x < 16; x++) { 00273 if (key1[x] != key2[x]) 00274 return 0; 00275 } 00276 00277 return 1; 00278 }
static struct ast_module* load_dynamic_module | ( | const char * | resource_in, | |
unsigned int | global_symbols_only | |||
) | [static] |
Definition at line 346 of file loader.c.
References ast_calloc, ast_config_AST_MODULE_DIR, ast_free, AST_LIST_LAST, ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, ast_test_flag, ast_module::info, ast_module::lib, LOG_WARNING, ast_module::resource, resource_being_loaded, RTLD_LOCAL, and RTLD_NOW.
Referenced by load_resource().
00347 { 00348 char fn[PATH_MAX] = ""; 00349 void *lib = NULL; 00350 struct ast_module *mod; 00351 unsigned int wants_global; 00352 int space; /* room needed for the descriptor */ 00353 int missing_so = 0; 00354 00355 space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1; 00356 if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) { 00357 missing_so = 1; 00358 space += 3; /* room for the extra ".so" */ 00359 } 00360 00361 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : ""); 00362 00363 /* make a first load of the module in 'quiet' mode... don't try to resolve 00364 any symbols, and don't export any symbols. this will allow us to peek into 00365 the module's info block (if available) to see what flags it has set */ 00366 00367 resource_being_loaded = ast_calloc(1, space); 00368 if (!resource_being_loaded) 00369 return NULL; 00370 strcpy(resource_being_loaded->resource, resource_in); 00371 if (missing_so) 00372 strcat(resource_being_loaded->resource, ".so"); 00373 00374 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { 00375 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00376 ast_free(resource_being_loaded); 00377 return NULL; 00378 } 00379 00380 /* the dlopen() succeeded, let's find out if the module 00381 registered itself */ 00382 /* note that this will only work properly as long as 00383 ast_module_register() (which is called by the module's 00384 constructor) places the new module at the tail of the 00385 module_list 00386 */ 00387 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) { 00388 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); 00389 /* no, it did not, so close it and return */ 00390 while (!dlclose(lib)); 00391 /* note that the module's destructor will call ast_module_unregister(), 00392 which will free the structure we allocated in resource_being_loaded */ 00393 return NULL; 00394 } 00395 00396 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); 00397 00398 /* if we are being asked only to load modules that provide global symbols, 00399 and this one does not, then close it and return */ 00400 if (global_symbols_only && !wants_global) { 00401 while (!dlclose(lib)); 00402 return NULL; 00403 } 00404 00405 while (!dlclose(lib)); 00406 resource_being_loaded = NULL; 00407 00408 /* start the load process again */ 00409 resource_being_loaded = ast_calloc(1, space); 00410 if (!resource_being_loaded) 00411 return NULL; 00412 strcpy(resource_being_loaded->resource, resource_in); 00413 if (missing_so) 00414 strcat(resource_being_loaded->resource, ".so"); 00415 00416 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { 00417 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00418 ast_free(resource_being_loaded); 00419 return NULL; 00420 } 00421 00422 /* since the module was successfully opened, and it registered itself 00423 the previous time we did that, we're going to assume it worked this 00424 time too :) */ 00425 00426 AST_LIST_LAST(&module_list)->lib = lib; 00427 resource_being_loaded = NULL; 00428 00429 return AST_LIST_LAST(&module_list); 00430 }
int load_modules | ( | unsigned | int | ) |
Provided by loader.c
Definition at line 745 of file loader.c.
References add_to_load_order(), ast_config_load2(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, ast_log(), AST_MODULE_CONFIG, ast_variable_browse(), ast_verb, config_flags, dir, embedding, LOG_WARNING, ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by main().
00746 { 00747 struct ast_config *cfg; 00748 struct ast_module *mod; 00749 struct load_order_entry *order; 00750 struct ast_variable *v; 00751 unsigned int load_count; 00752 struct load_order load_order; 00753 int res = 0; 00754 struct ast_flags config_flags = { 0 }; 00755 int modulecount = 0; 00756 00757 #ifdef LOADABLE_MODULES 00758 struct dirent *dirent; 00759 DIR *dir; 00760 #endif 00761 00762 /* all embedded modules have registered themselves by now */ 00763 embedding = 0; 00764 00765 ast_verb(1, "Asterisk Dynamic Loader Starting:\n"); 00766 00767 AST_LIST_HEAD_INIT_NOLOCK(&load_order); 00768 00769 AST_LIST_LOCK(&module_list); 00770 00771 if (embedded_module_list.first) { 00772 module_list.first = embedded_module_list.first; 00773 module_list.last = embedded_module_list.last; 00774 embedded_module_list.first = NULL; 00775 } 00776 00777 if (!(cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags))) { 00778 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); 00779 goto done; 00780 } 00781 00782 /* first, find all the modules we have been explicitly requested to load */ 00783 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00784 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) { 00785 add_to_load_order(v->value, &load_order); 00786 } 00787 } 00788 00789 /* check if 'autoload' is on */ 00790 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00791 /* if so, first add all the embedded modules that are not already running to the load order */ 00792 AST_LIST_TRAVERSE(&module_list, mod, entry) { 00793 /* if it's not embedded, skip it */ 00794 if (mod->lib) 00795 continue; 00796 00797 if (mod->flags.running) 00798 continue; 00799 00800 order = add_to_load_order(mod->resource, &load_order); 00801 } 00802 00803 #ifdef LOADABLE_MODULES 00804 /* if we are allowed to load dynamic modules, scan the directory for 00805 for all available modules and add them as well */ 00806 if ((dir = opendir(ast_config_AST_MODULE_DIR))) { 00807 while ((dirent = readdir(dir))) { 00808 int ld = strlen(dirent->d_name); 00809 00810 /* Must end in .so to load it. */ 00811 00812 if (ld < 4) 00813 continue; 00814 00815 if (strcasecmp(dirent->d_name + ld - 3, ".so")) 00816 continue; 00817 00818 /* if there is already a module by this name in the module_list, 00819 skip this file */ 00820 if (find_resource(dirent->d_name, 0)) 00821 continue; 00822 00823 add_to_load_order(dirent->d_name, &load_order); 00824 } 00825 00826 closedir(dir); 00827 } else { 00828 if (!ast_opt_quiet) 00829 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", 00830 ast_config_AST_MODULE_DIR); 00831 } 00832 #endif 00833 } 00834 00835 /* now scan the config for any modules we are prohibited from loading and 00836 remove them from the load order */ 00837 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00838 if (strcasecmp(v->name, "noload")) 00839 continue; 00840 00841 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00842 if (!resource_name_match(order->resource, v->value)) { 00843 AST_LIST_REMOVE_CURRENT(entry); 00844 ast_free(order->resource); 00845 ast_free(order); 00846 } 00847 } 00848 AST_LIST_TRAVERSE_SAFE_END; 00849 } 00850 00851 /* we are done with the config now, all the information we need is in the 00852 load_order list */ 00853 ast_config_destroy(cfg); 00854 00855 load_count = 0; 00856 AST_LIST_TRAVERSE(&load_order, order, entry) 00857 load_count++; 00858 00859 if (load_count) 00860 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); 00861 00862 /* first, load only modules that provide global symbols */ 00863 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00864 switch (load_resource(order->resource, 1)) { 00865 case AST_MODULE_LOAD_SUCCESS: 00866 modulecount++; 00867 case AST_MODULE_LOAD_DECLINE: 00868 AST_LIST_REMOVE_CURRENT(entry); 00869 ast_free(order->resource); 00870 ast_free(order); 00871 break; 00872 case AST_MODULE_LOAD_FAILURE: 00873 res = -1; 00874 goto done; 00875 case AST_MODULE_LOAD_SKIP: 00876 /* try again later */ 00877 break; 00878 } 00879 } 00880 AST_LIST_TRAVERSE_SAFE_END; 00881 00882 /* now load everything else */ 00883 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00884 switch (load_resource(order->resource, 0)) { 00885 case AST_MODULE_LOAD_SUCCESS: 00886 modulecount++; 00887 case AST_MODULE_LOAD_DECLINE: 00888 AST_LIST_REMOVE_CURRENT(entry); 00889 ast_free(order->resource); 00890 ast_free(order); 00891 break; 00892 case AST_MODULE_LOAD_FAILURE: 00893 res = -1; 00894 goto done; 00895 case AST_MODULE_LOAD_SKIP: 00896 /* should not happen */ 00897 break; 00898 } 00899 } 00900 AST_LIST_TRAVERSE_SAFE_END; 00901 00902 done: 00903 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { 00904 ast_free(order->resource); 00905 ast_free(order); 00906 } 00907 00908 AST_LIST_UNLOCK(&module_list); 00909 00910 /* Tell manager clients that are aggressive at logging in that we're done 00911 loading modules. If there's a DNS problem in chan_sip, we might not 00912 even reach this */ 00913 manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount); 00914 00915 return res; 00916 }
static enum ast_module_load_result load_resource | ( | const char * | resource_name, | |
unsigned int | global_symbols_only | |||
) | [static] |
Definition at line 635 of file loader.c.
References ast_fully_booted, ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SKIP, AST_MODULE_LOAD_SUCCESS, ast_opt_console, ast_test_flag, ast_update_use_count(), ast_verb, ast_verbose, ast_module_info::backup_globals, COLOR_BLACK, COLOR_BROWN, ast_module::declined, ast_module_info::description, find_resource(), ast_module::flags, ast_module::info, inspect_module(), ast_module::lib, ast_module_info::load, load_dynamic_module(), LOG_WARNING, option_verbose, ast_module::running, term_color(), and unload_dynamic_module().
Referenced by ast_load_resource().
00636 { 00637 struct ast_module *mod; 00638 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; 00639 char tmp[256]; 00640 00641 if ((mod = find_resource(resource_name, 0))) { 00642 if (mod->flags.running) { 00643 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); 00644 return AST_MODULE_LOAD_DECLINE; 00645 } 00646 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) 00647 return AST_MODULE_LOAD_SKIP; 00648 } else { 00649 #ifdef LOADABLE_MODULES 00650 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { 00651 /* don't generate a warning message during load_modules() */ 00652 if (!global_symbols_only) { 00653 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00654 return AST_MODULE_LOAD_DECLINE; 00655 } else { 00656 return AST_MODULE_LOAD_SKIP; 00657 } 00658 } 00659 #else 00660 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00661 return AST_MODULE_LOAD_DECLINE; 00662 #endif 00663 } 00664 00665 if (inspect_module(mod)) { 00666 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00667 #ifdef LOADABLE_MODULES 00668 unload_dynamic_module(mod); 00669 #endif 00670 return AST_MODULE_LOAD_DECLINE; 00671 } 00672 00673 if (!mod->lib && mod->info->backup_globals()) { 00674 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name); 00675 return AST_MODULE_LOAD_DECLINE; 00676 } 00677 00678 mod->flags.declined = 0; 00679 00680 if (mod->info->load) 00681 res = mod->info->load(); 00682 00683 switch (res) { 00684 case AST_MODULE_LOAD_SUCCESS: 00685 if (!ast_fully_booted) { 00686 ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00687 if (ast_opt_console && !option_verbose) 00688 ast_verbose( "."); 00689 } else { 00690 ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description); 00691 } 00692 00693 mod->flags.running = 1; 00694 00695 ast_update_use_count(); 00696 break; 00697 case AST_MODULE_LOAD_DECLINE: 00698 mod->flags.declined = 1; 00699 break; 00700 case AST_MODULE_LOAD_FAILURE: 00701 break; 00702 case AST_MODULE_LOAD_SKIP: 00703 /* modules should never return this value */ 00704 break; 00705 } 00706 00707 return res; 00708 }
static int printdigest | ( | const unsigned char * | d | ) | [static] |
Definition at line 255 of file loader.c.
References ast_debug, and buf.
Referenced by verify_key().
00256 { 00257 int x, pos; 00258 char buf[256]; /* large enough so we don't have to worry */ 00259 00260 for (pos = 0, x = 0; x < 16; x++) 00261 pos += sprintf(buf + pos, " %02x", *d++); 00262 00263 ast_debug(1, "Unexpected signature:%s\n", buf); 00264 00265 return 0; 00266 }
static int resource_name_match | ( | const char * | name1_in, | |
const char * | name2_in | |||
) | [static] |
Definition at line 297 of file loader.c.
References ast_strdupa.
Referenced by add_to_load_order(), ast_module_reload(), and find_resource().
00298 { 00299 char *name1 = (char *) name1_in; 00300 char *name2 = (char *) name2_in; 00301 00302 /* trim off any .so extensions */ 00303 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { 00304 name1 = ast_strdupa(name1); 00305 name1[strlen(name1) - 3] = '\0'; 00306 } 00307 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { 00308 name2 = ast_strdupa(name2); 00309 name2[strlen(name2) - 3] = '\0'; 00310 } 00311 00312 return strcasecmp(name1, name2); 00313 }
static void unload_dynamic_module | ( | struct ast_module * | mod | ) | [static] |
Definition at line 334 of file loader.c.
References ast_module::lib.
Referenced by ast_unload_resource(), and load_resource().
00335 { 00336 void *lib = mod->lib; 00337 00338 /* WARNING: the structure pointed to by mod is going to 00339 disappear when this operation succeeds, so we can't 00340 dereference it */ 00341 00342 if (lib) 00343 while (!dlclose(lib)); 00344 }
static int verify_key | ( | const unsigned char * | key | ) | [static] |
Definition at line 280 of file loader.c.
References expected_key, key_matches(), MD5Final(), MD5Init(), MD5Update(), and printdigest().
Referenced by inspect_module().
00281 { 00282 struct MD5Context c; 00283 unsigned char digest[16]; 00284 00285 MD5Init(&c); 00286 MD5Update(&c, key, strlen((char *)key)); 00287 MD5Final(digest, &c); 00288 00289 if (key_matches(expected_key, digest)) 00290 return 0; 00291 00292 printdigest(digest); 00293 00294 return -1; 00295 }
char buildopt_sum[33] = AST_BUILDOPT_SUM [static] |
struct module_list embedded_module_list [static] |
unsigned int embedding = 1 [static] |
unsigned char expected_key[] [static] |
Initial value:
{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3, 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 }
Definition at line 73 of file loader.c.
Referenced by verify_key().
ast_mutex_t reloadlock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static] |
struct ast_module* resource_being_loaded |
Definition at line 119 of file loader.c.
Referenced by ast_module_register(), and load_dynamic_module().