[asterisk-commits] mjordan: trunk r400061 - in /trunk: ./ apps/app_queue.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Sep 28 15:39:12 CDT 2013


Author: mjordan
Date: Sat Sep 28 15:39:10 2013
New Revision: 400061

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=400061
Log:
app_queue: Make manager events tolerant of Local channel shenanigans

app_queue currently attempts to handle Local channel optimizations in an effort
to provide accurate information in Stasis messages (and their corresponding
AMI events) as well as the Queue log. Sometimes, however, things don't go as
planned.

Consider the following scenario:
 SIP/foo <-> L;1 <-> L;2 <-> SIP/agent

SIP/agent answers, triggering a Local channel optimization. app_queue will
normally do the following:
 * Listen for the Local optimization events and update our agent accordingly
   to SIP/agent in the queue log and messages
 * When we get a hangup, publish the AgentComplete event based on our
   information (SIP/foo and SIP/agent)

However, as with all things that depend on sanity from something as capricious
as Local channels, things can go wrong:
 (1) SIP/agent immediately hangs up upon answering. This triggers a race
     condition between termination messages coming from SIP/agent and the
     ongoing Local channel optimization messages. (Note that this can also
     occur with SIP/foo)
 (2) In a race condition, Asterisk can (rarely) deliver the hangup messages
     prior to the Local channel optimization.

In that case, the messages *may* arrive to app_queue in the following order:
 * Hangup SIP/Agent
 * Hangup SIP/foo
 * Optimize L;1/L;2
 * Hangup L;2
 * Hangup L;1

When app_queue receives the hangup of the agent or the caller, it will attempt
to publish the AgentComplete event. However, it now has a problem - it thinks
its agent is the ;1 side of the Local channel, as it never received the
optimization event. At the same time, that channel is already gone. This
results in getting NULL from the Stasis cache. What's more, we can't really
wait for the optimization message, as we are currently handling the hangup
of the channel that the optimization event would tell us to use.

This patch modifies the behavior in app_queue such that, since we still have a
lot of pertinent queue information (interface, queue name, etc.), we now raise
the event with what information we know. The channels involved now may or may
not be present. Users will still at least get the "AgentComplete" event, which
"completes" the known Agent information.

Review: https://reviewboard.asterisk.org/r/2878/

(closes issue ASTERISK-22507)
Reported by: Richard Mudgett
........

Merged revisions 400060 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/apps/app_queue.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-12-merged' - no diff available.

Modified: trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_queue.c?view=diff&rev=400061&r1=400060&r2=400061
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Sat Sep 28 15:39:10 2013
@@ -1870,13 +1870,21 @@
 	RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
 
 	caller = ast_multi_channel_blob_get_channel(obj, "caller");
+	if (caller) {
+		caller_event_string = ast_manager_build_channel_state_string(caller);
+		if (!caller_event_string) {
+			ast_log(AST_LOG_NOTICE, "No caller event string, bailing\n");
+			return;
+		}
+	}
+
 	agent = ast_multi_channel_blob_get_channel(obj, "agent");
-
-	caller_event_string = ast_manager_build_channel_state_string(caller);
-	agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
-
-	if (!caller_event_string || !agent_event_string) {
-		return;
+	if (agent) {
+		agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
+		if (!agent_event_string) {
+			ast_log(AST_LOG_NOTICE, "No agent event string, bailing\n");
+			return;
+		}
 	}
 
 	event_string = ast_manager_str_from_json_object(ast_multi_channel_blob_get_json(obj), NULL);
@@ -1888,8 +1896,8 @@
 		"%s"
 		"%s"
 		"%s",
-		ast_str_buffer(caller_event_string),
-		ast_str_buffer(agent_event_string),
+		caller_event_string ? ast_str_buffer(caller_event_string) : "",
+		agent_event_string ? ast_str_buffer(agent_event_string) : "",
 		ast_str_buffer(event_string));
 }
 
@@ -1925,7 +1933,9 @@
 	}
 
 	ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
-	ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
+	if (agent_snapshot) {
+		ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
+	}
 
 	msg = stasis_message_create(type, payload);
 	if (!msg) {
@@ -5150,9 +5160,6 @@
 	const char *reason = NULL;	/* silence dumb compilers */
 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
-	ast_assert(peer != NULL);
-	ast_assert(caller != NULL);
-
 	switch (rsn) {
 	case CALLER:
 		reason = "caller";
@@ -5729,7 +5736,7 @@
 	ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
 			channel_blob->snapshot->name);
 
-	ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+	ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
 			reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
 		(long) (queue_data->starttime - queue_data->holdstart),
 		(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);




More information about the asterisk-commits mailing list