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

Generated on Mon Oct 8 12:39:03 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7