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(
const char *name)
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
if (!name || !strcasecmp(name,
"astconfig"))
00161
read_ast_cust_config();
00162
if (!name || !strcasecmp(name,
"manager"))
00163
reload_manager();
00164
if (!name || !strcasecmp(name,
"enum"))
00165
ast_enum_reload();
00166
if (!name || !strcasecmp(name,
"rtp"))
00167
ast_rtp_reload();
00168 time(&
ast_lastreloadtime);
00169
00170
ast_mutex_lock(&modlock);
00171 m = module_list;
00172
while(m) {
00173
if (!name || !strcasecmp(name, m->resource)) {
00174
if (m->reload) {
00175
if (
option_verbose > 2)
00176
ast_verbose(
VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
00177 m->reload();
00178 }
00179 }
00180 m = m->next;
00181 }
00182
ast_mutex_unlock(&modlock);
00183
ast_mutex_unlock(&reloadlock);
00184 }
00185
00186 int ast_load_resource(
char *resource_name)
00187 {
00188
static char fn[256];
00189
int errors=0;
00190
int res;
00191
struct module *m;
00192
int flags=
RTLD_NOW;
00193
#ifdef RTLD_GLOBAL
00194
char *
val;
00195
#endif
00196
char *
key;
00197
int o;
00198
struct ast_config *cfg;
00199
char tmp[80];
00200
00201 o =
option_verbose;
00202
if (strncasecmp(resource_name,
"res_", 4)) {
00203
option_verbose = 0;
00204 cfg =
ast_load(
AST_MODULE_CONFIG);
00205
option_verbose = o;
00206
if (cfg) {
00207
#ifdef RTLD_GLOBAL
00208
if ((val =
ast_variable_retrieve(cfg,
"global", resource_name))
00209 &&
ast_true(val))
00210 flags |=
RTLD_GLOBAL;
00211
#endif
00212
ast_destroy(cfg);
00213 }
00214 }
else {
00215
00216
#ifdef RTLD_GLOBAL
00217
flags = (
RTLD_GLOBAL |
RTLD_LAZY);
00218
#else
00219
flags =
RTLD_LAZY;
00220
#endif
00221
}
00222
00223
if (
ast_mutex_lock(&modlock))
00224
ast_log(
LOG_WARNING,
"Failed to lock\n");
00225 m = module_list;
00226
while(m) {
00227
if (!strcasecmp(m->resource, resource_name)) {
00228
ast_log(
LOG_WARNING,
"Module '%s' already exists\n", resource_name);
00229
ast_mutex_unlock(&modlock);
00230
return -1;
00231 }
00232 m = m->next;
00233 }
00234 m =
malloc(
sizeof(
struct module));
00235
if (!m) {
00236
ast_log(
LOG_WARNING,
"Out of memory\n");
00237
ast_mutex_unlock(&modlock);
00238
return -1;
00239 }
00240 strncpy(m->resource, resource_name,
sizeof(m->resource)-1);
00241
if (resource_name[0] ==
'/') {
00242 strncpy(fn, resource_name,
sizeof(fn)-1);
00243 }
else {
00244 snprintf(fn,
sizeof(fn),
"%s/%s", (
char *)
ast_config_AST_MODULE_DIR, resource_name);
00245 }
00246 m->lib =
dlopen(fn, flags);
00247
if (!m->lib) {
00248
ast_log(
LOG_WARNING,
"%s\n",
dlerror());
00249
free(m);
00250
ast_mutex_unlock(&modlock);
00251
return -1;
00252 }
00253 m->load_module =
dlsym(m->lib,
"load_module");
00254
if (m->load_module == NULL)
00255 m->load_module =
dlsym(m->lib,
"_load_module");
00256
if (!m->load_module) {
00257
ast_log(
LOG_WARNING,
"No load_module in module %s\n", fn);
00258 errors++;
00259 }
00260 m->unload_module =
dlsym(m->lib,
"unload_module");
00261
if (m->unload_module == NULL)
00262 m->unload_module =
dlsym(m->lib,
"_unload_module");
00263
if (!m->unload_module) {
00264
ast_log(
LOG_WARNING,
"No unload_module in module %s\n", fn);
00265 errors++;
00266 }
00267 m->usecount =
dlsym(m->lib,
"usecount");
00268
if (m->usecount == NULL)
00269 m->usecount =
dlsym(m->lib,
"_usecount");
00270
if (!m->usecount) {
00271
ast_log(
LOG_WARNING,
"No usecount in module %s\n", fn);
00272 errors++;
00273 }
00274 m->description =
dlsym(m->lib,
"description");
00275
if (m->description == NULL)
00276 m->description =
dlsym(m->lib,
"_description");
00277
if (!m->description) {
00278
ast_log(
LOG_WARNING,
"No description in module %s\n", fn);
00279 errors++;
00280 }
00281 m->key =
dlsym(m->lib,
"key");
00282
if (m->key == NULL)
00283 m->key =
dlsym(m->lib,
"_key");
00284
if (!m->key) {
00285
ast_log(
LOG_WARNING,
"No key routine in module %s\n", fn);
00286 errors++;
00287 }
00288 m->reload =
dlsym(m->lib,
"reload");
00289
if (m->reload == NULL)
00290 m->reload =
dlsym(m->lib,
"_reload");
00291
if (!m->key || !(
key = m->key())) {
00292
ast_log(
LOG_WARNING,
"Key routine returned NULL in module %s\n", fn);
00293
key = NULL;
00294 errors++;
00295 }
00296
if (
key && verify_key(
key)) {
00297
ast_log(
LOG_WARNING,
"Unexpected key returned by module %s\n", fn);
00298 errors++;
00299 }
00300
if (errors) {
00301
ast_log(
LOG_WARNING,
"%d error(s) loading module %s, aborted\n", errors, fn);
00302
dlclose(m->lib);
00303
free(m);
00304
ast_mutex_unlock(&modlock);
00305
return -1;
00306 }
00307
if (!
fully_booted) {
00308
if (
option_verbose)
00309
ast_verbose(
" => (%s)\n",
term_color(tmp, m->description(),
COLOR_BROWN,
COLOR_BLACK,
sizeof(tmp)));
00310
if (
option_console && !
option_verbose)
00311
ast_verbose(
".");
00312 }
else {
00313
if (
option_verbose)
00314
ast_verbose(
VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
00315 }
00316
00317
00318
00319 m->next = NULL;
00320
if (module_list == NULL) {
00321
00322 module_list = m;
00323 }
00324
else {
00325
struct module *i;
00326
00327
for (i = module_list; i->
next; i = i->
next)
00328 ;
00329 i->
next = m;
00330 }
00331
00332
ast_mutex_unlock(&modlock);
00333
if ((res = m->load_module())) {
00334
ast_log(
LOG_WARNING,
"%s: load_module failed, returning %d\n", m->resource, res);
00335
ast_unload_resource(resource_name, 0);
00336
return -1;
00337 }
00338
ast_update_use_count();
00339
return 0;
00340 }
00341
00342
static int ast_resource_exists(
char *resource)
00343 {
00344
struct module *m;
00345
if (
ast_mutex_lock(&modlock))
00346
ast_log(LOG_WARNING,
"Failed to lock\n");
00347 m = module_list;
00348
while(m) {
00349
if (!strcasecmp(resource, m->resource))
00350
break;
00351 m = m->
next;
00352 }
00353
ast_mutex_unlock(&modlock);
00354
if (m)
00355
return -1;
00356
else
00357
return 0;
00358 }
00359
00360 int load_modules()
00361 {
00362
struct ast_config *cfg;
00363
struct ast_variable *v;
00364
char tmp[80];
00365
if (
option_verbose)
00366
ast_verbose(
"Asterisk Dynamic Loader Starting:\n");
00367 cfg =
ast_load(
AST_MODULE_CONFIG);
00368
if (cfg) {
00369
00370 v =
ast_variable_browse(cfg,
"modules");
00371
while(v) {
00372
if (!strcasecmp(v->name,
"load")) {
00373
if (
option_debug && !
option_verbose)
00374
ast_log(
LOG_DEBUG,
"Loading module %s\n", v->value);
00375
if (
option_verbose) {
00376
ast_verbose(
VERBOSE_PREFIX_1 "[%s]",
term_color(tmp, v->value,
COLOR_BRWHITE, 0,
sizeof(tmp)));
00377 fflush(stdout);
00378 }
00379
if (
ast_load_resource(v->value)) {
00380
ast_log(
LOG_WARNING,
"Loading module %s failed!\n", v->value);
00381
if (cfg)
00382
ast_destroy(cfg);
00383
return -1;
00384 }
00385 }
00386 v=v->next;
00387 }
00388 }
00389
if (!cfg ||
ast_true(
ast_variable_retrieve(cfg,
"modules",
"autoload"))) {
00390
00391 DIR *mods;
00392
struct dirent *d;
00393
int x;
00394
00395
for (x=0;x<2;x++) {
00396 mods = opendir((
char *)
ast_config_AST_MODULE_DIR);
00397
if (mods) {
00398
while((d = readdir(mods))) {
00399
00400
if ((strlen(d->d_name) > 3) && (x || !strncasecmp(d->d_name,
"res_", 4)) &&
00401 !strcasecmp(d->d_name + strlen(d->d_name) - 3,
".so") &&
00402 !ast_resource_exists(d->d_name)) {
00403
00404
00405
if (cfg) {
00406 v =
ast_variable_browse(cfg,
"modules");
00407
while(v) {
00408
if (!strcasecmp(v->name,
"noload") &&
00409 !strcasecmp(v->value, d->d_name))
00410
break;
00411 v = v->next;
00412 }
00413
if (v) {
00414
if (
option_verbose) {
00415
ast_verbose(
VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name);
00416 fflush(stdout);
00417 }
00418
continue;
00419 }
00420
00421 }
00422
if (
option_debug && !
option_verbose)
00423
ast_log(
LOG_DEBUG,
"Loading module %s\n", d->d_name);
00424
if (
option_verbose) {
00425
ast_verbose(
VERBOSE_PREFIX_1 "[%s]",
term_color(tmp, d->d_name,
COLOR_BRWHITE, 0,
sizeof(tmp)));
00426 fflush(stdout);
00427 }
00428
if (
ast_load_resource(d->d_name)) {
00429
ast_log(
LOG_WARNING,
"Loading module %s failed!\n", d->d_name);
00430
if (cfg)
00431
ast_destroy(cfg);
00432
return -1;
00433 }
00434 }
00435 }
00436 closedir(mods);
00437 }
else {
00438
if (!
option_quiet)
00439
ast_log(
LOG_WARNING,
"Unable to open modules directory %s.\n", (
char *)
ast_config_AST_MODULE_DIR);
00440 }
00441 }
00442 }
00443
ast_destroy(cfg);
00444
return 0;
00445 }
00446
00447 void ast_update_use_count(
void)
00448 {
00449
00450
00451
struct loadupdate *m;
00452
if (
ast_mutex_lock(&modlock))
00453
ast_log(
LOG_WARNING,
"Failed to lock\n");
00454 m = updaters;
00455
while(m) {
00456 m->updater();
00457 m = m->next;
00458 }
00459
ast_mutex_unlock(&modlock);
00460
00461 }
00462
00463 int ast_update_module_list(
int (*modentry)(
char *
module,
char *description,
int usecnt))
00464 {
00465
struct module *m;
00466
int unlock = -1;
00467
if (
ast_mutex_trylock(&modlock))
00468 unlock = 0;
00469 m = module_list;
00470
while(m) {
00471 modentry(m->resource, m->description(), m->usecount());
00472 m = m->
next;
00473 }
00474
if (unlock)
00475
ast_mutex_unlock(&modlock);
00476
return 0;
00477 }
00478
00479 int ast_loader_register(
int (*v)(
void))
00480 {
00481
struct loadupdate *tmp;
00482
00483
if ((tmp =
malloc(
sizeof (
struct loadupdate)))) {
00484 tmp->updater = v;
00485
if (
ast_mutex_lock(&modlock))
00486
ast_log(
LOG_WARNING,
"Failed to lock\n");
00487 tmp->next = updaters;
00488 updaters = tmp;
00489
ast_mutex_unlock(&modlock);
00490
return 0;
00491 }
00492
return -1;
00493 }
00494
00495 int ast_loader_unregister(
int (*v)(
void))
00496 {
00497
int res = -1;
00498
struct loadupdate *tmp, *tmpl=NULL;
00499
if (
ast_mutex_lock(&modlock))
00500
ast_log(
LOG_WARNING,
"Failed to lock\n");
00501 tmp = updaters;
00502
while(tmp) {
00503
if (tmp->updater == v) {
00504
if (tmpl)
00505 tmpl->next = tmp->next;
00506
else
00507 updaters = tmp->next;
00508
break;
00509 }
00510 tmpl = tmp;
00511 tmp = tmp->next;
00512 }
00513
if (tmp)
00514 res = 0;
00515
ast_mutex_unlock(&modlock);
00516
return res;
00517 }