summaryrefslogtreecommitdiff
path: root/apps/app_queue.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-09-28 20:39:10 +0000
committerMatthew Jordan <mjordan@digium.com>2013-09-28 20:39:10 +0000
commitccab0f27bc4a64a92d52ef4c727697222854c9e6 (patch)
tree3160d0f6321a394faeeb4016375d75a94e1f937b /apps/app_queue.c
parent2ef63eaf3402575706533eb400c09eb3bebe6c48 (diff)
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 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400061 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps/app_queue.c')
-rw-r--r--apps/app_queue.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 8205b3b7c..e0889a5c3 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1870,13 +1870,21 @@ static void queue_multi_channel_manager_event(void *data,
RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
caller = ast_multi_channel_blob_get_channel(obj, "caller");
- 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) {
+ 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;
+ }
+ }
- if (!caller_event_string || !agent_event_string) {
- return;
+ agent = ast_multi_channel_blob_get_channel(obj, "agent");
+ 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 @@ static void queue_multi_channel_manager_event(void *data,
"%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 @@ static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic
}
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 @@ static void send_agent_complete(const char *queuename, struct ast_channel_snapsh
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 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
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);