[asterisk-commits] kmoore: branch group/ari-greedy-atxfer r419315 - in /team/group/ari-greedy-at...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Jul 23 10:59:22 CDT 2014
Author: kmoore
Date: Wed Jul 23 10:59:15 2014
New Revision: 419315
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419315
Log:
Stasis: Prevent non-stasis channels from entering stasis bridges
This intercepts channels attempting to enter stasis-controlled bridges
that are not themselves controlled by stasis and routes them through
Stasis() to be controlled by the Stasis application that controls the
channels they are replacing.
ASTERISK-23941
Review: https://reviewboard.asterisk.org/r/3731/
Modified:
team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c
team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h
team/group/ari-greedy-atxfer/res/res_stasis.c
team/group/ari-greedy-atxfer/res/stasis/app.c
team/group/ari-greedy-atxfer/res/stasis/app.h
team/group/ari-greedy-atxfer/res/stasis/control.c
team/group/ari-greedy-atxfer/res/stasis/control.h
team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c
team/group/ari-greedy-atxfer/rest-api/api-docs/events.json
Modified: team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c (original)
+++ team/group/ari-greedy-atxfer/res/ari/ari_model_validators.c Wed Jul 23 10:59:15 2014
@@ -4670,6 +4670,15 @@
res = 0;
}
} else
+ if (strcmp("replace_channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field replace_channel failed validation\n");
+ res = 0;
+ }
+ } else
{
ast_log(LOG_ERROR,
"ARI StasisStart has undocumented field %s\n",
Modified: team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h (original)
+++ team/group/ari-greedy-atxfer/res/ari/ari_model_validators.h Wed Jul 23 10:59:15 2014
@@ -1403,6 +1403,7 @@
* - timestamp: Date
* - args: List[string] (required)
* - channel: Channel (required)
+ * - replace_channel: Channel
* Application
* - bridge_ids: List[string] (required)
* - channel_ids: List[string] (required)
Modified: team/group/ari-greedy-atxfer/res/res_stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/res_stasis.c?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/res_stasis.c (original)
+++ team/group/ari-greedy-atxfer/res/res_stasis.c Wed Jul 23 10:59:15 2014
@@ -725,6 +725,112 @@
ast_bridge_destroy(bridge, 0);
}
+struct replace_channel_store {
+ struct ast_channel_snapshot *snapshot;
+ char *app;
+};
+
+static void replace_channel_destroy(void *obj)
+{
+ struct replace_channel_store *replace = obj;
+
+ ao2_cleanup(replace->snapshot);
+ ast_free(replace->app);
+ ast_free(replace);
+}
+
+static const struct ast_datastore_info replace_channel_store_info = {
+ .type = "replace-channel-store",
+ .destroy = replace_channel_destroy,
+};
+
+static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create)
+{
+ struct ast_datastore *datastore;
+
+ SCOPED_CHANNELLOCK(lock, chan);
+ datastore = ast_channel_datastore_find(chan, &replace_channel_store_info, NULL);
+ if (!datastore) {
+ if (no_create) {
+ return NULL;
+ }
+
+ datastore = ast_datastore_alloc(&replace_channel_store_info, NULL);
+ if (!datastore) {
+ return NULL;
+ }
+ ast_channel_datastore_add(chan, datastore);
+ }
+
+ if (!datastore->data) {
+ datastore->data = ast_calloc(1, sizeof(struct replace_channel_store));
+ }
+ return datastore->data;
+}
+
+int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot)
+{
+ struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
+
+ if (!replace) {
+ return -1;
+ }
+
+ ao2_replace(replace->snapshot, replace_snapshot);
+ return 0;
+}
+
+int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app)
+{
+ struct replace_channel_store *replace = get_replace_channel_store(chan, 0);
+
+ if (!replace) {
+ return -1;
+ }
+
+ ast_free(replace->app);
+ replace->app = NULL;
+
+ if (replace_app) {
+ replace->app = ast_strdup(replace_app);
+ if (!replace->app) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static struct ast_channel_snapshot *get_replace_channel_snapshot(struct ast_channel *chan)
+{
+ struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
+ struct ast_channel_snapshot *replace_channel_snapshot;
+
+ if (!replace) {
+ return NULL;
+ }
+
+ replace_channel_snapshot = replace->snapshot;
+ replace->snapshot = NULL;
+
+ return replace_channel_snapshot;
+}
+
+char *app_get_replace_channel_app(struct ast_channel *chan)
+{
+ struct replace_channel_store *replace = get_replace_channel_store(chan, 1);
+ char *replace_channel_app;
+
+ if (!replace) {
+ return NULL;
+ }
+
+ replace_channel_app = replace->app;
+ replace->app = NULL;
+
+ return replace_channel_app;
+}
+
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
int argc, char *argv[])
{
@@ -734,8 +840,12 @@
struct ast_json *json_args;
int i;
struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
+ RAII_VAR(struct ast_channel_snapshot *, replace_channel_snapshot,
+ NULL, ao2_cleanup);
ast_assert(chan != NULL);
+
+ replace_channel_snapshot = get_replace_channel_snapshot(chan);
/* Set channel info */
ast_channel_lock(chan);
@@ -757,6 +867,15 @@
"channel", ast_channel_snapshot_to_json(snapshot, NULL));
if (!msg) {
return -1;
+ }
+
+ if (replace_channel_snapshot) {
+ int res = ast_json_object_set(msg, "replace_channel",
+ ast_channel_snapshot_to_json(replace_channel_snapshot, NULL));
+
+ if (res) {
+ return -1;
+ }
}
/* Append arguments to args array */
Modified: team/group/ari-greedy-atxfer/res/stasis/app.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/app.c?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/app.c (original)
+++ team/group/ari-greedy-atxfer/res/stasis/app.c Wed Jul 23 10:59:15 2014
@@ -28,6 +28,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "app.h"
+#include "control.h"
#include "asterisk/callerid.h"
#include "asterisk/stasis_app.h"
@@ -712,6 +713,21 @@
if (subscribed) {
stasis_publish(app->topic, message);
}
+
+ if (transfer_msg->replace_channel) {
+ struct stasis_app_control *control = stasis_app_control_find_by_channel_id(
+ transfer_msg->to_transferee.channel_snapshot->uniqueid);
+ struct ast_channel *chan = ast_channel_get_by_name(transfer_msg->replace_channel->uniqueid);
+
+ if (control && chan) {
+ ast_channel_lock(chan);
+ app_set_replace_channel_app(chan, app_name(control_app(control)));
+ app_set_replace_channel_snapshot(chan, transfer_msg->to_transferee.channel_snapshot);
+ ast_channel_unlock(chan);
+ }
+ ast_channel_cleanup(chan);
+ ao2_cleanup(control);
+ }
}
static void bridge_default_handler(void *data, struct stasis_subscription *sub,
Modified: team/group/ari-greedy-atxfer/res/stasis/app.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/app.h?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/app.h (original)
+++ team/group/ari-greedy-atxfer/res/stasis/app.h Wed Jul 23 10:59:15 2014
@@ -226,4 +226,36 @@
*/
int app_is_subscribed_endpoint_id(struct stasis_app *app, const char *endpoint_id);
+/*!
+ * \brief Set the snapshot of the channel that this channel will replace
+ *
+ * \param channel The channel on which this will be set
+ * \param replace_snapshot The snapshot of the channel that is being replaced
+ *
+ * \retval zero success
+ * \retval non-zero failure
+ */
+int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot);
+
+/*!
+ * \brief Set the app that the replacement channel will be controlled by
+ *
+ * \param channel The channel on which this will be set
+ * \param replace_app The app that will be controlling this channel
+ *
+ * \retval zero success
+ * \retval non-zero failure
+ */
+int app_set_replace_channel_app(struct ast_channel *chan, const char *replace_app);
+
+/*!
+ * \brief Get the app that the replacement channel will be controlled by
+ *
+ * \param channel The channel on which this will be set
+ *
+ * \retval NULL on error
+ * \return the name of the controlling app (must be ast_free()d)
+ */
+char *app_get_replace_channel_app(struct ast_channel *chan);
+
#endif /* _ASTERISK_RES_STASIS_APP_H */
Modified: team/group/ari-greedy-atxfer/res/stasis/control.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/control.c?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/control.c (original)
+++ team/group/ari-greedy-atxfer/res/stasis/control.c Wed Jul 23 10:59:15 2014
@@ -276,10 +276,6 @@
int timeout;
};
-static int app_control_add_channel_to_bridge(
- struct stasis_app_control *control,
- struct ast_channel *chan, void *data);
-
static int app_control_dial(struct stasis_app_control *control,
struct ast_channel *chan, void *data)
{
@@ -322,7 +318,7 @@
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_hangup(new_chan);
} else {
- app_control_add_channel_to_bridge(control, chan, bridge);
+ control_add_channel_to_bridge(control, chan, bridge);
}
return 0;
@@ -855,7 +851,7 @@
ast_bridge_after_cb_reason_string(reason));
}
-static int app_control_add_channel_to_bridge(
+int control_add_channel_to_bridge(
struct stasis_app_control *control,
struct ast_channel *chan, void *data)
{
@@ -935,7 +931,7 @@
stasis_app_control_get_channel_id(control));
return app_send_command_on_condition(
- control, app_control_add_channel_to_bridge, bridge,
+ control, control_add_channel_to_bridge, bridge,
app_control_can_add_channel_to_bridge);
}
@@ -1064,3 +1060,8 @@
ao2_cleanup(command_queue);
return count;
}
+
+struct stasis_app *control_app(struct stasis_app_control *control)
+{
+ return control->app;
+}
Modified: team/group/ari-greedy-atxfer/res/stasis/control.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/control.h?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/control.h (original)
+++ team/group/ari-greedy-atxfer/res/stasis/control.h Wed Jul 23 10:59:15 2014
@@ -88,5 +88,25 @@
int control_prestart_dispatch_all(struct stasis_app_control *control,
struct ast_channel *chan);
+/*!
+ * \brief Returns the pointer (non-reffed) to the app associated with this control
+ *
+ * \param control Control to query.
+ *
+ * \returns A pointer to the associated stasis_app
+ */
+struct stasis_app *control_app(struct stasis_app_control *control);
+
+/*!
+ * \brief Command callback for adding a channel to a bridge
+ *
+ * \param control The control for chan
+ * \param channel The channel on which commands should be executed
+ * \param bridge Data to be passed to the callback
+ */
+int control_add_channel_to_bridge(
+ struct stasis_app_control *control,
+ struct ast_channel *chan, void *obj);
+
#endif /* _ASTERISK_RES_STASIS_CONTROL_H */
Modified: team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c (original)
+++ team/group/ari-greedy-atxfer/res/stasis/stasis_bridge.c Wed Jul 23 10:59:15 2014
@@ -32,10 +32,68 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/bridge.h"
+#include "asterisk/bridge_after.h"
#include "asterisk/bridge_internal.h"
#include "stasis_bridge.h"
+#include "control.h"
+#include "command.h"
+#include "app.h"
+#include "asterisk/stasis_app.h"
+#include "asterisk/pbx.h"
/* ------------------------------------------------------------------- */
+
+static void bridge_stasis_run_cb(struct ast_channel *chan, void *data)
+{
+ RAII_VAR(char *, app_name, data, ast_free);
+ struct ast_app *app_stasis;
+
+
+ /* find Stasis() */
+ app_stasis = pbx_findapp("Stasis");
+ if (!app_stasis) {
+ ast_log(LOG_WARNING, "Could not find application (Stasis)\n");
+ return;
+ }
+
+ if (ast_check_hangup_locked(chan)) {
+ /* channel hungup, don't run Stasis() */
+ return;
+ }
+
+ /* run Stasis() */
+ pbx_exec(chan, app_stasis, app_name);
+}
+
+static void bridge_stasis_fail_cb(enum ast_bridge_after_cb_reason reason, void *data)
+{
+ char *app_name = data;
+
+ ast_free(app_name);
+}
+
+static int add_channel_to_bridge(
+ struct stasis_app_control *control,
+ struct ast_channel *chan, void *obj)
+{
+ struct ast_bridge *bridge = obj;
+ int res;
+
+ res = control_add_channel_to_bridge(control,
+ chan, bridge);
+ ao2_cleanup(bridge);
+ return res;
+}
+
+static void bridge_stasis_queue_join_action(struct ast_bridge *self,
+ struct ast_bridge_channel *bridge_channel)
+{
+ ast_channel_lock(bridge_channel->chan);
+ if (command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge, ao2_bump(self))) {
+ ao2_cleanup(self);
+ }
+ ast_channel_unlock(bridge_channel->chan);
+}
/*!
* \internal
@@ -53,6 +111,34 @@
*/
static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
{
+ struct stasis_app_control *control = stasis_app_control_find_by_channel(bridge_channel->chan);
+
+ if (!control) {
+ /* channel not in Stasis(), get it there */
+ char *swap_app;
+
+ /* Take ownership of the swap_app memory from the datastore */
+ swap_app = app_get_replace_channel_app(bridge_channel->chan);
+ if (!swap_app) {
+ ast_log(LOG_ERROR, "Failed to get app name for channel at %p\n", bridge_channel->chan);
+ return -1;
+ }
+
+ /* Attach after-bridge callback and pass ownership of swap_app to it */
+ if (ast_bridge_set_after_callback(bridge_channel->chan,
+ bridge_stasis_run_cb, bridge_stasis_fail_cb, swap_app)) {
+ ast_log(LOG_ERROR, "Failed to set after bridge callback\n");
+ ast_free(swap_app);
+ return -1;
+ }
+
+ bridge_stasis_queue_join_action(self, bridge_channel);
+
+ /* Return -1 so the push fails and the after-bridge callback gets called */
+ return -1;
+ }
+
+ ao2_cleanup(control);
if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) {
ast_bridge_channel_update_linkedids(bridge_channel, swap);
if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) {
Modified: team/group/ari-greedy-atxfer/rest-api/api-docs/events.json
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/rest-api/api-docs/events.json?view=diff&rev=419315&r1=419314&r2=419315
==============================================================================
--- team/group/ari-greedy-atxfer/rest-api/api-docs/events.json (original)
+++ team/group/ari-greedy-atxfer/rest-api/api-docs/events.json Wed Jul 23 10:59:15 2014
@@ -674,6 +674,10 @@
"channel": {
"required": true,
"type": "Channel"
+ },
+ "replace_channel": {
+ "required": false,
+ "type": "Channel"
}
}
}
More information about the asterisk-commits
mailing list