Mon Sep 20 2010 00:23:05

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