summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/bridge_channel.c264
-rw-r--r--main/channel.c2
-rw-r--r--main/frame.c8
-rw-r--r--main/sorcery.c47
4 files changed, 287 insertions, 34 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 06da4eeed..75008fe18 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -35,6 +35,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <signal.h>
+#include <semaphore.h>
#include "asterisk/heap.h"
#include "asterisk/astobj2.h"
@@ -70,6 +71,142 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
*/
typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen);
+/*!
+ * \brief Counter used for assigning synchronous bridge action IDs
+ */
+static int sync_ids;
+
+/*!
+ * \brief Frame payload for synchronous bridge actions.
+ *
+ * The payload serves as a wrapper around the actual payload of the
+ * frame, with the addition of an id used to find the associated
+ * bridge_sync object.
+ */
+struct sync_payload {
+ /*! Unique ID for this synchronous action */
+ unsigned int id;
+ /*! Actual frame data to process */
+ unsigned char data[0];
+};
+
+/*!
+ * \brief Synchronous bridge action object.
+ *
+ * Synchronous bridge actions require the ability for one thread to wait
+ * and for another thread to indicate that the action has completed. This
+ * structure facilitates that goal by providing synchronization structures.
+ */
+struct bridge_sync {
+ /*! Unique ID of this synchronization object. Corresponds with ID in synchronous frame payload */
+ unsigned int id;
+ /*! Semaphore used for synchronization */
+ sem_t sem;
+ /*! Pointer to next entry in the list */
+ AST_LIST_ENTRY(bridge_sync) list;
+};
+
+/*!
+ * \brief List holding active synchronous action objects.
+ */
+static AST_RWLIST_HEAD_STATIC(sync_structs, bridge_sync);
+
+/*!
+ * \brief initialize a synchronous bridge object.
+ *
+ * This both initializes the structure and adds it to the list of
+ * synchronization structures.
+ *
+ * \param sync_struct The synchronization object to initialize.
+ * \param id ID to assign to the synchronization object.
+ */
+static void bridge_sync_init(struct bridge_sync *sync_struct, unsigned int id)
+{
+ memset(sync_struct, 0, sizeof(*sync_struct));
+ sync_struct->id = id;
+ sem_init(&sync_struct->sem, 0, 0);
+
+ AST_RWLIST_WRLOCK(&sync_structs);
+ AST_RWLIST_INSERT_TAIL(&sync_structs, sync_struct, list);
+ AST_RWLIST_UNLOCK(&sync_structs);
+}
+
+/*!
+ * \brief Clean up a syncrhonization bridge object.
+ *
+ * This frees fields within the synchronization object and removes
+ * it from the list of active synchronization objects.
+ *
+ * Since synchronization objects are stack-allocated, it is vital
+ * that this is called before the synchronization object goes
+ * out of scope.
+ *
+ * \param sync_struct Synchronization object to clean up.
+ */
+static void bridge_sync_cleanup(struct bridge_sync *sync_struct)
+{
+ struct bridge_sync *iter;
+
+ AST_RWLIST_WRLOCK(&sync_structs);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&sync_structs, iter, list) {
+ if (iter->id == sync_struct->id) {
+ AST_LIST_REMOVE_CURRENT(list);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&sync_structs);
+
+ sem_destroy(&sync_struct->sem);
+}
+
+/*!
+ * \brief Failsafe for synchronous bridge action waiting.
+ *
+ * When waiting for a synchronous bridge action to complete,
+ * if there is a frame resource leak somewhere, it is possible
+ * that we will never get notified that the synchronous action
+ * completed.
+ *
+ * If a significant amount of time passes, then we will abandon
+ * waiting for the synchrnous bridge action to complete.
+ *
+ * This constant represents the number of milliseconds we will
+ * wait for the bridge action to complete.
+ */
+#define PLAYBACK_TIMEOUT (600 * 1000)
+
+/*!
+ * \brief Wait for a synchronous bridge action to complete.
+ *
+ * \param sync_struct Synchronization object corresponding to the bridge action.
+ */
+static void bridge_sync_wait(struct bridge_sync *sync_struct)
+{
+ struct timeval timeout_val = ast_tvadd(ast_tvnow(), ast_samp2tv(PLAYBACK_TIMEOUT, 1000));
+ struct timespec timeout_spec = {
+ .tv_sec = timeout_val.tv_sec,
+ .tv_nsec = timeout_val.tv_usec * 1000,
+ };
+
+ sem_timedwait(&sync_struct->sem, &timeout_spec);
+}
+
+/*!
+ * \brief Signal that waiting for a synchronous bridge action is no longer necessary.
+ *
+ * This may occur for several reasons
+ * \li The synchronous bridge action has completed.
+ * \li The bridge channel has been removed from the bridge.
+ * \li The synchronous bridge action could not be queued.
+ *
+ * \param sync_struct Synchronization object corresponding to the bridge action.
+ */
+static void bridge_sync_signal(struct bridge_sync *sync_struct)
+{
+ sem_post(&sync_struct->sem);
+}
+
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
{
struct ast_bridge *bridge;
@@ -342,6 +479,8 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int caus
*/
static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
+ ast_assert(frame->frametype != AST_FRAME_BRIDGE_ACTION_SYNC);
+
ast_bridge_channel_lock_bridge(bridge_channel);
/*
* XXX need to implement a deferred write queue for when there
@@ -493,7 +632,8 @@ static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel)
* \retval 0 on success.
* \retval -1 on error.
*/
-static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
{
struct ast_frame frame = {
.frametype = AST_FRAME_BRIDGE_ACTION,
@@ -507,6 +647,52 @@ static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_ch
/*!
* \internal
+ * \brief Queue an action frame onto the bridge channel with data synchronously.
+ * \since 12.2.0
+ *
+ * The function will not return until the queued frame is freed.
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_queue_action_data_sync(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
+{
+ struct sync_payload *sync_payload;
+ int sync_payload_len = sizeof(*sync_payload) + datalen;
+ struct bridge_sync sync_struct;
+ struct ast_frame frame = {
+ .frametype = AST_FRAME_BRIDGE_ACTION_SYNC,
+ .subclass.integer = action,
+ };
+
+ /* Make sure we don't end up trying to wait on ourself to deliver the frame */
+ ast_assert(!pthread_equal(pthread_self(), bridge_channel->thread));
+
+ sync_payload = ast_alloca(sync_payload_len);
+ sync_payload->id = ast_atomic_fetchadd_int(&sync_ids, +1);
+ memcpy(sync_payload->data, data, datalen);
+
+ frame.datalen = sync_payload_len;
+ frame.data.ptr = sync_payload;
+
+ bridge_sync_init(&sync_struct, sync_payload->id);
+ if (ast_bridge_channel_queue_frame(bridge_channel, &frame)) {
+ bridge_sync_cleanup(&sync_struct);
+ return -1;
+ }
+
+ bridge_sync_wait(&sync_struct);
+ bridge_sync_cleanup(&sync_struct);
+ return 0;
+}
+/*!
+ * \internal
* \brief Write an action frame onto the bridge channel with data.
* \since 12.0.0
*
@@ -518,7 +704,8 @@ static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_ch
* \retval 0 on success.
* \retval -1 on error.
*/
-static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, const void *data, size_t datalen)
{
struct ast_frame frame = {
.frametype = AST_FRAME_BRIDGE_ACTION,
@@ -530,6 +717,27 @@ static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_ch
return bridge_channel_write_frame(bridge_channel, &frame);
}
+static void bridge_frame_free(struct ast_frame *frame)
+{
+ if (frame->frametype == AST_FRAME_BRIDGE_ACTION_SYNC) {
+ struct sync_payload *sync_payload = frame->data.ptr;
+ struct bridge_sync *sync;
+
+ AST_RWLIST_RDLOCK(&sync_structs);
+ AST_RWLIST_TRAVERSE(&sync_structs, sync, list) {
+ if (sync->id == sync_payload->id) {
+ break;
+ }
+ }
+ if (sync) {
+ bridge_sync_signal(sync);
+ }
+ AST_RWLIST_UNLOCK(&sync_structs);
+ }
+
+ ast_frfree(frame);
+}
+
int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
{
struct ast_frame *dup;
@@ -557,7 +765,7 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
/* Drop frames on channels leaving the bridge. */
ast_bridge_channel_unlock(bridge_channel);
- ast_frfree(dup);
+ bridge_frame_free(dup);
return 0;
}
@@ -816,7 +1024,7 @@ static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
size_t len_payload = sizeof(*payload) + len_name + len_moh;
/* Fill in play file frame data. */
- payload = alloca(len_payload);
+ payload = ast_alloca(len_payload);
payload->custom_play = custom_play;
payload->moh_offset = len_moh ? len_name : 0;
strcpy(payload->playfile, playfile);/* Safe */
@@ -839,6 +1047,13 @@ int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel,
bridge_channel, custom_play, playfile, moh_class);
}
+int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel,
+ ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
+{
+ return payload_helper_playfile(bridge_channel_queue_action_data_sync,
+ bridge_channel, custom_play, playfile, moh_class);
+}
+
struct bridge_custom_callback {
/*! Call this function on the bridge channel thread. */
ast_bridge_custom_callback_fn callback;
@@ -1389,53 +1604,55 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c
*
* \param bridge_channel Channel to execute the action on.
* \param action What to do.
+ * \param data data from the action.
*
* \return Nothing
*/
-static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel, struct ast_frame *action)
+static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_channel,
+ enum bridge_channel_action_type action, void *data)
{
- switch (action->subclass.integer) {
+ switch (action) {
case BRIDGE_CHANNEL_ACTION_DTMF_STREAM:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_dtmf_stream(bridge_channel, action->data.ptr);
+ bridge_channel_dtmf_stream(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_TALKING_START:
case BRIDGE_CHANNEL_ACTION_TALKING_STOP:
bridge_channel_talking(bridge_channel,
- action->subclass.integer == BRIDGE_CHANNEL_ACTION_TALKING_START);
+ action == BRIDGE_CHANNEL_ACTION_TALKING_START);
break;
case BRIDGE_CHANNEL_ACTION_PLAY_FILE:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_playfile(bridge_channel, action->data.ptr);
+ bridge_channel_playfile(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_RUN_APP:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_run_app(bridge_channel, action->data.ptr);
+ bridge_channel_run_app(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_CALLBACK:
- bridge_channel_do_callback(bridge_channel, action->data.ptr);
+ bridge_channel_do_callback(bridge_channel, data);
break;
case BRIDGE_CHANNEL_ACTION_PARK:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
- bridge_channel_park(bridge_channel, action->data.ptr);
+ bridge_channel_park(bridge_channel, data);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
case BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER:
- bridge_channel_blind_transfer(bridge_channel, action->data.ptr);
+ bridge_channel_blind_transfer(bridge_channel, data);
break;
case BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER:
- bridge_channel_attended_transfer(bridge_channel, action->data.ptr);
+ bridge_channel_attended_transfer(bridge_channel, data);
break;
default:
break;
@@ -1700,6 +1917,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
{
struct ast_frame *fr;
char nudge;
+ struct sync_payload *sync_payload;
ast_bridge_channel_lock(bridge_channel);
if (read(bridge_channel->alert_pipe[0], &nudge, sizeof(nudge)) < 0) {
@@ -1715,7 +1933,11 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
}
switch (fr->frametype) {
case AST_FRAME_BRIDGE_ACTION:
- bridge_channel_handle_action(bridge_channel, fr);
+ bridge_channel_handle_action(bridge_channel, fr->subclass.integer, fr->data.ptr);
+ break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ sync_payload = fr->data.ptr;
+ bridge_channel_handle_action(bridge_channel, fr->subclass.integer, sync_payload->data);
break;
case AST_FRAME_CONTROL:
bridge_channel_handle_control(bridge_channel, fr);
@@ -1728,7 +1950,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
ast_write(bridge_channel->chan, fr);
break;
}
- ast_frfree(fr);
+ bridge_frame_free(fr);
}
/*! \brief Internal function to handle DTMF from a channel */
@@ -1745,7 +1967,7 @@ static struct ast_frame *bridge_handle_dtmf(struct ast_bridge_channel *bridge_ch
if (hook) {
enum ast_frame_type frametype = frame->frametype;
- ast_frfree(frame);
+ bridge_frame_free(frame);
frame = NULL;
ao2_ref(hook, -1);
@@ -1805,7 +2027,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
switch (frame->subclass.integer) {
case AST_CONTROL_HANGUP:
ast_bridge_channel_kick(bridge_channel, 0);
- ast_frfree(frame);
+ bridge_frame_free(frame);
return;
default:
break;
@@ -1818,7 +2040,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
return;
}
if (!bridge_channel->features->dtmf_passthrough) {
- ast_frfree(frame);
+ bridge_frame_free(frame);
return;
}
break;
@@ -1828,7 +2050,7 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
/* Simply write the frame out to the bridge technology. */
bridge_channel_write_frame(bridge_channel, frame);
- ast_frfree(frame);
+ bridge_frame_free(frame);
}
/*!
@@ -2205,7 +2427,7 @@ static void bridge_channel_destroy(void *obj)
/* Flush any unhandled wr_queue frames. */
while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
- ast_frfree(fr);
+ bridge_frame_free(fr);
}
pipe_close(bridge_channel->alert_pipe);
diff --git a/main/channel.c b/main/channel.c
index 6145e3505..b264a2170 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1531,6 +1531,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
*/
switch (frame->frametype) {
case AST_FRAME_BRIDGE_ACTION:
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
case AST_FRAME_CONTROL:
case AST_FRAME_TEXT:
case AST_FRAME_IMAGE:
@@ -2875,6 +2876,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
case AST_FRAME_CONTROL:
case AST_FRAME_IAX:
case AST_FRAME_BRIDGE_ACTION:
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
case AST_FRAME_NULL:
case AST_FRAME_CNG:
break;
diff --git a/main/frame.c b/main/frame.c
index 8713ce40d..1b13abc69 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -639,6 +639,10 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch
/* Should never happen */
snprintf(subclass, slen, "Bridge Frametype %d", f->subclass.integer);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ /* Should never happen */
+ snprintf(subclass, slen, "Synchronous Bridge Frametype %d", f->subclass.integer);
+ break;
case AST_FRAME_TEXT:
ast_copy_string(subclass, "N/A", slen);
if (moreinfo) {
@@ -730,6 +734,10 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
/* Should never happen */
ast_copy_string(ftype, "Bridge Specific", len);
break;
+ case AST_FRAME_BRIDGE_ACTION_SYNC:
+ /* Should never happen */
+ ast_copy_string(ftype, "Bridge Specific", len);
+ break;
case AST_FRAME_TEXT:
ast_copy_string(ftype, "Text", len);
break;
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);