[asterisk-commits] file: branch file/gulp_transfer r388937 - in /team/file/gulp_transfer: channe...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu May 16 18:37:29 CDT 2013
Author: file
Date: Thu May 16 18:37:27 2013
New Revision: 388937
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=388937
Log:
Incorporate some review feedback from Mark, not all of it though.
Modified:
team/file/gulp_transfer/channels/chan_gulp.c
team/file/gulp_transfer/res/res_sip_refer.c
Modified: team/file/gulp_transfer/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_transfer/channels/chan_gulp.c?view=diff&rev=388937&r1=388936&r2=388937
==============================================================================
--- team/file/gulp_transfer/channels/chan_gulp.c (original)
+++ team/file/gulp_transfer/channels/chan_gulp.c Thu May 16 18:37:27 2013
@@ -845,8 +845,11 @@
return;
}
- contact = pjsip_contact_hdr_create(packet->pool);
- pj_strdup2(packet->pool, &tmp, target);
+ if (!(contact = pjsip_msg_find_hdr(packet->msg, PJSIP_H_CONTACT, NULL))) {
+ contact = pjsip_contact_hdr_create(packet->pool);
+ }
+
+ pj_strdup2_with_null(packet->pool, &tmp, target);
if (!(contact->uri = pjsip_parse_uri(packet->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR))) {
message = AST_TRANSFER_FAILED;
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
Modified: team/file/gulp_transfer/res/res_sip_refer.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_transfer/res/res_sip_refer.c?view=diff&rev=388937&r1=388936&r2=388937
==============================================================================
--- team/file/gulp_transfer/res/res_sip_refer.c (original)
+++ team/file/gulp_transfer/res/res_sip_refer.c Thu May 16 18:37:27 2013
@@ -104,6 +104,8 @@
/* If the subscription has already been terminated we can't send a notification */
if (!(sub = notification->progress->sub)) {
+ ast_debug(3, "Not sending NOTIFY of response '%d' and state '%d' on progress monitor '%p' as subscription has been terminated\n",
+ notification->response, notification->state, notification->progress);
return 0;
}
@@ -111,6 +113,8 @@
* stop a deadlock from occurring - basically terminated changes the state which queues a synchronous task
* but we are already running a task... thus it would deadlock */
if (notification->state == PJSIP_EVSUB_STATE_TERMINATED) {
+ ast_debug(3, "Subscription '%p' is being terminated as a result of a NOTIFY, removing REFER progress structure early on progress monitor '%p'\n",
+ notification->progress->sub, notification->progress);
pjsip_dlg_inc_lock(notification->progress->dlg);
pjsip_evsub_set_mod_data(notification->progress->sub, refer_progress_module.id, NULL);
pjsip_dlg_dec_lock(notification->progress->dlg);
@@ -120,6 +124,9 @@
notification->progress->sub = NULL;
}
+
+ ast_debug(3, "Sending NOTIFY with response '%d' and state '%d' on subscription '%p' and progress monitor '%p'\n",
+ notification->response, notification->state, sub, notification->progress);
/* Actually send the notification */
if (pjsip_xfer_notify(sub, notification->state, notification->response, NULL, &tdata) == PJ_SUCCESS) {
@@ -171,6 +178,8 @@
/* 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_channel_name(chan));
ast_framehook_detach(chan, progress->framehook);
}
@@ -185,10 +194,8 @@
struct refer_progress *progress = data;
struct refer_progress_notification *notification = refer_progress_notification_alloc(progress, 503, PJSIP_EVSUB_STATE_TERMINATED);
- if (notification) {
- if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
- ao2_cleanup(notification);
- }
+ if (notification && ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
+ ao2_cleanup(notification);
}
ao2_cleanup(progress);
@@ -213,12 +220,23 @@
/* If being destroyed queue it up to the serializer */
if (progress && (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)) {
/* To prevent a deadlock race condition we unlock the dialog so other serialized tasks can execute */
+ ast_debug(3, "Subscription '%p' has been remotely terminated, waiting for other tasks to complete on progress monitor '%p'\n",
+ sub, progress);
+
+ /* It's possible that a task is waiting to remove us already, so bump the refcount of progress so it doesn't get destroyed */
+ ao2_ref(progress, +1);
pjsip_dlg_dec_lock(progress->dlg);
ast_sip_push_task_synchronous(progress->serializer, refer_progress_terminate, progress);
pjsip_dlg_inc_lock(progress->dlg);
-
- pjsip_evsub_set_mod_data(sub, refer_progress_module.id, NULL);
- ao2_cleanup(progress);
+ ao2_ref(progress, -1);
+
+ ast_debug(3, "Subscription '%p' removed from progress monitor '%p'\n", sub, progress);
+
+ /* Since it was unlocked it is possible for this to have been removed already, so check again */
+ if (pjsip_evsub_get_mod_data(sub, refer_progress_module.id)) {
+ pjsip_evsub_set_mod_data(sub, refer_progress_module.id, NULL);
+ ao2_cleanup(progress);
+ }
}
}
@@ -241,16 +259,19 @@
struct refer_progress *progress;
const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
pjsip_generic_string_hdr *refer_sub = NULL;
+ const pj_str_t str_true = { "true", 4 };
pjsip_tx_data *tdata;
pjsip_hdr hdr_list;
/* 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_strnicmp2(&refer_sub->hvalue, "true", 4)) ||
+ if ((refer_sub && pj_strnicmp(&refer_sub->hvalue, &str_true, 4)) ||
!(progress = ao2_alloc(sizeof(*progress), refer_progress_destroy))) {
return NULL;
}
+
+ 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));
progress->framehook = -1;
@@ -272,16 +293,17 @@
pj_list_init(&hdr_list);
if (refer_sub) {
- const pj_str_t str_true = { "true", 4 };
pjsip_hdr *hdr = (pjsip_hdr*)pjsip_generic_string_hdr_create(session->inv_session->dlg->pool, &str_refer_sub, &str_true);
pj_list_push_back(&hdr_list, hdr);
}
/* Accept the REFER request */
+ ast_debug(3, "Accepting REFER request for progress monitor '%p'\n", progress);
pjsip_xfer_accept(progress->sub, rdata, 202, &hdr_list);
/* Send initial NOTIFY Request */
+ ast_debug(3, "Sending initial 100 Trying NOTIFY for progress monitor '%p'\n", progress);
if (pjsip_xfer_notify(progress->sub, PJSIP_EVSUB_STATE_ACTIVE, 100, NULL, &tdata) == PJ_SUCCESS) {
pjsip_xfer_send_request(progress->sub, tdata);
}
@@ -342,21 +364,27 @@
RAII_VAR(struct refer_attended *, attended, data, ao2_cleanup);
int response = 0;
+ ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n",
+ ast_channel_name(attended->transferer_chan), ast_channel_name(attended->transferee->channel));
+
switch (ast_bridge_transfer_attended(attended->transferer_chan, attended->transferee->channel, NULL)) {
- case AST_BRIDGE_TRANSFER_INVALID:
- response = 503;
- break;
- case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
- response = 403;
- break;
- case AST_BRIDGE_TRANSFER_FAIL:
- response = 500;
- break;
- case AST_BRIDGE_TRANSFER_SUCCESS:
- response = 200;
- attended->transferer->defer_terminate = 1;
- break;
- }
+ case AST_BRIDGE_TRANSFER_INVALID:
+ response = 400;
+ break;
+ case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
+ response = 403;
+ break;
+ case AST_BRIDGE_TRANSFER_FAIL:
+ response = 500;
+ break;
+ case AST_BRIDGE_TRANSFER_SUCCESS:
+ response = 200;
+ attended->transferer->defer_terminate = 1;
+ break;
+ }
+
+ ast_debug(3, "Final response for REFER attended transfer - Transferer #1: %s Transferer #2: %s is '%d'\n",
+ ast_channel_name(attended->transferer_chan), ast_channel_name(attended->transferee->channel), response);
if (attended->progress && response) {
struct refer_progress_notification *notification = refer_progress_notification_alloc(attended->progress, response, PJSIP_EVSUB_STATE_TERMINATED);
@@ -409,6 +437,9 @@
struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
PJSIP_EVSUB_STATE_TERMINATED);
+ ast_log(LOG_WARNING, "Could not attach REFER transfer progress monitoring hook to channel '%s' - assuming success\n",
+ ast_channel_name(chan));
+
if (notification) {
refer_progress_notify(notification);
}
@@ -457,6 +488,8 @@
/* Parsing the parameter as a Replaces header easily grabs the needed information */
if (!(replaces = pjsip_parse_hdr(rdata->tp_info.pool, &str_replaces, replaces_content.ptr,
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;
}
@@ -468,11 +501,15 @@
pjsip_dlg_dec_lock(dlg);
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;
}
/* 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;
}
@@ -482,6 +519,9 @@
return 500;
}
+ ast_debug(3, "Attended transfer from '%s' pushed to second channel serializer\n",
+ ast_channel_name(session->channel));
+
return 200;
} else {
const char *context = (session->channel ? pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT") : "");
@@ -492,6 +532,8 @@
}
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' context does not exist for handling\n",
+ ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
return 404;
}
@@ -502,48 +544,8 @@
refer.refer_to = target_uri;
switch (ast_bridge_transfer_blind(session->channel, "external_replaces", context, refer_blind_callback, &refer)) {
- case AST_BRIDGE_TRANSFER_INVALID:
- return 503;
- case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
- return 403;
- case AST_BRIDGE_TRANSFER_FAIL:
- return 500;
- case AST_BRIDGE_TRANSFER_SUCCESS:
- session->defer_terminate = 1;
- return 200;
- }
-
- return 503;
- }
-
- return 0;
-}
-
-static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
- struct refer_progress *progress)
-{
- const char *context = (session->channel ? pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT") : "");
- char exten[AST_MAX_EXTENSION];
- struct refer_blind refer = { 0, };
-
- /* If no explicit transfer context has been provided use their configured context */
- if (ast_strlen_zero(context)) {
- context = session->endpoint->context;
- }
-
- /* Using the user portion of the target URI see if it exists as a valid extension in their context */
- ast_copy_pj_str(exten, &target->user, sizeof(exten));
- if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
- return 404;
- }
-
- refer.context = context;
- refer.progress = progress;
- refer.rdata = rdata;
-
- switch (ast_bridge_transfer_blind(session->channel, exten, context, refer_blind_callback, &refer)) {
case AST_BRIDGE_TRANSFER_INVALID:
- return 503;
+ return 400;
case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
return 403;
case AST_BRIDGE_TRANSFER_FAIL:
@@ -551,6 +553,48 @@
case AST_BRIDGE_TRANSFER_SUCCESS:
session->defer_terminate = 1;
return 200;
+ }
+
+ return 503;
+ }
+
+ return 0;
+}
+
+static int refer_incoming_blind_request(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_sip_uri *target,
+ struct refer_progress *progress)
+{
+ const char *context = (session->channel ? pbx_builtin_getvar_helper(session->channel, "TRANSFER_CONTEXT") : "");
+ char exten[AST_MAX_EXTENSION];
+ struct refer_blind refer = { 0, };
+
+ /* If no explicit transfer context has been provided use their configured context */
+ if (ast_strlen_zero(context)) {
+ context = session->endpoint->context;
+ }
+
+ /* Using the user portion of the target URI see if it exists as a valid extension in their context */
+ ast_copy_pj_str(exten, &target->user, sizeof(exten));
+ if (!ast_exists_extension(NULL, context, exten, 1, NULL)) {
+ ast_log(LOG_ERROR, "Channel '%s' from endpoint '%s' attempted blind transfer to '%s@%s' but target does not exist\n",
+ ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint), exten, context);
+ return 404;
+ }
+
+ refer.context = context;
+ refer.progress = progress;
+ refer.rdata = rdata;
+
+ switch (ast_bridge_transfer_blind(session->channel, exten, context, refer_blind_callback, &refer)) {
+ case AST_BRIDGE_TRANSFER_INVALID:
+ return 400;
+ case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
+ return 403;
+ case AST_BRIDGE_TRANSFER_FAIL:
+ return 500;
+ case AST_BRIDGE_TRANSFER_SUCCESS:
+ session->defer_terminate = 1;
+ return 200;
}
return 503;
@@ -611,6 +655,8 @@
if (!other_session) {
response = 481;
+ ast_debug(3, "INVITE with Replaces received on channel '%s' from endpoint '%s', but requested session does not exist\n",
+ ast_channel_name(session->channel), ast_sorcery_object_get_id(session->endpoint));
goto end;
}
@@ -629,10 +675,20 @@
/* This will use a synchronous task but we aren't operating in the serializer at this point in time, so it
* won't deadlock */
- ast_channel_move(invite.channel, session->channel);
- ast_hangup(chan);
+ if (!ast_channel_move(invite.channel, session->channel)) {
+ ast_hangup(chan);
+ } else {
+ response = 500;
+ }
} else {
- ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL, 1);
+ if (ast_bridge_impart(invite.bridge, session->channel, invite.channel, NULL, 1)) {
+ response = 500;
+ }
+ }
+
+ if (!response) {
+ ast_debug(3, "INVITE with Replaces successfully completed on channels '%s' and '%s'\n",
+ ast_channel_name(session->channel), ast_channel_name(invite.channel));
}
ast_channel_unref(invite.channel);
@@ -640,6 +696,8 @@
end:
if (response) {
+ ast_debug(3, "INVITE with Replaces failed on channel '%s', sending response of '%d'\n",
+ ast_channel_name(session->channel), response);
session->defer_terminate = 1;
ast_hangup(session->channel);
session->channel = NULL;
@@ -668,6 +726,8 @@
/* A Refer-To header is required */
if (!(refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL))) {
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;
}
uri = refer_to->hvalue.ptr;
@@ -677,6 +737,8 @@
if (!(target = pjsip_parse_hdr(rdata->tp_info.pool, &str_to, refer_to->hvalue.ptr, refer_to->hvalue.slen, NULL)) ||
(!PJSIP_URI_SCHEME_IS_SIP(target->uri) && !PJSIP_URI_SCHEME_IS_SIPS(target->uri))) {
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;
}
target_uri = pjsip_uri_get_uri(target->uri);
@@ -687,6 +749,8 @@
/* If REFER progress monitoring *should* occur but an error occurred report it */
if (progress && !progress->sub) {
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;
}
@@ -705,6 +769,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);
+
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;
@@ -744,7 +811,7 @@
if (pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_invite_method) ||
!session->channel ||
- (ast_channel_state(session->channel) != AST_STATE_DOWN) ||
+ (session->inv_session->state != PJSIP_INV_STATE_CALLING) ||
!(replaces = pbx_builtin_getvar_helper(session->channel, "SIPREPLACESHDR"))) {
return;
}
More information about the asterisk-commits
mailing list