Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:49 2007

Asterisk developer's documentation :: Codename Pineapple


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: 46594 $")
00033 
00034 #include <stdio.h>
00035 #include <dirent.h>
00036 #include <unistd.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <string.h>
00040 
00041 #include "asterisk/linkedlists.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/term.h"
00048 #include "asterisk/manager.h"
00049 #include "asterisk/cdr.h"
00050 #include "asterisk/enum.h"
00051 #include "asterisk/rtp.h"
00052 #include "asterisk/http.h"
00053 #include "asterisk/lock.h"
00054 
00055 #ifdef DLFCNCOMPAT
00056 #include "asterisk/dlfcn-compat.h"
00057 #else
00058 #include <dlfcn.h>
00059 #endif
00060 
00061 #include "asterisk/md5.h"
00062 #include "asterisk/utils.h"
00063 
00064 #ifndef RTLD_NOW
00065 #define RTLD_NOW 0
00066 #endif
00067 
00068 struct ast_module_user {
00069    struct ast_channel *chan;
00070    AST_LIST_ENTRY(ast_module_user) entry;
00071 };
00072 
00073 AST_LIST_HEAD(module_user_list, ast_module_user);
00074 
00075 static unsigned char expected_key[] =
00076 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00077   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00078 
00079 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
00080                   since they are here before we dlopen() any
00081                */
00082 
00083 enum flags {
00084    FLAG_RUNNING = (1 << 1),      /* module successfully initialized */
00085    FLAG_DECLINED = (1 << 2),     /* module declined to initialize */
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    unsigned int flags;           /* flags for this module */
00094    AST_LIST_ENTRY(ast_module) entry;
00095    char resource[0];
00096 };
00097 
00098 static AST_LIST_HEAD_STATIC(module_list, ast_module);
00099 
00100 struct loadupdate {
00101    int (*updater)(void);
00102    AST_LIST_ENTRY(loadupdate) entry;
00103 };
00104 
00105 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
00106 
00107 AST_MUTEX_DEFINE_STATIC(reloadlock);
00108 
00109 /* when dynamic modules are being loaded, ast_module_register() will
00110    need to know what filename the module was loaded from while it
00111    is being registered
00112 */
00113 struct ast_module *resource_being_loaded;
00114 
00115 /* XXX: should we check for duplicate resource names here? */
00116 
00117 void ast_module_register(const struct ast_module_info *info)
00118 {
00119    struct ast_module *mod;
00120 
00121    if (embedding) {
00122       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00123          return;
00124       strcpy(mod->resource, info->name);
00125    } else {
00126       mod = resource_being_loaded;
00127    }
00128 
00129    mod->info = info;
00130    AST_LIST_HEAD_INIT(&mod->users);
00131 
00132    /* during startup, before the loader has been initialized,
00133       there are no threads, so there is no need to take the lock
00134       on this list to manipulate it. it is also possible that it
00135       might be unsafe to use the list lock at that point... so
00136       let's avoid it altogether
00137    */
00138    if (!embedding)
00139       AST_LIST_LOCK(&module_list);
00140 
00141    /* it is paramount that the new entry be placed at the tail of
00142       the list, otherwise the code that uses dlopen() to load
00143       dynamic modules won't be able to find out if the module it
00144       just opened was registered or failed to load
00145    */
00146    AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00147 
00148    if (!embedding)
00149       AST_LIST_UNLOCK(&module_list);
00150 
00151    /* give the module a copy of its own handle, for later use in registrations and the like */
00152    *((struct ast_module **) &(info->self)) = mod;
00153 }
00154 
00155 void ast_module_unregister(const struct ast_module_info *info)
00156 {
00157    struct ast_module *mod = NULL;
00158 
00159    /* it is assumed that the users list in the module structure
00160       will already be empty, or we cannot have gotten to this
00161       point
00162    */
00163    AST_LIST_LOCK(&module_list);
00164    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00165       if (mod->info == info) {
00166          AST_LIST_REMOVE_CURRENT(&module_list, entry);
00167          break;
00168       }
00169    }
00170    AST_LIST_TRAVERSE_SAFE_END;
00171    AST_LIST_UNLOCK(&module_list);
00172 
00173    if (mod) {
00174       AST_LIST_HEAD_DESTROY(&mod->users);
00175       free(mod);
00176    }
00177 }
00178 
00179 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
00180                      struct ast_channel *chan)
00181 {
00182    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00183 
00184    if (!u)
00185       return NULL;
00186 
00187    u->chan = chan;
00188 
00189    AST_LIST_LOCK(&mod->users);
00190    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00191    AST_LIST_UNLOCK(&mod->users);
00192 
00193    ast_atomic_fetchadd_int(&mod->usecount, +1);
00194 
00195    ast_update_use_count();
00196 
00197    return u;
00198 }
00199 
00200 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00201 {
00202    AST_LIST_LOCK(&mod->users);
00203    AST_LIST_REMOVE(&mod->users, u, entry);
00204    AST_LIST_UNLOCK(&mod->users);
00205    ast_atomic_fetchadd_int(&mod->usecount, -1);
00206    free(u);
00207 
00208    ast_update_use_count();
00209 }
00210 
00211 void __ast_module_user_hangup_all(struct ast_module *mod)
00212 {
00213    struct ast_module_user *u;
00214 
00215    AST_LIST_LOCK(&mod->users);
00216    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00217       ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00218       ast_atomic_fetchadd_int(&mod->usecount, -1);
00219       free(u);
00220    }
00221    AST_LIST_UNLOCK(&mod->users);
00222 
00223         ast_update_use_count();
00224 }
00225 
00226 /*! \note
00227  * In addition to modules, the reload command handles some extra keywords
00228  * which are listed here together with the corresponding handlers.
00229  * This table is also used by the command completion code.
00230  */
00231 static struct reload_classes {
00232    const char *name;
00233    int (*reload_fn)(void);
00234 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
00235    { "cdr", ast_cdr_engine_reload },
00236    { "dnsmgr", dnsmgr_reload },
00237    { "extconfig", read_config_maps },
00238    { "enum",   ast_enum_reload },
00239    { "manager",   reload_manager },
00240    { "rtp", ast_rtp_reload },
00241    { "http",   ast_http_reload },
00242    { NULL,  NULL }
00243 };
00244 
00245 static int printdigest(const unsigned char *d)
00246 {
00247    int x, pos;
00248    char buf[256]; /* large enough so we don't have to worry */
00249 
00250    for (pos = 0, x = 0; x < 16; x++)
00251       pos += sprintf(buf + pos, " %02x", *d++);
00252 
00253    if (option_debug)
00254       ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
00255 
00256    return 0;
00257 }
00258 
00259 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00260 {
00261    int x;
00262 
00263    for (x = 0; x < 16; x++) {
00264       if (key1[x] != key2[x])
00265          return 0;
00266    }
00267 
00268    return 1;
00269 }
00270 
00271 static int verify_key(const unsigned char *key)
00272 {
00273    struct MD5Context c;
00274    unsigned char digest[16];
00275 
00276    MD5Init(&c);
00277    MD5Update(&c, key, strlen((char *)key));
00278    MD5Final(digest, &c);
00279 
00280    if (key_matches(expected_key, digest))
00281       return 0;
00282 
00283    printdigest(digest);
00284 
00285    return -1;
00286 }
00287 
00288 static int resource_name_match(const char *name1_in, const char *name2_in)
00289 {
00290    char *name1 = (char *) name1_in;
00291    char *name2 = (char *) name2_in;
00292 
00293    /* trim off any .so extensions */
00294    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00295       name1 = ast_strdupa(name1);
00296       name1[strlen(name1) - 3] = '\0';
00297    }
00298    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00299       name2 = ast_strdupa(name2);
00300       name2[strlen(name2) - 3] = '\0';
00301    }
00302 
00303    return strcasecmp(name1, name2);
00304 }
00305 
00306 static struct ast_module *find_resource(const char *resource, int do_lock)
00307 {
00308    struct ast_module *cur;
00309 
00310    if (do_lock)
00311       AST_LIST_LOCK(&module_list);
00312 
00313    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00314       if (!resource_name_match(resource, cur->resource))
00315          break;
00316    }
00317 
00318    if (do_lock)
00319       AST_LIST_UNLOCK(&module_list);
00320 
00321    return cur;
00322 }
00323 
00324 #if LOADABLE_MODULES
00325 static void unload_dynamic_module(struct ast_module *mod)
00326 {
00327    void *lib = mod->lib;
00328 
00329    /* WARNING: the structure pointed to by mod is going to
00330       disappear when this operation succeeds, so we can't
00331       dereference it */
00332 
00333    if (lib)
00334       while (!dlclose(lib));
00335 }
00336 
00337 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
00338 {
00339    char fn[256];
00340    void *lib;
00341    struct ast_module *mod;
00342    char *resource = (char *) resource_in;
00343    unsigned int wants_global;
00344 
00345    if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
00346       resource = alloca(strlen(resource_in) + 3);
00347            strcpy(resource, resource_in);
00348       strcat(resource, ".so");
00349    }
00350 
00351    snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
00352 
00353    /* make a first load of the module in 'quiet' mode... don't try to resolve
00354       any symbols, and don't export any symbols. this will allow us to peek into
00355       the module's info block (if available) to see what flags it has set */
00356 
00357    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00358       return NULL;
00359 
00360    strcpy(resource_being_loaded->resource, resource);
00361 
00362    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00363       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00364       free(resource_being_loaded);
00365       return NULL;
00366    }
00367 
00368    /* the dlopen() succeeded, let's find out if the module
00369       registered itself */
00370    /* note that this will only work properly as long as
00371       ast_module_register() (which is called by the module's
00372       constructor) places the new module at the tail of the
00373       module_list
00374    */
00375    if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00376       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00377       /* no, it did not, so close it and return */
00378       while (!dlclose(lib));
00379       /* note that the module's destructor will call ast_module_unregister(),
00380          which will free the structure we allocated in resource_being_loaded */
00381       return NULL;
00382    }
00383 
00384    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00385 
00386    /* if we are being asked only to load modules that provide global symbols,
00387       and this one does not, then close it and return */
00388    if (global_symbols_only && !wants_global) {
00389       while (!dlclose(lib));
00390       return NULL;
00391    }
00392 
00393    /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
00394       on the already-opened library to what we want... if not, we have to
00395       close it and start over
00396    */
00397 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
00398    if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00399       ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
00400       while (!dlclose(lib));
00401       free(resource_being_loaded);
00402       return NULL;
00403    }
00404 #else
00405    while (!dlclose(lib));
00406    resource_being_loaded = NULL;
00407 
00408    /* start the load process again */
00409 
00410    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00411       return NULL;
00412 
00413    strcpy(resource_being_loaded->resource, resource);
00414 
00415    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00416       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00417       free(resource_being_loaded);
00418       return NULL;
00419    }
00420 
00421    /* since the module was successfully opened, and it registered itself
00422       the previous time we did that, we're going to assume it worked this
00423       time too :) */
00424 #endif
00425 
00426    AST_LIST_LAST(&module_list)->lib = lib;
00427    resource_being_loaded = NULL;
00428 
00429    return AST_LIST_LAST(&module_list);
00430 }
00431 #endif
00432 
00433 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00434 {
00435    struct ast_module *mod;
00436    int res = -1;
00437    int error = 0;
00438 
00439    AST_LIST_LOCK(&module_list);
00440 
00441    if (!(mod = find_resource(resource_name, 0))) {
00442       AST_LIST_UNLOCK(&module_list);
00443       return 0;
00444    }
00445 
00446    if (!ast_test_flag(mod, FLAG_RUNNING | FLAG_DECLINED))
00447       error = 1;
00448 
00449    if (!error && (mod->usecount > 0)) {
00450       if (force)
00451          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00452             resource_name, mod->usecount);
00453       else {
00454          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00455             mod->usecount);
00456          error = 1;
00457       }
00458    }
00459 
00460    if (!error) {
00461       __ast_module_user_hangup_all(mod);
00462       res = mod->info->unload();
00463 
00464       if (res) {
00465          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00466          if (force <= AST_FORCE_FIRM)
00467             error = 1;
00468          else
00469             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00470       }
00471    }
00472 
00473    if (!error)
00474       ast_clear_flag(mod, FLAG_RUNNING | FLAG_DECLINED);
00475 
00476    AST_LIST_UNLOCK(&module_list);
00477 
00478 #if LOADABLE_MODULES
00479    if (!error)
00480       unload_dynamic_module(mod);
00481 #endif
00482 
00483    if (!error)
00484       ast_update_use_count();
00485 
00486    return res;
00487 }
00488 
00489 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00490 {
00491    struct ast_module *cur;
00492    int i, which=0, l = strlen(word);
00493    char *ret = NULL;
00494 
00495    if (pos != rpos)
00496       return NULL;
00497 
00498    AST_LIST_LOCK(&module_list);
00499    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00500       if (!strncasecmp(word, cur->resource, l) &&
00501           (cur->info->reload || !needsreload) &&
00502           ++which > state) {
00503          ret = strdup(cur->resource);
00504          break;
00505       }
00506    }
00507    AST_LIST_UNLOCK(&module_list);
00508 
00509    if (!ret) {
00510       for (i=0; !ret && reload_classes[i].name; i++) {
00511          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00512             ret = strdup(reload_classes[i].name);
00513       }
00514    }
00515 
00516    return ret;
00517 }
00518 
00519 int ast_module_reload(const char *name)
00520 {
00521    struct ast_module *cur;
00522    int res = 0; /* return value. 0 = not found, others, see below */
00523    int i;
00524 
00525    if (ast_mutex_trylock(&reloadlock)) {
00526       ast_verbose("The previous reload command didn't finish yet\n");
00527       return -1;  /* reload already in progress */
00528    }
00529 
00530    /* Call "predefined" reload here first */
00531    for (i = 0; reload_classes[i].name; i++) {
00532       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00533          reload_classes[i].reload_fn();   /* XXX should check error ? */
00534          res = 2; /* found and reloaded */
00535       }
00536    }
00537    ast_lastreloadtime = time(NULL);
00538 
00539    if (name && res)
00540       return res;
00541 
00542    AST_LIST_LOCK(&module_list);
00543    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00544       const struct ast_module_info *info = cur->info;
00545 
00546       if (name && resource_name_match(name, cur->resource))
00547          continue;
00548 
00549       if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED))
00550          continue;
00551 
00552       if (!info->reload) { /* cannot be reloaded */
00553          if (res < 1)   /* store result if possible */
00554             res = 1; /* 1 = no reload() method */
00555          continue;
00556       }
00557 
00558       res = 2;
00559       if (option_verbose > 2)
00560          ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
00561       info->reload();
00562    }
00563    AST_LIST_UNLOCK(&module_list);
00564 
00565    ast_mutex_unlock(&reloadlock);
00566 
00567    return res;
00568 }
00569 
00570 static unsigned int inspect_module(const struct ast_module *mod)
00571 {
00572    if (!mod->info->description) {
00573       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00574       return 1;
00575    }
00576 
00577    if (!mod->info->key) {
00578       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00579       return 1;
00580    }
00581 
00582    if (verify_key((unsigned char *) mod->info->key)) {
00583       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00584       return 1;
00585    }
00586 
00587    return 0;
00588 }
00589 
00590 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
00591 {
00592    struct ast_module *mod;
00593    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00594    char tmp[256];
00595 
00596    if ((mod = find_resource(resource_name, 0))) {
00597       if (ast_test_flag(mod, FLAG_RUNNING)) {
00598          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00599          return AST_MODULE_LOAD_DECLINE;
00600       }
00601       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00602          return AST_MODULE_LOAD_SKIP;
00603    } else {
00604 #if LOADABLE_MODULES
00605       if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00606          /* don't generate a warning message during load_modules() */
00607          if (!global_symbols_only) {
00608             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00609             return AST_MODULE_LOAD_DECLINE;
00610          } else {
00611             return AST_MODULE_LOAD_SKIP;
00612          }
00613       }
00614 #else
00615       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00616       return AST_MODULE_LOAD_DECLINE;
00617 #endif
00618    }
00619 
00620    if (inspect_module(mod)) {
00621       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00622 #if LOADABLE_MODULES
00623       unload_dynamic_module(mod);
00624 #endif
00625       return AST_MODULE_LOAD_DECLINE;
00626    }
00627 
00628    ast_clear_flag(mod, FLAG_DECLINED);
00629 
00630    if (mod->info->load)
00631       res = mod->info->load();
00632 
00633    switch (res) {
00634    case AST_MODULE_LOAD_SUCCESS:
00635       if (!ast_fully_booted) {
00636          if (option_verbose)
00637             ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00638          if (ast_opt_console && !option_verbose)
00639             ast_verbose( ".");
00640       } else {
00641          if (option_verbose)
00642             ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
00643       }
00644 
00645       ast_set_flag(mod, FLAG_RUNNING);
00646 
00647       ast_update_use_count();
00648       break;
00649    case AST_MODULE_LOAD_DECLINE:
00650       ast_set_flag(mod, FLAG_DECLINED);
00651       break;
00652    case AST_MODULE_LOAD_FAILURE:
00653       break;
00654    case AST_MODULE_LOAD_SKIP:
00655       /* modules should never return this value */
00656       break;
00657    }
00658 
00659    return res;
00660 }
00661 
00662 int ast_load_resource(const char *resource_name)
00663 {
00664        AST_LIST_LOCK(&module_list);
00665        load_resource(resource_name, 0);
00666        AST_LIST_UNLOCK(&module_list);
00667 
00668        return 0;
00669 }
00670 
00671 struct load_order_entry {
00672    char *resource;
00673    AST_LIST_ENTRY(load_order_entry) entry;
00674 };
00675 
00676 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00677 
00678 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
00679 {
00680    struct load_order_entry *order;
00681 
00682    AST_LIST_TRAVERSE(load_order, order, entry) {
00683       if (!resource_name_match(order->resource, resource))
00684          return NULL;
00685    }
00686 
00687    if (!(order = ast_calloc(1, sizeof(*order))))
00688       return NULL;
00689 
00690    order->resource = ast_strdup(resource);
00691    AST_LIST_INSERT_TAIL(load_order, order, entry);
00692 
00693    return order;
00694 }
00695 
00696 int load_modules(unsigned int preload_only)
00697 {
00698    struct ast_config *cfg;
00699    struct ast_module *mod;
00700    struct load_order_entry *order;
00701    struct ast_variable *v;
00702    unsigned int load_count;
00703    struct load_order load_order;
00704    int res = 0;
00705 #if LOADABLE_MODULES
00706    struct dirent *dirent;
00707    DIR *dir;
00708 #endif
00709 
00710    /* all embedded modules have registered themselves by now */
00711    embedding = 0;
00712 
00713    if (option_verbose)
00714       ast_verbose("Asterisk Dynamic Loader Starting:\n");
00715 
00716    AST_LIST_TRAVERSE(&module_list, mod, entry) {
00717       if (option_debug > 1)
00718          ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
00719    }
00720 
00721    if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
00722       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
00723       return 0;
00724    }
00725 
00726    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
00727 
00728    /* first, find all the modules we have been explicitly requested to load */
00729    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00730       if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
00731          add_to_load_order(v->value, &load_order);
00732    }
00733 
00734    /* check if 'autoload' is on */
00735    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00736       /* if so, first add all the embedded modules to the load order */
00737       AST_LIST_TRAVERSE(&module_list, mod, entry)
00738          order = add_to_load_order(mod->resource, &load_order);
00739 
00740 #if LOADABLE_MODULES
00741       /* if we are allowed to load dynamic modules, scan the directory for
00742          for all available modules and add them as well */
00743       if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
00744          while ((dirent = readdir(dir))) {
00745             int ld = strlen(dirent->d_name);
00746 
00747             /* Must end in .so to load it.  */
00748 
00749             if (ld < 4)
00750                continue;
00751 
00752             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
00753                 continue;
00754 
00755             add_to_load_order(dirent->d_name, &load_order);
00756 
00757          }
00758 
00759          closedir(dir);
00760       } else {
00761          if (!ast_opt_quiet)
00762             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
00763                ast_config_AST_MODULE_DIR);
00764       }
00765 #endif
00766    }
00767 
00768    /* now scan the config for any modules we are prohibited from loading and
00769       remove them from the load order */
00770    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00771       if (strcasecmp(v->name, "noload"))
00772          continue;
00773 
00774       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00775          if (!resource_name_match(order->resource, v->value)) {
00776             AST_LIST_REMOVE_CURRENT(&load_order, entry);
00777             free(order->resource);
00778             free(order);
00779          }
00780       }
00781       AST_LIST_TRAVERSE_SAFE_END;
00782    }
00783 
00784    /* we are done with the config now, all the information we need is in the
00785       load_order list */
00786    ast_config_destroy(cfg);
00787 
00788    load_count = 0;
00789    AST_LIST_TRAVERSE(&load_order, order, entry)
00790       load_count++;
00791 
00792    if (load_count)
00793       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
00794 
00795    /* first, load only modules that provide global symbols */
00796    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00797       switch (load_resource(order->resource, 1)) {
00798       case AST_MODULE_LOAD_SUCCESS:
00799       case AST_MODULE_LOAD_DECLINE:
00800          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00801          free(order->resource);
00802          free(order);
00803          break;
00804       case AST_MODULE_LOAD_FAILURE:
00805          res = -1;
00806          goto done;
00807       case AST_MODULE_LOAD_SKIP:
00808          /* try again later */
00809          break;
00810       }
00811    }
00812    AST_LIST_TRAVERSE_SAFE_END;
00813 
00814    /* now load everything else */
00815    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00816       switch (load_resource(order->resource, 0)) {
00817       case AST_MODULE_LOAD_SUCCESS:
00818       case AST_MODULE_LOAD_DECLINE:
00819          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00820          free(order->resource);
00821          free(order);
00822          break;
00823       case AST_MODULE_LOAD_FAILURE:
00824          res = -1;
00825          goto done;
00826       case AST_MODULE_LOAD_SKIP:
00827          /* should not happen */
00828          break;
00829       }
00830    }
00831    AST_LIST_TRAVERSE_SAFE_END;
00832 
00833 done:
00834    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
00835       free(order->resource);
00836       free(order);
00837    }
00838 
00839    return res;
00840 }
00841 
00842 void ast_update_use_count(void)
00843 {
00844    /* Notify any module monitors that the use count for a
00845       resource has changed */
00846    struct loadupdate *m;
00847 
00848    AST_LIST_LOCK(&module_list);
00849    AST_LIST_TRAVERSE(&updaters, m, entry)
00850       m->updater();
00851    AST_LIST_UNLOCK(&module_list);
00852 }
00853 
00854 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
00855             const char *like)
00856 {
00857    struct ast_module *cur;
00858    int unlock = -1;
00859    int total_mod_loaded = 0;
00860 
00861    if (AST_LIST_TRYLOCK(&module_list))
00862       unlock = 0;
00863 
00864    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00865       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
00866    }
00867 
00868    if (unlock)
00869       AST_LIST_UNLOCK(&module_list);
00870 
00871    return total_mod_loaded;
00872 }
00873 
00874 /*! \brief Check if module exists */
00875 int ast_module_check(char *name)
00876 {
00877    struct ast_module *cur;
00878 
00879    if (ast_strlen_zero(name))
00880       return 0;       /* FALSE */
00881 
00882    cur = find_resource(name, 1);
00883 
00884    return (cur != NULL);
00885 }
00886 
00887 
00888 int ast_loader_register(int (*v)(void))
00889 {
00890    struct loadupdate *tmp;
00891 
00892    if (!(tmp = ast_malloc(sizeof(*tmp))))
00893       return -1;
00894 
00895    tmp->updater = v;
00896    AST_LIST_LOCK(&module_list);
00897    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
00898    AST_LIST_UNLOCK(&module_list);
00899 
00900    return 0;
00901 }
00902 
00903 int ast_loader_unregister(int (*v)(void))
00904 {
00905    struct loadupdate *cur;
00906 
00907    AST_LIST_LOCK(&module_list);
00908    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
00909       if (cur->updater == v)  {
00910          AST_LIST_REMOVE_CURRENT(&updaters, entry);
00911          break;
00912       }
00913    }
00914    AST_LIST_TRAVERSE_SAFE_END;
00915    AST_LIST_UNLOCK(&module_list);
00916 
00917    return cur ? 0 : -1;
00918 }
00919 
00920 struct ast_module *ast_module_ref(struct ast_module *mod)
00921 {
00922    ast_atomic_fetchadd_int(&mod->usecount, +1);
00923    ast_update_use_count();
00924 
00925    return mod;
00926 }
00927 
00928 void ast_module_unref(struct ast_module *mod)
00929 {
00930    ast_atomic_fetchadd_int(&mod->usecount, -1);
00931    ast_update_use_count();
00932 }

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen