*/
static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
{
- struct ast_sip_session *session;
- struct ast_channel *chan = NULL;
+ struct ast_channel *chan;
enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
int res = 0;
return;
}
- session = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
- if (!session) {
- return;
- }
-
- chan = session->channel;
+ chan = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
if (!chan) {
return;
}
*/
if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
/* Since no subscription is desired, assume that call has been transferred successfully. */
+ /* Channel reference will be released at end of function */
/* Terminate subscription. */
+ pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
pjsip_evsub_terminate(sub, PJ_TRUE);
res = -1;
}
}
if (res) {
- ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ ao2_ref(chan, -1);
}
}
const char *ref_by_val;
char local_info[pj_strlen(&session->inv_session->dlg->local.info_str) + 1];
struct pjsip_evsub_user xfer_cb;
+ struct ast_channel *chan = session->channel;
pj_bzero(&xfer_cb, sizeof(xfer_cb));
xfer_cb.on_evsub_state = &xfer_client_on_evsub_state;
if (pjsip_xfer_create_uac(session->inv_session->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
message = AST_TRANSFER_FAILED;
- ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message));
return;
}
- pjsip_evsub_set_mod_data(sub, refer_callback_module.id, session);
+ /* refer_callback_module requires a reference to chan
+ * which will be released in xfer_client_on_evsub_state()
+ * when the implicit REFER subscription terminates */
+ pjsip_evsub_set_mod_data(sub, refer_callback_module.id, chan);
+ ao2_ref(chan, +1);
if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
- message = AST_TRANSFER_FAILED;
- ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
- pjsip_evsub_terminate(sub, PJ_FALSE);
-
- return;
+ goto failure;
}
- ref_by_val = pbx_builtin_getvar_helper(session->channel, "SIPREFERREDBYHDR");
+ ref_by_val = pbx_builtin_getvar_helper(chan, "SIPREFERREDBYHDR");
if (!ast_strlen_zero(ref_by_val)) {
ast_sip_add_header(packet, "Referred-By", ref_by_val);
} else {
ast_sip_add_header(packet, "Referred-By", local_info);
}
- pjsip_xfer_send_request(sub, packet);
+ if (pjsip_xfer_send_request(sub, packet) == PJ_SUCCESS) {
+ return;
+ }
+
+failure:
+ message = AST_TRANSFER_FAILED;
+ ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
+ pjsip_evsub_terminate(sub, PJ_FALSE);
+
+ ao2_ref(chan, -1);
}
static int transfer(void *data)