00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <stdio.h>
00015
#include <dirent.h>
00016
#include <unistd.h>
00017
#include <stdlib.h>
00018
#include <string.h>
00019
#include <asterisk/module.h>
00020
#include <asterisk/options.h>
00021
#include <asterisk/config.h>
00022
#include <asterisk/config_pvt.h>
00023
#include <asterisk/logger.h>
00024
#include <asterisk/channel.h>
00025
#include <asterisk/term.h>
00026
#include <asterisk/manager.h>
00027
#include <asterisk/enum.h>
00028
#include <asterisk/rtp.h>
00029
#include <asterisk/lock.h>
00030
#ifdef __APPLE__
00031
#include <asterisk/dlfcn-compat.h>
00032
#else
00033
#include <dlfcn.h>
00034
#endif
00035
#include <asterisk/md5.h>
00036
#include "asterisk.h"
00037
#include "astconf.h"
00038
00039
#ifndef RTLD_NOW
00040 #define RTLD_NOW 0
00041
#endif
00042
00043
static char expected_key[] =
00044 { 0x8e, 0x93, 0x22, 0x83, 0xf5, 0xc3, 0xc0, 0x75,
00045 0xff, 0x8b, 0xa9, 0xbe, 0x7c, 0x43, 0x74, 0x63 };
00046
00047 struct module {
00048 int (*
load_module)(
void);
00049 int (*
unload_module)(
void);
00050 int (*
usecount)(
void);
00051
char *(*description)(
void);
00052
char *(*key)(
void);
00053 int (*
reload)(
void);
00054 void *
lib;
00055 char resource[256];
00056 struct module *
next;
00057 };
00058
00059
static int printdigest(
unsigned char *d)
00060 {
00061
int x;
00062
char buf[256];
00063
char buf2[16];
00064 snprintf(buf,
sizeof(buf),
"Unexpected signature:");
00065
for (x=0;x<16;x++) {
00066 snprintf(buf2,
sizeof(buf2),
" %02x", *(d++));
00067 strcat(buf, buf2);
00068 }
00069 strcat(buf,
"\n");
00070
ast_log(LOG_DEBUG, buf);
00071
return 0;
00072 }
00073
00074
static int key_matches(
char *key1,
char *key2)
00075 {
00076
int match = 1;
00077
int x;
00078
for (x=0;x<16;x++) {
00079 match &= (key1[x] == key2[x]);
00080 }
00081
return match;
00082 }
00083
00084
static int verify_key(
char *key)
00085 {
00086
struct MD5Context c;
00087
char digest[16];
00088
MD5Init(&c);
00089
MD5Update(&c, key, strlen(key));
00090
MD5Final(digest, &c);
00091
if (key_matches(expected_key, digest))
00092
return 0;
00093 printdigest(digest);
00094
return -1;
00095 }
00096
00097
static struct loadupdate {
00098 int (*updater)(
void);
00099
struct loadupdate *next;
00100 } *updaters = NULL;
00101
00102
AST_MUTEX_DEFINE_STATIC(modlock);
00103
AST_MUTEX_DEFINE_STATIC(reloadlock);
00104
00105
static struct module *module_list=NULL;
00106
00107 int ast_unload_resource(
char *resource_name,
int force)
00108 {
00109
struct module *m, *ml = NULL;
00110
int res = -1;
00111
if (
ast_mutex_lock(&modlock))
00112
ast_log(
LOG_WARNING,
"Failed to lock\n");
00113 m = module_list;
00114
while(m) {
00115
if (!strcasecmp(m->resource, resource_name)) {
00116
if ((res = m->usecount()) > 0) {
00117
if (force)
00118
ast_log(
LOG_WARNING,
"Warning: Forcing removal of module %s with use count %d\n", resource_name, res);
00119
else {
00120
ast_log(
LOG_WARNING,
"Soft unload failed, '%s' has use count %d\n", resource_name, res);
00121
ast_mutex_unlock(&modlock);
00122
return -1;
00123 }
00124 }
00125 res = m->unload_module();
00126
if (res) {
00127
ast_log(
LOG_WARNING,
"Firm unload failed for %s\n", resource_name);
00128
if (force <=
AST_FORCE_FIRM) {
00129
ast_mutex_unlock(&modlock);
00130
return -1;
00131 }
else
00132
ast_log(
LOG_WARNING,
"** Dangerous **: Unloading resource anyway, at user request\n");
00133 }
00134
if (ml)
00135 ml->next = m->next;
00136
else
00137 module_list = m->
next;
00138
dlclose(m->lib);
00139
free(m);
00140
break;
00141 }
00142 ml = m;
00143 m = m->next;
00144 }
00145
ast_mutex_unlock(&modlock);
00146
ast_update_use_count();
00147
return res;
00148 }
00149
00150 void ast_module_reload(
void)
00151 {
00152
struct module *m;
00153
00154
00155
00156
if (
ast_mutex_trylock(&reloadlock)) {
00157
ast_verbose(
"The previous reload command didn't finish yet\n");
00158
return;
00159 }
00160
read_ast_cust_config();
00161
reload_manager();
00162
ast_enum_reload();
00163
ast_rtp_reload();
00164 time(&
ast_lastreloadtime);
00165
00166
ast_mutex_lock(&modlock);
00167 m = module_list;
00168
while(m) {
00169
if (m->reload) {
00170
if (
option_verbose > 2)
00171
ast_verbose(
VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
00172 m->reload();
00173 }
00174 m = m->next;
00175 }
00176
ast_mutex_unlock(&modlock);
00177
ast_mutex_unlock(&reloadlock);
00178 }
00179
00180 int ast_load_resource(
char *resource_name)
00181 {
00182
static char fn[256];
00183
int errors=0;
00184
int res;
00185
struct module *m;
00186
int flags=
RTLD_NOW;
00187
#ifdef RTLD_GLOBAL
00188
char *
val;
00189
#endif
00190
char *
key;
00191
int o;
00192
struct ast_config *cfg;
00193
char tmp[80];
00194
00195 o =
option_verbose;
00196
if (strncasecmp(resource_name,
"res_", 4)) {
00197
option_verbose = 0;
00198 cfg =
ast_load(
AST_MODULE_CONFIG);
00199
option_verbose = o;
00200
if (cfg) {
00201
#ifdef RTLD_GLOBAL
00202
if ((val =
ast_variable_retrieve(cfg,
"global", resource_name))
00203 &&
ast_true(val))
00204 flags |=
RTLD_GLOBAL;
00205
#endif
00206
ast_destroy(cfg);
00207 }
00208 }
else {
00209
00210
#ifdef RTLD_GLOBAL
00211
flags = (
RTLD_GLOBAL |
RTLD_LAZY);
00212
#else
00213
flags =
RTLD_LAZY;
00214
#endif
00215
}
00216
00217
if (
ast_mutex_lock(&modlock))
00218
ast_log(
LOG_WARNING,
"Failed to lock\n");
00219 m = module_list;
00220
while(m) {
00221
if (!strcasecmp(m->resource, resource_name)) {
00222
ast_log(
LOG_WARNING,
"Module '%s' already exists\n", resource_name);
00223
ast_mutex_unlock(&modlock);
00224
return -1;
00225 }
00226 m = m->next;
00227 }
00228 m =
malloc(
sizeof(
struct module));
00229
if (!m) {
00230
ast_log(
LOG_WARNING,
"Out of memory\n");
00231
ast_mutex_unlock(&modlock);
00232
return -1;
00233 }
00234 strncpy(m->resource, resource_name,
sizeof(m->resource)-1);
00235
if (resource_name[0] ==
'/') {
00236 strncpy(fn, resource_name,
sizeof(fn)-1);
00237 }
else {
00238 snprintf(fn,
sizeof(fn),
"%s/%s", (
char *)
ast_config_AST_MODULE_DIR, resource_name);
00239 }
00240 m->lib =
dlopen(fn, flags);
00241
if (!m->lib) {
00242
ast_log(
LOG_WARNING,
"%s\n",
dlerror());
00243
free(m);
00244
ast_mutex_unlock(&modlock);
00245
return -1;
00246 }
00247 m->load_module =
dlsym(m->lib,
"load_module");
00248
if (m->load_module == NULL)
00249 m->load_module =
dlsym(m->lib,
"_load_module");
00250
if (!m->load_module) {
00251
ast_log(
LOG_WARNING,
"No load_module in module %s\n", fn);
00252 errors++;
00253 }
00254 m->unload_module =
dlsym(m->lib,
"unload_module");
00255
if (m->unload_module == NULL)
00256 m->unload_module =
dlsym(m->lib,
"_unload_module");
00257
if (!m->unload_module) {
00258
ast_log(
LOG_WARNING,
"No unload_module in module %s\n", fn);
00259 errors++;
00260 }
00261 m->usecount =
dlsym(m->lib,
"usecount");
00262
if (m->usecount == NULL)
00263 m->usecount =
dlsym(m->lib,
"_usecount");
00264
if (!m->usecount) {
00265
ast_log(
LOG_WARNING,
"No usecount in module %s\n", fn);
00266 errors++;
00267 }
00268 m->description =
dlsym(m->lib,
"description");
00269
if (m->description == NULL)
00270 m->description =
dlsym(m->lib,
"_description");
00271
if (!m->description) {
00272
ast_log(
LOG_WARNING,
"No description in module %s\n", fn);
00273 errors++;
00274 }
00275 m->key =
dlsym(m->lib,
"key");
00276
if (m->key == NULL)
00277 m->key =
dlsym(m->lib,
"_key");
00278
if (!m->key) {
00279
ast_log(
LOG_WARNING,
"No key routine in module %s\n", fn);
00280 errors++;
00281 }
00282 m->reload =
dlsym(m->lib,
"reload");
00283
if (m->reload == NULL)
00284 m->reload =
dlsym(m->lib,
"_reload");
00285
if (!m->key || !(
key = m->key())) {
00286
ast_log(
LOG_WARNING,
"Key routine returned NULL in module %s\n", fn);
00287
key = NULL;
00288 errors++;
00289 }
00290
if (
key && verify_key(
key)) {
00291
ast_log(
LOG_WARNING,
"Unexpected key returned by module %s\n", fn);
00292 errors++;
00293 }
00294
if (errors) {
00295
ast_log(
LOG_WARNING,
"%d error(s) loading module %s, aborted\n", errors, fn);
00296
dlclose(m->lib);
00297
free(m);
00298
ast_mutex_unlock(&modlock);
00299
return -1;
00300 }
00301
if (!
fully_booted) {
00302
if (
option_verbose)
00303
ast_verbose(
" => (%s)\n",
term_color(tmp, m->description(),
COLOR_BROWN,
COLOR_BLACK,
sizeof(tmp)));
00304
if (
option_console && !
option_verbose)
00305
ast_verbose(
".");
00306 }
else {
00307
if (
option_verbose)
00308
ast_verbose(
VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
00309 }
00310
00311
00312
00313 m->next = NULL;
00314
if (module_list == NULL) {
00315
00316 module_list = m;
00317 }
00318
else {
00319
struct module *i;
00320
00321
for (i = module_list; i->
next; i = i->
next)
00322 ;
00323 i->
next = m;
00324 }
00325
00326
ast_mutex_unlock(&modlock);
00327
if ((res = m->load_module())) {
00328
ast_log(
LOG_WARNING,
"%s: load_module failed, returning %d\n", m->resource, res);
00329
ast_unload_resource(resource_name, 0);
00330
return -1;
00331 }
00332
ast_update_use_count();
00333
return 0;
00334 }
00335
00336
static int ast_resource_exists(
char *resource)
00337 {
00338
struct module *m;
00339
if (
ast_mutex_lock(&modlock))
00340
ast_log(LOG_WARNING,
"Failed to lock\n");
00341 m = module_list;
00342
while(m) {
00343
if (!strcasecmp(resource, m->resource))
00344
break;
00345 m = m->
next;
00346 }
00347
ast_mutex_unlock(&modlock);
00348
if (m)
00349
return -1;
00350
else
00351
return 0;
00352 }
00353
00354 int load_modules()
00355 {
00356
struct ast_config *cfg;
00357
struct ast_variable *v;
00358
char tmp[80];
00359
if (
option_verbose)
00360
ast_verbose(
"Asterisk Dynamic Loader Starting:\n");
00361 cfg =
ast_load(
AST_MODULE_CONFIG);
00362
if (cfg) {
00363
00364 v =
ast_variable_browse(cfg,
"modules");
00365
while(v) {
00366
if (!strcasecmp(v->name,
"load")) {
00367
if (
option_debug && !
option_verbose)
00368
ast_log(
LOG_DEBUG,
"Loading module %s\n", v->value);
00369
if (
option_verbose) {
00370
ast_verbose(
VERBOSE_PREFIX_1 "[%s]",
term_color(tmp, v->value,
COLOR_BRWHITE, 0,
sizeof(tmp)));
00371 fflush(stdout);
00372 }
00373
if (
ast_load_resource(v->value)) {
00374
ast_log(
LOG_WARNING,
"Loading module %s failed!\n", v->value);
00375
if (cfg)
00376
ast_destroy(cfg);
00377
return -1;
00378 }
00379 }
00380 v=v->next;
00381 }
00382 }
00383
if (!cfg ||
ast_true(
ast_variable_retrieve(cfg,
"modules",
"autoload"))) {
00384
00385 DIR *mods;
00386
struct dirent *d;
00387
int x;
00388
00389
for (x=0;x<2;x++) {
00390 mods = opendir((
char *)
ast_config_AST_MODULE_DIR);
00391
if (mods) {
00392
while((d = readdir(mods))) {
00393
00394
if ((strlen(d->d_name) > 3) && (x || !strncasecmp(d->d_name,
"res_", 4)) &&
00395 !strcasecmp(d->d_name + strlen(d->d_name) - 3,
".so") &&
00396 !ast_resource_exists(d->d_name)) {
00397
00398
00399
if (cfg) {
00400 v =
ast_variable_browse(cfg,
"modules");
00401
while(v) {
00402
if (!strcasecmp(v->name,
"noload") &&
00403 !strcasecmp(v->value, d->d_name))
00404
break;
00405 v = v->next;
00406 }
00407
if (v) {
00408
if (
option_verbose) {
00409
ast_verbose(
VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name);
00410 fflush(stdout);
00411 }
00412
continue;
00413 }
00414
00415 }
00416
if (
option_debug && !
option_verbose)
00417
ast_log(
LOG_DEBUG,
"Loading module %s\n", d->d_name);
00418
if (
option_verbose) {
00419
ast_verbose(
VERBOSE_PREFIX_1 "[%s]",
term_color(tmp, d->d_name,
COLOR_BRWHITE, 0,
sizeof(tmp)));
00420 fflush(stdout);
00421 }
00422
if (
ast_load_resource(d->d_name)) {
00423
ast_log(
LOG_WARNING,
"Loading module %s failed!\n", d->d_name);
00424
if (cfg)
00425
ast_destroy(cfg);
00426
return -1;
00427 }
00428 }
00429 }
00430 closedir(mods);
00431 }
else {
00432
if (!
option_quiet)
00433
ast_log(
LOG_WARNING,
"Unable to open modules directory %s.\n", (
char *)
ast_config_AST_MODULE_DIR);
00434 }
00435 }
00436 }
00437
ast_destroy(cfg);
00438
return 0;
00439 }
00440
00441 void ast_update_use_count(
void)
00442 {
00443
00444
00445
struct loadupdate *m;
00446
if (
ast_mutex_lock(&modlock))
00447
ast_log(
LOG_WARNING,
"Failed to lock\n");
00448 m = updaters;
00449
while(m) {
00450 m->updater();
00451 m = m->next;
00452 }
00453
ast_mutex_unlock(&modlock);
00454
00455 }
00456
00457 int ast_update_module_list(
int (*modentry)(
char *
module,
char *description,
int usecnt))
00458 {
00459
struct module *m;
00460
int unlock = -1;
00461
if (
ast_mutex_trylock(&modlock))
00462 unlock = 0;
00463 m = module_list;
00464
while(m) {
00465 modentry(m->resource, m->description(), m->usecount());
00466 m = m->
next;
00467 }
00468
if (unlock)
00469
ast_mutex_unlock(&modlock);
00470
return 0;
00471 }
00472
00473 int ast_loader_register(
int (*v)(
void))
00474 {
00475
struct loadupdate *tmp;
00476
00477
if ((tmp =
malloc(
sizeof (
struct loadupdate)))) {
00478 tmp->updater = v;
00479
if (
ast_mutex_lock(&modlock))
00480
ast_log(
LOG_WARNING,
"Failed to lock\n");
00481 tmp->next = updaters;
00482 updaters = tmp;
00483
ast_mutex_unlock(&modlock);
00484
return 0;
00485 }
00486
return -1;
00487 }
00488
00489 int ast_loader_unregister(
int (*v)(
void))
00490 {
00491
int res = -1;
00492
struct loadupdate *tmp, *tmpl=NULL;
00493
if (
ast_mutex_lock(&modlock))
00494
ast_log(
LOG_WARNING,
"Failed to lock\n");
00495 tmp = updaters;
00496
while(tmp) {
00497
if (tmp->updater == v) {
00498
if (tmpl)
00499 tmpl->next = tmp->next;
00500
else
00501 updaters = tmp->next;
00502
break;
00503 }
00504 tmpl = tmp;
00505 tmp = tmp->next;
00506 }
00507
if (tmp)
00508 res = 0;
00509
ast_mutex_unlock(&modlock);
00510
return res;
00511 }