summaryrefslogtreecommitdiff
path: root/apps/app_queue.c
diff options
context:
space:
mode:
authorMartin Tomec <tomec.martin@gmail.com>2015-12-29 11:31:19 +0100
committerMartin Tomec <tomec.martin@gmail.com>2016-01-05 17:52:12 +0100
commit338a8ffed673e4c3a828c7c216575f8e3e712350 (patch)
tree1e8cbf14a2a304bf6b1e72fcd4f341b61d7c2850 /apps/app_queue.c
parente13719bff1c4a723edf08252da17fef04b6f88cf (diff)
app_queue: Add member flag "in_call" to prevent reading wrong lastcall time
Member lastcall time is updated later than member status. There was chance to check wrapuptime for available member with wrong (old) lastcall time. New boolean flag "in_call" is set to true right before connecting call, and reset to false after update of lastcall time. Members with "in_call" set to true are treat as unavailable. ASTERISK-19820 #close Change-Id: I1923230cf9859ee51563a8ed420a0628b4d2e500
Diffstat (limited to 'apps/app_queue.c')
-rw-r--r--apps/app_queue.c63
1 files changed, 60 insertions, 3 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index c2450765c..e77b2be23 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -982,6 +982,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<parameter name="LastCall">
<para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
</parameter>
+ <parameter name="InCall">
+ <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
+ <enumlist>
+ <enum name="0"/>
+ <enum name="1"/>
+ </enumlist>
+ </parameter>
<parameter name="Status">
<para>The numeric device state status of the queue member.</para>
<enumlist>
@@ -1499,6 +1506,7 @@ struct member {
char reason_paused[80]; /*!< Reason of paused if member is paused */
int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
time_t lastcall; /*!< When last successful call was hungup */
+ unsigned int in_call:1; /*!< True if member is still in call. (so lastcall is not actual) */
struct call_queue *lastqueue; /*!< Last queue we received a call */
unsigned int dead:1; /*!< Used to detect members deleted in realtime */
unsigned int delme:1; /*!< Flag to delete entry on reload */
@@ -2159,7 +2167,7 @@ static void queue_publish_member_blob(struct stasis_message_type *type, struct a
static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
{
- return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: s, s: i}",
+ return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i}",
"Queue", q->name,
"MemberName", mem->membername,
"Interface", mem->interface,
@@ -2168,6 +2176,7 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me
"Penalty", mem->penalty,
"CallsTaken", mem->calls,
"LastCall", (int)mem->lastcall,
+ "InCall", mem->in_call,
"Status", mem->status,
"Paused", mem->paused,
"PausedReason", mem->reason_paused,
@@ -2231,6 +2240,10 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
break;
+ } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->in_call && q->wrapuptime) {
+ ast_debug(4, "%s is unavailable because still in call, so we can`t check "
+ "wrapuptime (%d)\n", member->membername, q->wrapuptime);
+ break;
} else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
break;
@@ -2298,6 +2311,9 @@ static int is_member_available(struct call_queue *q, struct member *mem)
}
/* Let wrapuptimes override device state availability */
+ if (q->wrapuptime && mem->in_call) {
+ available = 0; /* member is still in call, cant check wrapuptime to lastcall time */
+ }
if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {
available = 0;
}
@@ -2650,6 +2666,7 @@ static void clear_queue(struct call_queue *q)
while ((mem = ao2_iterator_next(&mem_iter))) {
mem->calls = 0;
mem->lastcall = 0;
+ mem->in_call = 0;
ao2_ref(mem, -1);
}
ao2_iterator_destroy(&mem_iter);
@@ -4147,6 +4164,12 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
return 0;
}
+ if (call->member->in_call && call->lastqueue->wrapuptime) {
+ ast_debug(1, "%s is in call, so not available (wrapuptime %d)\n",
+ call->interface, call->lastqueue->wrapuptime);
+ return 0;
+ }
+
if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))
|| (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {
ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
@@ -5369,6 +5392,9 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
time(&mem->lastcall);
mem->calls++;
mem->lastqueue = q;
+ mem->in_call = 0;
+ ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n",
+ mem->membername, (long)mem->lastcall);
ao2_ref(mem, -1);
}
ao2_unlock(qtmp);
@@ -5380,6 +5406,9 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
time(&member->lastcall);
member->calls++;
member->lastqueue = q;
+ member->in_call = 0;
+ ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n",
+ member->membername, (long)member->lastcall);
ao2_unlock(q);
}
ao2_lock(q);
@@ -6358,6 +6387,9 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
int callcompletedinsl;
struct ao2_iterator memi;
struct queue_end_bridge *queue_end_bridge = NULL;
+ struct ao2_iterator queue_iter; /* to iterate through all queues (for shared_lastcall)*/
+ struct member *mem;
+ struct call_queue *queuetmp;
memset(&bridge_config, 0, sizeof(bridge_config));
tmpid[0] = 0;
@@ -6783,6 +6815,28 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
}
}
qe->handled++;
+
+ /** mark member as "in_call" in all queues */
+ if (shared_lastcall) {
+ queue_iter = ao2_iterator_init(queues, 0);
+ while ((queuetmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
+ ao2_lock(queuetmp);
+ if ((mem = ao2_find(queuetmp->members, member, OBJ_POINTER))) {
+ mem->in_call = 1;
+ ast_debug(4, "Marked member %s as in_call \n", mem->membername);
+ ao2_ref(mem, -1);
+ }
+ ao2_unlock(queuetmp);
+ queue_t_unref(queuetmp, "Done with iterator");
+ }
+ ao2_iterator_destroy(&queue_iter);
+ } else {
+ ao2_lock(qe->parent);
+ member->in_call = 1;
+ ast_debug(4, "Marked member %s as in_call \n", member->membername);
+ ao2_unlock(qe->parent);
+ }
+
ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
@@ -9153,10 +9207,11 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
- ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s (%s%s%s)",
+ ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s%s%s%s (%s%s%s)",
mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
mem->paused ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->paused ? " (paused)" : "", ast_term_reset(),
+ mem->in_call ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->in_call ? " (in call)" : "", ast_term_reset(),
ast_term_color(
mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ?
COLOR_RED : COLOR_GREEN, COLOR_BLACK),
@@ -9524,13 +9579,15 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
"Penalty: %d\r\n"
"CallsTaken: %d\r\n"
"LastCall: %d\r\n"
+ "InCall: %d\r\n"
"Status: %d\r\n"
"Paused: %d\r\n"
"PausedReason: %s\r\n"
"%s"
"\r\n",
q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
- mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, mem->reason_paused, idText);
+ mem->penalty, mem->calls, (int)mem->lastcall, mem->in_call, mem->status,
+ mem->paused, mem->reason_paused, idText);
++q_items;
}
ao2_ref(mem, -1);