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 */
{
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;
}
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:
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;
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;
}