00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 356291 $")
00033
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"
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;
00081
00082
00083
00084 struct ast_module {
00085 const struct ast_module_info *info;
00086 void *lib;
00087 int usecount;
00088 struct module_user_list users;
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
00110
00111
00112
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
00135
00136
00137
00138 static struct ast_module *resource_being_loaded;
00139
00140
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
00158
00159
00160
00161
00162
00163 if (embedding) {
00164 AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00165 } else {
00166 AST_LIST_LOCK(&module_list);
00167
00168
00169
00170
00171
00172 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00173 AST_LIST_UNLOCK(&module_list);
00174 }
00175
00176
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
00185
00186
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 if (u->chan) {
00243 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00244 }
00245 ast_atomic_fetchadd_int(&mod->usecount, -1);
00246 ast_free(u);
00247 }
00248 AST_LIST_UNLOCK(&mod->users);
00249
00250 ast_update_use_count();
00251 }
00252
00253
00254
00255
00256
00257
00258 static struct reload_classes {
00259 const char *name;
00260 int (*reload_fn)(void);
00261 } reload_classes[] = {
00262 { "cdr", ast_cdr_engine_reload },
00263 { "dnsmgr", dnsmgr_reload },
00264 { "extconfig", read_config_maps },
00265 { "enum", ast_enum_reload },
00266 { "manager", reload_manager },
00267 { "http", ast_http_reload },
00268 { "logger", logger_reload },
00269 { "features", ast_features_reload },
00270 { "dsp", ast_dsp_reload},
00271 { "udptl", ast_udptl_reload },
00272 { "indications", ast_indications_reload },
00273 { "cel", ast_cel_engine_reload },
00274 { "plc", ast_plc_reload },
00275 { NULL, NULL }
00276 };
00277
00278 static int printdigest(const unsigned char *d)
00279 {
00280 int x, pos;
00281 char buf[256];
00282
00283 for (pos = 0, x = 0; x < 16; x++)
00284 pos += sprintf(buf + pos, " %02x", *d++);
00285
00286 ast_debug(1, "Unexpected signature:%s\n", buf);
00287
00288 return 0;
00289 }
00290
00291 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00292 {
00293 int x;
00294
00295 for (x = 0; x < 16; x++) {
00296 if (key1[x] != key2[x])
00297 return 0;
00298 }
00299
00300 return 1;
00301 }
00302
00303 static int verify_key(const unsigned char *key)
00304 {
00305 struct MD5Context c;
00306 unsigned char digest[16];
00307
00308 MD5Init(&c);
00309 MD5Update(&c, key, strlen((char *)key));
00310 MD5Final(digest, &c);
00311
00312 if (key_matches(expected_key, digest))
00313 return 0;
00314
00315 printdigest(digest);
00316
00317 return -1;
00318 }
00319
00320 static int resource_name_match(const char *name1_in, const char *name2_in)
00321 {
00322 char *name1 = (char *) name1_in;
00323 char *name2 = (char *) name2_in;
00324
00325
00326 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00327 name1 = ast_strdupa(name1);
00328 name1[strlen(name1) - 3] = '\0';
00329 }
00330 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00331 name2 = ast_strdupa(name2);
00332 name2[strlen(name2) - 3] = '\0';
00333 }
00334
00335 return strcasecmp(name1, name2);
00336 }
00337
00338 static struct ast_module *find_resource(const char *resource, int do_lock)
00339 {
00340 struct ast_module *cur;
00341
00342 if (do_lock)
00343 AST_LIST_LOCK(&module_list);
00344
00345 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00346 if (!resource_name_match(resource, cur->resource))
00347 break;
00348 }
00349
00350 if (do_lock)
00351 AST_LIST_UNLOCK(&module_list);
00352
00353 return cur;
00354 }
00355
00356 #ifdef LOADABLE_MODULES
00357 static void unload_dynamic_module(struct ast_module *mod)
00358 {
00359 void *lib = mod->lib;
00360
00361
00362
00363
00364
00365 if (lib)
00366 while (!dlclose(lib));
00367 }
00368
00369 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
00370 {
00371 char fn[PATH_MAX] = "";
00372 void *lib = NULL;
00373 struct ast_module *mod;
00374 unsigned int wants_global;
00375 int space;
00376 int missing_so = 0;
00377
00378 space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
00379 if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
00380 missing_so = 1;
00381 space += 3;
00382 }
00383
00384 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
00385
00386
00387
00388
00389
00390 resource_being_loaded = ast_calloc(1, space);
00391 if (!resource_being_loaded)
00392 return NULL;
00393 strcpy(resource_being_loaded->resource, resource_in);
00394 if (missing_so)
00395 strcat(resource_being_loaded->resource, ".so");
00396
00397 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00398 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00399 ast_free(resource_being_loaded);
00400 return NULL;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00411 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00412
00413 while (!dlclose(lib));
00414
00415
00416 return NULL;
00417 }
00418
00419 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00420
00421
00422
00423 if (global_symbols_only && !wants_global) {
00424 while (!dlclose(lib));
00425 return NULL;
00426 }
00427
00428
00429
00430
00431
00432
00433 #if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
00434 if (!ast_strlen_zero(mod->info->nonoptreq)) {
00435
00436 char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
00437 while ((each = strsep(&required_resource, ","))) {
00438 each = ast_strip(each);
00439
00440
00441 if (!find_resource(each, 0)) {
00442 load_dynamic_module(each, global_symbols_only);
00443 }
00444 }
00445 }
00446 #endif
00447
00448 while (!dlclose(lib));
00449 resource_being_loaded = NULL;
00450
00451
00452 resource_being_loaded = ast_calloc(1, space);
00453 if (!resource_being_loaded)
00454 return NULL;
00455 strcpy(resource_being_loaded->resource, resource_in);
00456 if (missing_so)
00457 strcat(resource_being_loaded->resource, ".so");
00458
00459 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00460 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00461 ast_free(resource_being_loaded);
00462 return NULL;
00463 }
00464
00465
00466
00467
00468
00469 AST_LIST_LAST(&module_list)->lib = lib;
00470 resource_being_loaded = NULL;
00471
00472 return AST_LIST_LAST(&module_list);
00473 }
00474 #endif
00475
00476 void ast_module_shutdown(void)
00477 {
00478 struct ast_module *mod;
00479 int somethingchanged = 1, final = 0;
00480
00481 AST_LIST_LOCK(&module_list);
00482
00483
00484
00485
00486 do {
00487 if (!somethingchanged) {
00488
00489
00490 final = 1;
00491 }
00492
00493
00494 somethingchanged = 0;
00495
00496 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00497 if (!final && mod->usecount) {
00498 continue;
00499 }
00500 AST_LIST_REMOVE_CURRENT(entry);
00501 if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
00502 mod->info->unload();
00503 }
00504 AST_LIST_HEAD_DESTROY(&mod->users);
00505 free(mod);
00506 somethingchanged = 1;
00507 }
00508 AST_LIST_TRAVERSE_SAFE_END;
00509 } while (somethingchanged && !final);
00510
00511 AST_LIST_UNLOCK(&module_list);
00512 }
00513
00514 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00515 {
00516 struct ast_module *mod;
00517 int res = -1;
00518 int error = 0;
00519
00520 AST_LIST_LOCK(&module_list);
00521
00522 if (!(mod = find_resource(resource_name, 0))) {
00523 AST_LIST_UNLOCK(&module_list);
00524 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00525 return -1;
00526 }
00527
00528 if (!mod->flags.running || mod->flags.declined) {
00529 ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
00530 error = 1;
00531 }
00532
00533 if (!error && (mod->usecount > 0)) {
00534 if (force)
00535 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
00536 resource_name, mod->usecount);
00537 else {
00538 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00539 mod->usecount);
00540 error = 1;
00541 }
00542 }
00543
00544 if (!error) {
00545 __ast_module_user_hangup_all(mod);
00546 res = mod->info->unload();
00547
00548 if (res) {
00549 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00550 if (force <= AST_FORCE_FIRM)
00551 error = 1;
00552 else
00553 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00554 }
00555 }
00556
00557 if (!error)
00558 mod->flags.running = mod->flags.declined = 0;
00559
00560 AST_LIST_UNLOCK(&module_list);
00561
00562 if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00563 mod->info->restore_globals();
00564
00565 #ifdef LOADABLE_MODULES
00566 if (!error)
00567 unload_dynamic_module(mod);
00568 #endif
00569
00570 if (!error)
00571 ast_update_use_count();
00572
00573 return res;
00574 }
00575
00576 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00577 {
00578 struct ast_module *cur;
00579 int i, which=0, l = strlen(word);
00580 char *ret = NULL;
00581
00582 if (pos != rpos)
00583 return NULL;
00584
00585 AST_LIST_LOCK(&module_list);
00586 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00587 if (!strncasecmp(word, cur->resource, l) &&
00588 (cur->info->reload || !needsreload) &&
00589 ++which > state) {
00590 ret = ast_strdup(cur->resource);
00591 break;
00592 }
00593 }
00594 AST_LIST_UNLOCK(&module_list);
00595
00596 if (!ret) {
00597 for (i=0; !ret && reload_classes[i].name; i++) {
00598 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00599 ret = ast_strdup(reload_classes[i].name);
00600 }
00601 }
00602
00603 return ret;
00604 }
00605
00606 void ast_process_pending_reloads(void)
00607 {
00608 struct reload_queue_item *item;
00609
00610 if (!ast_fully_booted) {
00611 return;
00612 }
00613
00614 AST_LIST_LOCK(&reload_queue);
00615
00616 if (do_full_reload) {
00617 do_full_reload = 0;
00618 AST_LIST_UNLOCK(&reload_queue);
00619 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00620 ast_module_reload(NULL);
00621 return;
00622 }
00623
00624 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00625 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00626 ast_module_reload(item->module);
00627 ast_free(item);
00628 }
00629
00630 AST_LIST_UNLOCK(&reload_queue);
00631 }
00632
00633 static void queue_reload_request(const char *module)
00634 {
00635 struct reload_queue_item *item;
00636
00637 AST_LIST_LOCK(&reload_queue);
00638
00639 if (do_full_reload) {
00640 AST_LIST_UNLOCK(&reload_queue);
00641 return;
00642 }
00643
00644 if (ast_strlen_zero(module)) {
00645
00646
00647 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00648 ast_free(item);
00649 }
00650 do_full_reload = 1;
00651 } else {
00652
00653 AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00654 if (!strcasecmp(item->module, module)) {
00655 AST_LIST_UNLOCK(&reload_queue);
00656 return;
00657 }
00658 }
00659 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00660 if (!item) {
00661 ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00662 AST_LIST_UNLOCK(&reload_queue);
00663 return;
00664 }
00665 strcpy(item->module, module);
00666 AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00667 }
00668 AST_LIST_UNLOCK(&reload_queue);
00669 }
00670
00671 int ast_module_reload(const char *name)
00672 {
00673 struct ast_module *cur;
00674 int res = 0;
00675 int i;
00676
00677
00678
00679 if (!ast_fully_booted) {
00680 queue_reload_request(name);
00681 return 0;
00682 }
00683
00684 if (ast_mutex_trylock(&reloadlock)) {
00685 ast_verbose("The previous reload command didn't finish yet\n");
00686 return -1;
00687 }
00688 ast_lastreloadtime = ast_tvnow();
00689
00690 if (ast_opt_lock_confdir) {
00691 int try;
00692 int res;
00693 for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
00694 res = ast_lock_path(ast_config_AST_CONFIG_DIR);
00695 if (res == AST_LOCK_TIMEOUT) {
00696 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
00697 }
00698 }
00699 if (res != AST_LOCK_SUCCESS) {
00700 ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
00701 ast_mutex_unlock(&reloadlock);
00702 return -1;
00703 }
00704 }
00705
00706
00707 for (i = 0; reload_classes[i].name; i++) {
00708 if (!name || !strcasecmp(name, reload_classes[i].name)) {
00709 reload_classes[i].reload_fn();
00710 res = 2;
00711 }
00712 }
00713
00714 if (name && res) {
00715 if (ast_opt_lock_confdir) {
00716 ast_unlock_path(ast_config_AST_CONFIG_DIR);
00717 }
00718 ast_mutex_unlock(&reloadlock);
00719 return res;
00720 }
00721
00722 AST_LIST_LOCK(&module_list);
00723 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00724 const struct ast_module_info *info = cur->info;
00725
00726 if (name && resource_name_match(name, cur->resource))
00727 continue;
00728
00729 if (!cur->flags.running || cur->flags.declined) {
00730 if (!name)
00731 continue;
00732 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
00733 "Before reloading the module, you must run \"module load %s\" "
00734 "and fix whatever is preventing the module from being initialized.\n",
00735 name, name);
00736 res = 2;
00737 break;
00738 }
00739
00740 if (!info->reload) {
00741 if (res < 1)
00742 res = 1;
00743 continue;
00744 }
00745
00746 res = 2;
00747 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00748 info->reload();
00749 }
00750 AST_LIST_UNLOCK(&module_list);
00751
00752 if (ast_opt_lock_confdir) {
00753 ast_unlock_path(ast_config_AST_CONFIG_DIR);
00754 }
00755 ast_mutex_unlock(&reloadlock);
00756
00757 return res;
00758 }
00759
00760 static unsigned int inspect_module(const struct ast_module *mod)
00761 {
00762 if (!mod->info->description) {
00763 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00764 return 1;
00765 }
00766
00767 if (!mod->info->key) {
00768 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00769 return 1;
00770 }
00771
00772 if (verify_key((unsigned char *) mod->info->key)) {
00773 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00774 return 1;
00775 }
00776
00777 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00778 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00779 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00780 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00781 return 1;
00782 }
00783
00784 return 0;
00785 }
00786
00787 static enum ast_module_load_result start_resource(struct ast_module *mod)
00788 {
00789 char tmp[256];
00790 enum ast_module_load_result res;
00791
00792 if (!mod->info->load) {
00793 return AST_MODULE_LOAD_FAILURE;
00794 }
00795
00796 res = mod->info->load();
00797
00798 switch (res) {
00799 case AST_MODULE_LOAD_SUCCESS:
00800 if (!ast_fully_booted) {
00801 ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00802 if (ast_opt_console && !option_verbose)
00803 ast_verbose( ".");
00804 } else {
00805 ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
00806 }
00807
00808 mod->flags.running = 1;
00809
00810 ast_update_use_count();
00811 break;
00812 case AST_MODULE_LOAD_DECLINE:
00813 mod->flags.declined = 1;
00814 break;
00815 case AST_MODULE_LOAD_FAILURE:
00816 case AST_MODULE_LOAD_SKIP:
00817 case AST_MODULE_LOAD_PRIORITY:
00818 break;
00819 }
00820
00821 return res;
00822 }
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
00834 {
00835 struct ast_module *mod;
00836 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00837
00838 if ((mod = find_resource(resource_name, 0))) {
00839 if (mod->flags.running) {
00840 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00841 return AST_MODULE_LOAD_DECLINE;
00842 }
00843 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00844 return AST_MODULE_LOAD_SKIP;
00845 } else {
00846 #ifdef LOADABLE_MODULES
00847 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00848
00849 if (!global_symbols_only) {
00850 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00851 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00852 } else {
00853 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
00854 }
00855 }
00856 #else
00857 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00858 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00859 #endif
00860 }
00861
00862 if (inspect_module(mod)) {
00863 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00864 #ifdef LOADABLE_MODULES
00865 unload_dynamic_module(mod);
00866 #endif
00867 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00868 }
00869
00870 if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
00871 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
00872 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00873 }
00874
00875 mod->flags.declined = 0;
00876
00877 if (resource_heap) {
00878 ast_heap_push(resource_heap, mod);
00879 res = AST_MODULE_LOAD_PRIORITY;
00880 } else {
00881 res = start_resource(mod);
00882 }
00883
00884 return res;
00885 }
00886
00887 int ast_load_resource(const char *resource_name)
00888 {
00889 int res;
00890 AST_LIST_LOCK(&module_list);
00891 res = load_resource(resource_name, 0, NULL, 0);
00892 AST_LIST_UNLOCK(&module_list);
00893
00894 return res;
00895 }
00896
00897 struct load_order_entry {
00898 char *resource;
00899 int required;
00900 AST_LIST_ENTRY(load_order_entry) entry;
00901 };
00902
00903 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00904
00905 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
00906 {
00907 struct load_order_entry *order;
00908
00909 AST_LIST_TRAVERSE(load_order, order, entry) {
00910 if (!resource_name_match(order->resource, resource)) {
00911
00912
00913 order->required |= required;
00914 return NULL;
00915 }
00916 }
00917
00918 if (!(order = ast_calloc(1, sizeof(*order))))
00919 return NULL;
00920
00921 order->resource = ast_strdup(resource);
00922 order->required = required;
00923 AST_LIST_INSERT_TAIL(load_order, order, entry);
00924
00925 return order;
00926 }
00927
00928 static int mod_load_cmp(void *a, void *b)
00929 {
00930 struct ast_module *a_mod = (struct ast_module *) a;
00931 struct ast_module *b_mod = (struct ast_module *) b;
00932 int res = -1;
00933
00934 unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
00935 unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
00936 if (a_pri == b_pri) {
00937 res = 0;
00938 } else if (a_pri < b_pri) {
00939 res = 1;
00940 }
00941 return res;
00942 }
00943
00944
00945
00946
00947 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
00948 {
00949 struct ast_heap *resource_heap;
00950 struct load_order_entry *order;
00951 struct ast_module *mod;
00952 int count = 0;
00953 int res = 0;
00954
00955 if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
00956 return -1;
00957 }
00958
00959
00960 AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
00961 switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
00962 case AST_MODULE_LOAD_SUCCESS:
00963 case AST_MODULE_LOAD_DECLINE:
00964 AST_LIST_REMOVE_CURRENT(entry);
00965 ast_free(order->resource);
00966 ast_free(order);
00967 break;
00968 case AST_MODULE_LOAD_FAILURE:
00969 ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00970 fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00971 res = order->required ? -2 : -1;
00972 goto done;
00973 case AST_MODULE_LOAD_SKIP:
00974 break;
00975 case AST_MODULE_LOAD_PRIORITY:
00976 AST_LIST_REMOVE_CURRENT(entry);
00977 break;
00978 }
00979 }
00980 AST_LIST_TRAVERSE_SAFE_END;
00981
00982
00983 while ((mod = ast_heap_pop(resource_heap))) {
00984 switch (start_resource(mod)) {
00985 case AST_MODULE_LOAD_SUCCESS:
00986 count++;
00987 case AST_MODULE_LOAD_DECLINE:
00988 break;
00989 case AST_MODULE_LOAD_FAILURE:
00990 res = -1;
00991 goto done;
00992 case AST_MODULE_LOAD_SKIP:
00993 case AST_MODULE_LOAD_PRIORITY:
00994 break;
00995 }
00996 }
00997
00998 done:
00999 if (mod_count) {
01000 *mod_count += count;
01001 }
01002 ast_heap_destroy(resource_heap);
01003
01004 return res;
01005 }
01006
01007 int load_modules(unsigned int preload_only)
01008 {
01009 struct ast_config *cfg;
01010 struct ast_module *mod;
01011 struct load_order_entry *order;
01012 struct ast_variable *v;
01013 unsigned int load_count;
01014 struct load_order load_order;
01015 int res = 0;
01016 struct ast_flags config_flags = { 0 };
01017 int modulecount = 0;
01018
01019 #ifdef LOADABLE_MODULES
01020 struct dirent *dirent;
01021 DIR *dir;
01022 #endif
01023
01024
01025 embedding = 0;
01026
01027 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
01028
01029 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
01030
01031 AST_LIST_LOCK(&module_list);
01032
01033 if (embedded_module_list.first) {
01034 module_list.first = embedded_module_list.first;
01035 module_list.last = embedded_module_list.last;
01036 embedded_module_list.first = NULL;
01037 }
01038
01039 cfg = ast_config_load2(AST_MODULE_CONFIG, "" , config_flags);
01040 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01041 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
01042 goto done;
01043 }
01044
01045
01046 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01047 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
01048 add_to_load_order(v->value, &load_order, 0);
01049 }
01050 if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
01051
01052 add_to_load_order(v->value, &load_order, 1);
01053 ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
01054 }
01055
01056 }
01057
01058
01059 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
01060
01061 AST_LIST_TRAVERSE(&module_list, mod, entry) {
01062
01063 if (mod->lib)
01064 continue;
01065
01066 if (mod->flags.running)
01067 continue;
01068
01069 order = add_to_load_order(mod->resource, &load_order, 0);
01070 }
01071
01072 #ifdef LOADABLE_MODULES
01073
01074
01075 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
01076 while ((dirent = readdir(dir))) {
01077 int ld = strlen(dirent->d_name);
01078
01079
01080
01081 if (ld < 4)
01082 continue;
01083
01084 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
01085 continue;
01086
01087
01088
01089 if (find_resource(dirent->d_name, 0))
01090 continue;
01091
01092 add_to_load_order(dirent->d_name, &load_order, 0);
01093 }
01094
01095 closedir(dir);
01096 } else {
01097 if (!ast_opt_quiet)
01098 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01099 ast_config_AST_MODULE_DIR);
01100 }
01101 #endif
01102 }
01103
01104
01105
01106 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01107 if (strcasecmp(v->name, "noload"))
01108 continue;
01109
01110 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01111 if (!resource_name_match(order->resource, v->value)) {
01112 AST_LIST_REMOVE_CURRENT(entry);
01113 ast_free(order->resource);
01114 ast_free(order);
01115 }
01116 }
01117 AST_LIST_TRAVERSE_SAFE_END;
01118 }
01119
01120
01121
01122 ast_config_destroy(cfg);
01123
01124 load_count = 0;
01125 AST_LIST_TRAVERSE(&load_order, order, entry)
01126 load_count++;
01127
01128 if (load_count)
01129 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
01130
01131
01132 if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01133 goto done;
01134 }
01135
01136
01137 if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01138 goto done;
01139 }
01140
01141 done:
01142 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01143 ast_free(order->resource);
01144 ast_free(order);
01145 }
01146
01147 AST_LIST_UNLOCK(&module_list);
01148
01149
01150
01151
01152 manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
01153
01154 return res;
01155 }
01156
01157 void ast_update_use_count(void)
01158 {
01159
01160
01161 struct loadupdate *m;
01162
01163 AST_LIST_LOCK(&updaters);
01164 AST_LIST_TRAVERSE(&updaters, m, entry)
01165 m->updater();
01166 AST_LIST_UNLOCK(&updaters);
01167 }
01168
01169 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
01170 const char *like)
01171 {
01172 struct ast_module *cur;
01173 int unlock = -1;
01174 int total_mod_loaded = 0;
01175
01176 if (AST_LIST_TRYLOCK(&module_list))
01177 unlock = 0;
01178
01179 AST_LIST_TRAVERSE(&module_list, cur, entry) {
01180 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
01181 }
01182
01183 if (unlock)
01184 AST_LIST_UNLOCK(&module_list);
01185
01186 return total_mod_loaded;
01187 }
01188
01189
01190 int ast_module_check(const char *name)
01191 {
01192 struct ast_module *cur;
01193
01194 if (ast_strlen_zero(name))
01195 return 0;
01196
01197 cur = find_resource(name, 1);
01198
01199 return (cur != NULL);
01200 }
01201
01202
01203 int ast_loader_register(int (*v)(void))
01204 {
01205 struct loadupdate *tmp;
01206
01207 if (!(tmp = ast_malloc(sizeof(*tmp))))
01208 return -1;
01209
01210 tmp->updater = v;
01211 AST_LIST_LOCK(&updaters);
01212 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01213 AST_LIST_UNLOCK(&updaters);
01214
01215 return 0;
01216 }
01217
01218 int ast_loader_unregister(int (*v)(void))
01219 {
01220 struct loadupdate *cur;
01221
01222 AST_LIST_LOCK(&updaters);
01223 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01224 if (cur->updater == v) {
01225 AST_LIST_REMOVE_CURRENT(entry);
01226 break;
01227 }
01228 }
01229 AST_LIST_TRAVERSE_SAFE_END;
01230 AST_LIST_UNLOCK(&updaters);
01231
01232 return cur ? 0 : -1;
01233 }
01234
01235 struct ast_module *ast_module_ref(struct ast_module *mod)
01236 {
01237 if (!mod) {
01238 return NULL;
01239 }
01240
01241 ast_atomic_fetchadd_int(&mod->usecount, +1);
01242 ast_update_use_count();
01243
01244 return mod;
01245 }
01246
01247 void ast_module_unref(struct ast_module *mod)
01248 {
01249 if (!mod) {
01250 return;
01251 }
01252
01253 ast_atomic_fetchadd_int(&mod->usecount, -1);
01254 ast_update_use_count();
01255 }