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