mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
chan_pjsip: Incorporate channel reference count into transfer_refer().
Add channel reference count for PJSIP REFER. The call could be terminated prior to the result of the transfer. In that scenario, when the SUBSCRIBE/NOTIFY occurred several minutes later, it would attempt to access a session which was no longer valid. Terminate event subscription if pjsip_xfer_initiate() or pjsip_xfer_send_request() fails in transfer_refer(). ASTERISK-29201 #close Reported-by: Dan Cropp Change-Id: I3fd92fd14b4e3844d3d7b0f60fe417a4df5f2435
This commit is contained in:
committed by
Friendly Automation
parent
0e1ba9a778
commit
fb23f98521
@@ -1922,8 +1922,7 @@ static pjsip_module refer_callback_module = {
|
|||||||
*/
|
*/
|
||||||
static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
||||||
{
|
{
|
||||||
struct ast_sip_session *session;
|
struct ast_channel *chan;
|
||||||
struct ast_channel *chan = NULL;
|
|
||||||
enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
|
enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
@@ -1931,12 +1930,7 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
|
chan = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
|
||||||
if (!session) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
chan = session->channel;
|
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1962,7 +1956,9 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
|||||||
*/
|
*/
|
||||||
if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
|
if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
|
||||||
/* Since no subscription is desired, assume that call has been transferred successfully. */
|
/* Since no subscription is desired, assume that call has been transferred successfully. */
|
||||||
|
/* Channel reference will be released at end of function */
|
||||||
/* Terminate subscription. */
|
/* Terminate subscription. */
|
||||||
|
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
|
||||||
pjsip_evsub_terminate(sub, PJ_TRUE);
|
pjsip_evsub_terminate(sub, PJ_TRUE);
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
@@ -2027,7 +2023,8 @@ static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2040,28 +2037,29 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
|
|||||||
const char *ref_by_val;
|
const char *ref_by_val;
|
||||||
char local_info[pj_strlen(&session->inv_session->dlg->local.info_str) + 1];
|
char local_info[pj_strlen(&session->inv_session->dlg->local.info_str) + 1];
|
||||||
struct pjsip_evsub_user xfer_cb;
|
struct pjsip_evsub_user xfer_cb;
|
||||||
|
struct ast_channel *chan = session->channel;
|
||||||
|
|
||||||
pj_bzero(&xfer_cb, sizeof(xfer_cb));
|
pj_bzero(&xfer_cb, sizeof(xfer_cb));
|
||||||
xfer_cb.on_evsub_state = &xfer_client_on_evsub_state;
|
xfer_cb.on_evsub_state = &xfer_client_on_evsub_state;
|
||||||
|
|
||||||
if (pjsip_xfer_create_uac(session->inv_session->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
|
if (pjsip_xfer_create_uac(session->inv_session->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
|
||||||
message = AST_TRANSFER_FAILED;
|
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;
|
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) {
|
if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
|
||||||
message = AST_TRANSFER_FAILED;
|
goto failure;
|
||||||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
|
||||||
pjsip_evsub_terminate(sub, PJ_FALSE);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
if (!ast_strlen_zero(ref_by_val)) {
|
||||||
ast_sip_add_header(packet, "Referred-By", ref_by_val);
|
ast_sip_add_header(packet, "Referred-By", ref_by_val);
|
||||||
} else {
|
} else {
|
||||||
@@ -2069,7 +2067,17 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
|
|||||||
ast_sip_add_header(packet, "Referred-By", local_info);
|
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)
|
static int transfer(void *data)
|
||||||
|
Reference in New Issue
Block a user