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