[asterisk-commits] jrose: branch 12 r418914 - in /branches/12: ./ bridges/ funcs/ include/asteri...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jul 18 11:02:01 CDT 2014


Author: jrose
Date: Fri Jul 18 11:01:57 2014
New Revision: 418914

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=418914
Log:
Channels: Masquerades to automatically move frame/audio hooks

Whenever possible, audiohooks and framehooks will now be copied over
to the channel that the masquerading channel gets cloned into. This
should occur for all audiohooks and most framehooks. As a result,
in Asterisk 12.5 and up, the AUDIOHOOK_INHERIT function is now
deprecated and its behavior is essentially the new default for all
audiohooks, plus some additional audiohooks/framehooks.

Review: https://reviewboard.asterisk.org/r/3721/

Modified:
    branches/12/CHANGES
    branches/12/bridges/bridge_native_rtp.c
    branches/12/funcs/func_audiohookinherit.c
    branches/12/include/asterisk/audiohook.h
    branches/12/include/asterisk/framehook.h
    branches/12/include/asterisk/res_fax.h
    branches/12/main/audiohook.c
    branches/12/main/bridge_basic.c
    branches/12/main/channel.c
    branches/12/main/framehook.c
    branches/12/res/res_fax.c
    branches/12/res/res_pjsip_refer.c

Modified: branches/12/CHANGES
URL: http://svnview.digium.com/svn/asterisk/branches/12/CHANGES?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/CHANGES (original)
+++ branches/12/CHANGES Fri Jul 18 11:01:57 2014
@@ -18,6 +18,11 @@
    created for an endpoint with this setting will have its accountcode set
    to the specified value.
 
+Functions
+------------------
+ * Function AUDIOHOOK_INHERIT has been deprecated. Audiohooks are now
+   unconditionally inhereted through masquerades. As a side benefit, more
+   than one audiohook of a given type may persist through a masquerade now.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 12.3.0 to Asterisk 12.4.0 ------------

Modified: branches/12/bridges/bridge_native_rtp.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/bridges/bridge_native_rtp.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/bridges/bridge_native_rtp.c (original)
+++ branches/12/bridges/bridge_native_rtp.c Fri Jul 18 11:01:57 2014
@@ -405,6 +405,7 @@
 		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
 		.event_cb = native_rtp_framehook,
 		.consume_cb = native_rtp_framehook_consume,
+		.disable_inheritance = 1,
 	};
 
 	if (!data) {

Modified: branches/12/funcs/func_audiohookinherit.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/funcs/func_audiohookinherit.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/funcs/func_audiohookinherit.c (original)
+++ branches/12/funcs/func_audiohookinherit.c Fri Jul 18 11:01:57 2014
@@ -29,19 +29,17 @@
  */
 
 /*** MODULEINFO
-	<support_level>core</support_level>
+	<support_level>deprecated</support_level>
  ***/
 
 #include "asterisk.h"
-#include "asterisk/datastore.h"
 #include "asterisk/channel.h"
 #include "asterisk/logger.h"
-#include "asterisk/audiohook.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
 
 /*** DOCUMENTATION
- 	<function name = "AUDIOHOOK_INHERIT" language="en_US">
+	<function name = "AUDIOHOOK_INHERIT" language="en_US">
 		<synopsis>
 			Set whether an audiohook may be inherited to another channel
 		</synopsis>
@@ -90,199 +88,26 @@
 			<para>        transfer to 4000.</para>
 			<para>Result: Since extension 5000 did not set MixMonitor to be inheritable, the</para>
 			<para>        recording will stop once the call has been transferred to 4000.</para>
+			<para>Prior to Asterisk 12, masquerades would occur under all sorts of
+			situations which were hard to predict. In Asterisk, masquerades only occur
+			as a result of small set of similar operations for which inheriting all
+			audiohooks from the original channel is now safe, so in Asterisk 12.5+,
+			all audiohooks are inherited without needing other controls expressing
+			which audiohooks should	be inherited under which which conditions.</para>
 		</description>
 	</function>
  ***/
 
-struct inheritable_audiohook {
-	AST_LIST_ENTRY(inheritable_audiohook) list;
-	char source[1];
-};
+static int func_inheritance_write(struct ast_channel *chan, const char *function, char *data, const char *value)
+{
+	static int warned = 0;
 
-struct audiohook_inheritance_datastore {
-	AST_LIST_HEAD (, inheritable_audiohook) allowed_list;
-};
-
-static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
-static void audiohook_inheritance_destroy (void *data);
-static const struct ast_datastore_info audiohook_inheritance_info = {
-	.type = "audiohook inheritance",
-	.destroy = audiohook_inheritance_destroy,
-	.chan_fixup = audiohook_inheritance_fixup,
-};
-
-/*! \brief Move audiohooks as defined by previous calls to the AUDIOHOOK_INHERIT function
- *
- * Move allowed audiohooks from the old channel to the new channel.
- *
- * \param data The ast_datastore containing audiohook inheritance information that will be moved
- * \param old_chan The "clone" channel from a masquerade. We are moving the audiohook in question off of this channel
- * \param new_chan The "original" channel from a masquerade. We are moving the audiohook in question to this channel
- * \return Void
- */
-static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-	struct inheritable_audiohook *audiohook = NULL;
-	struct audiohook_inheritance_datastore *datastore = data;
-
-	ast_debug(2, "inheritance fixup occurring for channels %s(%p) and %s(%p)", ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
-
-	AST_LIST_TRAVERSE(&datastore->allowed_list, audiohook, list) {
-		ast_audiohook_move_by_source(old_chan, new_chan, audiohook->source);
-		ast_debug(3, "Moved audiohook %s from %s(%p) to %s(%p)\n",
-			audiohook->source, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
-	}
-	return;
-}
-
-/*! \brief Destroy dynamically allocated data on an audiohook_inheritance_datastore
- *
- * \param data Pointer to the audiohook_inheritance_datastore in question.
- * \return Void
- */
-static void audiohook_inheritance_destroy(void *data)
-{
-	struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = data;
-	struct inheritable_audiohook *inheritable_audiohook = NULL;
-
-	while ((inheritable_audiohook = AST_LIST_REMOVE_HEAD(&audiohook_inheritance_datastore->allowed_list, list))) {
-		ast_free(inheritable_audiohook);
+	if (!warned) {
+		ast_log(LOG_NOTICE, "AUDIOHOOK_INHERIT is deprecated and now does nothing.\n");
+		warned++;
 	}
 
-	ast_free(audiohook_inheritance_datastore);
-}
-
-/*! \brief create an audiohook_inheritance_datastore and attach it to a channel
- *
- * \param chan The channel to which we wish to attach the new datastore
- * \return Returns the newly created audiohook_inheritance_datastore or NULL on error
- */
-static struct audiohook_inheritance_datastore *setup_inheritance_datastore(struct ast_channel *chan)
-{
-	struct ast_datastore *datastore = NULL;
-	struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = NULL;
-
-	if (!(datastore = ast_datastore_alloc(&audiohook_inheritance_info, NULL))) {
-		return NULL;
-	}
-
-	if (!(audiohook_inheritance_datastore = ast_calloc(1, sizeof(*audiohook_inheritance_datastore)))) {
-		ast_datastore_free(datastore);
-		return NULL;
-	}
-
-	datastore->data = audiohook_inheritance_datastore;
-	ast_channel_lock(chan);
-	ast_channel_datastore_add(chan, datastore);
-	ast_channel_unlock(chan);
-	return audiohook_inheritance_datastore;
-}
-
-/*! \brief Create a new inheritable_audiohook structure and add it to an audiohook_inheritance_datastore
- *
- * \param audiohook_inheritance_datastore The audiohook_inheritance_datastore we want to add the new inheritable_audiohook to
- * \param source The audiohook source for the newly created inheritable_audiohook
- * \retval 0 Success
- * \retval non-zero Failure
- */
-static int setup_inheritable_audiohook(struct audiohook_inheritance_datastore *audiohook_inheritance_datastore, const char *source)
-{
-	struct inheritable_audiohook *inheritable_audiohook = NULL;
-
-	inheritable_audiohook = ast_calloc(1, sizeof(*inheritable_audiohook) + strlen(source));
-
-	if (!inheritable_audiohook) {
-		return -1;
-	}
-
-	strcpy(inheritable_audiohook->source, source);
-	AST_LIST_INSERT_TAIL(&audiohook_inheritance_datastore->allowed_list, inheritable_audiohook, list);
-	ast_debug(3, "Set audiohook %s to be inheritable\n", source);
 	return 0;
-}
-
-/*! \brief Set the permissibility of inheritance for a particular audiohook source on a channel
- *
- * For details regarding what happens in the function, see the inline comments
- *
- * \param chan The channel we are operating on
- * \param function The name of the dialplan function (AUDIOHOOK_INHERIT)
- * \param data The audiohook source for which we are setting inheritance permissions
- * \param value The value indicating the permission for audiohook inheritance
- */
-static int func_inheritance_write(struct ast_channel *chan, const char *function, char *data, const char *value)
-{
-	int allow;
-	struct ast_datastore *datastore = NULL;
-	struct audiohook_inheritance_datastore *inheritance_datastore = NULL;
-	struct inheritable_audiohook *inheritable_audiohook;
-
-	/* Step 1: Get data from function call */
-	if (ast_strlen_zero(data)) {
-		ast_log(LOG_WARNING, "No argument provided to INHERITANCE function.\n");
-		return -1;
-	}
-
-	if (ast_strlen_zero(value)) {
-		ast_log(LOG_WARNING, "No value provided to INHERITANCE function.\n");
-		return -1;
-	}
-
-	if (!chan) {
-		ast_log(LOG_WARNING, "No channel was provided to INHERITANCE function.\n");
-		return -1;
-	}
-
-	allow = ast_true(value);
-
-	/* Step 2: retrieve or set up datastore */
-	ast_channel_lock(chan);
-	if (!(datastore = ast_channel_datastore_find(chan, &audiohook_inheritance_info, NULL))) {
-		ast_channel_unlock(chan);
-		/* In the case where we cannot find the datastore, we can take a few shortcuts */
-		if (!allow) {
-			ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
-			return 0;
-		} else if (!(inheritance_datastore = setup_inheritance_datastore(chan))) {
-			ast_log(LOG_WARNING, "Unable to set up audiohook inheritance datastore on channel %s\n", ast_channel_name(chan));
-			return -1;
-		} else {
-			return setup_inheritable_audiohook(inheritance_datastore, data);
-		}
-	} else {
-		inheritance_datastore = datastore->data;
-	}
-	ast_channel_unlock(chan);
-
-	/* Step 3: Traverse the list to see if we're trying something redundant */
-
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&inheritance_datastore->allowed_list, inheritable_audiohook, list) {
-		if (!strcasecmp(inheritable_audiohook->source, data)) {
-			if (allow) {
-				ast_debug(2, "Audiohook source %s is already set up to be inherited from channel %s\n", data, ast_channel_name(chan));
-				return 0;
-			} else {
-				ast_debug(2, "Removing inheritability of audiohook %s from channel %s\n", data, ast_channel_name(chan));
-				AST_LIST_REMOVE_CURRENT(list);
-				ast_free(inheritable_audiohook);
-				return 0;
-			}
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-
-	/* Step 4: There is no step 4 */
-
-	/* Step 5: This means we are addressing an audiohook source which we have not encountered yet for the channel. Create a new inheritable
-	 * audiohook structure if we're allowing inheritance, or just return if not
-	 */
-
-	if (allow) {
-		return setup_inheritable_audiohook(inheritance_datastore, data);
-	} else {
-		ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
-		return 0;
-	}
 }
 
 static struct ast_custom_function inheritance_function = {
@@ -303,4 +128,4 @@
 		return AST_MODULE_LOAD_SUCCESS;
 	}
 }
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audiohook inheritance function");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audiohook inheritance placeholder function");

Modified: branches/12/include/asterisk/audiohook.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/audiohook.h?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/include/asterisk/audiohook.h (original)
+++ branches/12/include/asterisk/audiohook.h Fri Jul 18 11:01:57 2014
@@ -197,6 +197,17 @@
  */
 void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source);
 
+/*! \brief Move all audiohooks from one channel to another
+ *
+ * \note It is required that both old_chan and new_chan are locked prior to calling
+ * this function. Besides needing to protect the data within the channels, not locking
+ * these channels can lead to a potential deadlock.
+ *
+ * \param old_chan The source of the audiohooks being moved
+ * \param new_chan The destination channel for the audiohooks to be moved to
+ */
+void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan);
+
 /*!
  * \brief Detach specified source audiohook from channel
  *

Modified: branches/12/include/asterisk/framehook.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/framehook.h?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/include/asterisk/framehook.h (original)
+++ branches/12/include/asterisk/framehook.h Fri Jul 18 11:01:57 2014
@@ -212,7 +212,19 @@
  */
 typedef int (*ast_framehook_consume_callback)(void *data, enum ast_frame_type type);
 
-#define AST_FRAMEHOOK_INTERFACE_VERSION 2
+/*!
+ * \brief This callback is called when a masquerade occurs on a channel with a framehook
+ * \since 12
+ *
+ * \param data, The data pointer provided at framehook initialization.
+ * \param framehook_id, The framehook ID where the framehook lives now
+ * \param old_chan, The channel that was masqueraded.
+ * \param new_chan, The channel that the masqueraded channel became.
+ */
+typedef void (*ast_framehook_chan_fixup_callback)(void *data, int framehook_id,
+	struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+#define AST_FRAMEHOOK_INTERFACE_VERSION 3
 /*! This interface is required for attaching a framehook to a channel. */
 struct ast_framehook_interface {
 	/*! framehook interface version number */
@@ -226,6 +238,13 @@
 	* frames of a specific type at this time. If this callback is not implemented it is assumed that the
 	* framehook will consume frames of all types. */
 	ast_framehook_consume_callback consume_cb;
+	/*! chan_fixup_cb is optional. This function is called when the channel that a framehook is running
+	 * on is masqueraded and should be used to move any essential framehook data onto the channel the
+	 * old channel was masqueraded to. */
+	ast_framehook_chan_fixup_callback chan_fixup_cb;
+	/*! disable_inheritance is optional. If set to non-zero, when a channel using this framehook is
+	 * masqueraded, detach and destroy the framehook instead of moving it to the new channel. */
+	int disable_inheritance;
 	 /*! This pointer can represent any custom data to be stored on the !framehook. This
 	 * data pointer will be provided during each event callback which allows the framehook
 	 * to store any stateful data associated with the application using the hook. */
@@ -282,6 +301,18 @@
 int ast_framehook_list_destroy(struct ast_channel *chan);
 
 /*!
+ * \brief This is used by the channel API during a masquerade operation
+ * to move all mobile framehooks from the original channel to the clone channel.
+ * \since 12.5.0
+ *
+ * \pre Both channels must be locked prior to this function call.
+ *
+ * \param old_chan The channel being cloned from
+ * \param new_chan The channel being cloned to
+ */
+void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+/*!
  * \brief This is used by the channel API push a frame read event to a channel's framehook list.
  * \since 1.8
  *

Modified: branches/12/include/asterisk/res_fax.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/res_fax.h?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/include/asterisk/res_fax.h (original)
+++ branches/12/include/asterisk/res_fax.h Fri Jul 18 11:01:57 2014
@@ -180,6 +180,10 @@
 	int gateway_timeout;
 	/*! the id of the faxdetect framehook for this channel */
 	int faxdetect_id;
+	/*! The timeout for this fax detect in seconds */
+	int faxdetect_timeout;
+	/*! flags used for fax detection */
+	int faxdetect_flags;
 };
 
 struct ast_fax_tech;

Modified: branches/12/main/audiohook.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/audiohook.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/main/audiohook.c (original)
+++ branches/12/main/audiohook.c Fri Jul 18 11:01:57 2014
@@ -573,14 +573,9 @@
 	return NULL;
 }
 
-void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
-{
-	struct ast_audiohook *audiohook;
+static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
+{
 	enum ast_audiohook_status oldstatus;
-
-	if (!ast_channel_audiohooks(old_chan) || !(audiohook = find_audiohook_by_source(ast_channel_audiohooks(old_chan), source))) {
-		return;
-	}
 
 	/* By locking both channels and the audiohook, we can assure that
 	 * another thread will not have a chance to read the audiohook's status
@@ -595,6 +590,48 @@
 
 	audiohook->status = oldstatus;
 	ast_audiohook_unlock(audiohook);
+}
+
+void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
+{
+	struct ast_audiohook *audiohook;
+
+	if (!ast_channel_audiohooks(old_chan)) {
+		return;
+	}
+
+	audiohook = find_audiohook_by_source(ast_channel_audiohooks(old_chan), source);
+	if (!audiohook) {
+		return;
+	}
+
+	audiohook_move(old_chan, new_chan, audiohook);
+}
+
+void ast_audiohook_move_all(struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct ast_audiohook *audiohook;
+	struct ast_audiohook_list *audiohook_list;
+
+	audiohook_list = ast_channel_audiohooks(old_chan);
+	if (!audiohook_list) {
+		return;
+	}
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) {
+		audiohook_move(old_chan, new_chan, audiohook);
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->whisper_list, audiohook, list) {
+		audiohook_move(old_chan, new_chan, audiohook);
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->manipulate_list, audiohook, list) {
+		audiohook_move(old_chan, new_chan, audiohook);
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
 }
 
 /*! \brief Detach specified source audiohook from channel

Modified: branches/12/main/bridge_basic.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/bridge_basic.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/main/bridge_basic.c (original)
+++ branches/12/main/bridge_basic.c Fri Jul 18 11:01:57 2014
@@ -2858,6 +2858,7 @@
 		.event_cb = transfer_target_framehook_cb,
 		.destroy_cb = transfer_target_framehook_destroy_cb,
 		.consume_cb = transfer_target_framehook_consume,
+		.disable_inheritance = 1,
 	};
 
 	ao2_ref(props, +1);

Modified: branches/12/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/channel.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/main/channel.c (original)
+++ branches/12/main/channel.c Fri Jul 18 11:01:57 2014
@@ -6582,6 +6582,12 @@
 		AST_LIST_TRAVERSE_SAFE_END;
 		AST_LIST_APPEND_LIST(ast_channel_datastores(original), ast_channel_datastores(clonechan), entry);
 	}
+
+	/* Move framehooks over */
+	ast_framehook_list_fixup(clonechan, original);
+
+	/* Move audiohooks over */
+	ast_audiohook_move_all(clonechan, original);
 
 	ast_autochan_new_channel(clonechan, original);
 
@@ -10300,6 +10306,13 @@
 	int framehook_id;
 };
 
+static void suppress_framehook_fixup_cb(void *data, int framehook_id, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct suppress_data *suppress = data;
+
+	suppress->framehook_id = framehook_id;
+}
+
 static struct ast_frame *suppress_framehook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
 {
 	struct suppress_data *suppress = data;
@@ -10351,6 +10364,7 @@
 		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
 		.event_cb = suppress_framehook_event_cb,
 		.destroy_cb = suppress_framehook_destroy_cb,
+		.chan_fixup_cb = suppress_framehook_fixup_cb,
 	};
 	int framehook_id;
 

Modified: branches/12/main/framehook.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/framehook.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/main/framehook.c (original)
+++ branches/12/main/framehook.c Fri Jul 18 11:01:57 2014
@@ -56,7 +56,16 @@
 	AST_LIST_HEAD_NOLOCK(, ast_framehook) list;
 };
 
-static void framehook_detach_and_destroy(struct ast_framehook *framehook)
+enum framehook_detachment_mode
+{
+	/*! Destroy the framehook outright. */
+	FRAMEHOOK_DETACH_DESTROY = 0,
+	/*! Remove the framehook from the channel, but don't destroy the data since
+	 *  it will be used by a replacement framehook on another channel. */
+	FRAMEHOOK_DETACH_PRESERVE,
+};
+
+static void framehook_detach(struct ast_framehook *framehook, enum framehook_detachment_mode mode)
 {
 	struct ast_frame *frame;
 	frame = framehook->i.event_cb(framehook->chan, NULL, AST_FRAMEHOOK_EVENT_DETACHED, framehook->i.data);
@@ -67,7 +76,7 @@
 	}
 	framehook->chan = NULL;
 
-	if (framehook->i.destroy_cb) {
+	if (mode == FRAMEHOOK_DETACH_DESTROY && framehook->i.destroy_cb) {
 		framehook->i.destroy_cb(framehook->i.data);
 	}
 	ast_free(framehook);
@@ -96,7 +105,7 @@
 			if (framehook->detach_and_destroy_me) {
 				/* this guy is signaled for destruction */
 				AST_LIST_REMOVE_CURRENT(list);
-				framehook_detach_and_destroy(framehook);
+				framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
 				continue;
 			}
 
@@ -205,7 +214,7 @@
 	}
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&ast_channel_framehooks(chan)->list, framehook, list) {
 		AST_LIST_REMOVE_CURRENT(list);
-		framehook_detach_and_destroy(framehook);
+		framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
 	}
 	AST_LIST_TRAVERSE_SAFE_END;
 	ast_free(ast_channel_framehooks(chan));
@@ -213,6 +222,42 @@
 	return 0;
 }
 
+void ast_framehook_list_fixup(struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct ast_framehook *framehook;
+	int moved_framehook_id;
+
+	if (!ast_channel_framehooks(old_chan)) {
+		return;
+	}
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&ast_channel_framehooks(old_chan)->list, framehook, list) {
+		AST_LIST_REMOVE_CURRENT(list);
+
+		/* If inheritance is not allowed for this framehook, just destroy it. */
+		if (framehook->i.disable_inheritance) {
+			framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
+			continue;
+		}
+
+		/* Otherwise move it to the other channel and perform any fixups set by the framehook interface */
+		moved_framehook_id = ast_framehook_attach(new_chan, &framehook->i);
+
+		if (moved_framehook_id < 0) {
+			ast_log(LOG_WARNING, "Failed framehook copy during masquerade. Expect loss of features.\n");
+			framehook_detach(framehook, FRAMEHOOK_DETACH_DESTROY);
+		} else {
+			if (framehook->i.chan_fixup_cb) {
+				framehook->i.chan_fixup_cb(framehook->i.data, moved_framehook_id,
+					old_chan, new_chan);
+			}
+
+			framehook_detach(framehook, FRAMEHOOK_DETACH_PRESERVE);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+}
+
 int ast_framehook_list_is_empty(struct ast_framehook_list *framehooks)
 {
 	if (!framehooks) {

Modified: branches/12/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_fax.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/res/res_fax.c (original)
+++ branches/12/res/res_fax.c Fri Jul 18 11:01:57 2014
@@ -425,10 +425,46 @@
 	}
 }
 
+static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
 static const struct ast_datastore_info fax_datastore = {
 	.type = "res_fax",
 	.destroy = destroy_callback,
+	.chan_fixup = fixup_callback,
 };
+
+static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details);
+static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags);
+static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan);
+
+/*! \brief Copies fax detection and gateway framehooks during masquerades
+ *
+ * \note must be called with both old_chan and new_chan locked. Since this
+ *       is only called by do_masquerade, that shouldn't be an issue.
+ */
+static void fixup_callback(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct ast_fax_session_details *old_details = data;
+	struct ast_datastore *datastore = ast_channel_datastore_find(old_chan, &fax_datastore, NULL);
+
+	if (old_details->gateway_id >= 0) {
+		struct ast_fax_session_details *new_details = find_or_create_details(new_chan);
+
+		ast_framehook_detach(old_chan, old_details->gateway_id);
+		fax_gateway_attach(new_chan, new_details);
+		ao2_cleanup(new_details);
+	}
+
+	if (old_details->faxdetect_id >= 0) {
+		ast_framehook_detach(old_chan, old_details->faxdetect_id);
+		fax_detect_attach(new_chan, old_details->faxdetect_timeout, old_details->faxdetect_flags);
+	}
+
+	if (datastore) {
+		ast_channel_datastore_remove(old_chan, datastore);
+		ast_datastore_free(datastore);
+	}
+}
 
 /*! \brief returns a reference counted pointer to a fax datastore, if it exists */
 static struct ast_fax_session_details *find_details(struct ast_channel *chan)
@@ -3249,6 +3285,7 @@
 		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
 		.event_cb = fax_gateway_framehook,
 		.destroy_cb = fax_gateway_framehook_destroy,
+		.disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */
 	};
 
 	ast_string_field_set(details, result, "SUCCESS");
@@ -3518,6 +3555,8 @@
 	faxdetect->details = details;
 	ast_channel_lock(chan);
 	details->faxdetect_id = ast_framehook_attach(chan, &fr_hook);
+	details->faxdetect_timeout = timeout;
+	details->faxdetect_flags = flags;
 	ast_channel_unlock(chan);
 
 	if (details->faxdetect_id < 0) {

Modified: branches/12/res/res_pjsip_refer.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip_refer.c?view=diff&rev=418914&r1=418913&r2=418914
==============================================================================
--- branches/12/res/res_pjsip_refer.c (original)
+++ branches/12/res/res_pjsip_refer.c Fri Jul 18 11:01:57 2014
@@ -509,6 +509,7 @@
 			.event_cb = refer_progress_framehook,
 			.destroy_cb = refer_progress_framehook_destroy,
 			.data = refer->progress,
+			.disable_inheritance = 1,
 		};
 
 		refer->progress->transferee = ast_strdup(ast_channel_uniqueid(chan));




More information about the asterisk-commits mailing list