Commit 1480af1227 for asterisk.org
commit 1480af1227cc1ef047c59459c294d222ab59b934
Author: George Joseph <gjoseph@sangoma.com>
Date: Wed Jul 1 11:38:30 2026 -0600
res_pjsip_refer: Fix issues with Refer-Sub:false and ARI.
When an attended transfer is controlled by ARI using
PJSIP_TRANSFER_HANDLING()=ari-only, and a REFER request is received with
a Refer-Sub: false header to suppress the automatic progress
subscription, a segfault occurs in
res_pjsip_refer:refer_incoming_ari_request().
However, even if the segfault were prevented, there's another issue...
Suppressing the subscription and NOTIFYs to the referer also prevents
the ARI app from getting any progress events for the transfer which it's
controlling.
So...
* The segfault has been fixed.
* Suppressing the subscription no longer suppress the ARI events from being
sent to the controlling ARI app.
* A good amount of tracing has also been added.
Resolves: #2021
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index 863973683e..2ff8abb015 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -807,6 +807,8 @@ struct ast_ari_transfer_message *ast_ari_transfer_message_create(struct ast_chan
const char *protocol_id, struct ast_channel *dest,
struct ast_refer_params *params, enum ast_control_transfer);
+const char *ast_channel_transfer_state2str(enum ast_control_transfer state);
+
/*!
* \brief Initialize the stasis channel topic and message types
* \retval 0 on success
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index 0094e03aab..368b571ed7 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -1649,7 +1649,7 @@ static struct ast_json *unhold_to_json(struct stasis_message *message,
"channel", json_channel);
}
-static const char *state2str(enum ast_control_transfer state) {
+const char *ast_channel_transfer_state2str(enum ast_control_transfer state) {
switch (state) {
case AST_TRANSFER_FAILED:
return "channel_declined";
@@ -1753,7 +1753,7 @@ static struct ast_json *ari_transfer_to_json(struct stasis_message *msg,
}
if (transfer_msg->state != AST_TRANSFER_INVALID) {
- ast_json_object_set(res, "state", ast_json_string_create(state2str(transfer_msg->state)));
+ ast_json_object_set(res, "state", ast_json_string_create(ast_channel_transfer_state2str(transfer_msg->state)));
}
return res;
}
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index eb6e2f1f3f..841cc83ac0 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -87,6 +87,8 @@ struct refer_progress {
unsigned int refer_blind_progress;
/*! \brief State related to the transfer in ARI only mode */
struct transfer_ari_state *ari_state;
+ /*! \brief Refer-Sub: false was specified on the REFER */
+ int no_refer_sub;
};
/*! \brief REFER Progress notification structure */
@@ -109,6 +111,8 @@ static pjsip_module refer_progress_module = {
static void transfer_ari_state_destroy(void *obj)
{
struct transfer_ari_state *state = obj;
+ char *chan_name = ast_strdupa(state->transferer_chan ? ast_channel_name(state->transferer_chan) : "unknown");
+ SCOPE_ENTER(3, "%s: state destructor", chan_name);
ao2_cleanup(state->transferer);
ao2_cleanup(state->other_session);
@@ -116,6 +120,8 @@ static void transfer_ari_state_destroy(void *obj)
ast_free(state->referred_by);
ast_free(state->protocol_id);
ao2_cleanup(state->params);
+
+ SCOPE_EXIT_RTN("%s: done", chan_name);
}
static void refer_params_destroy(void *obj)
@@ -133,16 +139,23 @@ static void refer_params_destroy(void *obj)
static void refer_progress_notification_destroy(void *obj)
{
struct refer_progress_notification *notification = obj;
+ SCOPE_ENTER(3, "%p\n", obj);
ao2_cleanup(notification->progress);
+ SCOPE_EXIT_RTN("%p\n", obj);
}
static int ari_notify(struct transfer_ari_state *state)
{
- return ast_refer_notify_transfer_request(state->transferer_chan, state->referred_by,
+ int res = 0;
+ SCOPE_ENTER(3, "%s: state: %s\n", ast_channel_name(state->transferer_chan),
+ ast_channel_transfer_state2str(state->last_response));
+
+ res = ast_refer_notify_transfer_request(state->transferer_chan, state->referred_by,
state->exten, state->protocol_id,
state->other_session ? state->other_session->channel : NULL,
state->params, state->last_response);
+ SCOPE_EXIT_RTN_VALUE(res, "%s: done: %d\n", ast_channel_name(state->transferer_chan), res);
}
/*! \brief Allocator for REFER Progress notification structure */
@@ -195,8 +208,25 @@ static struct refer_progress_notification *refer_progress_notification_alloc(str
static int refer_progress_notify(void *data)
{
RAII_VAR(struct refer_progress_notification *, notification, data, ao2_cleanup);
+ struct transfer_ari_state *ari_state = notification->progress->ari_state;
pjsip_evsub *sub;
pjsip_tx_data *tdata;
+ SCOPE_ENTER(3, "%s: no_refer_sub: %s\n",
+ ari_state ? ast_channel_name(ari_state->transferer_chan) : "????",
+ AST_YESNO(notification->progress->no_refer_sub));
+
+ /*
+ * If the referer included a "Refer-Sub: false" header, we don't want to
+ * create the automatic subscription but, if the transfer is being controlled
+ * by ARI, we still want the app to get the progress events.
+ */
+ if (notification->progress->no_refer_sub) {
+ if (ari_state) {
+ ari_notify(ari_state);
+ }
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done\n",
+ ari_state ? ast_channel_name(ari_state->transferer_chan) : "????");
+ }
pjsip_dlg_inc_lock(notification->progress->dlg);
@@ -205,7 +235,7 @@ static int refer_progress_notify(void *data)
ast_debug(3, "Not sending NOTIFY of response '%d' and state '%u' on progress monitor '%p' as subscription has been terminated\n",
notification->response, notification->state, notification->progress);
pjsip_dlg_dec_lock(notification->progress->dlg);
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "???\n");
}
/* Send a deferred initial 100 Trying SIP frag NOTIFY if we haven't already. */
@@ -236,7 +266,7 @@ static int refer_progress_notify(void *data)
pjsip_dlg_dec_lock(notification->progress->dlg);
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "???\n");
}
static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
@@ -294,7 +324,8 @@ static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
}
/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
-static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
+static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, struct ast_frame *f,
+ enum ast_framehook_event event, void *data)
{
struct refer_progress *progress = data;
struct refer_progress_notification *notification = NULL;
@@ -359,10 +390,11 @@ static struct ast_frame *refer_ari_progress_framehook(struct ast_channel *chan,
{
struct refer_progress *progress = data;
struct refer_progress_notification *notification = NULL;
+ SCOPE_ENTER(3, "%s\n", ast_channel_name(chan));
/* We only care about frames *to* the channel */
if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
- return f;
+ SCOPE_EXIT_RTN_VALUE(f, "%s: Not EVENT_WRITE\n", ast_channel_name(chan));
}
/* Determine the state of the REFER based on the control frames (or voice frames) passing */
@@ -370,6 +402,7 @@ static struct ast_frame *refer_ari_progress_framehook(struct ast_channel *chan,
&& f->subclass.integer == AST_CONTROL_TRANSFER
&& f->datalen >= sizeof(enum ast_control_transfer)) {
enum ast_control_transfer *message = f->data.ptr;
+ ast_trace(-1, "%s message: %d\n", ast_channel_name(chan), *message);
switch (*message) {
case AST_TRANSFER_FAILED:
notification = refer_progress_notification_alloc(progress, 603, PJSIP_EVSUB_STATE_TERMINATED);
@@ -393,27 +426,48 @@ static struct ast_frame *refer_ari_progress_framehook(struct ast_channel *chan,
if (notification) {
/* If the subscription is being terminated we don't need the frame hook any longer */
if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
- ast_debug(3, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
+ ast_trace(-1, "Detaching REFER progress monitoring hook from '%s' as subscription is being terminated\n",
ast_channel_name(chan));
ast_framehook_detach(chan, progress->framehook);
}
+ /*
+ * If the referer specified "Refer-Sub: false", we can call refer_progress_notify()
+ * directly without pushing a task because it won't be doing any pjproject wotk.
+ * All it will do is send an ARI event.
+ */
+ if (notification->progress->no_refer_sub) {
+ refer_progress_notify(notification);
+ SCOPE_EXIT_RTN_VALUE(f, "%s: done ari no refer sub\n",
+ progress->ari_state ? ast_channel_name(progress->ari_state->transferer_chan) : "????");
+ }
+
if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
ao2_cleanup(notification);
}
+ } else {
+ SCOPE_EXIT_RTN_VALUE(f, "%s: Not a transfer event\n", ast_channel_name(chan));
}
- return f;
+ SCOPE_EXIT_RTN_VALUE(f, "%s: done\n", ast_channel_name(chan));
}
/*! \brief Destroy callback for monitoring framehook */
static void refer_progress_framehook_destroy(void *data)
{
struct refer_progress *progress = data;
- struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
+ struct refer_progress_notification *notification = NULL;
+ SCOPE_ENTER(3, "%p\n", progress);
- if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
- ao2_cleanup(notification);
+ /*
+ * If the referer didn't request the subscription be suppressed, we need to do
+ * a final notification.
+ */
+ if (!progress->no_refer_sub) {
+ notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
+ if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
+ ao2_cleanup(notification);
+ }
}
if (progress->bridge_sub) {
@@ -421,6 +475,7 @@ static void refer_progress_framehook_destroy(void *data)
}
ao2_cleanup(progress);
+ SCOPE_EXIT_RTN("%p\n", progress);
}
/*!
@@ -462,6 +517,7 @@ static int dlg_releaser_task(void *data) {
static void refer_progress_destroy(void *obj)
{
struct refer_progress *progress = obj;
+ SCOPE_ENTER(3, "%p\n", progress);
if (progress->bridge_sub) {
progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
@@ -490,6 +546,7 @@ static void refer_progress_destroy(void *obj)
ast_free(progress->transferee);
ast_taskprocessor_unreference(progress->serializer);
+ SCOPE_EXIT_RTN("%p\n", progress);
}
/*! \brief Internal helper function which sets up a refer progress structure if needed */
@@ -500,19 +557,23 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *
const pj_str_t str_true = { "true", 4 };
pjsip_hdr hdr_list;
char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
+ int no_refer_sub = 0;
+ SCOPE_ENTER(3, "%s\n", ast_channel_name(session->channel));
*progress = NULL;
/* Grab the optional Refer-Sub header, it can be used to suppress the implicit subscription */
refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4))) {
- return 0;
+ no_refer_sub = 1;
}
if (!(*progress = ao2_alloc(sizeof(struct refer_progress), refer_progress_destroy))) {
- return -1;
+ SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
}
+ (*progress)->no_refer_sub = no_refer_sub;
+
ast_debug(3, "Created progress monitor '%p' for transfer occurring from channel '%s' and endpoint '%s'\n",
progress, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
@@ -528,6 +589,13 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *
goto error;
}
+ /*
+ * If the referer request the subscription be suppressed, we can stop here.
+ */
+ if ((*progress)->no_refer_sub) {
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done no refer sub: %d\n", ast_channel_name(session->channel), 0);
+ }
+
/* Create the implicit subscription for monitoring of this transfer */
if (pjsip_xfer_create_uas(session->inv_session->dlg, &refer_progress_evsub_cb, rdata, &(*progress)->sub) != PJ_SUCCESS) {
goto error;
@@ -538,7 +606,6 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *
/* We also need to make sure it stays around until we're done with it */
pjsip_dlg_inc_session((*progress)->dlg, &refer_progress_module);
-
/* Associate the REFER progress structure with the subscription */
ao2_ref(*progress, +1);
pjsip_evsub_set_mod_data((*progress)->sub, refer_progress_module.id, *progress);
@@ -554,12 +621,12 @@ static int refer_progress_alloc(struct ast_sip_session *session, pjsip_rx_data *
ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", *progress);
pjsip_xfer_accept((*progress)->sub, rdata, 202, &hdr_list);
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
error:
ao2_cleanup(*progress);
*progress = NULL;
- return -1;
+ SCOPE_EXIT_RTN_VALUE(-1, "%s: done: %d\n", ast_channel_name(session->channel), -1);
}
/*! \brief Structure for attended transfer task */
@@ -1504,18 +1571,22 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
static const pj_str_t str_referred_by = { "Referred-By", 11 };
static const pj_str_t str_referred_by_s = { "b", 1 };
static const pj_str_t str_replaces = { "Replaces", 8 };
+ SCOPE_ENTER(3, "%s: progress: %p\n", ast_channel_name(session->channel), progress);
+ if (!progress) {
+ SCOPE_EXIT_RTN_VALUE(204, "%s: done: %d\n", ast_channel_name(session->channel), 204);
+ }
state = ao2_alloc(sizeof(struct transfer_ari_state), transfer_ari_state_destroy);
if (!state) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
state->last_response = AST_TRANSFER_INVALID;
state->params = ao2_alloc(sizeof(struct ast_refer_params), refer_params_destroy);
if (!state->params) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
AST_VECTOR_INIT(state->params, 0);
@@ -1537,7 +1608,7 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
if (referred_hdr) {
state->referred_by = copy_string(&referred_hdr->hvalue);
if (!state->referred_by) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
}
@@ -1551,7 +1622,7 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
pj_strlen(&replaces_content), &parsed_len))) {
ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 400;
+ SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
}
dlg = pjsip_ua_find_dialog(&replaces->call_id, &replaces->to_tag, &replaces->from_tag, PJ_TRUE);
@@ -1562,15 +1633,15 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
state->protocol_id = copy_string(&replaces->call_id);
if (!state->protocol_id) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
if (!add_refer_param(state->params, "from", &replaces->from_tag)) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
if (!add_refer_param(state->params, "to", &replaces->to_tag)) {
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
}
@@ -1586,7 +1657,7 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
if (progress->framehook < 0) {
ao2_cleanup(progress);
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
if (ari_notify(state)) {
@@ -1595,13 +1666,13 @@ static int refer_incoming_ari_request(struct ast_sip_session *session, pjsip_rx_
progress->framehook = -1;
ao2_cleanup(progress);
ast_channel_unlock(session->channel);
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
/* Transfer ownership to the progress */
progress->ari_state = state;
state = NULL;
- return 200;
+ SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
}
static int refer_incoming_attended_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target_uri,
@@ -1612,6 +1683,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
pjsip_replaces_hdr *replaces;
int parsed_len;
pjsip_dialog *dlg;
+ SCOPE_ENTER(3, "%s", ast_channel_name(session->channel));
pj_strdup_with_null(rdata->tp_info.pool, &replaces_content, &replaces_param->value);
@@ -1620,7 +1692,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
pj_strlen(&replaces_content), &parsed_len))) {
ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' with invalid Replaces header, rejecting\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 400;
+ SCOPE_EXIT_RTN_VALUE(400, "%s: done: %d\n", ast_channel_name(session->channel), 400);
}
/* See if the dialog is local, or remote */
@@ -1633,21 +1705,21 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
if (!other_session) {
ast_debug(3, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but no session exists on it\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 603;
+ SCOPE_EXIT_RTN_VALUE(503, "%s: done: %d\n", ast_channel_name(session->channel), 603);
}
/* We defer actually doing the attended transfer to the other session so no deadlock can occur */
if (!(attended = refer_attended_alloc(session, other_session, progress))) {
ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not allocate structure to complete, rejecting\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
if (ast_sip_session_defer_termination(session)) {
ast_log(LOG_ERROR, "Received REFER request on channel '%s' from endpoint '%s' for local dialog but could not defer termination, rejecting\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
ao2_cleanup(attended);
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
/* Push it to the other session, which will have both channels with minimal locking */
@@ -1655,13 +1727,13 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
ast_sip_session_end_if_deferred(session);
ast_sip_session_defer_termination_cancel(session);
ao2_cleanup(attended);
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
ast_channel_name(session->channel));
- return 200;
+ SCOPE_EXIT_RTN_VALUE(200, "%s: done: %d\n", ast_channel_name(session->channel), 200);
} else {
const char *context;
struct refer_blind refer = { 0, };
@@ -1672,7 +1744,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
if (!ast_exists_extension(NULL, context, "external_replaces", 1, NULL)) {
ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but 'external_replaces' extension not found in context %s\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), context);
- return 404;
+ SCOPE_EXIT_RTN_VALUE(404, "%s: done: %d\n", ast_channel_name(session->channel), 404);
}
refer.context = context;
@@ -1686,7 +1758,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
ast_log(LOG_ERROR, "Received REFER for remote session on channel '%s' from endpoint '%s' but could not defer termination, rejecting\n",
ast_channel_name(session->channel),
ast_sorcery_object_get_id(session->endpoint));
- return 500;
+ SCOPE_EXIT_RTN_VALUE(500, "%s: done: %d\n", ast_channel_name(session->channel), 500);
}
response = xfer_response_code2sip(ast_bridge_transfer_blind(1, session->channel,
@@ -1697,7 +1769,7 @@ static int refer_incoming_attended_request(struct ast_sip_session *session, pjsi
ast_sip_session_defer_termination_cancel(session);
}
- return response;
+ SCOPE_EXIT_RTN_VALUE(response, "%s: done: %d\n", ast_channel_name(session->channel), response);
}
}
@@ -1922,19 +1994,21 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
static const pj_str_t str_refer_to_s = { "r", 1 };
static const pj_str_t str_replaces = { "Replaces", 8 };
+ SCOPE_ENTER(3, "%s\n", session->channel ? ast_channel_name(session->channel) : "unknown");
+
if (!session->channel) {
/* No channel to refer. Likely because the call was just hung up. */
pjsip_dlg_respond(session->inv_session->dlg, rdata, 404, NULL, NULL, NULL);
ast_debug(3, "Received a REFER on a session with no channel from endpoint '%s'.\n",
ast_sorcery_object_get_id(session->endpoint));
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
if (!session->endpoint->allowtransfer) {
pjsip_dlg_respond(session->inv_session->dlg, rdata, 603, NULL, NULL, NULL);
ast_log(LOG_WARNING, "Endpoint %s transfer attempt blocked due to configuration\n",
ast_sorcery_object_get_id(session->endpoint));
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
/* A Refer-To header is required */
@@ -1943,7 +2017,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
/* The ast_copy_pj_str to uri is needed because it puts the NULL terminator to the uri
@@ -1963,7 +2037,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
ast_debug(3, "Received a REFER without a parseable Refer-To ('%s') on channel '%s' from endpoint '%s'\n",
uri, ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
target_uri = pjsip_uri_get_uri(target);
@@ -1972,7 +2046,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
pjsip_dlg_respond(session->inv_session->dlg, rdata, 500, NULL, NULL, NULL);
ast_debug(3, "Could not set up subscription for REFER on channel '%s' from endpoint '%s'\n",
ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
replaces = pjsip_param_find(&target_uri->header_param, &str_replaces);
@@ -1982,32 +2056,36 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
/* Determine if this is handled externally or an attended or blind transfer */
if (session->transferhandling_ari) {
+ ast_trace(-1, "%s: incoming ari\n", session->channel ? ast_channel_name(session->channel) : "unknown");
response = refer_incoming_ari_request(session, rdata, target_uri, replaces, progress);
} else if (replaces) {
+ ast_trace(-1, "%s: incoming attended\n", session->channel ? ast_channel_name(session->channel) : "unknown");
response = refer_incoming_attended_request(session, rdata, target_uri, replaces, progress);
} else {
+ ast_trace(-1, "%s: incoming blind\n", session->channel ? ast_channel_name(session->channel) : "unknown");
response = refer_incoming_blind_request(session, rdata, target_uri, progress);
}
- if (!progress) {
+ if (progress->no_refer_sub) {
/* The transferer has requested no subscription, so send a final response immediately */
pjsip_tx_data *tdata;
const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
const pj_str_t str_false = { "false", 5 };
pjsip_hdr *hdr;
- ast_debug(3, "Progress monitoring not requested for REFER on channel '%s' from endpoint '%s', sending immediate response of '%d'\n",
- ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), response);
+ ast_trace(-1, "%s: No refer sub from endpoint '%s'. Sending reponse %d\n", ast_channel_name(session->channel),
+ ast_sorcery_object_get_id(session->endpoint), response);
if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, response, NULL, &tdata) != PJ_SUCCESS) {
pjsip_dlg_respond(session->inv_session->dlg, rdata, response, NULL, NULL, NULL);
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub, &str_false);
pjsip_msg_add_hdr(tdata->msg, hdr);
pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
+
} else if (response != 200) {
/* Since this failed we can send a final NOTIFY now and terminate the subscription */
struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, response, PJSIP_EVSUB_STATE_TERMINATED);
@@ -2020,7 +2098,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
}
}
- return 0;
+ SCOPE_EXIT_RTN_VALUE(0, "%s: done: %d\n", ast_channel_name(session->channel), 0);
}
static int refer_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)