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