[svn-commits] kmoore: branch group/ari-greedy-atxfer r419788 - in /team/group/ari-greedy-at...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 29 11:05:37 CDT 2014


Author: kmoore
Date: Tue Jul 29 11:05:33 2014
New Revision: 419788

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=419788
Log:
Stasis: Handle incoming masquerades

This adds handling for a channel being pushed into Stasis() via
masquerade. It notifies the Stasis() application using the previously
established StasisStart with the "replace_channel" key populated with
a channel snapshot of the channel that is being replaced. It also sets
up the new channel topic forwards required to get information from the
new channel and tears down the old channel topic forwards.

This patch also introduces the concept of chan_breakdown datastore
callbacks which are called for the channel being masqueraded into
during a masquerade.

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

Modified:
    team/group/ari-greedy-atxfer/include/asterisk/datastore.h
    team/group/ari-greedy-atxfer/main/channel.c
    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

Modified: team/group/ari-greedy-atxfer/include/asterisk/datastore.h
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/include/asterisk/datastore.h?view=diff&rev=419788&r1=419787&r2=419788
==============================================================================
--- team/group/ari-greedy-atxfer/include/asterisk/datastore.h (original)
+++ team/group/ari-greedy-atxfer/include/asterisk/datastore.h Tue Jul 29 11:05:33 2014
@@ -34,7 +34,7 @@
 	void (*destroy)(void *data);		/*!< Destroy function */
 
 	/*!
-	 * \brief Fix up channel references
+	 * \brief Fix up channel references on the masquerading channel
 	 *
 	 * \arg data The datastore data
 	 * \arg old_chan The old channel owning the datastore
@@ -48,6 +48,20 @@
 	 * \return nothing.
 	 */
 	void (*chan_fixup)(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+	/*!
+	 * \brief Fix up channel references on the channel being masqueraded into
+	 *
+	 * \arg data The datastore data
+	 * \arg old_chan The old channel owning the datastore
+	 * \arg new_chan The new channel owning the datastore
+	 *
+	 * This is the same as the above callback, except it is called for the channel
+	 * being masqueraded into instead of the channel that is masquerading.
+	 *
+	 * \return nothing.
+	 */
+	void (*chan_breakdown)(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
 };
 
 /*! \brief Structure for a data store object */

Modified: team/group/ari-greedy-atxfer/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/ari-greedy-atxfer/main/channel.c?view=diff&rev=419788&r1=419787&r2=419788
==============================================================================
--- team/group/ari-greedy-atxfer/main/channel.c (original)
+++ team/group/ari-greedy-atxfer/main/channel.c Tue Jul 29 11:05:33 2014
@@ -6575,17 +6575,36 @@
 	*ast_channel_hangup_handlers(original) = *ast_channel_hangup_handlers(clonechan);
 	*ast_channel_hangup_handlers(clonechan) = exchange.handlers;
 
-	/* Move data stores over */
+	/* Call fixup handlers for the clone chan */
 	if (AST_LIST_FIRST(ast_channel_datastores(clonechan))) {
 		struct ast_datastore *ds;
 		/* We use a safe traversal here because some fixup routines actually
 		 * remove the datastore from the list and free them.
 		 */
 		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_datastores(clonechan), ds, entry) {
-			if (ds->info->chan_fixup)
+			if (ds->info->chan_fixup) {
 				ds->info->chan_fixup(ds->data, clonechan, original);
+			}
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
+	}
+
+	/* Call breakdown handlers for the original chan */
+	if (AST_LIST_FIRST(ast_channel_datastores(original))) {
+		struct ast_datastore *ds;
+		/* We use a safe traversal here because some breakdown routines may
+		 * remove the datastore from the list and free them.
+		 */
+		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_datastores(original), ds, entry) {
+			if (ds->info->chan_breakdown) {
+				ds->info->chan_breakdown(ds->data, clonechan, original);
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END;
+	}
+
+	/* Move data stores over */
+	if (AST_LIST_FIRST(ast_channel_datastores(clonechan))) {
 		AST_LIST_APPEND_LIST(ast_channel_datastores(original), ast_channel_datastores(clonechan), entry);
 	}
 

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=419788&r1=419787&r2=419788
==============================================================================
--- team/group/ari-greedy-atxfer/res/res_stasis.c (original)
+++ team/group/ari-greedy-atxfer/res/res_stasis.c Tue Jul 29 11:05:33 2014
@@ -856,29 +856,14 @@
 	return replace_channel_app;
 }
 
-static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
-	int argc, char *argv[])
+static int send_start_msg_snapshots(struct stasis_app *app,
+	int argc, char *argv[], struct ast_channel_snapshot *snapshot,
+	struct ast_channel_snapshot *replace_channel_snapshot)
 {
 	RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
-	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
 	struct ast_json *json_args;
+	struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
 	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);
-	snapshot = ast_channel_snapshot_create(chan);
-	ast_channel_unlock(chan);
-	if (!snapshot) {
-		return -1;
-	}
 
 	if (sanitize && sanitize->channel_snapshot
 		&& sanitize->channel_snapshot(snapshot)) {
@@ -919,6 +904,27 @@
 	return 0;
 }
 
+static int send_start_msg(struct stasis_app *app, struct ast_channel *chan,
+	int argc, char *argv[])
+{
+	RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+	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);
+	snapshot = ast_channel_snapshot_create(chan);
+	ast_channel_unlock(chan);
+	if (!snapshot) {
+		return -1;
+	}
+	return send_start_msg_snapshots(app, argc, argv, snapshot, replace_channel_snapshot);
+}
+
 static int send_end_msg_snapshot(struct stasis_app *app, struct ast_channel_snapshot *snapshot)
 {
 	struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
@@ -984,9 +990,59 @@
 	ao2_cleanup(snapshot);
 }
 
+static void channel_replaced_cb(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	RAII_VAR(struct ast_channel_snapshot *, new_snapshot, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel_snapshot *, old_snapshot, NULL, ao2_cleanup);
+	struct stasis_app_control *control;
+
+	/* At this point, new_chan is the channel pointer that is in Stasis() and
+	 * has the unknown channel's name in it while old_chan is the channel pointer
+	 * that is not in Stasis(), but has the guts of the channel that Stasis() knows
+	 * about */
+
+	/* grab a snapshot for the channel that is jumping into Stasis() */
+	new_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(new_chan));
+	if (!new_snapshot) {
+		ast_log(LOG_ERROR, "Could not get snapshot for masquerading channel\n");
+		return;
+	}
+
+	/* grab a snapshot for the channel that has been kicked out of Stasis() */
+	old_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(old_chan));
+	if (!old_snapshot) {
+		ast_log(LOG_ERROR, "Could not get snapshot for masqueraded channel\n");
+		return;
+	}
+
+	/* find, unlink, and relink control since the channel has a new name and
+	 * its hash has likely changed */
+	control = ao2_callback(app_controls, OBJ_UNLINK, masq_match_cb, new_chan);
+	if (!control) {
+		ast_log(LOG_ERROR, "Could not find control for masquerading channel\n");
+		return;
+	}
+	ao2_link(app_controls, control);
+
+
+	/* send the StasisStart with replace_channel to the app */
+	send_start_msg_snapshots(control_app(control), 0, NULL, new_snapshot,
+		old_snapshot);
+	/* send the StasisEnd message to the app */
+	send_end_msg_snapshot(control_app(control), old_snapshot);
+
+	/* fixup channel topic forwards */
+	if (app_replace_channel_forwards(control_app(control), old_snapshot->uniqueid, new_chan)) {
+		ast_log(LOG_ERROR, "Failed to fixup channel topic forwards for %s(%s) owned by %s\n",
+			old_snapshot->name, old_snapshot->uniqueid, app_name(control_app(control)));
+	}
+	ao2_cleanup(control);
+}
+
 static const struct ast_datastore_info masquerade_store_info = {
 	.type = "stasis-masqerade",
 	.chan_fixup = channel_stolen_cb,
+	.chan_breakdown = channel_replaced_cb,
 };
 
 static int has_masquerade_store(struct ast_channel *chan)

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=419788&r1=419787&r2=419788
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/app.c (original)
+++ team/group/ari-greedy-atxfer/res/stasis/app.c Tue Jul 29 11:05:33 2014
@@ -1065,6 +1065,30 @@
 	return forwards != NULL;
 }
 
+int app_replace_channel_forwards(struct stasis_app *app, const char *old_id, struct ast_channel *new_chan)
+{
+	RAII_VAR(struct app_forwards *, old_forwards, NULL, ao2_cleanup);
+	struct app_forwards *new_forwards;
+
+	old_forwards = ao2_find(app->forwards, old_id, OBJ_SEARCH_KEY | OBJ_UNLINK);
+	if (!old_forwards) {
+		return -1;
+	}
+
+	new_forwards = forwards_create_channel(app, new_chan);
+	if (!new_forwards) {
+		return -1;
+	}
+
+	new_forwards->interested = old_forwards->interested;
+	ao2_link_flags(app->forwards, new_forwards, 0);
+	ao2_cleanup(new_forwards);
+
+	/* Clean up old forwards */
+	forwards_unsubscribe(old_forwards);
+	return 0;
+}
+
 static void *channel_find(const struct stasis_app *app, const char *id)
 {
 	return ast_channel_get_by_name(id);

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=419788&r1=419787&r2=419788
==============================================================================
--- team/group/ari-greedy-atxfer/res/stasis/app.h (original)
+++ team/group/ari-greedy-atxfer/res/stasis/app.h Tue Jul 29 11:05:33 2014
@@ -258,4 +258,16 @@
  */
 char *app_get_replace_channel_app(struct ast_channel *chan);
 
+/*!
+ * \brief Replace channel topic forwards for the old channel with forwards for the new channel
+ *
+ * \param app The app that owns the channel
+ * \param old_id The unique ID of the channel to be replaced
+ * \param new_chan The channel that is replacing the old one
+ *
+ * \retval zero on success
+ * \return non-zero on failure
+ */
+int app_replace_channel_forwards(struct stasis_app *app, const char *old_id, struct ast_channel *new_chan);
+
 #endif /* _ASTERISK_RES_STASIS_APP_H */




More information about the svn-commits mailing list