[Asterisk-code-review] app queue: Add member flag "in call" to prevent reading wron... (asterisk[master])

Martin Tomec asteriskteam at digium.com
Tue Dec 22 02:53:10 CST 2015


Martin Tomec has uploaded a new change for review.

  https://gerrit.asterisk.org/1847

Change subject: app_queue: Add member flag "in_call" to prevent reading wrong lastcall time
......................................................................

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
---
M apps/app_queue.c
1 file changed, 49 insertions(+), 9 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/47/1847/1

diff --git a/apps/app_queue.c b/apps/app_queue.c
index 416ebff..c541826 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1540,6 +1540,7 @@
 	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 */
@@ -2177,7 +2178,7 @@
 
 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,
@@ -2186,6 +2187,7 @@
 		"Penalty", mem->penalty,
 		"CallsTaken", mem->calls,
 		"LastCall", (int)mem->lastcall,
+		"InCall", mem->in_call,
 		"Status", mem->status,
 		"Paused", mem->paused,
 		"PausedReason", mem->reason_paused,
@@ -2248,6 +2250,9 @@
 		default_case:
 			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);
@@ -2316,6 +2321,9 @@
 	}
 
 	/* 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;
 	}
@@ -2668,6 +2676,7 @@
 		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);
@@ -4165,6 +4174,11 @@
 		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",
@@ -5214,11 +5228,6 @@
 		res = 0;
 	}
 
-	/* Update realtime members if this is the first call and number of avalable members is 0 */
-	if (avl == 0 && qe->pos == 1) {
-		update_realtime_members(qe->parent);
-	}
-
 	return res;
 }
 
@@ -5387,6 +5396,8 @@
 				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);
@@ -5398,6 +5409,8 @@
 		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);
@@ -6376,6 +6389,9 @@
 	int callcompletedinsl;
 	struct ao2_iterator memi;
 	struct queue_end_bridge *queue_end_bridge = NULL;
+	struct ao2_iterator queue_iter; /* for shared_lastcall we need to iterate through all queues */
+	struct member *mem;
+	struct call_queue *queuetmp;
 
 	memset(&bridge_config, 0, sizeof(bridge_config));
 	tmpid[0] = 0;
@@ -6801,6 +6817,28 @@
 			}
 		}
 		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", mem->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));
 
@@ -9255,9 +9293,10 @@
 
 				ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
 
-				ast_str_append(&out, 0, "%s%s%s%s%s%s",
+				ast_str_append(&out, 0, "%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->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
+					mem->in_call ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->in_call ? " (in call)" : "", ast_term_reset());
 				if (mem->paused) {
 					if (ast_strlen_zero(mem->reason_paused)) {
 						ast_str_append(&out, 0, " %s(paused)%s",
@@ -9636,13 +9675,14 @@
 						"Penalty: %d\r\n"
 						"CallsTaken: %d\r\n"
 						"LastCall: %d\r\n"
+						"IsInCall: %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);

-- 
To view, visit https://gerrit.asterisk.org/1847
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1923230cf9859ee51563a8ed420a0628b4d2e500
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Martin Tomec <tomec.martin at gmail.com>



More information about the asterisk-code-review mailing list