[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