Thu May 14 14:50:02 2009

Asterisk developer's documentation


loader.c File Reference

Module Loader. More...

#include "asterisk.h"
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/config.h"
#include "asterisk/logger.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 <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_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_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.
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_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)
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)
static struct ast_moduleload_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 int translate_module_name (char *oldname, char *newname)
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 unsigned int embedding = 1
static unsigned char expected_key []
static ast_mutex_t reloadlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
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>

Definition in file loader.c.


Define Documentation

#define RTLD_NOW   0

Definition at line 61 of file loader.c.

Referenced by load_dynamic_module().


Function Documentation

struct ast_module_user* __ast_module_user_add ( struct ast_module mod,
struct ast_channel chan 
)

Definition at line 175 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.

00177 {
00178    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00179 
00180    if (!u)
00181       return NULL;
00182 
00183    u->chan = chan;
00184 
00185    AST_LIST_LOCK(&mod->users);
00186    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00187    AST_LIST_UNLOCK(&mod->users);
00188 
00189    ast_atomic_fetchadd_int(&mod->usecount, +1);
00190 
00191    ast_update_use_count();
00192 
00193    return u;
00194 }

void __ast_module_user_hangup_all ( struct ast_module mod  ) 

Definition at line 207 of file loader.c.

References ast_atomic_fetchadd_int(), 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, free, ast_module::usecount, and ast_module::users.

Referenced by ast_unload_resource().

00208 {
00209    struct ast_module_user *u;
00210 
00211    AST_LIST_LOCK(&mod->users);
00212    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00213       ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00214       ast_atomic_fetchadd_int(&mod->usecount, -1);
00215       free(u);
00216    }
00217    AST_LIST_UNLOCK(&mod->users);
00218 
00219         ast_update_use_count();
00220 }

void __ast_module_user_remove ( struct ast_module mod,
struct ast_module_user u 
)

Definition at line 196 of file loader.c.

References ast_atomic_fetchadd_int(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::entry, free, ast_module::usecount, and ast_module::users.

00197 {
00198    AST_LIST_LOCK(&mod->users);
00199    AST_LIST_REMOVE(&mod->users, u, entry);
00200    AST_LIST_UNLOCK(&mod->users);
00201    ast_atomic_fetchadd_int(&mod->usecount, -1);
00202    free(u);
00203 
00204    ast_update_use_count();
00205 }

static struct load_order_entry* add_to_load_order ( const char *  resource,
struct load_order load_order 
) [static]

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

00730 {
00731    struct load_order_entry *order;
00732 
00733    AST_LIST_TRAVERSE(load_order, order, entry) {
00734       if (!resource_name_match(order->resource, resource))
00735          return NULL;
00736    }
00737 
00738    if (!(order = ast_calloc(1, sizeof(*order))))
00739       return NULL;
00740 
00741    order->resource = ast_strdup(resource);
00742    AST_LIST_INSERT_TAIL(load_order, order, entry);
00743 
00744    return order;
00745 }

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 initilization 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 713 of file loader.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, and load_resource().

Referenced by file_ok_sel(), handle_load(), handle_load_deprecated(), and reload().

00714 {
00715        AST_LIST_LOCK(&module_list);
00716        load_resource(resource_name, 0);
00717        AST_LIST_UNLOCK(&module_list);
00718 
00719        return 0;
00720 }

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.

Returns:
Zero on success and -1 on failure.

Definition at line 963 of file loader.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and ast_malloc.

Referenced by show_console().

00964 {
00965    struct loadupdate *tmp;
00966 
00967    if (!(tmp = ast_malloc(sizeof(*tmp))))
00968       return -1;
00969 
00970    tmp->updater = v;
00971    AST_LIST_LOCK(&updaters);
00972    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
00973    AST_LIST_UNLOCK(&updaters);
00974 
00975    return 0;
00976 }

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.

Returns:
Zero on success, -1 on failure.

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

00979 {
00980    struct loadupdate *cur;
00981 
00982    AST_LIST_LOCK(&updaters);
00983    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
00984       if (cur->updater == v)  {
00985          AST_LIST_REMOVE_CURRENT(&updaters, entry);
00986          break;
00987       }
00988    }
00989    AST_LIST_TRAVERSE_SAFE_END;
00990    AST_LIST_UNLOCK(&updaters);
00991 
00992    return cur ? 0 : -1;
00993 }

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.
Returns:
A possible completion of the partial match, or NULL if no matches were found.

Definition at line 521 of file loader.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module_user::entry, ast_module::info, name, ast_module_info::reload, ast_module::resource, and strdup.

Referenced by complete_mod_2(), complete_mod_3(), complete_mod_3_nr(), complete_mod_4(), and load_module().

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

struct ast_module* ast_module_ref ( struct ast_module mod  ) 

Definition at line 995 of file loader.c.

References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.

Referenced by __oh323_new(), alsa_new(), ast_iax2_new(), cli_audio_convert(), cli_audio_convert_deprecated(), complete_orig(), dahdi_new(), features_new(), fn_wrapper(), gtalk_new(), handle_orig(), mgcp_new(), newpvt(), oss_new(), phone_check_exception(), phone_new(), sip_new(), and skinny_new().

00996 {
00997    ast_atomic_fetchadd_int(&mod->usecount, +1);
00998    ast_update_use_count();
00999 
01000    return mod;
01001 }

void ast_module_register ( const struct ast_module_info info  ) 

Definition at line 113 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.

00114 {
00115    struct ast_module *mod;
00116 
00117    if (embedding) {
00118       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00119          return;
00120       strcpy(mod->resource, info->name);
00121    } else {
00122       mod = resource_being_loaded;
00123    }
00124 
00125    mod->info = info;
00126    AST_LIST_HEAD_INIT(&mod->users);
00127 
00128    /* during startup, before the loader has been initialized,
00129       there are no threads, so there is no need to take the lock
00130       on this list to manipulate it. it is also possible that it
00131       might be unsafe to use the list lock at that point... so
00132       let's avoid it altogether
00133    */
00134    if (!embedding)
00135       AST_LIST_LOCK(&module_list);
00136 
00137    /* it is paramount that the new entry be placed at the tail of
00138       the list, otherwise the code that uses dlopen() to load
00139       dynamic modules won't be able to find out if the module it
00140       just opened was registered or failed to load
00141    */
00142    AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00143 
00144    if (!embedding)
00145       AST_LIST_UNLOCK(&module_list);
00146 
00147    /* give the module a copy of its own handle, for later use in registrations and the like */
00148    *((struct ast_module **) &(info->self)) = mod;
00149 }

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:
Zero if the specified module was not found, 1 if the module was found but cannot be reloaded, -1 if a reload operation is already in progress, and 2 if the specfied module was found and reloaded.

Definition at line 551 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_verbose(), ast_module::declined, ast_module_info::description, ast_module_user::entry, ast_module::flags, ast_module::info, LOG_NOTICE, option_verbose, ast_module_info::reload, reloadlock, ast_module::resource, resource_name_match(), ast_module::running, and VERBOSE_PREFIX_3.

Referenced by action_updateconfig(), handle_reload(), handle_reload_deprecated(), and monitor_sig_flags().

00552 {
00553    struct ast_module *cur;
00554    int res = 0; /* return value. 0 = not found, others, see below */
00555    int i;
00556 
00557    if (ast_mutex_trylock(&reloadlock)) {
00558       ast_verbose("The previous reload command didn't finish yet\n");
00559       return -1;  /* reload already in progress */
00560    }
00561    ast_lastreloadtime = time(NULL);
00562 
00563    /* Call "predefined" reload here first */
00564    for (i = 0; reload_classes[i].name; i++) {
00565       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00566          reload_classes[i].reload_fn();   /* XXX should check error ? */
00567          res = 2; /* found and reloaded */
00568       }
00569    }
00570 
00571    if (name && res) {
00572       ast_mutex_unlock(&reloadlock);
00573       return res;
00574    }
00575 
00576    AST_LIST_LOCK(&module_list);
00577    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00578       const struct ast_module_info *info = cur->info;
00579 
00580       if (name && resource_name_match(name, cur->resource))
00581          continue;
00582 
00583       if (!cur->flags.running || cur->flags.declined) {
00584          if (!name)
00585             continue;
00586          ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
00587             "Before reloading the module, you must run \"module load %s\" "
00588             "and fix whatever is preventing the module from being initialized.\n",
00589             name, name);
00590          res = 2; /* Don't report that the module was not found */
00591          break;
00592       }
00593 
00594       if (!info->reload) { /* cannot be reloaded */
00595          if (res < 1)   /* store result if possible */
00596             res = 1; /* 1 = no reload() method */
00597          continue;
00598       }
00599 
00600       res = 2;
00601       if (option_verbose > 2)
00602          ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
00603       info->reload();
00604    }
00605    AST_LIST_UNLOCK(&module_list);
00606 
00607    ast_mutex_unlock(&reloadlock);
00608 
00609    return res;
00610 }

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 435 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().

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

void ast_module_unref ( struct ast_module mod  ) 

Definition at line 1003 of file loader.c.

References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.

Referenced by alsa_hangup(), ast_smdi_interface_destroy(), cli_audio_convert(), cli_audio_convert_deprecated(), complete_orig(), dahdi_destroy_channel_bynum(), dahdi_hangup(), destroy(), filestream_destructor(), gtalk_hangup(), handle_orig(), iax2_predestroy(), mgcp_hangup(), oh323_hangup(), oss_hangup(), phone_check_exception(), phone_hangup(), and sip_hangup().

01004 {
01005    ast_atomic_fetchadd_int(&mod->usecount, -1);
01006    ast_update_use_count();
01007 }

void ast_module_unregister ( const struct ast_module_info info  ) 

Definition at line 151 of file loader.c.

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

00152 {
00153    struct ast_module *mod = NULL;
00154 
00155    /* it is assumed that the users list in the module structure
00156       will already be empty, or we cannot have gotten to this
00157       point
00158    */
00159    AST_LIST_LOCK(&module_list);
00160    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00161       if (mod->info == info) {
00162          AST_LIST_REMOVE_CURRENT(&module_list, entry);
00163          break;
00164       }
00165    }
00166    AST_LIST_TRAVERSE_SAFE_END;
00167    AST_LIST_UNLOCK(&module_list);
00168 
00169    if (mod) {
00170       AST_LIST_HEAD_DESTROY(&mod->users);
00171       free(mod);
00172    }
00173 }

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).

Returns:
Zero on success, -1 on error.

Definition at line 460 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::lib, LOG_WARNING, ast_module::running, unload_dynamic_module(), and ast_module::usecount.

Referenced by exit_now(), handle_unload(), handle_unload_deprecated(), reload(), and remove_module().

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

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 943 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().

00945 {
00946    struct ast_module *cur;
00947    int unlock = -1;
00948    int total_mod_loaded = 0;
00949 
00950    if (AST_LIST_TRYLOCK(&module_list))
00951       unlock = 0;
00952 
00953    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00954       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
00955    }
00956 
00957    if (unlock)
00958       AST_LIST_UNLOCK(&module_list);
00959 
00960    return total_mod_loaded;
00961 }

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 LOCAL_USER macros take care of calling this function for you.

Definition at line 931 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(), agent_new(), ast_module_ref(), ast_module_unref(), ast_unload_resource(), exit_now(), load_module(), load_resource(), oh323_request(), sip_request_call(), and sipsock_read().

00932 {
00933    /* Notify any module monitors that the use count for a
00934       resource has changed */
00935    struct loadupdate *m;
00936 
00937    AST_LIST_LOCK(&updaters);
00938    AST_LIST_TRAVERSE(&updaters, m, entry)
00939       m->updater();
00940    AST_LIST_UNLOCK(&updaters);
00941 }

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

Definition at line 302 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_unload_resource(), and load_resource().

00303 {
00304    struct ast_module *cur;
00305 
00306    if (do_lock)
00307       AST_LIST_LOCK(&module_list);
00308 
00309    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00310       if (!resource_name_match(resource, cur->resource))
00311          break;
00312    }
00313 
00314    if (do_lock)
00315       AST_LIST_UNLOCK(&module_list);
00316 
00317    return cur;
00318 }

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

Definition at line 612 of file loader.c.

References ast_log(), AST_MODFLAG_BUILDSUM, ast_strlen_zero(), ast_test_flag, 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().

00613 {
00614    if (!mod->info->description) {
00615       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00616       return 1;
00617    }
00618 
00619    if (!mod->info->key) {
00620       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00621       return 1;
00622    }
00623 
00624    if (verify_key((unsigned char *) mod->info->key)) {
00625       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00626       return 1;
00627    }
00628 
00629    if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) {
00630       ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource);
00631    } else if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00632          strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00633       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00634       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00635       return 1;
00636    }
00637 
00638    return 0;
00639 }

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

Definition at line 255 of file loader.c.

Referenced by verify_key().

00256 {
00257    int x;
00258 
00259    for (x = 0; x < 16; x++) {
00260       if (key1[x] != key2[x])
00261          return 0;
00262    }
00263 
00264    return 1;
00265 }

static struct ast_module* load_dynamic_module ( const char *  resource_in,
unsigned int  global_symbols_only 
) [static]

Definition at line 333 of file loader.c.

References ast_calloc, ast_config_AST_MODULE_DIR, AST_LIST_LAST, ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, ast_test_flag, free, ast_module::info, ast_module::lib, LOG_WARNING, resource_being_loaded, and RTLD_NOW.

Referenced by load_resource().

00334 {
00335    char fn[256];
00336    void *lib;
00337    struct ast_module *mod;
00338    char *resource = (char *) resource_in;
00339    unsigned int wants_global;
00340 
00341    if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
00342       resource = alloca(strlen(resource_in) + 3);
00343            strcpy(resource, resource_in);
00344       strcat(resource, ".so");
00345    }
00346 
00347    snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
00348 
00349    /* make a first load of the module in 'quiet' mode... don't try to resolve
00350       any symbols, and don't export any symbols. this will allow us to peek into
00351       the module's info block (if available) to see what flags it has set */
00352 
00353    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00354       return NULL;
00355 
00356    strcpy(resource_being_loaded->resource, resource);
00357 
00358    /* libopenh323 is buggy and segfaults on dlclose() when opened with
00359     * RTLD_LAZY. Workaround this until it gets fixed */
00360    if (!strcasecmp(resource, "chan_h323.so") ||
00361          !strcasecmp(resource, "chan_oh323.so"))
00362          lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
00363 
00364    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00365       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00366       free(resource_being_loaded);
00367       return NULL;
00368    }
00369 
00370    /* the dlopen() succeeded, let's find out if the module
00371       registered itself */
00372    /* note that this will only work properly as long as
00373       ast_module_register() (which is called by the module's
00374       constructor) places the new module at the tail of the
00375       module_list
00376    */
00377    if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00378       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00379       /* no, it did not, so close it and return */
00380       while (!dlclose(lib));
00381       /* note that the module's destructor will call ast_module_unregister(),
00382          which will free the structure we allocated in resource_being_loaded */
00383       return NULL;
00384    }
00385 
00386    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00387 
00388    /* if we are being asked only to load modules that provide global symbols,
00389       and this one does not, then close it and return */
00390    if (global_symbols_only && !wants_global) {
00391       while (!dlclose(lib));
00392       return NULL;
00393    }
00394 
00395    /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
00396       on the already-opened library to what we want... if not, we have to
00397       close it and start over
00398    */
00399 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
00400    if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00401       ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
00402       while (!dlclose(lib));
00403       free(resource_being_loaded);
00404       return NULL;
00405    }
00406 #else
00407    while (!dlclose(lib));
00408    resource_being_loaded = NULL;
00409 
00410    /* start the load process again */
00411 
00412    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00413       return NULL;
00414 
00415    strcpy(resource_being_loaded->resource, resource);
00416 
00417    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00418       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00419       free(resource_being_loaded);
00420       return NULL;
00421    }
00422 
00423    /* since the module was successfully opened, and it registered itself
00424       the previous time we did that, we're going to assume it worked this
00425       time too :) */
00426 #endif
00427 
00428    AST_LIST_LAST(&module_list)->lib = lib;
00429    resource_being_loaded = NULL;
00430 
00431    return AST_LIST_LAST(&module_list);
00432 }

int load_modules ( unsigned  int  ) 

Provided by loader.c

Definition at line 764 of file loader.c.

References add_to_load_order(), ast_config_load(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, ast_log(), AST_MODULE_CONFIG, ast_variable_browse(), ast_verbose(), embedding, LOG_WARNING, ast_variable::name, ast_variable::next, option_verbose, translate_module_name(), and ast_variable::value.

Referenced by main().

00765 {
00766    struct ast_config *cfg;
00767    struct ast_module *mod;
00768    struct load_order_entry *order;
00769    struct ast_variable *v;
00770    unsigned int load_count;
00771    struct load_order load_order;
00772    int res = 0;
00773 
00774    int translate_status;
00775    char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */
00776 #ifdef LOADABLE_MODULES
00777    struct dirent *dirent;
00778    DIR *dir;
00779 #endif
00780 
00781    /* all embedded modules have registered themselves by now */
00782    embedding = 0;
00783 
00784    if (option_verbose)
00785       ast_verbose("Asterisk Dynamic Loader Starting:\n");
00786 
00787    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
00788 
00789    AST_LIST_LOCK(&module_list);
00790 
00791    if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
00792       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
00793       goto done;
00794    }
00795 
00796    /* first, find all the modules we have been explicitly requested to load */
00797    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00798       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
00799          translate_status = translate_module_name(v->value, newname);
00800             if (!translate_status)
00801                ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00802          add_to_load_order(translate_status ? v->value : newname, &load_order);
00803       }
00804    }
00805 
00806    /* check if 'autoload' is on */
00807    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00808       /* if so, first add all the embedded modules that are not already running to the load order */
00809       AST_LIST_TRAVERSE(&module_list, mod, entry) {
00810          /* if it's not embedded, skip it */
00811          if (mod->lib)
00812             continue;
00813 
00814          if (mod->flags.running)
00815             continue;
00816 
00817          order = add_to_load_order(mod->resource, &load_order);
00818       }
00819 
00820 #ifdef LOADABLE_MODULES
00821       /* if we are allowed to load dynamic modules, scan the directory for
00822          for all available modules and add them as well */
00823       if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
00824          while ((dirent = readdir(dir))) {
00825             int ld = strlen(dirent->d_name);
00826 
00827             /* Must end in .so to load it.  */
00828 
00829             if (ld < 4)
00830                continue;
00831 
00832             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
00833                continue;
00834 
00835             /* if there is already a module by this name in the module_list,
00836                skip this file */
00837             if (find_resource(dirent->d_name, 0))
00838                continue;
00839 
00840             add_to_load_order(dirent->d_name, &load_order);
00841          }
00842 
00843          closedir(dir);
00844       } else {
00845          if (!ast_opt_quiet)
00846             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
00847                ast_config_AST_MODULE_DIR);
00848       }
00849 #endif
00850    }
00851 
00852    /* now scan the config for any modules we are prohibited from loading and
00853       remove them from the load order */
00854    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00855       if (strcasecmp(v->name, "noload"))
00856          continue;
00857 
00858       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00859          translate_status = translate_module_name(v->value, newname);
00860          if (!resource_name_match(order->resource, translate_status ? v->value : newname)) {
00861                if (!translate_status)
00862                   ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00863             AST_LIST_REMOVE_CURRENT(&load_order, entry);
00864             free(order->resource);
00865             free(order);
00866          }
00867       }
00868       AST_LIST_TRAVERSE_SAFE_END;
00869    }
00870 
00871    /* we are done with the config now, all the information we need is in the
00872       load_order list */
00873    ast_config_destroy(cfg);
00874 
00875    load_count = 0;
00876    AST_LIST_TRAVERSE(&load_order, order, entry)
00877       load_count++;
00878 
00879    if (load_count)
00880       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
00881 
00882    /* first, load only modules that provide global symbols */
00883    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00884       switch (load_resource(order->resource, 1)) {
00885       case AST_MODULE_LOAD_SUCCESS:
00886       case AST_MODULE_LOAD_DECLINE:
00887          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00888          free(order->resource);
00889          free(order);
00890          break;
00891       case AST_MODULE_LOAD_FAILURE:
00892          res = -1;
00893          goto done;
00894       case AST_MODULE_LOAD_SKIP:
00895          /* try again later */
00896          break;
00897       }
00898    }
00899    AST_LIST_TRAVERSE_SAFE_END;
00900 
00901    /* now load everything else */
00902    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00903       switch (load_resource(order->resource, 0)) {
00904       case AST_MODULE_LOAD_SUCCESS:
00905       case AST_MODULE_LOAD_DECLINE:
00906          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00907          free(order->resource);
00908          free(order);
00909          break;
00910       case AST_MODULE_LOAD_FAILURE:
00911          res = -1;
00912          goto done;
00913       case AST_MODULE_LOAD_SKIP:
00914          /* should not happen */
00915          break;
00916       }
00917    }
00918    AST_LIST_TRAVERSE_SAFE_END;
00919 
00920 done:
00921    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
00922       free(order->resource);
00923       free(order);
00924    }
00925 
00926    AST_LIST_UNLOCK(&module_list);
00927 
00928    return res;
00929 }

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

Definition at line 641 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_verbose(), COLOR_BLACK, COLOR_BROWN, ast_module::declined, ast_module_info::description, find_resource(), ast_module::flags, ast_module::info, inspect_module(), ast_module_info::load, load_dynamic_module(), LOG_WARNING, option_verbose, ast_module::running, term_color(), unload_dynamic_module(), and VERBOSE_PREFIX_1.

Referenced by ast_load_resource().

00642 {
00643    struct ast_module *mod;
00644    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00645    char tmp[256];
00646 
00647    if ((mod = find_resource(resource_name, 0))) {
00648       if (mod->flags.running) {
00649          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00650          return AST_MODULE_LOAD_DECLINE;
00651       }
00652       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00653          return AST_MODULE_LOAD_SKIP;
00654    } else {
00655 #ifdef LOADABLE_MODULES
00656       if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00657          /* don't generate a warning message during load_modules() */
00658          if (!global_symbols_only) {
00659             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00660             return AST_MODULE_LOAD_DECLINE;
00661          } else {
00662             return AST_MODULE_LOAD_SKIP;
00663          }
00664       }
00665 #else
00666       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00667       return AST_MODULE_LOAD_DECLINE;
00668 #endif
00669    }
00670 
00671    if (inspect_module(mod)) {
00672       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00673 #ifdef LOADABLE_MODULES
00674       unload_dynamic_module(mod);
00675 #endif
00676       return AST_MODULE_LOAD_DECLINE;
00677    }
00678 
00679    mod->flags.declined = 0;
00680 
00681    if (mod->info->load)
00682       res = mod->info->load();
00683 
00684    switch (res) {
00685    case AST_MODULE_LOAD_SUCCESS:
00686       if (!ast_fully_booted) {
00687          if (option_verbose)
00688             ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00689          if (ast_opt_console && !option_verbose)
00690             ast_verbose( ".");
00691       } else {
00692          if (option_verbose)
00693             ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
00694       }
00695 
00696       mod->flags.running = 1;
00697 
00698       ast_update_use_count();
00699       break;
00700    case AST_MODULE_LOAD_DECLINE:
00701       mod->flags.declined = 1;
00702       break;
00703    case AST_MODULE_LOAD_FAILURE:
00704       break;
00705    case AST_MODULE_LOAD_SKIP:
00706       /* modules should never return this value */
00707       break;
00708    }
00709 
00710    return res;
00711 }

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

Definition at line 242 of file loader.c.

References ast_log(), and LOG_DEBUG.

Referenced by verify_key().

00243 {
00244    int x, pos;
00245    char buf[256]; /* large enough so we don't have to worry */
00246 
00247    for (pos = 0, x = 0; x < 16; x++)
00248       pos += sprintf(buf + pos, " %02x", *d++);
00249 
00250    ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
00251 
00252    return 0;
00253 }

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

Definition at line 284 of file loader.c.

References ast_strdupa.

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

00285 {
00286    char *name1 = (char *) name1_in;
00287    char *name2 = (char *) name2_in;
00288 
00289    /* trim off any .so extensions */
00290    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00291       name1 = ast_strdupa(name1);
00292       name1[strlen(name1) - 3] = '\0';
00293    }
00294    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00295       name2 = ast_strdupa(name2);
00296       name2[strlen(name2) - 3] = '\0';
00297    }
00298 
00299    return strcasecmp(name1, name2);
00300 }

static int translate_module_name ( char *  oldname,
char *  newname 
) [static]

Definition at line 747 of file loader.c.

References ast_copy_string().

Referenced by load_modules().

00748 {
00749    if (!strcasecmp(oldname, "app_zapbarge.so"))
00750       ast_copy_string(newname, "app_dahdibarge.so", 18);
00751    else if(!strcasecmp(oldname, "app_zapras.so"))
00752       ast_copy_string(newname, "app_dahdiras.so", 16);
00753    else if(!strcasecmp(oldname, "app_zapscan.so"))
00754       ast_copy_string(newname, "app_dahdiscan.so", 17);
00755    else if(!strcasecmp(oldname, "codec_zap.so"))
00756       ast_copy_string(newname, "codec_dahdi.so", 16);
00757    else
00758       return -1; /* no use for newname, oldname is fine */
00759 
00760    return 0;
00761 }

static void unload_dynamic_module ( struct ast_module mod  )  [static]

Definition at line 321 of file loader.c.

References ast_module::lib.

Referenced by ast_unload_resource(), and load_resource().

00322 {
00323    void *lib = mod->lib;
00324 
00325    /* WARNING: the structure pointed to by mod is going to
00326       disappear when this operation succeeds, so we can't
00327       dereference it */
00328 
00329    if (lib)
00330       while (!dlclose(lib));
00331 }

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

Definition at line 267 of file loader.c.

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

Referenced by inspect_module().

00268 {
00269    struct MD5Context c;
00270    unsigned char digest[16];
00271 
00272    MD5Init(&c);
00273    MD5Update(&c, key, strlen((char *)key));
00274    MD5Final(digest, &c);
00275 
00276    if (key_matches(expected_key, digest))
00277       return 0;
00278 
00279    printdigest(digest);
00280 
00281    return -1;
00282 }


Variable Documentation

char buildopt_sum[33] = AST_BUILDOPT_SUM [static]

Definition at line 75 of file loader.c.

Referenced by inspect_module().

unsigned int embedding = 1 [static]

Definition at line 77 of file loader.c.

Referenced by ast_module_register(), and load_modules().

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 71 of file loader.c.

Referenced by verify_key().

ast_mutex_t reloadlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 103 of file loader.c.

Referenced by ast_module_reload().

struct ast_module* resource_being_loaded

Definition at line 109 of file loader.c.

Referenced by ast_module_register(), and load_dynamic_module().


Generated on Thu May 14 14:50:02 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7