Sat Mar 10 01:54:19 2012

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

Generated on Sat Mar 10 01:54:19 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7