[svn-commits] kmoore: branch group/ari-greedy-atxfer r419629 - /team/group/ari-greedy-atxfe...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Jul 25 17:15:31 CDT 2014


Author: kmoore
Date: Fri Jul 25 17:15:25 2014
New Revision: 419629

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419629
Log:
Stasis App: Handle outbound masquerades

This handles the situation where a channel is masqueraded out of stasis
to go elsewhere. It ensures that the correct StasisEnd message is sent
and performs other cleanup necessary to prevent spurious messages from
reaching Stasis applications that aren't prepared for them.

ASTERISK-23941
Review: https://reviewboard.asterisk.org/r/3852/

Modified:
    team/group/ari-greedy-atxfer/res/res_stasis.c

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=419629&r1=419628&r2=419629
==============================================================================
--- team/group/ari-greedy-atxfer/res/res_stasis.c (original)
+++ team/group/ari-greedy-atxfer/res/res_stasis.c Fri Jul 25 17:15:25 2014
@@ -894,21 +894,10 @@
 	return 0;
 }
 
-static int send_end_msg(struct stasis_app *app, struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+static int send_end_msg_snapshot(struct stasis_app *app, struct ast_channel_snapshot *snapshot)
+{
 	struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
-
-	ast_assert(chan != NULL);
-
-	/* Set channel info */
-	ast_channel_lock(chan);
-	snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (snapshot == NULL) {
-		return -1;
-	}
+	struct ast_json *msg;
 
 	if (sanitize && sanitize->channel_snapshot
 		&& sanitize->channel_snapshot(snapshot)) {
@@ -924,7 +913,124 @@
 	}
 
 	app_send(app, msg);
+	ast_json_unref(msg);
 	return 0;
+}
+
+static void remove_masquerade_store(struct ast_channel *chan);
+
+static int masq_match_cb(void *obj, void *data, int flags)
+{
+	struct stasis_app_control *control = obj;
+	struct ast_channel *chan = data;
+
+	if (!strcmp(ast_channel_uniqueid(chan),
+		stasis_app_control_get_channel_id(control))) {
+		return CMP_MATCH;
+	}
+
+	return 0;
+}
+
+static void channel_stolen_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct ast_channel_snapshot *snapshot;
+	struct stasis_app_control *control;
+
+	/* grab a snapshot */
+	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
+	if (!snapshot) {
+		ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
+		return;
+	}
+
+	/* find control */
+	control = ao2_callback(app_controls, 0, masq_match_cb, old_chan);
+	if (!control) {
+		ast_log(LOG_ERROR, "Could not find control for masqueraded channel\n");
+		ao2_cleanup(snapshot);
+		return;
+	}
+
+	/* send the StasisEnd message to the app */
+	send_end_msg_snapshot(control_app(control), snapshot);
+
+	/* remove the datastore */
+	remove_masquerade_store(old_chan);
+
+	ao2_cleanup(control);
+	ao2_cleanup(snapshot);
+}
+
+static const struct ast_datastore_info masquerade_store_info = {
+	.type = "stasis-masqerade",
+	.chan_fixup = channel_stolen_cb,
+};
+
+static int has_masquerade_store(struct ast_channel *chan)
+{
+	SCOPED_CHANNELLOCK(lock, chan);
+	return !!ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
+}
+
+static int add_masquerade_store(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	SCOPED_CHANNELLOCK(lock, chan);
+	if (ast_channel_datastore_find(chan, &masquerade_store_info, NULL)) {
+		return 0;
+	}
+
+	datastore = ast_datastore_alloc(&masquerade_store_info, NULL);
+	if (!datastore) {
+		return -1;
+	}
+
+	ast_channel_datastore_add(chan, datastore);
+
+	return 0;
+}
+
+static void remove_masquerade_store(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore;
+
+	SCOPED_CHANNELLOCK(lock, chan);
+	datastore = ast_channel_datastore_find(chan, &masquerade_store_info, NULL);
+	if (!datastore) {
+		return;
+	}
+
+	ast_channel_datastore_remove(chan, datastore);
+	ast_datastore_free(datastore);
+}
+
+static int send_end_msg(struct stasis_app *app, struct ast_channel *chan)
+{
+	struct ast_channel_snapshot *snapshot;
+	int res = 0;
+
+	ast_assert(chan != NULL);
+
+	/* A masquerade has occurred and this message will be wrong so it
+	 * has already been sent elsewhere. */
+	if (!has_masquerade_store(chan)) {
+		return 0;
+	}
+
+	/* Set channel info */
+	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
+	if (!snapshot) {
+		return -1;
+	}
+
+	if (send_end_msg_snapshot(app, snapshot)) {
+		res = -1;
+	}
+
+	ao2_cleanup(snapshot);
+	return res;
 }
 
 void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
@@ -987,10 +1093,16 @@
 	}
 	ao2_link(app_controls, control);
 
+	if (add_masquerade_store(chan)) {
+		ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
+		return -1;
+	}
+
 	res = send_start_msg(app, chan, argc, argv);
 	if (res != 0) {
 		ast_log(LOG_ERROR,
 			"Error sending start message to '%s'\n", app_name);
+		remove_masquerade_store(chan);
 		return -1;
 	}
 
@@ -998,6 +1110,7 @@
 	if (res != 0) {
 		ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
 			app_name, ast_channel_name(chan));
+		remove_masquerade_store(chan);
 		return -1;
 	}
 
@@ -1073,6 +1186,7 @@
 	ao2_cleanup(bridge);
 
 	res = send_end_msg(app, chan);
+	remove_masquerade_store(chan);
 	if (res != 0) {
 		ast_log(LOG_ERROR,
 			"Error sending end message to %s\n", app_name);




More information about the svn-commits mailing list