Thu Apr 28 2011 17:13:34

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