Wed Oct 28 13:33:05 2009

Asterisk developer's documentation


loader.c File Reference

Module Loader. More...

#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/http.h"
#include "asterisk/lock.h"
#include "asterisk/features.h"
#include "asterisk/dsp.h"
#include "asterisk/udptl.h"
#include "asterisk/heap.h"
#include <dlfcn.h>
#include "asterisk/md5.h"
#include "asterisk/utils.h"

Include dependency graph for loader.c:

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  reload_queue
struct  reload_queue_item
struct  updaters

Defines

#define RTLD_LOCAL   0
#define RTLD_NOW   0

Functions

struct 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_entryadd_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 exists.
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.
struct ast_moduleast_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)
void ast_process_pending_reloads (void)
 Process reload requests received during startup.
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_modulefind_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)
int load_modules (unsigned int preload_only)
static enum ast_module_load_result load_resource (const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap)
static int load_resource_list (struct load_order *load_order, unsigned int global_symbols, int *mod_count)
static int mod_load_cmp (void *a, void *b)
static int printdigest (const unsigned char *d)
static void queue_reload_request (const char *module)
static int resource_name_match (const char *name1_in, const char *name2_in)
static enum ast_module_load_result start_resource (struct ast_module *mod)
static int verify_key (const unsigned char *key)

Variables

static char buildopt_sum [33] = AST_BUILDOPT_SUM
static int do_full_reload = 0
static struct module_list embedded_module_list
static unsigned int embedding = 1
static const unsigned char expected_key []
static ast_mutex_t reloadlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static struct ast_moduleresource_being_loaded


Detailed Description

Module Loader.

Author:
Mark Spencer <markster@digium.com>

Kevin P. Fleming <kpfleming@digium.com>

Luigi Rizzo <rizzo@icir.org>

  • See ModMngMnt

Definition in file loader.c.


Define Documentation

#define RTLD_LOCAL   0

Definition at line 63 of file loader.c.

#define RTLD_NOW   0

Definition at line 59 of file loader.c.


Function Documentation

struct ast_module_user* __ast_module_user_add ( struct ast_module mod,
struct ast_channel chan 
) [read]

Definition at line 194 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::usecount, and ast_module::users.

Referenced by ast_func_read(), ast_func_read2(), ast_func_write(), and pbx_exec().

00196 {
00197    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00198 
00199    if (!u)
00200       return NULL;
00201 
00202    u->chan = chan;
00203 
00204    AST_LIST_LOCK(&mod->users);
00205    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00206    AST_LIST_UNLOCK(&mod->users);
00207 
00208    ast_atomic_fetchadd_int(&mod->usecount, +1);
00209 
00210    ast_update_use_count();
00211 
00212    return u;
00213 }

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 
) [static, read]

Definition at line 834 of file loader.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strdup, load_order_entry::resource, and resource_name_match().

Referenced by load_modules().

00835 {
00836    struct load_order_entry *order;
00837 
00838    AST_LIST_TRAVERSE(load_order, order, entry) {
00839       if (!resource_name_match(order->resource, resource))
00840          return NULL;
00841    }
00842 
00843    if (!(order = ast_calloc(1, sizeof(*order))))
00844       return NULL;
00845 
00846    order->resource = ast_strdup(resource);
00847    AST_LIST_INSERT_TAIL(load_order, order, entry);
00848 
00849    return order;
00850 }

int ast_load_resource ( const char *  resource_name  ) 

Load a module.

Parameters:
resource_name The name of the module to load.
This function is run by the PBX to load the modules. It performs all loading and initialization tasks. Basically, to load a module, just give it the name of the module and it will do the rest.

Returns:
See possible enum values for ast_module_load_result.

Definition at line 817 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().

00818 {
00819    int res;
00820    AST_LIST_LOCK(&module_list);
00821    res = load_resource(resource_name, 0, NULL);
00822    AST_LIST_UNLOCK(&module_list);
00823 
00824    return res;
00825 }

int ast_loader_register ( int(*)(void)  updater  ) 

Add a procedure to be run when modules have been updated.

Parameters:
updater The function to run when modules have been updated.
This function adds the given function to a linked list of functions to be run when the modules are updated.

Return values:
0 on success
-1 on failure.

Definition at line 1117 of file loader.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_malloc, and loadupdate::updater.

Referenced by show_console().

01118 {
01119    struct loadupdate *tmp;
01120 
01121    if (!(tmp = ast_malloc(sizeof(*tmp))))
01122       return -1;
01123 
01124    tmp->updater = v;
01125    AST_LIST_LOCK(&updaters);
01126    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01127    AST_LIST_UNLOCK(&updaters);
01128 
01129    return 0;
01130 }

int ast_loader_unregister ( int(*)(void)  updater  ) 

Remove a procedure to be run when modules are updated.

Parameters:
updater The updater function to unregister.
This removes the given function from the updater list.

Return values:
0 on success
-1 on failure.

Definition at line 1132 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().

01133 {
01134    struct loadupdate *cur;
01135 
01136    AST_LIST_LOCK(&updaters);
01137    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01138       if (cur->updater == v)  {
01139          AST_LIST_REMOVE_CURRENT(entry);
01140          break;
01141       }
01142    }
01143    AST_LIST_TRAVERSE_SAFE_END;
01144    AST_LIST_UNLOCK(&updaters);
01145 
01146    return cur ? 0 : -1;
01147 }

int ast_module_check ( const char *  name  ) 

Check if module exists.

Check if module with the name given is loaded.

Definition at line 1104 of file loader.c.

References ast_strlen_zero(), and find_resource().

Referenced by ifmodule_read(), load_module(), manager_modulecheck(), and unload_module().

01105 {
01106    struct ast_module *cur;
01107 
01108    if (ast_strlen_zero(name))
01109       return 0;       /* FALSE */
01110 
01111    cur = find_resource(name, 1);
01112 
01113    return (cur != NULL);
01114 }

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.

Parameters:
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.
Return values:
A possible completion of the partial match.
NULL if no matches were found.

Definition at line 528 of file loader.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_module::info, name, ast_module_info::reload, and ast_module::resource.

Referenced by conf_run(), handle_modlist(), handle_reload(), handle_unload(), and load_module().

00529 {
00530    struct ast_module *cur;
00531    int i, which=0, l = strlen(word);
00532    char *ret = NULL;
00533 
00534    if (pos != rpos)
00535       return NULL;
00536 
00537    AST_LIST_LOCK(&module_list);
00538    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00539       if (!strncasecmp(word, cur->resource, l) &&
00540           (cur->info->reload || !needsreload) &&
00541           ++which > state) {
00542          ret = ast_strdup(cur->resource);
00543          break;
00544       }
00545    }
00546    AST_LIST_UNLOCK(&module_list);
00547 
00548    if (!ret) {
00549       for (i=0; !ret && reload_classes[i].name; i++) {
00550          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00551             ret = ast_strdup(reload_classes[i].name);
00552       }
00553    }
00554 
00555    return ret;
00556 }

struct ast_module* ast_module_ref ( struct ast_module mod  )  [read]

void ast_module_register ( const struct ast_module_info info  ) 

Definition at line 132 of file loader.c.

References ast_calloc, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, embedding, ast_module::info, ast_module::resource, and ast_module::users.

00133 {
00134    struct ast_module *mod;
00135 
00136    if (embedding) {
00137       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00138          return;
00139       strcpy(mod->resource, info->name);
00140    } else {
00141       mod = resource_being_loaded;
00142    }
00143 
00144    mod->info = info;
00145    AST_LIST_HEAD_INIT(&mod->users);
00146 
00147    /* during startup, before the loader has been initialized,
00148       there are no threads, so there is no need to take the lock
00149       on this list to manipulate it. it is also possible that it
00150       might be unsafe to use the list lock at that point... so
00151       let's avoid it altogether
00152    */
00153    if (embedding) {
00154       AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00155    } else {
00156       AST_LIST_LOCK(&module_list);
00157       /* it is paramount that the new entry be placed at the tail of
00158          the list, otherwise the code that uses dlopen() to load
00159          dynamic modules won't be able to find out if the module it
00160          just opened was registered or failed to load
00161       */
00162       AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00163       AST_LIST_UNLOCK(&module_list);
00164    }
00165 
00166    /* give the module a copy of its own handle, for later use in registrations and the like */
00167    *((struct ast_module **) &(info->self)) = mod;
00168 }

int ast_module_reload ( const char *  name  ) 

Reload asterisk modules.

Parameters:
name the name of the module to reload
This function reloads the specified module, or if no modules are specified, it will reload all loaded modules.

Note:
Modules are reloaded using their reload() functions, not unloading them and loading them again.
Returns:
0 if the specified module was not found.
Return values:
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 623 of file loader.c.

References ast_fully_booted, 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::flags, ast_module::info, LOG_NOTICE, queue_reload_request(), ast_module_info::reload, ast_module::resource, resource_name_match(), and ast_module::running.

Referenced by action_reload(), action_updateconfig(), ast_process_pending_reloads(), handle_reload(), manager_moduleload(), and monitor_sig_flags().

00624 {
00625    struct ast_module *cur;
00626    int res = 0; /* return value. 0 = not found, others, see below */
00627    int i;
00628 
00629    /* If we aren't fully booted, we just pretend we reloaded but we queue this
00630       up to run once we are booted up. */
00631    if (!ast_fully_booted) {
00632       queue_reload_request(name);
00633       return 0;
00634    }
00635 
00636    if (ast_mutex_trylock(&reloadlock)) {
00637       ast_verbose("The previous reload command didn't finish yet\n");
00638       return -1;  /* reload already in progress */
00639    }
00640    ast_lastreloadtime = ast_tvnow();
00641 
00642    /* Call "predefined" reload here first */
00643    for (i = 0; reload_classes[i].name; i++) {
00644       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00645          reload_classes[i].reload_fn();   /* XXX should check error ? */
00646          res = 2; /* found and reloaded */
00647       }
00648    }
00649 
00650    if (name && res) {
00651       ast_mutex_unlock(&reloadlock);
00652       return res;
00653    }
00654 
00655    AST_LIST_LOCK(&module_list);
00656    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00657       const struct ast_module_info *info = cur->info;
00658 
00659       if (name && resource_name_match(name, cur->resource))
00660          continue;
00661 
00662       if (!cur->flags.running || cur->flags.declined) {
00663          if (!name)
00664             continue;
00665          ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
00666             "Before reloading the module, you must run \"module load %s\" "
00667             "and fix whatever is preventing the module from being initialized.\n",
00668             name, name);
00669          res = 2; /* Don't report that the module was not found */
00670          break;
00671       }
00672 
00673       if (!info->reload) { /* cannot be reloaded */
00674          if (res < 1)   /* store result if possible */
00675             res = 1; /* 1 = no reload() method */
00676          continue;
00677       }
00678 
00679       res = 2;
00680       ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00681       info->reload();
00682    }
00683    AST_LIST_UNLOCK(&module_list);
00684 
00685    ast_mutex_unlock(&reloadlock);
00686 
00687    return res;
00688 }

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 443 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, free, ast_module::info, ast_module_info::unload, and ast_module::users.

Referenced by quit_handler().

00444 {
00445    struct ast_module *mod;
00446    AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
00447 
00448    /* We have to call the unload() callbacks in reverse order that the modules
00449     * exist in the module list so it is the reverse order of how they were
00450     * loaded. */
00451 
00452    AST_LIST_LOCK(&module_list);
00453    while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
00454       AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
00455    AST_LIST_UNLOCK(&module_list);
00456 
00457    while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
00458       if (mod->info->unload)
00459          mod->info->unload();
00460       /* Since this should only be called when shutting down "gracefully",
00461        * all channels should be down before we get to this point, meaning
00462        * there will be no module users left. */
00463       AST_LIST_HEAD_DESTROY(&mod->users);
00464       free(mod);
00465    }
00466 }

void ast_module_unref ( struct ast_module mod  ) 

void ast_module_unregister ( const struct ast_module_info info  ) 

Definition at line 170 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::info, and ast_module::users.

00171 {
00172    struct ast_module *mod = NULL;
00173 
00174    /* it is assumed that the users list in the module structure
00175       will already be empty, or we cannot have gotten to this
00176       point
00177    */
00178    AST_LIST_LOCK(&module_list);
00179    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00180       if (mod->info == info) {
00181          AST_LIST_REMOVE_CURRENT(entry);
00182          break;
00183       }
00184    }
00185    AST_LIST_TRAVERSE_SAFE_END;
00186    AST_LIST_UNLOCK(&module_list);
00187 
00188    if (mod) {
00189       AST_LIST_HEAD_DESTROY(&mod->users);
00190       ast_free(mod);
00191    }
00192 }

void ast_process_pending_reloads ( void   ) 

Process reload requests received during startup.

This function requests that the loader execute the pending reload requests that were queued during server startup.

Note:
This function will do nothing if the server has not completely started up. Once called, the reload queue is emptied, and further invocations will have no affect.

Definition at line 558 of file loader.c.

References ast_free, ast_fully_booted, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_module_reload(), do_full_reload, LOG_NOTICE, and reload_queue_item::module.

Referenced by main().

00559 {
00560    struct reload_queue_item *item;
00561 
00562    if (!ast_fully_booted) {
00563       return;
00564    }
00565 
00566    AST_LIST_LOCK(&reload_queue);
00567 
00568    if (do_full_reload) {
00569       do_full_reload = 0;
00570       AST_LIST_UNLOCK(&reload_queue);
00571       ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00572       ast_module_reload(NULL);
00573       return;
00574    }
00575 
00576    while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00577       ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00578       ast_module_reload(item->module);
00579       ast_free(item);
00580    }
00581 
00582    AST_LIST_UNLOCK(&reload_queue);
00583 }

int ast_unload_resource ( const char *  resource_name,
enum  ast_module_unload_mode 
)

Unload a module.

Parameters:
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.
This function unloads a module. It will only unload modules that are not in use (usecount not zero), unless AST_FORCE_FIRM or AST_FORCE_HARD is specified. Setting AST_FORCE_FIRM or AST_FORCE_HARD will unload the module regardless of consequences (NOT RECOMMENDED).

Return values:
0 on success.
-1 on error.

Definition at line 468 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, ast_module_info::unload, and ast_module::usecount.

Referenced by exit_now(), handle_unload(), manager_moduleload(), reload(), remove_module(), and unload_module().

00469 {
00470    struct ast_module *mod;
00471    int res = -1;
00472    int error = 0;
00473 
00474    AST_LIST_LOCK(&module_list);
00475 
00476    if (!(mod = find_resource(resource_name, 0))) {
00477       AST_LIST_UNLOCK(&module_list);
00478       ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00479       return 0;
00480    }
00481 
00482    if (!(mod->flags.running || mod->flags.declined))
00483       error = 1;
00484 
00485    if (!error && (mod->usecount > 0)) {
00486       if (force)
00487          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00488             resource_name, mod->usecount);
00489       else {
00490          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00491             mod->usecount);
00492          error = 1;
00493       }
00494    }
00495 
00496    if (!error) {
00497       __ast_module_user_hangup_all(mod);
00498       res = mod->info->unload();
00499 
00500       if (res) {
00501          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00502          if (force <= AST_FORCE_FIRM)
00503             error = 1;
00504          else
00505             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00506       }
00507    }
00508 
00509    if (!error)
00510       mod->flags.running = mod->flags.declined = 0;
00511 
00512    AST_LIST_UNLOCK(&module_list);
00513 
00514    if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00515       mod->info->restore_globals();
00516 
00517 #ifdef LOADABLE_MODULES
00518    if (!error)
00519       unload_dynamic_module(mod);
00520 #endif
00521 
00522    if (!error)
00523       ast_update_use_count();
00524 
00525    return res;
00526 }

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.

Parameters:
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.
Returns:
the number of modules loaded

Definition at line 1083 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 ast_var_Modules(), handle_modlist(), and mod_update().

01085 {
01086    struct ast_module *cur;
01087    int unlock = -1;
01088    int total_mod_loaded = 0;
01089 
01090    if (AST_LIST_TRYLOCK(&module_list))
01091       unlock = 0;
01092  
01093    AST_LIST_TRAVERSE(&module_list, cur, entry) {
01094       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
01095    }
01096 
01097    if (unlock)
01098       AST_LIST_UNLOCK(&module_list);
01099 
01100    return total_mod_loaded;
01101 }

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.

Note:
The ast_module_user_* functions take care of calling this function for you.

Definition at line 1071 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(), oh323_request(), scheduler_process_request_queue(), sip_request_call(), start_resource(), and unistim_new().

01072 {
01073    /* Notify any module monitors that the use count for a
01074       resource has changed */
01075    struct loadupdate *m;
01076 
01077    AST_LIST_LOCK(&updaters);
01078    AST_LIST_TRAVERSE(&updaters, m, entry)
01079       m->updater();
01080    AST_LIST_UNLOCK(&updaters);
01081 }

static struct ast_module* find_resource ( const char *  resource,
int  do_lock 
) [static, read]

Definition at line 325 of file loader.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module::resource, and resource_name_match().

Referenced by ast_module_check(), ast_unload_resource(), load_modules(), and load_resource().

00326 {
00327    struct ast_module *cur;
00328 
00329    if (do_lock)
00330       AST_LIST_LOCK(&module_list);
00331 
00332    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00333       if (!resource_name_match(resource, cur->resource))
00334          break;
00335    }
00336 
00337    if (do_lock)
00338       AST_LIST_UNLOCK(&module_list);
00339 
00340    return cur;
00341 }

static unsigned int inspect_module ( const struct ast_module mod  )  [static]

Definition at line 690 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().

00691 {
00692    if (!mod->info->description) {
00693       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00694       return 1;
00695    }
00696 
00697    if (!mod->info->key) {
00698       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00699       return 1;
00700    }
00701 
00702    if (verify_key((unsigned char *) mod->info->key)) {
00703       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00704       return 1;
00705    }
00706 
00707    if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00708        strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00709       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00710       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00711       return 1;
00712    }
00713 
00714    return 0;
00715 }

static int key_matches ( const unsigned char *  key1,
const unsigned char *  key2 
) [static]

Definition at line 278 of file loader.c.

Referenced by verify_key().

00279 {
00280    int x;
00281 
00282    for (x = 0; x < 16; x++) {
00283       if (key1[x] != key2[x])
00284          return 0;
00285    }
00286 
00287    return 1;
00288 }

int load_modules ( unsigned  int  ) 

Provided by loader.c

Definition at line 927 of file loader.c.

References add_to_load_order(), ast_config_AST_MODULE_DIR, ast_config_destroy(), ast_config_load2(), ast_free, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MODULE_CONFIG, ast_opt_quiet, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, dir, embedding, EVENT_FLAG_SYSTEM, find_resource(), ast_module::flags, ast_module::lib, load_resource_list(), LOG_NOTICE, LOG_WARNING, manager_event, ast_variable::name, ast_variable::next, load_order_entry::resource, ast_module::resource, resource_name_match(), ast_module::running, and ast_variable::value.

Referenced by main().

00928 {
00929    struct ast_config *cfg;
00930    struct ast_module *mod;
00931    struct load_order_entry *order;
00932    struct ast_variable *v;
00933    unsigned int load_count;
00934    struct load_order load_order;
00935    int res = 0;
00936    struct ast_flags config_flags = { 0 };
00937    int modulecount = 0;
00938 
00939 #ifdef LOADABLE_MODULES
00940    struct dirent *dirent;
00941    DIR *dir;
00942 #endif
00943 
00944    /* all embedded modules have registered themselves by now */
00945    embedding = 0;
00946 
00947    ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
00948 
00949    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
00950 
00951    AST_LIST_LOCK(&module_list);
00952 
00953    if (embedded_module_list.first) {
00954       module_list.first = embedded_module_list.first;
00955       module_list.last = embedded_module_list.last;
00956       embedded_module_list.first = NULL;
00957    }
00958 
00959    cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
00960    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
00961       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
00962       goto done;
00963    }
00964 
00965    /* first, find all the modules we have been explicitly requested to load */
00966    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00967       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
00968          add_to_load_order(v->value, &load_order);
00969       }
00970    }
00971 
00972    /* check if 'autoload' is on */
00973    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00974       /* if so, first add all the embedded modules that are not already running to the load order */
00975       AST_LIST_TRAVERSE(&module_list, mod, entry) {
00976          /* if it's not embedded, skip it */
00977          if (mod->lib)
00978             continue;
00979 
00980          if (mod->flags.running)
00981             continue;
00982 
00983          order = add_to_load_order(mod->resource, &load_order);
00984       }
00985 
00986 #ifdef LOADABLE_MODULES
00987       /* if we are allowed to load dynamic modules, scan the directory for
00988          for all available modules and add them as well */
00989       if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
00990          while ((dirent = readdir(dir))) {
00991             int ld = strlen(dirent->d_name);
00992 
00993             /* Must end in .so to load it.  */
00994 
00995             if (ld < 4)
00996                continue;
00997 
00998             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
00999                continue;
01000 
01001             /* if there is already a module by this name in the module_list,
01002                skip this file */
01003             if (find_resource(dirent->d_name, 0))
01004                continue;
01005 
01006             add_to_load_order(dirent->d_name, &load_order);
01007          }
01008 
01009          closedir(dir);
01010       } else {
01011          if (!ast_opt_quiet)
01012             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01013                ast_config_AST_MODULE_DIR);
01014       }
01015 #endif
01016    }
01017 
01018    /* now scan the config for any modules we are prohibited from loading and
01019       remove them from the load order */
01020    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01021       if (strcasecmp(v->name, "noload"))
01022          continue;
01023 
01024       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01025          if (!resource_name_match(order->resource, v->value)) {
01026             AST_LIST_REMOVE_CURRENT(entry);
01027             ast_free(order->resource);
01028             ast_free(order);
01029          }
01030       }
01031       AST_LIST_TRAVERSE_SAFE_END;
01032    }
01033 
01034    /* we are done with the config now, all the information we need is in the
01035       load_order list */
01036    ast_config_destroy(cfg);
01037 
01038    load_count = 0;
01039    AST_LIST_TRAVERSE(&load_order, order, entry)
01040       load_count++;
01041 
01042    if (load_count)
01043       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
01044 
01045    /* first, load only modules that provide global symbols */
01046    if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01047       goto done;
01048    }
01049 
01050    /* now load everything else */
01051    if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01052       goto done;
01053    }
01054 
01055 done:
01056    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01057       ast_free(order->resource);
01058       ast_free(order);
01059    }
01060 
01061    AST_LIST_UNLOCK(&module_list);
01062    
01063    /* Tell manager clients that are aggressive at logging in that we're done
01064       loading modules. If there's a DNS problem in chan_sip, we might not
01065       even reach this */
01066    manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
01067    
01068    return res;
01069 }

static enum ast_module_load_result load_resource ( const char *  resource_name,
unsigned int  global_symbols_only,
struct ast_heap resource_heap 
) [static]

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 ast_heap is not provided, the module's load function will be executed immediately

Definition at line 763 of file loader.c.

References ast_heap_push(), ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_PRIORITY, AST_MODULE_LOAD_SKIP, AST_MODULE_LOAD_SUCCESS, ast_test_flag, ast_module_info::backup_globals, ast_module::declined, find_resource(), ast_module::flags, ast_module::info, inspect_module(), ast_module::lib, LOG_WARNING, ast_module::running, and start_resource().

Referenced by ast_load_resource(), and load_resource_list().

00764 {
00765    struct ast_module *mod;
00766    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00767 
00768    if ((mod = find_resource(resource_name, 0))) {
00769       if (mod->flags.running) {
00770          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00771          return AST_MODULE_LOAD_DECLINE;
00772       }
00773       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00774          return AST_MODULE_LOAD_SKIP;
00775    } else {
00776 #ifdef LOADABLE_MODULES
00777       if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00778          /* don't generate a warning message during load_modules() */
00779          if (!global_symbols_only) {
00780             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00781             return AST_MODULE_LOAD_DECLINE;
00782          } else {
00783             return AST_MODULE_LOAD_SKIP;
00784          }
00785       }
00786 #else
00787       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00788       return AST_MODULE_LOAD_DECLINE;
00789 #endif
00790    }
00791 
00792    if (inspect_module(mod)) {
00793       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00794 #ifdef LOADABLE_MODULES
00795       unload_dynamic_module(mod);
00796 #endif
00797       return AST_MODULE_LOAD_DECLINE;
00798    }
00799 
00800    if (!mod->lib && mod->info->backup_globals()) {
00801       ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
00802       return AST_MODULE_LOAD_DECLINE;
00803    }
00804 
00805    mod->flags.declined = 0;
00806 
00807    if (resource_heap) {
00808       ast_heap_push(resource_heap, mod);
00809       res = AST_MODULE_LOAD_PRIORITY;
00810    } else {
00811       res = start_resource(mod);
00812    }
00813 
00814    return res;
00815 }

static int load_resource_list ( struct load_order load_order,
unsigned int  global_symbols,
int *  mod_count 
) [static]

loads modules in order by load_pri, updates mod_count

Definition at line 869 of file loader.c.

References ast_free, ast_heap_create(), ast_heap_destroy(), ast_heap_pop(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_PRIORITY, AST_MODULE_LOAD_SKIP, AST_MODULE_LOAD_SUCCESS, load_resource(), mod_load_cmp(), load_order_entry::resource, and start_resource().

Referenced by load_modules().

00870 {
00871    struct ast_heap *resource_heap;
00872    struct load_order_entry *order;
00873    struct ast_module *mod;
00874    int count = 0;
00875    int res = 0;
00876 
00877    if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
00878       return -1;
00879    }
00880 
00881    /* first, add find and add modules to heap */
00882    AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
00883       switch (load_resource(order->resource, global_symbols, resource_heap)) {
00884       case AST_MODULE_LOAD_SUCCESS:
00885       case AST_MODULE_LOAD_DECLINE:
00886          AST_LIST_REMOVE_CURRENT(entry);
00887          ast_free(order->resource);
00888          ast_free(order);
00889          break;
00890       case AST_MODULE_LOAD_FAILURE:
00891          res = -1;
00892          goto done;
00893       case AST_MODULE_LOAD_SKIP:
00894          break;
00895       case AST_MODULE_LOAD_PRIORITY:
00896          AST_LIST_REMOVE_CURRENT(entry);
00897          break;
00898       }
00899    }
00900    AST_LIST_TRAVERSE_SAFE_END;
00901 
00902    /* second remove modules from heap sorted by priority */
00903    while ((mod = ast_heap_pop(resource_heap))) {
00904       switch (start_resource(mod)) {
00905       case AST_MODULE_LOAD_SUCCESS:
00906          count++;
00907       case AST_MODULE_LOAD_DECLINE:
00908          break;
00909       case AST_MODULE_LOAD_FAILURE:
00910          res = -1;
00911          goto done;
00912       case AST_MODULE_LOAD_SKIP:
00913       case AST_MODULE_LOAD_PRIORITY:
00914          break;
00915       }
00916    }
00917 
00918 done:
00919    if (mod_count) {
00920       *mod_count += count;
00921    }
00922    ast_heap_destroy(resource_heap);
00923 
00924    return res;
00925 }

static int mod_load_cmp ( void *  a,
void *  b 
) [static]

Definition at line 852 of file loader.c.

References AST_MODFLAG_LOAD_ORDER, ast_test_flag, ast_module::info, and ast_module_info::load_pri.

Referenced by load_resource_list().

00853 {
00854    struct ast_module *a_mod = (struct ast_module *) a;
00855    struct ast_module *b_mod = (struct ast_module *) b;
00856    int res = -1;
00857    /* if load_pri is not set, default is 255.  Lower is better*/
00858    unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 255;
00859    unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 255;
00860    if (a_pri == b_pri) {
00861       res = 0;
00862    } else if (a_pri < b_pri) {
00863       res = 1;
00864    }
00865    return res;
00866 }

static int printdigest ( const unsigned char *  d  )  [static]

Definition at line 265 of file loader.c.

References ast_debug, and buf.

Referenced by verify_key().

00266 {
00267    int x, pos;
00268    char buf[256]; /* large enough so we don't have to worry */
00269 
00270    for (pos = 0, x = 0; x < 16; x++)
00271       pos += sprintf(buf + pos, " %02x", *d++);
00272 
00273    ast_debug(1, "Unexpected signature:%s\n", buf);
00274 
00275    return 0;
00276 }

static void queue_reload_request ( const char *  module  )  [static]

Definition at line 585 of file loader.c.

References ast_calloc, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), do_full_reload, LOG_ERROR, and reload_queue_item::module.

Referenced by ast_module_reload().

00586 {
00587    struct reload_queue_item *item;
00588 
00589    AST_LIST_LOCK(&reload_queue);
00590 
00591    if (do_full_reload) {
00592       AST_LIST_UNLOCK(&reload_queue);
00593       return;
00594    }
00595 
00596    if (ast_strlen_zero(module)) {
00597       /* A full reload request (when module is NULL) wipes out any previous
00598          reload requests and causes the queue to ignore future ones */
00599       while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00600          ast_free(item);
00601       }
00602       do_full_reload = 1;
00603    } else {
00604       /* No reason to add the same module twice */
00605       AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00606          if (!strcasecmp(item->module, module)) {
00607             AST_LIST_UNLOCK(&reload_queue);
00608             return;
00609          }
00610       }
00611       item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00612       if (!item) {
00613          ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00614          AST_LIST_UNLOCK(&reload_queue);
00615          return;
00616       }
00617       strcpy(item->module, module);
00618       AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00619    }
00620    AST_LIST_UNLOCK(&reload_queue);
00621 }

static int resource_name_match ( const char *  name1_in,
const char *  name2_in 
) [static]

Definition at line 307 of file loader.c.

References ast_strdupa.

Referenced by add_to_load_order(), ast_module_reload(), find_resource(), and load_modules().

00308 {
00309    char *name1 = (char *) name1_in;
00310    char *name2 = (char *) name2_in;
00311 
00312    /* trim off any .so extensions */
00313    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00314       name1 = ast_strdupa(name1);
00315       name1[strlen(name1) - 3] = '\0';
00316    }
00317    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00318       name2 = ast_strdupa(name2);
00319       name2[strlen(name2) - 3] = '\0';
00320    }
00321 
00322    return strcasecmp(name1, name2);
00323 }

static enum ast_module_load_result start_resource ( struct ast_module mod  )  [static]

Definition at line 717 of file loader.c.

References ast_fully_booted, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_PRIORITY, AST_MODULE_LOAD_SKIP, AST_MODULE_LOAD_SUCCESS, ast_opt_console, ast_update_use_count(), ast_verb, ast_verbose, COLOR_BLACK, COLOR_BROWN, ast_module::declined, ast_module_info::description, ast_module::flags, ast_module::info, ast_module_info::load, option_verbose, ast_module::resource, ast_module::running, and term_color().

Referenced by load_resource(), and load_resource_list().

00718 {
00719    char tmp[256];
00720    enum ast_module_load_result res;
00721 
00722    if (!mod->info->load) {
00723       return AST_MODULE_LOAD_FAILURE;
00724    }
00725 
00726    res = mod->info->load();
00727 
00728    switch (res) {
00729    case AST_MODULE_LOAD_SUCCESS:
00730       if (!ast_fully_booted) {
00731          ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00732          if (ast_opt_console && !option_verbose)
00733             ast_verbose( ".");
00734       } else {
00735          ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
00736       }
00737 
00738       mod->flags.running = 1;
00739 
00740       ast_update_use_count();
00741       break;
00742    case AST_MODULE_LOAD_DECLINE:
00743       mod->flags.declined = 1;
00744       break;
00745    case AST_MODULE_LOAD_FAILURE:
00746    case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
00747    case AST_MODULE_LOAD_PRIORITY:
00748       break;
00749    }
00750 
00751    return res;
00752 }

static int verify_key ( const unsigned char *  key  )  [static]

Definition at line 290 of file loader.c.

References expected_key, key_matches(), MD5Final(), MD5Init(), MD5Update(), and printdigest().

Referenced by inspect_module().

00291 {
00292    struct MD5Context c;
00293    unsigned char digest[16];
00294 
00295    MD5Init(&c);
00296    MD5Update(&c, key, strlen((char *)key));
00297    MD5Final(digest, &c);
00298 
00299    if (key_matches(expected_key, digest))
00300       return 0;
00301 
00302    printdigest(digest);
00303 
00304    return -1;
00305 }


Variable Documentation

char buildopt_sum[33] = AST_BUILDOPT_SUM [static]

Definition at line 77 of file loader.c.

Referenced by inspect_module().

int do_full_reload = 0 [static]

Definition at line 120 of file loader.c.

Referenced by ast_process_pending_reloads(), and queue_reload_request().

Definition at line 104 of file loader.c.

unsigned int embedding = 1 [static]

Definition at line 79 of file loader.c.

Referenced by ast_module_register(), and load_modules().

const 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_MUTEX_INITIALIZER ) [static]

Definition at line 113 of file loader.c.

Definition at line 128 of file loader.c.


Generated on Wed Oct 28 13:33:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6