Wed Oct 28 11:51:05 2009

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

Generated on Wed Oct 28 11:51:05 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6