diff options
author | Mark Michelson <mmichelson@digium.com> | 2014-03-17 17:22:12 +0000 |
---|---|---|
committer | Mark Michelson <mmichelson@digium.com> | 2014-03-17 17:22:12 +0000 |
commit | d44aefeef476d744f2915d47c3fdc9b138cdd584 (patch) | |
tree | 59aa013e9a8c0fb7ab1607e2e98076dd88a60f1b /main/sorcery.c | |
parent | 1900bae7b6cec9479ba0e89aed31d02aa71f3133 (diff) |
Fix stuck channel in ARI through the introduction of synchronous bridge actions.
Playing back a file to a channel in an ARI bridge would attempt to wait until
the playback concluded before returning. The method used involved signaling the
waiting thread in the ARI custom playback function.
The problem with this is that there were some corner cases that were not accounted for:
* If a bridge channel could not be found, then we never would attempt the playback but
would still attempt to wait for the playback to complete.
* If the bridge playfile action failed to queue, we would still attempt to wait for the
playback to complete.
* If the bridge playfile action were queued but some circumstance caused the playback
not to occur (the bridge dies, the channel is removed from the bridge), then we would
never be notified.
The solution to this is to move the waiting logic into the bridge code. A new bridge
API function is added to queue a synchronous action on a bridge. The waiting thread
is notified when the queued frame has been freed, either due to an error occurring
or due to successful playback. As a failsafe, the waiting thread has a 10 minute
timeout just in case there is a frame leak somewhere.
Review: https://reviewboard.asterisk.org/r/3338
........
Merged revisions 410673 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410684 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/sorcery.c')
-rw-r--r-- | main/sorcery.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/main/sorcery.c b/main/sorcery.c index 2ab4933be..94a11103b 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -580,6 +580,14 @@ struct ast_sorcery *__ast_sorcery_open(const char *module_name) } strcpy(sorcery->module_name, module_name); /* Safe */ + + if (__ast_sorcery_apply_config(sorcery, module_name, module_name) == AST_SORCERY_APPLY_FAIL) { + ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.", module_name); + ao2_cleanup(sorcery); + sorcery = NULL; + goto done; + } + ao2_link_flags(instances, sorcery, OBJ_NOLOCK); done: @@ -623,7 +631,7 @@ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *typ } /* Order matters for object wizards */ - if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) { + if (!(object_type->wizards = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, sorcery_wizard_cmp))) { ao2_ref(object_type, -1); return NULL; } @@ -683,7 +691,8 @@ static void sorcery_object_wizard_destructor(void *obj) } /*! \brief Internal function which creates an object type and adds a wizard mapping */ -static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data, unsigned int caching) +static enum ast_sorcery_apply_result sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, + const char *type, const char *module, const char *name, const char *data, unsigned int caching) { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); RAII_VAR(struct ast_sorcery_wizard *, wizard, ao2_find(wizards, name, OBJ_KEY), ao2_cleanup); @@ -691,18 +700,30 @@ static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char int created = 0; if (!wizard || !object_wizard) { - return -1; + return AST_SORCERY_APPLY_FAIL; } if (!object_type) { if (!(object_type = sorcery_object_type_alloc(type, module))) { - return -1; + return AST_SORCERY_APPLY_FAIL; } created = 1; } + if (!created) { + struct ast_sorcery_wizard *found; + + found = ao2_find(object_type->wizards, wizard, OBJ_SEARCH_OBJECT); + if (found) { + ast_debug(1, "Wizard %s already applied to object type %s\n", + wizard->name, object_type->name); + ao2_cleanup(found); + return AST_SORCERY_APPLY_DUPLICATE; + } + } + if (wizard->open && !(object_wizard->data = wizard->open(data))) { - return -1; + return AST_SORCERY_APPLY_FAIL; } ast_module_ref(wizard->module); @@ -716,18 +737,18 @@ static int sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char ao2_link(sorcery->types, object_type); } - return 0; + return AST_SORCERY_APPLY_SUCCESS; } -int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module) +enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module) { struct ast_flags flags = { 0 }; struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags); struct ast_variable *mapping; - int res = 0; + int res = AST_SORCERY_APPLY_SUCCESS; if (!config || config == CONFIG_STATUS_FILEINVALID) { - return -1; + return AST_SORCERY_APPLY_FAIL; } for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) { @@ -750,8 +771,8 @@ int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, co } /* Any error immediately causes us to stop */ - if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching)) { - res = -1; + if (sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) { + res = AST_SORCERY_APPLY_FAIL; break; } } @@ -761,13 +782,13 @@ int __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, co return res; } -int __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data) +enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data) { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); /* Defaults can not be added if any existing mapping exists */ if (object_type) { - return -1; + return AST_SORCERY_APPLY_DEFAULT_UNNECESSARY; } return sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0); |