mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
This patch makes it so that all queue member status changes are handled through device state
code. This removes several problems people were seeing where their queue members would get into an "unknown" state. Huge props go to atis on this one since he was the one who found the code section that was causing the problem and proposed the solution. I just wrote what he suggested :) (closes issue #12127) Reported by: atis Patches: 12127v3.patch uploaded by putnopvut (license 60) Tested by: atis, jvandal git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@109713 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
156
apps/app_queue.c
156
apps/app_queue.c
@@ -572,12 +572,62 @@ struct statechange {
|
||||
int state;
|
||||
char dev[0];
|
||||
};
|
||||
|
||||
static int update_status(const char *interface, const int status)
|
||||
{
|
||||
struct member *cur;
|
||||
struct ao2_iterator mem_iter;
|
||||
struct call_queue *q;
|
||||
|
||||
AST_LIST_LOCK(&queues);
|
||||
AST_LIST_TRAVERSE(&queues, q, list) {
|
||||
ast_mutex_lock(&q->lock);
|
||||
mem_iter = ao2_iterator_init(q->members, 0);
|
||||
while ((cur = ao2_iterator_next(&mem_iter))) {
|
||||
char *tmp_interface;
|
||||
char *slash_pos;
|
||||
tmp_interface = ast_strdupa(cur->interface);
|
||||
if ((slash_pos = strchr(tmp_interface, '/')))
|
||||
if ((slash_pos = strchr(slash_pos + 1, '/')))
|
||||
*slash_pos = '\0';
|
||||
|
||||
if (strcasecmp(interface, tmp_interface)) {
|
||||
ao2_ref(cur, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur->status != status) {
|
||||
cur->status = status;
|
||||
if (q->maskmemberstatus) {
|
||||
ao2_ref(cur, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
|
||||
"Queue: %s\r\n"
|
||||
"Location: %s\r\n"
|
||||
"MemberName: %s\r\n"
|
||||
"Membership: %s\r\n"
|
||||
"Penalty: %d\r\n"
|
||||
"CallsTaken: %d\r\n"
|
||||
"LastCall: %d\r\n"
|
||||
"Status: %d\r\n"
|
||||
"Paused: %d\r\n",
|
||||
q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
|
||||
cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
|
||||
}
|
||||
ao2_ref(cur, -1);
|
||||
}
|
||||
ast_mutex_unlock(&q->lock);
|
||||
}
|
||||
AST_LIST_UNLOCK(&queues);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief set a member's status based on device state of that member's interface*/
|
||||
static void *handle_statechange(struct statechange *sc)
|
||||
{
|
||||
struct call_queue *q;
|
||||
struct member *cur;
|
||||
struct ao2_iterator mem_iter;
|
||||
struct member_interface *curint;
|
||||
char *loc;
|
||||
char *technology;
|
||||
@@ -612,48 +662,8 @@ static void *handle_statechange(struct statechange *sc)
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
|
||||
AST_LIST_LOCK(&queues);
|
||||
AST_LIST_TRAVERSE(&queues, q, list) {
|
||||
ast_mutex_lock(&q->lock);
|
||||
mem_iter = ao2_iterator_init(q->members, 0);
|
||||
while ((cur = ao2_iterator_next(&mem_iter))) {
|
||||
char *interface;
|
||||
char *slash_pos;
|
||||
interface = ast_strdupa(cur->interface);
|
||||
if ((slash_pos = strchr(interface, '/')))
|
||||
if ((slash_pos = strchr(slash_pos + 1, '/')))
|
||||
*slash_pos = '\0';
|
||||
|
||||
if (strcasecmp(sc->dev, interface)) {
|
||||
ao2_ref(cur, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur->status != sc->state) {
|
||||
cur->status = sc->state;
|
||||
if (q->maskmemberstatus) {
|
||||
ao2_ref(cur, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
|
||||
"Queue: %s\r\n"
|
||||
"Location: %s\r\n"
|
||||
"MemberName: %s\r\n"
|
||||
"Membership: %s\r\n"
|
||||
"Penalty: %d\r\n"
|
||||
"CallsTaken: %d\r\n"
|
||||
"LastCall: %d\r\n"
|
||||
"Status: %d\r\n"
|
||||
"Paused: %d\r\n",
|
||||
q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
|
||||
cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
|
||||
}
|
||||
ao2_ref(cur, -1);
|
||||
}
|
||||
ast_mutex_unlock(&q->lock);
|
||||
}
|
||||
AST_LIST_UNLOCK(&queues);
|
||||
update_status(sc->dev, sc->state);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1685,54 +1695,6 @@ static void hangupcalls(struct callattempt *outgoing, struct ast_channel *except
|
||||
}
|
||||
}
|
||||
|
||||
static int update_status(struct call_queue *q, struct member *member, int status)
|
||||
{
|
||||
struct member *cur;
|
||||
struct ao2_iterator mem_iter;
|
||||
|
||||
/* Since a reload could have taken place, we have to traverse the list to
|
||||
be sure it's still valid */
|
||||
ast_mutex_lock(&q->lock);
|
||||
mem_iter = ao2_iterator_init(q->members, 0);
|
||||
while ((cur = ao2_iterator_next(&mem_iter))) {
|
||||
if (member != cur) {
|
||||
ao2_ref(cur, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->status = status;
|
||||
if (!q->maskmemberstatus) {
|
||||
manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
|
||||
"Queue: %s\r\n"
|
||||
"Location: %s\r\n"
|
||||
"MemberName: %s\r\n"
|
||||
"Membership: %s\r\n"
|
||||
"Penalty: %d\r\n"
|
||||
"CallsTaken: %d\r\n"
|
||||
"LastCall: %d\r\n"
|
||||
"Status: %d\r\n"
|
||||
"Paused: %d\r\n",
|
||||
q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime": "static",
|
||||
cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
|
||||
}
|
||||
ao2_ref(cur, -1);
|
||||
}
|
||||
ast_mutex_unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_dial_status(struct call_queue *q, struct member *member, int status)
|
||||
{
|
||||
if (status == AST_CAUSE_BUSY)
|
||||
status = AST_DEVICE_BUSY;
|
||||
else if (status == AST_CAUSE_UNREGISTERED)
|
||||
status = AST_DEVICE_UNAVAILABLE;
|
||||
else if (status == AST_CAUSE_NOSUCHDRIVER)
|
||||
status = AST_DEVICE_INVALID;
|
||||
else
|
||||
status = AST_DEVICE_UNKNOWN;
|
||||
return update_status(q, member, status);
|
||||
}
|
||||
|
||||
/* traverse all defined queues which have calls waiting and contain this member
|
||||
return 0 if no other queue has precedence (higher weight) or 1 if found */
|
||||
@@ -1869,7 +1831,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
||||
if (qe->chan->cdr)
|
||||
ast_cdr_busy(qe->chan->cdr);
|
||||
tmp->stillgoing = 0;
|
||||
update_dial_status(qe->parent, tmp->member, status);
|
||||
|
||||
update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
|
||||
|
||||
ast_mutex_lock(&qe->parent->lock);
|
||||
qe->parent->rrpos++;
|
||||
@@ -1877,8 +1840,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
||||
|
||||
(*busies)++;
|
||||
return 0;
|
||||
} else if (status != tmp->oldstatus)
|
||||
update_dial_status(qe->parent, tmp->member, status);
|
||||
}
|
||||
|
||||
tmp->chan->appl = "AppQueue";
|
||||
tmp->chan->data = "(Outgoing Line)";
|
||||
@@ -2208,8 +2170,6 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
|
||||
/* Setup parameters */
|
||||
o->chan = ast_request(tech, in->nativeformats, stuff, &status);
|
||||
if (status != o->oldstatus)
|
||||
update_dial_status(qe->parent, o->member, status);
|
||||
if (!o->chan) {
|
||||
ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
|
||||
o->stillgoing = 0;
|
||||
@@ -2788,8 +2748,8 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
||||
else
|
||||
to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
|
||||
++qe->pending;
|
||||
ring_one(qe, outgoing, &numbusies);
|
||||
ast_mutex_unlock(&qe->parent->lock);
|
||||
ring_one(qe, outgoing, &numbusies);
|
||||
if (use_weight)
|
||||
AST_LIST_UNLOCK(&queues);
|
||||
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
|
||||
|
Reference in New Issue
Block a user