loader: Create ast_module_running_ref.
This function returns NULL if the module in question is not running. I did not change ast_module_ref as most callers do not check the result and they always call ast_module_unref. Make use of this function when running registered items from: * app_stack API's * bridge technologies * CLI commands * File formats * Manager Actions * RTP engines * Sorcery Wizards * Timing Interfaces * Translators * AGI Commands * Fax Technologies ASTERISK-20346 #close Change-Id: Ia16fd28e188b2fc0b9d18b8a5d9cacc31df73fcc
This commit is contained in:
parent
7f4facc5e4
commit
55f1d69c43
|
@ -357,6 +357,7 @@ void __ast_module_user_hangup_all(struct ast_module *);
|
|||
#define ast_module_user_hangup_all() __ast_module_user_hangup_all(AST_MODULE_SELF)
|
||||
|
||||
struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func);
|
||||
struct ast_module *__ast_module_running_ref(struct ast_module *mod, const char *file, int line, const char *func);
|
||||
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func);
|
||||
void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func);
|
||||
|
||||
|
@ -369,6 +370,20 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons
|
|||
* from being unloaded.
|
||||
*/
|
||||
#define ast_module_ref(mod) __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
/*!
|
||||
* \brief Hold a reference to the module if it is running.
|
||||
* \param mod Module to reference
|
||||
* \retval mod if running
|
||||
* \retval NULL if not running
|
||||
*
|
||||
* The returned pointer should be released with ast_module_unref.
|
||||
*
|
||||
* \note A module reference will prevent the module from being unloaded.
|
||||
*/
|
||||
#define ast_module_running_ref(mod) \
|
||||
__ast_module_running_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
/*!
|
||||
* \brief Prevent unload of the module before shutdown
|
||||
* \param mod Module to hold
|
||||
|
|
|
@ -386,6 +386,7 @@ int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *
|
|||
return res;
|
||||
}
|
||||
|
||||
/* BUGBUG this is not thread safe. */
|
||||
static const struct ast_app_stack_funcs *app_stack_callbacks;
|
||||
|
||||
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
|
||||
|
@ -399,16 +400,16 @@ const char *ast_app_expand_sub_args(struct ast_channel *chan, const char *args)
|
|||
const char *new_args;
|
||||
|
||||
funcs = app_stack_callbacks;
|
||||
if (!funcs || !funcs->expand_sub_args) {
|
||||
if (!funcs || !funcs->expand_sub_args || !ast_module_running_ref(funcs->module)) {
|
||||
ast_log(LOG_WARNING,
|
||||
"Cannot expand 'Gosub(%s)' arguments. The app_stack module is not available.\n",
|
||||
args);
|
||||
return NULL;
|
||||
}
|
||||
ast_module_ref(funcs->module);
|
||||
|
||||
new_args = funcs->expand_sub_args(chan, args);
|
||||
ast_module_unref(funcs->module);
|
||||
|
||||
return new_args;
|
||||
}
|
||||
|
||||
|
@ -418,13 +419,12 @@ int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *s
|
|||
int res;
|
||||
|
||||
funcs = app_stack_callbacks;
|
||||
if (!funcs || !funcs->run_sub) {
|
||||
if (!funcs || !funcs->run_sub || !ast_module_running_ref(funcs->module)) {
|
||||
ast_log(LOG_WARNING,
|
||||
"Cannot run 'Gosub(%s)'. The app_stack module is not available.\n",
|
||||
sub_args);
|
||||
return -1;
|
||||
}
|
||||
ast_module_ref(funcs->module);
|
||||
|
||||
if (autoservice_chan) {
|
||||
ast_autoservice_start(autoservice_chan);
|
||||
|
|
|
@ -234,8 +234,21 @@ int __ast_bridge_technology_register(struct ast_bridge_technology *technology, s
|
|||
/* Copy module pointer so reference counting can keep the module from unloading */
|
||||
technology->mod = module;
|
||||
|
||||
/* Insert our new bridge technology into the list and print out a pretty message */
|
||||
AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
|
||||
/* Find the correct position to insert the technology. */
|
||||
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&bridge_technologies, current, entry) {
|
||||
/* Put the highest preference tech's first in the list. */
|
||||
if (technology->preference >= current->preference) {
|
||||
AST_RWLIST_INSERT_BEFORE_CURRENT(technology, entry);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_RWLIST_TRAVERSE_SAFE_END;
|
||||
|
||||
if (!current) {
|
||||
/* Insert our new bridge technology to the end of the list. */
|
||||
AST_RWLIST_INSERT_TAIL(&bridge_technologies, technology, entry);
|
||||
}
|
||||
|
||||
AST_RWLIST_UNLOCK(&bridge_technologies);
|
||||
|
||||
|
@ -517,12 +530,17 @@ static struct ast_bridge_technology *find_best_technology(uint32_t capabilities,
|
|||
current->name);
|
||||
continue;
|
||||
}
|
||||
if (!ast_module_running_ref(current->mod)) {
|
||||
ast_debug(1, "Bridge technology %s is not running, skipping.\n", current->name);
|
||||
continue;
|
||||
}
|
||||
if (best) {
|
||||
ast_module_unref(best->mod);
|
||||
}
|
||||
best = current;
|
||||
}
|
||||
|
||||
if (best) {
|
||||
/* Increment it's module reference count if present so it does not get unloaded while in use */
|
||||
ast_module_ref(best->mod);
|
||||
ast_debug(1, "Chose bridge technology %s\n", best->name);
|
||||
}
|
||||
|
||||
|
|
17
main/cli.c
17
main/cli.c
|
@ -2679,9 +2679,12 @@ static char *__ast_cli_generator(const char *text, const char *word, int state,
|
|||
.n = state - matchnum,
|
||||
.argv = argv,
|
||||
.argc = x};
|
||||
ast_module_ref(e->module);
|
||||
ret = e->handler(e, CLI_GENERATE, &a);
|
||||
ast_module_unref(e->module);
|
||||
|
||||
/* If the command is in a module it must be running. */
|
||||
if (!e->module || ast_module_running_ref(e->module)) {
|
||||
ret = e->handler(e, CLI_GENERATE, &a);
|
||||
ast_module_unref(e->module);
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -2760,9 +2763,11 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
|
|||
*/
|
||||
args[0] = (char *)e;
|
||||
|
||||
ast_module_ref(e->module);
|
||||
retval = e->handler(e, CLI_HANDLER, &a);
|
||||
ast_module_unref(e->module);
|
||||
/* If the command is in a module it must be running. */
|
||||
if (!e->module || ast_module_running_ref(e->module)) {
|
||||
retval = e->handler(e, CLI_HANDLER, &a);
|
||||
ast_module_unref(e->module);
|
||||
}
|
||||
|
||||
if (retval == CLI_SHOWUSAGE) {
|
||||
ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
|
||||
|
|
12
main/file.c
12
main/file.c
|
@ -425,11 +425,17 @@ static void filestream_destructor(void *arg)
|
|||
static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *bfile)
|
||||
{
|
||||
struct ast_filestream *s;
|
||||
|
||||
int l = sizeof(*s) + fmt->buf_size + fmt->desc_size; /* total allocation size */
|
||||
if ( (s = ao2_alloc(l, filestream_destructor)) == NULL)
|
||||
|
||||
if (!ast_module_running_ref(fmt->module)) {
|
||||
return NULL;
|
||||
ast_module_ref(fmt->module);
|
||||
}
|
||||
|
||||
s = ao2_alloc(l, filestream_destructor);
|
||||
if (!s) {
|
||||
ast_module_unref(fmt->module);
|
||||
return NULL;
|
||||
}
|
||||
s->fmt = fmt;
|
||||
s->f = bfile;
|
||||
|
||||
|
|
|
@ -1702,6 +1702,16 @@ struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, in
|
|||
return mod;
|
||||
}
|
||||
|
||||
struct ast_module *__ast_module_running_ref(struct ast_module *mod,
|
||||
const char *file, int line, const char *func)
|
||||
{
|
||||
if (!mod || !mod->flags.running) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return __ast_module_ref(mod, file, line, func);
|
||||
}
|
||||
|
||||
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
|
||||
{
|
||||
if (!mod || mod->flags.keepuntilshutdown) {
|
||||
|
|
|
@ -2923,34 +2923,41 @@ int ast_hook_send_action(struct manager_custom_hook *hook, const char *msg)
|
|||
}
|
||||
|
||||
action = astman_get_header(&m, "Action");
|
||||
if (strcasecmp(action, "login")) {
|
||||
act_found = action_find(action);
|
||||
if (act_found) {
|
||||
/*
|
||||
* we have to simulate a session for this action request
|
||||
* to be able to pass it down for processing
|
||||
* This is necessary to meet the previous design of manager.c
|
||||
*/
|
||||
s.hook = hook;
|
||||
|
||||
ao2_lock(act_found);
|
||||
if (act_found->registered && act_found->func) {
|
||||
if (act_found->module) {
|
||||
ast_module_ref(act_found->module);
|
||||
}
|
||||
ao2_unlock(act_found);
|
||||
ret = act_found->func(&s, &m);
|
||||
ao2_lock(act_found);
|
||||
if (act_found->module) {
|
||||
ast_module_unref(act_found->module);
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
ao2_unlock(act_found);
|
||||
ao2_t_ref(act_found, -1, "done with found action object");
|
||||
do {
|
||||
if (!strcasecmp(action, "login")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
act_found = action_find(action);
|
||||
if (!act_found) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have to simulate a session for this action request
|
||||
* to be able to pass it down for processing
|
||||
* This is necessary to meet the previous design of manager.c
|
||||
*/
|
||||
s.hook = hook;
|
||||
|
||||
ret = -1;
|
||||
ao2_lock(act_found);
|
||||
if (act_found->registered && act_found->func) {
|
||||
struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
|
||||
|
||||
ao2_unlock(act_found);
|
||||
/* If the action is in a module it must be running. */
|
||||
if (!act_found->module || mod_ref) {
|
||||
ret = act_found->func(&s, &m);
|
||||
ast_module_unref(mod_ref);
|
||||
}
|
||||
} else {
|
||||
ao2_unlock(act_found);
|
||||
}
|
||||
ao2_t_ref(act_found, -1, "done with found action object");
|
||||
} while (0);
|
||||
|
||||
ast_free(dup_str);
|
||||
return ret;
|
||||
}
|
||||
|
@ -6442,21 +6449,21 @@ static int process_message(struct mansession *s, const struct message *m)
|
|||
if ((s->session->writeperm & act_found->authority)
|
||||
|| act_found->authority == 0) {
|
||||
/* We have the authority to execute the action. */
|
||||
ret = -1;
|
||||
ao2_lock(act_found);
|
||||
if (act_found->registered && act_found->func) {
|
||||
ast_debug(1, "Running action '%s'\n", act_found->action);
|
||||
if (act_found->module) {
|
||||
ast_module_ref(act_found->module);
|
||||
}
|
||||
struct ast_module *mod_ref = ast_module_running_ref(act_found->module);
|
||||
|
||||
ao2_unlock(act_found);
|
||||
ret = act_found->func(s, m);
|
||||
acted = 1;
|
||||
ao2_lock(act_found);
|
||||
if (act_found->module) {
|
||||
ast_module_unref(act_found->module);
|
||||
if (mod_ref || !act_found->module) {
|
||||
ast_debug(1, "Running action '%s'\n", act_found->action);
|
||||
ret = act_found->func(s, m);
|
||||
acted = 1;
|
||||
ast_module_unref(mod_ref);
|
||||
}
|
||||
} else {
|
||||
ao2_unlock(act_found);
|
||||
}
|
||||
ao2_unlock(act_found);
|
||||
}
|
||||
if (!acted) {
|
||||
/*
|
||||
|
|
|
@ -428,6 +428,7 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
|
|||
struct ast_sockaddr address = {{0,}};
|
||||
struct ast_rtp_instance *instance = NULL;
|
||||
struct ast_rtp_engine *engine = NULL;
|
||||
struct ast_module *mod_ref;
|
||||
|
||||
AST_RWLIST_RDLOCK(&engines);
|
||||
|
||||
|
@ -450,10 +451,15 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name,
|
|||
}
|
||||
|
||||
/* Bump up the reference count before we return so the module can not be unloaded */
|
||||
ast_module_ref(engine->mod);
|
||||
mod_ref = ast_module_running_ref(engine->mod);
|
||||
|
||||
AST_RWLIST_UNLOCK(&engines);
|
||||
|
||||
if (!mod_ref) {
|
||||
/* BUGBUG: improve handling of this situation. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate a new RTP instance */
|
||||
if (!(instance = ao2_alloc(sizeof(*instance), instance_destructor))) {
|
||||
ast_module_unref(engine->mod);
|
||||
|
|
|
@ -835,16 +835,19 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
|||
RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, ao2_alloc(sizeof(*object_wizard), sorcery_object_wizard_destructor), ao2_cleanup);
|
||||
int created = 0;
|
||||
|
||||
if (!wizard) {
|
||||
if (!object_wizard) {
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
if (!wizard || wizard->callbacks.module != ast_module_running_ref(wizard->callbacks.module)) {
|
||||
ast_log(LOG_ERROR, "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
|
||||
name, type);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
} else if (!object_wizard) {
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
if (!object_type) {
|
||||
if (!(object_type = sorcery_object_type_alloc(type, module))) {
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
created = 1;
|
||||
|
@ -861,6 +864,7 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
|||
ast_debug(1, "Wizard %s already applied to object type %s\n",
|
||||
wizard->callbacks.name, object_type->name);
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_DUPLICATE;
|
||||
}
|
||||
}
|
||||
|
@ -871,11 +875,10 @@ enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sor
|
|||
ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
|
||||
name, object_type->name, S_OR(data, ""));
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
ast_module_unref(wizard->callbacks.module);
|
||||
return AST_SORCERY_APPLY_FAIL;
|
||||
}
|
||||
|
||||
ast_module_ref(wizard->callbacks.module);
|
||||
|
||||
object_wizard->wizard = ao2_bump(wizard);
|
||||
object_wizard->caching = caching;
|
||||
|
||||
|
|
|
@ -124,17 +124,22 @@ struct ast_timer *ast_timer_open(void)
|
|||
void *data = NULL;
|
||||
struct timing_holder *h;
|
||||
struct ast_timer *t = NULL;
|
||||
int idx = 1;
|
||||
|
||||
ast_heap_rdlock(timing_interfaces);
|
||||
|
||||
if ((h = ast_heap_peek(timing_interfaces, 1))) {
|
||||
data = h->iface->timer_open();
|
||||
ast_module_ref(h->mod);
|
||||
while ((h = ast_heap_peek(timing_interfaces, idx))) {
|
||||
if (ast_module_running_ref(h->mod)) {
|
||||
data = h->iface->timer_open();
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (!(t = ast_calloc(1, sizeof(*t)))) {
|
||||
h->iface->timer_close(data);
|
||||
ast_module_unref(h->mod);
|
||||
} else {
|
||||
t->data = data;
|
||||
t->holder = h;
|
||||
|
|
|
@ -342,7 +342,10 @@ static struct ast_trans_pvt *newpvt(struct ast_translator *t, struct ast_format
|
|||
*/
|
||||
pvt->explicit_dst = ao2_bump(explicit_dst);
|
||||
|
||||
ast_module_ref(t->module);
|
||||
if (!ast_module_running_ref(t->module)) {
|
||||
ast_free(pvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* call local init routine, if present */
|
||||
if (t->newpvt && t->newpvt(pvt)) {
|
||||
|
|
|
@ -4040,14 +4040,19 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
|
|||
|
||||
parse_args(buf, &argc, argv);
|
||||
c = find_command(argv, 0);
|
||||
if (c && (!dead || (dead && c->dead))) {
|
||||
/* if this command wasn't registered by res_agi, be sure to usecount
|
||||
the module we are using */
|
||||
if (c->mod != ast_module_info->self)
|
||||
ast_module_ref(c->mod);
|
||||
if (!c || !ast_module_running_ref(c->mod)) {
|
||||
ami_res = "Invalid or unknown command";
|
||||
resultcode = 510;
|
||||
|
||||
ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
|
||||
|
||||
publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
|
||||
|
||||
return AGI_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!dead || (dead && c->dead)) {
|
||||
res = c->handler(chan, agi, argc, argv);
|
||||
if (c->mod != ast_module_info->self)
|
||||
ast_module_unref(c->mod);
|
||||
switch (res) {
|
||||
case RESULT_SHOWUSAGE:
|
||||
ami_res = "Usage";
|
||||
|
@ -4094,21 +4099,15 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
|
|||
|
||||
break;
|
||||
}
|
||||
} else if (c) {
|
||||
} else {
|
||||
ami_res = "Command Not Permitted on a dead channel or intercept routine";
|
||||
resultcode = 511;
|
||||
|
||||
ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
|
||||
|
||||
publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
|
||||
} else {
|
||||
ami_res = "Invalid or unknown command";
|
||||
resultcode = 510;
|
||||
|
||||
ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
|
||||
|
||||
publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
|
||||
}
|
||||
ast_module_unref(c->mod);
|
||||
|
||||
return AGI_RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1161,8 +1161,10 @@ static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_detail
|
|||
if ((faxmod->tech->caps & details->caps) != details->caps) {
|
||||
continue;
|
||||
}
|
||||
if (!ast_module_running_ref(faxmod->tech->module)) {
|
||||
continue;
|
||||
}
|
||||
ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description);
|
||||
ast_module_ref(faxmod->tech->module);
|
||||
s->tech = faxmod->tech;
|
||||
break;
|
||||
}
|
||||
|
@ -1279,8 +1281,10 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
|
|||
if ((faxmod->tech->caps & details->caps) != details->caps) {
|
||||
continue;
|
||||
}
|
||||
if (!ast_module_running_ref(faxmod->tech->module)) {
|
||||
continue;
|
||||
}
|
||||
ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description);
|
||||
ast_module_ref(faxmod->tech->module);
|
||||
if (reserved) {
|
||||
/* Balance module ref from reserved session */
|
||||
ast_module_unref(reserved->tech->module);
|
||||
|
|
Loading…
Reference in New Issue