summaryrefslogtreecommitdiff
path: root/main/bridge_basic.c
diff options
context:
space:
mode:
authorScott Griepentrog <sgriepentrog@digium.com>2015-01-05 22:49:40 +0000
committerScott Griepentrog <sgriepentrog@digium.com>2015-01-05 22:49:40 +0000
commit566907fabd6acfd20f59145044649991af23d976 (patch)
tree60051e790937a1b1e32d60a1a00b77dcade93df4 /main/bridge_basic.c
parentb9a7875dd6a14a13981e5141b4464c21263b6346 (diff)
bridge: avoid leaking channel during blond transfer pt2
A blond transfer to a failed destination, when followed by a recall attempt, lead to a leak of the reference to the destination channel. In addition to correcting the regression on the previous attempt (r429826) this fixes the leak and two additional reference leaks on failures of bridge_import. ASTERISK-24513 #close Review: https://reviewboard.asterisk.org/r/4302/ ........ Merged revisions 430199 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@430200 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/bridge_basic.c')
-rw-r--r--main/bridge_basic.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index 48b791d9d..e3318b9f2 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -1322,7 +1322,10 @@ struct attended_transfer_properties {
struct ast_channel *transfer_target;
/*! The party that is currently being recalled. Depending on
* the current state, this may be either the party that originally
- * was the transferer or the original transfer target
+ * was the transferer or the original transfer target. This is
+ * set with reference when entering the BLOND_NONFINAL, RECALLING,
+ * and RETRANSFER states, and the reference released on state exit
+ * if continuing with recall or retransfer to avoid leak.
*/
struct ast_channel *recall_target;
/*! The absolute starting time for running timers */
@@ -2275,10 +2278,10 @@ static int blond_nonfinal_enter(struct attended_transfer_properties *props)
{
int res;
props->superstate = SUPERSTATE_RECALL;
+ /* move the transfer target to the recall target along with its reference */
props->recall_target = ast_channel_ref(props->transfer_target);
res = blond_enter(props);
- /* transfer properties holds a separate reference to transfer_target, don't set it to NULL here */
- ast_channel_unref(props->transfer_target);
+ props->transfer_target = ast_channel_unref(props->transfer_target);
return res;
}
@@ -2292,8 +2295,8 @@ static enum attended_transfer_state blond_nonfinal_exit(struct attended_transfer
return TRANSFER_RESUME;
case STIMULUS_TIMEOUT:
ast_softhangup(props->recall_target, AST_SOFTHANGUP_EXPLICIT);
- props->recall_target = ast_channel_unref(props->recall_target);
case STIMULUS_RECALL_TARGET_HANGUP:
+ props->recall_target = ast_channel_unref(props->recall_target);
return TRANSFER_RECALLING;
case STIMULUS_NONE:
case STIMULUS_DTMF_ATXFER_ABORT:
@@ -2480,6 +2483,7 @@ static enum attended_transfer_state recalling_exit(struct attended_transfer_prop
if (ast_bridge_impart(props->transferee_bridge, props->recall_target, NULL, NULL,
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_hangup(props->recall_target);
+ ast_channel_unref(props->recall_target);
return TRANSFER_FAIL;
}
return TRANSFER_RESUME;
@@ -2586,6 +2590,7 @@ static int retransfer_enter(struct attended_transfer_properties *props)
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_log(LOG_ERROR, "Unable to place recall target into bridge\n");
ast_hangup(props->recall_target);
+ ast_channel_unref(props->recall_target);
return -1;
}