Wed Nov 28 2012 04:18:12

Asterisk developer's documentation


loader.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  * Kevin P. Fleming <kpfleming@digium.com>
00008  * Luigi Rizzo <rizzo@icir.org>
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief Module Loader
00024  * \author Mark Spencer <markster@digium.com>
00025  * \author Kevin P. Fleming <kpfleming@digium.com>
00026  * \author Luigi Rizzo <rizzo@icir.org>
00027  * - See ModMngMnt
00028  */
00029 
00030 /*** MODULEINFO
00031    <support_level>core</support_level>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 373909 $")
00037 
00038 #include "asterisk/_private.h"
00039 #include "asterisk/paths.h"   /* use ast_config_AST_MODULE_DIR */
00040 #include <dirent.h>
00041 
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/term.h"
00047 #include "asterisk/manager.h"
00048 #include "asterisk/cdr.h"
00049 #include "asterisk/enum.h"
00050 #include "asterisk/http.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/features.h"
00053 #include "asterisk/dsp.h"
00054 #include "asterisk/udptl.h"
00055 #include "asterisk/heap.h"
00056 #include "asterisk/app.h"
00057 #include "asterisk/test.h"
00058 
00059 #include <dlfcn.h>
00060 
00061 #include "asterisk/md5.h"
00062 #include "asterisk/utils.h"
00063 
00064 #ifndef RTLD_NOW
00065 #define RTLD_NOW 0
00066 #endif
00067 
00068 #ifndef RTLD_LOCAL
00069 #define RTLD_LOCAL 0
00070 #endif
00071 
00072 struct ast_module_user {
00073    struct ast_channel *chan;
00074    AST_LIST_ENTRY(ast_module_user) entry;
00075 };
00076 
00077 AST_LIST_HEAD(module_user_list, ast_module_user);
00078 
00079 static const unsigned char expected_key[] =
00080 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00081   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00082 
00083 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
00084 
00085 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
00086                   since they are here before we dlopen() any
00087                */
00088 
00089 struct ast_module {
00090    const struct ast_module_info *info;
00091    void *lib;              /* the shared lib, or NULL if embedded */
00092    int usecount;              /* the number of 'users' currently in this module */
00093    struct module_user_list users;         /* the list of users in the module */
00094    struct {
00095       unsigned int running:1;
00096       unsigned int declined:1;
00097    } flags;
00098    AST_LIST_ENTRY(ast_module) entry;
00099    char resource[0];
00100 };
00101 
00102 static AST_LIST_HEAD_STATIC(module_list, ast_module);
00103 
00104 const char *ast_module_name(const struct ast_module *mod)
00105 {
00106    if (!mod || !mod->info) {
00107       return NULL;
00108    }
00109 
00110    return mod->info->name;
00111 }
00112 
00113 /*
00114  * module_list is cleared by its constructor possibly after
00115  * we start accumulating embedded modules, so we need to
00116  * use another list (without the lock) to accumulate them.
00117  * Then we update the main list when embedding is done.
00118  */
00119 static struct module_list embedded_module_list;
00120 
00121 struct loadupdate {
00122    int (*updater)(void);
00123    AST_LIST_ENTRY(loadupdate) entry;
00124 };
00125 
00126 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
00127 
00128 AST_MUTEX_DEFINE_STATIC(reloadlock);
00129 
00130 struct reload_queue_item {
00131    AST_LIST_ENTRY(reload_queue_item) entry;
00132    char module[0];
00133 };
00134 
00135 static int do_full_reload = 0;
00136 
00137 static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
00138 
00139 /* when dynamic modules are being loaded, ast_module_register() will
00140    need to know what filename the module was loaded from while it
00141    is being registered
00142 */
00143 static struct ast_module *resource_being_loaded;
00144 
00145 /* XXX: should we check for duplicate resource names here? */
00146 
00147 void ast_module_register(const struct ast_module_info *info)
00148 {
00149    struct ast_module *mod;
00150 
00151    if (embedding) {
00152       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00153          return;
00154       strcpy(mod->resource, info->name);
00155    } else {
00156       mod = resource_being_loaded;
00157    }
00158 
00159    mod->info = info;
00160    AST_LIST_HEAD_INIT(&mod->users);
00161 
00162    /* during startup, before the loader has been initialized,
00163       there are no threads, so there is no need to take the lock
00164       on this list to manipulate it. it is also possible that it
00165       might be unsafe to use the list lock at that point... so
00166       let's avoid it altogether
00167    */
00168    if (embedding) {
00169       AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00170    } else {
00171       AST_LIST_LOCK(&module_list);
00172       /* it is paramount that the new entry be placed at the tail of
00173          the list, otherwise the code that uses dlopen() to load
00174          dynamic modules won't be able to find out if the module it
00175          just opened was registered or failed to load
00176       */
00177       AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00178       AST_LIST_UNLOCK(&module_list);
00179    }
00180 
00181    /* give the module a copy of its own handle, for later use in registrations and the like */
00182    *((struct ast_module **) &(info->self)) = mod;
00183 }
00184 
00185 void ast_module_unregister(const struct ast_module_info *info)
00186 {
00187    struct ast_module *mod = NULL;
00188 
00189    /* it is assumed that the users list in the module structure
00190       will already be empty, or we cannot have gotten to this
00191       point
00192    */
00193    AST_LIST_LOCK(&module_list);
00194    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00195       if (mod->info == info) {
00196          AST_LIST_REMOVE_CURRENT(entry);
00197          break;
00198       }
00199    }
00200    AST_LIST_TRAVERSE_SAFE_END;
00201    AST_LIST_UNLOCK(&module_list);
00202 
00203    if (mod) {
00204       AST_LIST_HEAD_DESTROY(&mod->users);
00205       ast_free(mod);
00206    }
00207 }
00208 
00209 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
00210                      struct ast_channel *chan)
00211 {
00212    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00213 
00214    if (!u)
00215       return NULL;
00216 
00217    u->chan = chan;
00218 
00219    AST_LIST_LOCK(&mod->users);
00220    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00221    AST_LIST_UNLOCK(&mod->users);
00222 
00223    ast_atomic_fetchadd_int(&mod->usecount, +1);
00224 
00225    ast_update_use_count();
00226 
00227    return u;
00228 }
00229 
00230 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00231 {
00232    AST_LIST_LOCK(&mod->users);
00233    AST_LIST_REMOVE(&mod->users, u, entry);
00234    AST_LIST_UNLOCK(&mod->users);
00235    ast_atomic_fetchadd_int(&mod->usecount, -1);
00236    ast_free(u);
00237 
00238    ast_update_use_count();
00239 }
00240 
00241 void __ast_module_user_hangup_all(struct ast_module *mod)
00242 {
00243    struct ast_module_user *u;
00244 
00245    AST_LIST_LOCK(&mod->users);
00246    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00247       if (u->chan) {
00248          ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00249       }
00250       ast_atomic_fetchadd_int(&mod->usecount, -1);
00251       ast_free(u);
00252    }
00253    AST_LIST_UNLOCK(&mod->users);
00254 
00255    ast_update_use_count();
00256 }
00257 
00258 /*! \note
00259  * In addition to modules, the reload command handles some extra keywords
00260  * which are listed here together with the corresponding handlers.
00261  * This table is also used by the command completion code.
00262  */
00263 static struct reload_classes {
00264    const char *name;
00265    int (*reload_fn)(void);
00266 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
00267    { "cdr", ast_cdr_engine_reload },
00268    { "dnsmgr", dnsmgr_reload },
00269    { "extconfig", read_config_maps },
00270    { "enum",   ast_enum_reload },
00271    { "manager",   reload_manager },
00272    { "http",   ast_http_reload },
00273    { "logger", logger_reload },
00274    { "features",  ast_features_reload },
00275    { "dsp", ast_dsp_reload},
00276    { "udptl",  ast_udptl_reload },
00277    { "indications", ast_indications_reload },
00278    { "cel",        ast_cel_engine_reload },
00279    { "plc",        ast_plc_reload },
00280    { NULL,  NULL }
00281 };
00282 
00283 static int printdigest(const unsigned char *d)
00284 {
00285    int x, pos;
00286    char buf[256]; /* large enough so we don't have to worry */
00287 
00288    for (pos = 0, x = 0; x < 16; x++)
00289       pos += sprintf(buf + pos, " %02x", *d++);
00290 
00291    ast_debug(1, "Unexpected signature:%s\n", buf);
00292 
00293    return 0;
00294 }
00295 
00296 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00297 {
00298    int x;
00299 
00300    for (x = 0; x < 16; x++) {
00301       if (key1[x] != key2[x])
00302          return 0;
00303    }
00304 
00305    return 1;
00306 }
00307 
00308 static int verify_key(const unsigned char *key)
00309 {
00310    struct MD5Context c;
00311    unsigned char digest[16];
00312 
00313    MD5Init(&c);
00314    MD5Update(&c, key, strlen((char *)key));
00315    MD5Final(digest, &c);
00316 
00317    if (key_matches(expected_key, digest))
00318       return 0;
00319 
00320    printdigest(digest);
00321 
00322    return -1;
00323 }
00324 
00325 static int resource_name_match(const char *name1_in, const char *name2_in)
00326 {
00327    char *name1 = (char *) name1_in;
00328    char *name2 = (char *) name2_in;
00329 
00330    /* trim off any .so extensions */
00331    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00332       name1 = ast_strdupa(name1);
00333       name1[strlen(name1) - 3] = '\0';
00334    }
00335    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00336       name2 = ast_strdupa(name2);
00337       name2[strlen(name2) - 3] = '\0';
00338    }
00339 
00340    return strcasecmp(name1, name2);
00341 }
00342 
00343 static struct ast_module *find_resource(const char *resource, int do_lock)
00344 {
00345    struct ast_module *cur;
00346 
00347    if (do_lock)
00348       AST_LIST_LOCK(&module_list);
00349 
00350    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00351       if (!resource_name_match(resource, cur->resource))
00352          break;
00353    }
00354 
00355    if (do_lock)
00356       AST_LIST_UNLOCK(&module_list);
00357 
00358    return cur;
00359 }
00360 
00361 #ifdef LOADABLE_MODULES
00362 static void unload_dynamic_module(struct ast_module *mod)
00363 {
00364    void *lib = mod->lib;
00365 
00366    /* WARNING: the structure pointed to by mod is going to
00367       disappear when this operation succeeds, so we can't
00368       dereference it */
00369 
00370    if (lib)
00371       while (!dlclose(lib));
00372 }
00373 
00374 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
00375 
00376 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, struct ast_heap *resource_heap)
00377 {
00378    char fn[PATH_MAX] = "";
00379    void *lib = NULL;
00380    struct ast_module *mod;
00381    unsigned int wants_global;
00382    int space;  /* room needed for the descriptor */
00383    int missing_so = 0;
00384 
00385    space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
00386    if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
00387       missing_so = 1;
00388       space += 3; /* room for the extra ".so" */
00389    }
00390 
00391    snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
00392 
00393    /* make a first load of the module in 'quiet' mode... don't try to resolve
00394       any symbols, and don't export any symbols. this will allow us to peek into
00395       the module's info block (if available) to see what flags it has set */
00396 
00397    resource_being_loaded = ast_calloc(1, space);
00398    if (!resource_being_loaded)
00399       return NULL;
00400    strcpy(resource_being_loaded->resource, resource_in);
00401    if (missing_so)
00402       strcat(resource_being_loaded->resource, ".so");
00403 
00404    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00405       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00406       ast_free(resource_being_loaded);
00407       return NULL;
00408    }
00409 
00410    /* the dlopen() succeeded, let's find out if the module
00411       registered itself */
00412    /* note that this will only work properly as long as
00413       ast_module_register() (which is called by the module's
00414       constructor) places the new module at the tail of the
00415       module_list
00416    */
00417    if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00418       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00419       /* no, it did not, so close it and return */
00420       while (!dlclose(lib));
00421       /* note that the module's destructor will call ast_module_unregister(),
00422          which will free the structure we allocated in resource_being_loaded */
00423       return NULL;
00424    }
00425 
00426    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00427 
00428    /* if we are being asked only to load modules that provide global symbols,
00429       and this one does not, then close it and return */
00430    if (global_symbols_only && !wants_global) {
00431       while (!dlclose(lib));
00432       return NULL;
00433    }
00434 
00435    /* This section is a workaround for a gcc 4.1 bug that has already been
00436     * fixed in later versions.  Unfortunately, some distributions, such as
00437     * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
00438     * with this issue.  This basically ensures that optional_api modules are
00439     * loaded before any module which requires their functionality. */
00440 #if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
00441    if (!ast_strlen_zero(mod->info->nonoptreq)) {
00442       /* Force any required dependencies to load */
00443       char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
00444       while ((each = strsep(&required_resource, ","))) {
00445          struct ast_module *dependency;
00446          each = ast_strip(each);
00447          dependency = find_resource(each, 0);
00448          /* Is it already loaded? */
00449          if (!dependency) {
00450             load_resource(each, global_symbols_only, resource_heap, 1);
00451          }
00452       }
00453    }
00454 #endif
00455 
00456    while (!dlclose(lib));
00457    resource_being_loaded = NULL;
00458 
00459    /* start the load process again */
00460    resource_being_loaded = ast_calloc(1, space);
00461    if (!resource_being_loaded)
00462       return NULL;
00463    strcpy(resource_being_loaded->resource, resource_in);
00464    if (missing_so)
00465       strcat(resource_being_loaded->resource, ".so");
00466 
00467    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00468       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00469       ast_free(resource_being_loaded);
00470       return NULL;
00471    }
00472 
00473    /* since the module was successfully opened, and it registered itself
00474       the previous time we did that, we're going to assume it worked this
00475       time too :) */
00476 
00477    AST_LIST_LAST(&module_list)->lib = lib;
00478    resource_being_loaded = NULL;
00479 
00480    return AST_LIST_LAST(&module_list);
00481 }
00482 #endif
00483 
00484 void ast_module_shutdown(void)
00485 {
00486    struct ast_module *mod;
00487    int somethingchanged = 1, final = 0;
00488 
00489    AST_LIST_LOCK(&module_list);
00490 
00491    /*!\note Some resources, like timers, are started up dynamically, and thus
00492     * may be still in use, even if all channels are dead.  We must therefore
00493     * check the usecount before asking modules to unload. */
00494    do {
00495       if (!somethingchanged) {
00496          /*!\note If we go through the entire list without changing
00497           * anything, ignore the usecounts and unload, then exit. */
00498          final = 1;
00499       }
00500 
00501       /* Reset flag before traversing the list */
00502       somethingchanged = 0;
00503 
00504       AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00505          if (!final && mod->usecount) {
00506             continue;
00507          }
00508          AST_LIST_REMOVE_CURRENT(entry);
00509          if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
00510             mod->info->unload();
00511          }
00512          AST_LIST_HEAD_DESTROY(&mod->users);
00513          free(mod);
00514          somethingchanged = 1;
00515       }
00516       AST_LIST_TRAVERSE_SAFE_END;
00517    } while (somethingchanged && !final);
00518 
00519    AST_LIST_UNLOCK(&module_list);
00520 }
00521 
00522 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00523 {
00524    struct ast_module *mod;
00525    int res = -1;
00526    int error = 0;
00527 
00528    AST_LIST_LOCK(&module_list);
00529 
00530    if (!(mod = find_resource(resource_name, 0))) {
00531       AST_LIST_UNLOCK(&module_list);
00532       ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00533       return -1;
00534    }
00535 
00536    if (!mod->flags.running || mod->flags.declined) {
00537       ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
00538       error = 1;
00539    }
00540 
00541    if (!error && (mod->usecount > 0)) {
00542       if (force)
00543          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00544             resource_name, mod->usecount);
00545       else {
00546          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00547             mod->usecount);
00548          error = 1;
00549       }
00550    }
00551 
00552    if (!error) {
00553       __ast_module_user_hangup_all(mod);
00554       res = mod->info->unload();
00555 
00556       if (res) {
00557          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00558          if (force <= AST_FORCE_FIRM)
00559             error = 1;
00560          else
00561             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00562       }
00563    }
00564 
00565    if (!error)
00566       mod->flags.running = mod->flags.declined = 0;
00567 
00568    AST_LIST_UNLOCK(&module_list);
00569 
00570    if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00571       mod->info->restore_globals();
00572 
00573 #ifdef LOADABLE_MODULES
00574    if (!error) {
00575       unload_dynamic_module(mod);
00576       ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
00577    }
00578 #endif
00579 
00580    if (!error)
00581       ast_update_use_count();
00582 
00583    return res;
00584 }
00585 
00586 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00587 {
00588    struct ast_module *cur;
00589    int i, which=0, l = strlen(word);
00590    char *ret = NULL;
00591 
00592    if (pos != rpos)
00593       return NULL;
00594 
00595    AST_LIST_LOCK(&module_list);
00596    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00597       if (!strncasecmp(word, cur->resource, l) &&
00598           (cur->info->reload || !needsreload) &&
00599           ++which > state) {
00600          ret = ast_strdup(cur->resource);
00601          break;
00602       }
00603    }
00604    AST_LIST_UNLOCK(&module_list);
00605 
00606    if (!ret) {
00607       for (i=0; !ret && reload_classes[i].name; i++) {
00608          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00609             ret = ast_strdup(reload_classes[i].name);
00610       }
00611    }
00612 
00613    return ret;
00614 }
00615 
00616 void ast_process_pending_reloads(void)
00617 {
00618    struct reload_queue_item *item;
00619 
00620    if (!ast_fully_booted) {
00621       return;
00622    }
00623 
00624    AST_LIST_LOCK(&reload_queue);
00625 
00626    if (do_full_reload) {
00627       do_full_reload = 0;
00628       AST_LIST_UNLOCK(&reload_queue);
00629       ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00630       ast_module_reload(NULL);
00631       return;
00632    }
00633 
00634    while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00635       ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00636       ast_module_reload(item->module);
00637       ast_free(item);
00638    }
00639 
00640    AST_LIST_UNLOCK(&reload_queue);
00641 }
00642 
00643 static void queue_reload_request(const char *module)
00644 {
00645    struct reload_queue_item *item;
00646 
00647    AST_LIST_LOCK(&reload_queue);
00648 
00649    if (do_full_reload) {
00650       AST_LIST_UNLOCK(&reload_queue);
00651       return;
00652    }
00653 
00654    if (ast_strlen_zero(module)) {
00655       /* A full reload request (when module is NULL) wipes out any previous
00656          reload requests and causes the queue to ignore future ones */
00657       while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00658          ast_free(item);
00659       }
00660       do_full_reload = 1;
00661    } else {
00662       /* No reason to add the same module twice */
00663       AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00664          if (!strcasecmp(item->module, module)) {
00665             AST_LIST_UNLOCK(&reload_queue);
00666             return;
00667          }
00668       }
00669       item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00670       if (!item) {
00671          ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00672          AST_LIST_UNLOCK(&reload_queue);
00673          return;
00674       }
00675       strcpy(item->module, module);
00676       AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00677    }
00678    AST_LIST_UNLOCK(&reload_queue);
00679 }
00680 
00681 int ast_module_reload(const char *name)
00682 {
00683    struct ast_module *cur;
00684    int res = 0; /* return value. 0 = not found, others, see below */
00685    int i;
00686 
00687    /* If we aren't fully booted, we just pretend we reloaded but we queue this
00688       up to run once we are booted up. */
00689    if (!ast_fully_booted) {
00690       queue_reload_request(name);
00691       return 0;
00692    }
00693 
00694    if (ast_mutex_trylock(&reloadlock)) {
00695       ast_verbose("The previous reload command didn't finish yet\n");
00696       return -1;  /* reload already in progress */
00697    }
00698    ast_lastreloadtime = ast_tvnow();
00699 
00700    if (ast_opt_lock_confdir) {
00701       int try;
00702       int res;
00703       for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
00704          res = ast_lock_path(ast_config_AST_CONFIG_DIR);
00705          if (res == AST_LOCK_TIMEOUT) {
00706             ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
00707          }
00708       }
00709       if (res != AST_LOCK_SUCCESS) {
00710          ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
00711          ast_mutex_unlock(&reloadlock);
00712          return -1;
00713       }
00714    }
00715 
00716    /* Call "predefined" reload here first */
00717    for (i = 0; reload_classes[i].name; i++) {
00718       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00719          if (!reload_classes[i].reload_fn()) {
00720             ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", name);
00721          }
00722          res = 2; /* found and reloaded */
00723       }
00724    }
00725 
00726    if (name && res) {
00727       if (ast_opt_lock_confdir) {
00728          ast_unlock_path(ast_config_AST_CONFIG_DIR);
00729       }
00730       ast_mutex_unlock(&reloadlock);
00731       return res;
00732    }
00733 
00734    AST_LIST_LOCK(&module_list);
00735    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00736       const struct ast_module_info *info = cur->info;
00737 
00738       if (name && resource_name_match(name, cur->resource))
00739          continue;
00740 
00741       if (!cur->flags.running || cur->flags.declined) {
00742          if (!name)
00743             continue;
00744          ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
00745             "Before reloading the module, you must run \"module load %s\" "
00746             "and fix whatever is preventing the module from being initialized.\n",
00747             name, name);
00748          res = 2; /* Don't report that the module was not found */
00749          break;
00750       }
00751 
00752       if (!info->reload) { /* cannot be reloaded */
00753          /* Nothing to reload, so reload is successful */
00754          ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
00755          if (res < 1)   /* store result if possible */
00756             res = 1; /* 1 = no reload() method */
00757          continue;
00758       }
00759 
00760       res = 2;
00761       ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00762       if (!info->reload()) {
00763          ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
00764       }
00765    }
00766    AST_LIST_UNLOCK(&module_list);
00767 
00768    if (ast_opt_lock_confdir) {
00769       ast_unlock_path(ast_config_AST_CONFIG_DIR);
00770    }
00771    ast_mutex_unlock(&reloadlock);
00772 
00773    return res;
00774 }
00775 
00776 static unsigned int inspect_module(const struct ast_module *mod)
00777 {
00778    if (!mod->info->description) {
00779       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00780       return 1;
00781    }
00782 
00783    if (!mod->info->key) {
00784       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00785       return 1;
00786    }
00787 
00788    if (verify_key((unsigned char *) mod->info->key)) {
00789       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00790       return 1;
00791    }
00792 
00793    if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00794        strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00795       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00796       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00797       return 1;
00798    }
00799 
00800    return 0;
00801 }
00802 
00803 static enum ast_module_load_result start_resource(struct ast_module *mod)
00804 {
00805    char tmp[256];
00806    enum ast_module_load_result res;
00807 
00808    if (mod->flags.running) {
00809       return AST_MODULE_LOAD_SUCCESS;
00810    }
00811 
00812    if (!mod->info->load) {
00813       return AST_MODULE_LOAD_FAILURE;
00814    }
00815 
00816    res = mod->info->load();
00817 
00818    switch (res) {
00819    case AST_MODULE_LOAD_SUCCESS:
00820       if (!ast_fully_booted) {
00821          ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00822          if (ast_opt_console && !option_verbose)
00823             ast_verbose( ".");
00824       } else {
00825          ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
00826       }
00827 
00828       mod->flags.running = 1;
00829 
00830       ast_update_use_count();
00831       break;
00832    case AST_MODULE_LOAD_DECLINE:
00833       mod->flags.declined = 1;
00834       break;
00835    case AST_MODULE_LOAD_FAILURE:
00836    case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
00837    case AST_MODULE_LOAD_PRIORITY:
00838       break;
00839    }
00840 
00841    return res;
00842 }
00843 
00844 /*! loads a resource based upon resource_name. If global_symbols_only is set
00845  *  only modules with global symbols will be loaded.
00846  *
00847  *  If the ast_heap is provided (not NULL) the module is found and added to the
00848  *  heap without running the module's load() function.  By doing this, modules
00849  *  added to the resource_heap can be initialized later in order by priority. 
00850  *
00851  *  If the ast_heap is not provided, the module's load function will be executed
00852  *  immediately */
00853 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
00854 {
00855    struct ast_module *mod;
00856    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00857 
00858    if ((mod = find_resource(resource_name, 0))) {
00859       if (mod->flags.running) {
00860          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00861          return AST_MODULE_LOAD_DECLINE;
00862       }
00863       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00864          return AST_MODULE_LOAD_SKIP;
00865    } else {
00866 #ifdef LOADABLE_MODULES
00867       if (!(mod = load_dynamic_module(resource_name, global_symbols_only, resource_heap))) {
00868          /* don't generate a warning message during load_modules() */
00869          if (!global_symbols_only) {
00870             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00871             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00872          } else {
00873             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
00874          }
00875       }
00876 #else
00877       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00878       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00879 #endif
00880    }
00881 
00882    if (inspect_module(mod)) {
00883       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00884 #ifdef LOADABLE_MODULES
00885       unload_dynamic_module(mod);
00886 #endif
00887       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00888    }
00889 
00890    if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
00891       ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
00892       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00893    }
00894 
00895    mod->flags.declined = 0;
00896 
00897    if (resource_heap) {
00898       ast_heap_push(resource_heap, mod);
00899       res = AST_MODULE_LOAD_PRIORITY;
00900    } else {
00901       res = start_resource(mod);
00902    }
00903 
00904    return res;
00905 }
00906 
00907 int ast_load_resource(const char *resource_name)
00908 {
00909    int res;
00910    AST_LIST_LOCK(&module_list);
00911    res = load_resource(resource_name, 0, NULL, 0);
00912    if (!res) {
00913       ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
00914    }
00915    AST_LIST_UNLOCK(&module_list);
00916 
00917    return res;
00918 }
00919 
00920 struct load_order_entry {
00921    char *resource;
00922    int required;
00923    AST_LIST_ENTRY(load_order_entry) entry;
00924 };
00925 
00926 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00927 
00928 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
00929 {
00930    struct load_order_entry *order;
00931 
00932    AST_LIST_TRAVERSE(load_order, order, entry) {
00933       if (!resource_name_match(order->resource, resource)) {
00934          /* Make sure we have the proper setting for the required field 
00935             (we might have both load= and required= lines in modules.conf) */
00936          order->required |= required;
00937          return NULL;
00938       }
00939    }
00940 
00941    if (!(order = ast_calloc(1, sizeof(*order))))
00942       return NULL;
00943 
00944    order->resource = ast_strdup(resource);
00945    order->required = required;
00946    AST_LIST_INSERT_TAIL(load_order, order, entry);
00947 
00948    return order;
00949 }
00950 
00951 static int mod_load_cmp(void *a, void *b)
00952 {
00953    struct ast_module *a_mod = (struct ast_module *) a;
00954    struct ast_module *b_mod = (struct ast_module *) b;
00955    int res = -1;
00956    /* if load_pri is not set, default is 128.  Lower is better*/
00957    unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
00958    unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
00959    if (a_pri == b_pri) {
00960       res = 0;
00961    } else if (a_pri < b_pri) {
00962       res = 1;
00963    }
00964    return res;
00965 }
00966 
00967 /*! loads modules in order by load_pri, updates mod_count 
00968    \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
00969 */
00970 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
00971 {
00972    struct ast_heap *resource_heap;
00973    struct load_order_entry *order;
00974    struct ast_module *mod;
00975    int count = 0;
00976    int res = 0;
00977 
00978    if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
00979       return -1;
00980    }
00981 
00982    /* first, add find and add modules to heap */
00983    AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
00984       switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
00985       case AST_MODULE_LOAD_SUCCESS:
00986       case AST_MODULE_LOAD_DECLINE:
00987          AST_LIST_REMOVE_CURRENT(entry);
00988          ast_free(order->resource);
00989          ast_free(order);
00990          break;
00991       case AST_MODULE_LOAD_FAILURE:
00992          ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00993          fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00994          res = order->required ? -2 : -1;
00995          goto done;
00996       case AST_MODULE_LOAD_SKIP:
00997          break;
00998       case AST_MODULE_LOAD_PRIORITY:
00999          AST_LIST_REMOVE_CURRENT(entry);
01000          break;
01001       }
01002    }
01003    AST_LIST_TRAVERSE_SAFE_END;
01004 
01005    /* second remove modules from heap sorted by priority */
01006    while ((mod = ast_heap_pop(resource_heap))) {
01007       switch (start_resource(mod)) {
01008       case AST_MODULE_LOAD_SUCCESS:
01009          count++;
01010       case AST_MODULE_LOAD_DECLINE:
01011          break;
01012       case AST_MODULE_LOAD_FAILURE:
01013          res = -1;
01014          goto done;
01015       case AST_MODULE_LOAD_SKIP:
01016       case AST_MODULE_LOAD_PRIORITY:
01017          break;
01018       }
01019    }
01020 
01021 done:
01022    if (mod_count) {
01023       *mod_count += count;
01024    }
01025    ast_heap_destroy(resource_heap);
01026 
01027    return res;
01028 }
01029 
01030 int load_modules(unsigned int preload_only)
01031 {
01032    struct ast_config *cfg;
01033    struct ast_module *mod;
01034    struct load_order_entry *order;
01035    struct ast_variable *v;
01036    unsigned int load_count;
01037    struct load_order load_order;
01038    int res = 0;
01039    struct ast_flags config_flags = { 0 };
01040    int modulecount = 0;
01041 
01042 #ifdef LOADABLE_MODULES
01043    struct dirent *dirent;
01044    DIR *dir;
01045 #endif
01046 
01047    /* all embedded modules have registered themselves by now */
01048    embedding = 0;
01049 
01050    ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
01051 
01052    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
01053 
01054    AST_LIST_LOCK(&module_list);
01055 
01056    if (embedded_module_list.first) {
01057       module_list.first = embedded_module_list.first;
01058       module_list.last = embedded_module_list.last;
01059       embedded_module_list.first = NULL;
01060    }
01061 
01062    cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
01063    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01064       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
01065       goto done;
01066    }
01067 
01068    /* first, find all the modules we have been explicitly requested to load */
01069    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01070       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
01071          add_to_load_order(v->value, &load_order, 0);
01072       }
01073       if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
01074          /* Add the module to the list and make sure it's required */
01075          add_to_load_order(v->value, &load_order, 1);
01076          ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
01077       }
01078 
01079    }
01080 
01081    /* check if 'autoload' is on */
01082    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
01083       /* if so, first add all the embedded modules that are not already running to the load order */
01084       AST_LIST_TRAVERSE(&module_list, mod, entry) {
01085          /* if it's not embedded, skip it */
01086          if (mod->lib)
01087             continue;
01088 
01089          if (mod->flags.running)
01090             continue;
01091 
01092          add_to_load_order(mod->resource, &load_order, 0);
01093       }
01094 
01095 #ifdef LOADABLE_MODULES
01096       /* if we are allowed to load dynamic modules, scan the directory for
01097          for all available modules and add them as well */
01098       if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
01099          while ((dirent = readdir(dir))) {
01100             int ld = strlen(dirent->d_name);
01101 
01102             /* Must end in .so to load it.  */
01103 
01104             if (ld < 4)
01105                continue;
01106 
01107             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
01108                continue;
01109 
01110             /* if there is already a module by this name in the module_list,
01111                skip this file */
01112             if (find_resource(dirent->d_name, 0))
01113                continue;
01114 
01115             add_to_load_order(dirent->d_name, &load_order, 0);
01116          }
01117 
01118          closedir(dir);
01119       } else {
01120          if (!ast_opt_quiet)
01121             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01122                ast_config_AST_MODULE_DIR);
01123       }
01124 #endif
01125    }
01126 
01127    /* now scan the config for any modules we are prohibited from loading and
01128       remove them from the load order */
01129    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01130       if (strcasecmp(v->name, "noload"))
01131          continue;
01132 
01133       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01134          if (!resource_name_match(order->resource, v->value)) {
01135             AST_LIST_REMOVE_CURRENT(entry);
01136             ast_free(order->resource);
01137             ast_free(order);
01138          }
01139       }
01140       AST_LIST_TRAVERSE_SAFE_END;
01141    }
01142 
01143    /* we are done with the config now, all the information we need is in the
01144       load_order list */
01145    ast_config_destroy(cfg);
01146 
01147    load_count = 0;
01148    AST_LIST_TRAVERSE(&load_order, order, entry)
01149       load_count++;
01150 
01151    if (load_count)
01152       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
01153 
01154    /* first, load only modules that provide global symbols */
01155    if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01156       goto done;
01157    }
01158 
01159    /* now load everything else */
01160    if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01161       goto done;
01162    }
01163 
01164 done:
01165    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01166       ast_free(order->resource);
01167       ast_free(order);
01168    }
01169 
01170    AST_LIST_UNLOCK(&module_list);
01171    
01172    /* Tell manager clients that are aggressive at logging in that we're done
01173       loading modules. If there's a DNS problem in chan_sip, we might not
01174       even reach this */
01175    manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
01176    
01177    return res;
01178 }
01179 
01180 void ast_update_use_count(void)
01181 {
01182    /* Notify any module monitors that the use count for a
01183       resource has changed */
01184    struct loadupdate *m;
01185 
01186    AST_LIST_LOCK(&updaters);
01187    AST_LIST_TRAVERSE(&updaters, m, entry)
01188       m->updater();
01189    AST_LIST_UNLOCK(&updaters);
01190 }
01191 
01192 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
01193             const char *like)
01194 {
01195    struct ast_module *cur;
01196    int unlock = -1;
01197    int total_mod_loaded = 0;
01198 
01199    if (AST_LIST_TRYLOCK(&module_list))
01200       unlock = 0;
01201  
01202    AST_LIST_TRAVERSE(&module_list, cur, entry) {
01203       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
01204    }
01205 
01206    if (unlock)
01207       AST_LIST_UNLOCK(&module_list);
01208 
01209    return total_mod_loaded;
01210 }
01211 
01212 /*! \brief Check if module exists */
01213 int ast_module_check(const char *name)
01214 {
01215    struct ast_module *cur;
01216 
01217    if (ast_strlen_zero(name))
01218       return 0;       /* FALSE */
01219 
01220    cur = find_resource(name, 1);
01221 
01222    return (cur != NULL);
01223 }
01224 
01225 
01226 int ast_loader_register(int (*v)(void))
01227 {
01228    struct loadupdate *tmp;
01229 
01230    if (!(tmp = ast_malloc(sizeof(*tmp))))
01231       return -1;
01232 
01233    tmp->updater = v;
01234    AST_LIST_LOCK(&updaters);
01235    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01236    AST_LIST_UNLOCK(&updaters);
01237 
01238    return 0;
01239 }
01240 
01241 int ast_loader_unregister(int (*v)(void))
01242 {
01243    struct loadupdate *cur;
01244 
01245    AST_LIST_LOCK(&updaters);
01246    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01247       if (cur->updater == v)  {
01248          AST_LIST_REMOVE_CURRENT(entry);
01249          break;
01250       }
01251    }
01252    AST_LIST_TRAVERSE_SAFE_END;
01253    AST_LIST_UNLOCK(&updaters);
01254 
01255    return cur ? 0 : -1;
01256 }
01257 
01258 struct ast_module *ast_module_ref(struct ast_module *mod)
01259 {
01260    if (!mod) {
01261       return NULL;
01262    }
01263 
01264    ast_atomic_fetchadd_int(&mod->usecount, +1);
01265    ast_update_use_count();
01266 
01267    return mod;
01268 }
01269 
01270 void ast_module_unref(struct ast_module *mod)
01271 {
01272    if (!mod) {
01273       return;
01274    }
01275 
01276    ast_atomic_fetchadd_int(&mod->usecount, -1);
01277    ast_update_use_count();
01278 }