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