summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--bridges/bridge_native_rtp.c1
-rw-r--r--funcs/func_audiohookinherit.c251
-rw-r--r--include/asterisk/audiohook.h11
-rw-r--r--include/asterisk/framehook.h33
-rw-r--r--include/asterisk/res_fax.h4
-rw-r--r--main/audiohook.c49
-rw-r--r--main/bridge_basic.c1
-rw-r--r--main/channel.c14
-rw-r--r--main/framehook.c53
-rw-r--r--res/res_fax.c39
-rw-r--r--res/res_pjsip_refer.c1
12 files changed, 217 insertions, 245 deletions
diff --git a/CHANGES b/CHANGES
index 7f1e98f16..b992edf4c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -192,6 +192,11 @@ res_pjsip
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 ------------
diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c
index 725a6f67f..2362ad296 100644
--- a/bridges/bridge_native_rtp.c
+++ b/bridges/bridge_native_rtp.c
@@ -405,6 +405,7 @@ static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_
.version = AST_FRAMEHOOK_INTERFACE_VERSION,
.event_cb = native_rtp_framehook,
.consume_cb = native_rtp_framehook_consume,
+ .disable_inheritance = 1,
};
if (!data) {
diff --git a/funcs/func_audiohookinherit.c b/funcs/func_audiohookinherit.c
index ea5c5e9ab..28a2a4550 100644
--- a/funcs/func_audiohookinherit.c
+++ b/funcs/func_audiohookinherit.c
@@ -29,260 +29,43 @@
*/
/*** 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
+ DEPRECATED: Used to set whether an audiohook may be inherited to another
+ channel. Due to architectural changes in Asterisk 12, audiohook inheritance
+ is performed automatically and this function now lacks function.
</synopsis>
- <syntax>
- <parameter name="source" required="true">
- <para>The built-in sources in Asterisk are</para>
- <enumlist>
- <enum name="MixMonitor" />
- <enum name="Chanspy" />
- <enum name="Volume" />
- <enum name="Speex" />
- <enum name="pitch_shift" />
- <enum name="JACK_HOOK" />
- <enum name="Mute" />
- </enumlist>
- <para>Note that the names are not case-sensitive</para>
- </parameter>
- </syntax>
<description>
- <para>By enabling audiohook inheritance on the channel, you are giving
- permission for an audiohook to be inherited by a descendent channel.
- Inheritance may be be disabled at any point as well.</para>
-
- <para>Example scenario:</para>
- <para>exten => 2000,1,MixMonitor(blah.wav)</para>
- <para>exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)</para>
- <para>exten => 2000,n,Dial(SIP/2000)</para>
- <para>
- </para>
- <para>exten => 4000,1,Dial(SIP/4000)</para>
- <para>
- </para>
- <para>exten => 5000,1,MixMonitor(blah2.wav)</para>
- <para>exten => 5000,n,Dial(SIP/5000)</para>
- <para>
- </para>
- <para>In this basic dialplan scenario, let's consider the following sample calls</para>
- <para>Call 1: Caller dials 2000. The person who answers then executes an attended</para>
- <para> transfer to 4000.</para>
- <para>Result: Since extension 2000 set MixMonitor to be inheritable, after the</para>
- <para> transfer to 4000 has completed, the call will continue to be recorded
- to blah.wav</para>
- <para>
- </para>
- <para>Call 2: Caller dials 5000. The person who answers then executes an attended</para>
- <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 12, masquerades now 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];
-};
-
-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);
- }
-
- 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;
+ static int warned = 0;
- /* 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 (!warned) {
+ ast_log(LOG_NOTICE, "AUDIOHOOK_INHERIT is deprecated and now does nothing.\n");
+ warned++;
}
- 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;
- }
+ return 0;
}
static struct ast_custom_function inheritance_function = {
@@ -303,4 +86,4 @@ static int load_module(void)
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");
diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h
index 1a4e4696a..6b0716092 100644
--- a/include/asterisk/audiohook.h
+++ b/include/asterisk/audiohook.h
@@ -197,6 +197,17 @@ void ast_audiohook_detach_list(struct ast_audiohook_list *audiohook_list);
*/
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
*
diff --git a/include/asterisk/framehook.h b/include/asterisk/framehook.h
index f33927c7b..8a58323f2 100644
--- a/include/asterisk/framehook.h
+++ b/include/asterisk/framehook.h
@@ -212,7 +212,19 @@ typedef void (*ast_framehook_destroy_callback)(void *data);
*/
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 @@ struct ast_framehook_interface {
* 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_detach(struct ast_channel *chan, int framehook_id);
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
*
diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h
index 4d1ada6ef..b0a1a221b 100644
--- a/include/asterisk/res_fax.h
+++ b/include/asterisk/res_fax.h
@@ -181,6 +181,10 @@ struct ast_fax_session_details {
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;
diff --git a/main/audiohook.c b/main/audiohook.c
index 4dc7c136b..549ad31eb 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -586,15 +586,10 @@ static struct ast_audiohook *find_audiohook_by_source(struct ast_audiohook_list
return NULL;
}
-void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
+static void audiohook_move(struct ast_channel *old_chan, struct ast_channel *new_chan, struct ast_audiohook *audiohook)
{
- 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
* as done, even though ast_audiohook_remove signals the trigger
@@ -610,6 +605,48 @@ void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_chann
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
* \param chan Channel to detach from
* \param source Name of source to detach
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index eb44867f1..60ce37a98 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -2858,6 +2858,7 @@ static int attach_framehook(struct attended_transfer_properties *props, struct a
.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);
diff --git a/main/channel.c b/main/channel.c
index 7d9f04837..15f2cbce0 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -6578,6 +6578,12 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
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);
clone_variables(original, clonechan);
@@ -10295,6 +10301,13 @@ struct suppress_data {
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;
@@ -10346,6 +10359,7 @@ int ast_channel_suppress(struct ast_channel *chan, unsigned int direction, enum
.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;
diff --git a/main/framehook.c b/main/framehook.c
index 84719ef49..0d42b4990 100644
--- a/main/framehook.c
+++ b/main/framehook.c
@@ -56,7 +56,16 @@ struct ast_framehook_list {
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 @@ static void framehook_detach_and_destroy(struct ast_framehook *framehook)
}
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 @@ static struct ast_frame *framehook_list_push_event(struct ast_framehook_list *fr
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 @@ int ast_framehook_list_destroy(struct ast_channel *chan)
}
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 @@ int ast_framehook_list_destroy(struct ast_channel *chan)
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) {
diff --git a/res/res_fax.c b/res/res_fax.c
index b9a3b2ec4..758309822 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -607,11 +607,47 @@ static void destroy_callback(void *data)
}
}
+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)
{
@@ -3431,6 +3467,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d
.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");
@@ -3700,6 +3737,8 @@ static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags)
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) {
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index efcee67a2..b88396f7a 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -508,6 +508,7 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann
.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));