Wed Aug 18 22:33:53 2010

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

Generated on Wed Aug 18 22:33:53 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7