[svn-commits] irroot: branch irroot/distrotech-customers-10 r347940 - in /team/irroot/distr...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Dec 12 08:20:58 CST 2011


Author: irroot
Date: Mon Dec 12 08:20:50 2011
New Revision: 347940

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=347940
Log:
Multiple revisions 347656,347727,347812

........
  r347656 | jrose | 2011-12-08 22:43:20 +0200 (Thu, 08 Dec 2011) | 13 lines
  
  Fix regressed behavior of queue set penalty to work without specifying 'in <queuename>'
  
  r325483 caused a regression in Asterisk 10+ that would make Asterisk segfault when
  attempting to set penalty on an interface without specifying a queue in the queue set
  penalty CLI command. In addition, no attempt would be made whatsoever to perform the
  penalty setting on all the queues in the core list with either the cli command or the
  non-segfaulting ami equivalent. This patch fixes that and also makes an attempt to
  document and rename some functions required by this command to better represent what
  they actually do. Oh yeah, and the use of this command without specifying a specific
  queue actually works now.
  
  Review: https://reviewboard.asterisk.org/r/1609/
........
  r347727 | wdoekes | 2011-12-08 23:31:00 +0200 (Thu, 08 Dec 2011) | 12 lines
  
  Fix regression when using tcpenable=no and tlsenable=yes.
  
  The tlsenable settings are tucked away in main/tcptls.c, so I missed
  them when resolving ASTERISK-18837. This should resolve the test suite
  breakage of the sip tls tests.
  
  Review: https://reviewboard.asterisk.org/r/1615
  Reviewed by: Matt Jordan
  ........
  
  Merged revisions 347718 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r347812 | rmudgett | 2011-12-09 03:29:59 +0200 (Fri, 09 Dec 2011) | 33 lines
  
  Fix some parsing issues in add_exten_to_pattern_tree().
  
  * Simplify compare_char() and avoid potential sign extension issue.
  
  * Fix infinite loop in add_exten_to_pattern_tree() handling of character
  set escape handling.
  
  * Added buffer overflow checks in add_exten_to_pattern_tree() character
  set collection.
  
  * Made ignore empty character sets.
  
  * Added escape character handling to end-of-range character in character
  sets.  This has a slight change in behavior if the end-of-range character
  is an escape character.  You must now escape it.
  
  * Fix potential sign extension issue when expanding character set ranges.
  
  * Made remove duplicated characters from character sets.  The duplicate
  characters lower extension matching priority and prevent duplicate
  extension detection.
  
  * Fix escape character handling when the escape character is trying to
  escape the end-of-string.  We could have continued processing characters
  after the end of the exten string.  We could have added the previous
  character to the pattern matching tree incorrectly.
  
  (closes issue ASTERISK-18909)
  Reported by: Luke-Jr
  ........
  
  Merged revisions 347811 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 347656,347727,347812 from http://svn.asterisk.org/svn/asterisk/branches/10

Modified:
    team/irroot/distrotech-customers-10/   (props changed)
    team/irroot/distrotech-customers-10/apps/app_queue.c
    team/irroot/distrotech-customers-10/channels/chan_sip.c
    team/irroot/distrotech-customers-10/main/pbx.c

Propchange: team/irroot/distrotech-customers-10/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/irroot/distrotech-customers-10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Propchange: team/irroot/distrotech-customers-10/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Dec 12 08:20:50 2011
@@ -1,1 +1,1 @@
-/branches/10:1-347610
+/branches/10:1-347939

Modified: team/irroot/distrotech-customers-10/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/irroot/distrotech-customers-10/apps/app_queue.c?view=diff&rev=347940&r1=347939&r2=347940
==============================================================================
--- team/irroot/distrotech-customers-10/apps/app_queue.c (original)
+++ team/irroot/distrotech-customers-10/apps/app_queue.c Mon Dec 12 08:20:50 2011
@@ -25,17 +25,18 @@
  * \arg Config in \ref Config_qu queues.conf
  *
  * \par Development notes
- * \note 2011-11-01: Made application more thread safe
+ * \note 2011-11-01: Reworked to seperate structures make more thread safe
  *		Distrotech PTY (LTD) (www.distrotech.co.za)
  *		Gregory Nietsky (irroot) <gregory at distrotech.co.za>
  *
  *		Split away from locking queues/queue to having locks per
- *		Queue/Member/Device.
+ *		Queue Data/Member/Device.
  *		Added device state struct to mange device states shared
  *		for multiple members sharing same device.
+ *		Added queue data struct to mange queue data.
  *
  *		Made all functions work with realtime/dynamic/static members.
- *		Added missing CLI/AMI functions for handling callinuse.
+ *		Added missing CLI/AMI functions for handling callinuse (ignorebusy).
  *
  * \note 2004-11-25: Persistent Dynamic Members added by:
  *             NetNation Communications (www.netnation.com)
@@ -117,25 +118,22 @@
  * \par Please read before modifying this file.
  * There are locks which are regularly used
  * throughout this file, the lock
- * for each individual queue, the individual member lock ,
+ * for each individual queue, queue data, the individual member lock ,
  * and the device state lock.
  * there are container locks for the queues list, the member
- * list on each queue and the devices container.
+ * list on each queue the devices container and rules container.
+ * in the queue data struct there is linked lists for the entries in queue.
  * Please be extra careful to always lock in the following order
  *
- * 1) queues container lock (ao2 functions that lock the container)
- * 2) queue lock
- * 3) queue member lock
- * 4) member lock
- * 5) devices container lock
- * 6) member device lock
+ * 1) container lock first
+ * 2) container element
+ *
+ * Never call a function on a container while a element is locked
+ *
  * This order has sort of "evolved" over the lifetime of this
  * application, but it is now in place this way, so please adhere
  * to this order!
  *
- * the only elements that do not require a read lock (ie will not change)
- * the queue name and members container, the member interface and
- * device state_interface as they are never altered after been linked.
  */
 
 /*** DOCUMENTATION
@@ -270,7 +268,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -312,7 +309,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -349,7 +345,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -393,7 +388,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -434,7 +428,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -465,7 +458,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -519,7 +511,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -575,34 +566,6 @@
 			<ref type="application">UnpauseQueueMember</ref>
 			<ref type="function">QUEUE_VARIABLES</ref>
 			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
-			<ref type="function">QUEUE_EXISTS</ref>
-			<ref type="function">QUEUE_WAITING_COUNT</ref>
-			<ref type="function">QUEUE_MEMBER_LIST</ref>
-			<ref type="function">QUEUE_MEMBER_PENALTY</ref>
-		</see-also>
-	</function>
-	<function name="QUEUE_MEMBER_COUNT" language="en_US">
-		<synopsis>
-			Count number of members answering a queue.
-		</synopsis>
-		<syntax>
-			<parameter name="queuename" required="true" />
-		</syntax>
-		<description>
-			<para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
-			<warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
-		</description>
-		<see-also>
-			<ref type="application">Queue</ref>
-			<ref type="application">QueueLog</ref>
-			<ref type="application">AddQueueMember</ref>
-			<ref type="application">RemoveQueueMember</ref>
-			<ref type="application">PauseQueueMember</ref>
-			<ref type="application">UnpauseQueueMember</ref>
-			<ref type="function">QUEUE_VARIABLES</ref>
-			<ref type="function">QUEUE_MEMBER</ref>
-			<ref type="function">QUEUE_MEMBER_COUNT</ref>
 			<ref type="function">QUEUE_EXISTS</ref>
 			<ref type="function">QUEUE_WAITING_COUNT</ref>
 			<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -949,22 +912,20 @@
                                                      The default value of 15 provides backwards compatibility */
 #define MAX_QUEUE_BUCKETS 53
 
-#define	RES_OKAY	0		/*!< Action completed */
-#define	RES_EXISTS	(-1)		/*!< Entry already exists */
-#define	RES_OUTOFMEMORY	(-2)		/*!< Out of memory */
-#define	RES_NOSUCHQUEUE	(-3)		/*!< No such queue */
-#define RES_NOT_DYNAMIC (-4)		/*!< Member is not dynamic */
-#define RES_ERROR	(-5)		/*!< Member is mis configured */
+enum member_result {
+	RES_OKAY = 0,			/*!< Action completed */
+	RES_EXISTS = -1,		/*!< Entry already exists */
+	RES_OUTOFMEMORY	= -2,		/*!< Out of memory */
+	RES_NOSUCHQUEUE	= -3,		/*!< No such queue */
+	RES_NOT_DYNAMIC = -4,		/*!< Member is not dynamic */
+	RES_ERROR = -5,			/*!< Member is mis configured */
+};
+
 static char *app = "Queue";
-
 static char *app_aqm = "AddQueueMember" ;
-
 static char *app_rqm = "RemoveQueueMember" ;
-
 static char *app_pqm = "PauseQueueMember" ;
-
 static char *app_upqm = "UnpauseQueueMember" ;
-
 static char *app_ql = "QueueLog" ;
 
 /*! \brief Persistent Members astdb family */
@@ -1037,14 +998,15 @@
 
 struct callattempt {
 	struct ast_channel *chan;                  /*! Channel called */
-	int stillgoing;                            /*! This attempt is valid and active */
 	int metric;                                /*! Metric calculated according to strategy */
 	struct member *member;                     /*! Member assosiated with this attempt */
 	struct ast_party_connected_line connected; /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
+	unsigned int stillgoing:1;                 /*! This attempt is valid and active */
 	unsigned int reserved:1;                   /*! Is this attempt been attempted*/
 	unsigned int active:1;                     /*! Is this attempt active in a call*/
 	unsigned int pending_connected_update:1;   /*! TRUE if caller id is not available for connected line*/
 	unsigned int dial_callerid_absent:1;       /*! TRUE if caller id is not available for connected line */
+	unsigned int watching:1;                   /*! TRUE if callattempt is been watched */
 	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
@@ -1188,7 +1150,6 @@
 	int strategy:4;
 	unsigned int maskmemberstatus:1;
 	unsigned int realtime:1;
-	unsigned int found:1;
 	unsigned int relativeperiodicannounce:1;
 	unsigned int autopausebusy:1;
 	unsigned int autopauseunavail:1;
@@ -1249,7 +1210,6 @@
 static char *queue_refshow(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static struct member *interface_exists(struct call_queue *q, const char *interface);
 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
-
 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
 
 /*! \brief sets the QUEUESTATUS channel variable */
@@ -1331,9 +1291,13 @@
 static int queue_cmp_cb(void *obj, void *arg, int flags)
 {
 	const struct call_queue *q = obj, *q2 = arg;
-	const char *name = (flags & OBJ_POINTER) ? q2->name : arg;
-
-	return !strcasecmp(q->name, name) ? CMP_MATCH | CMP_STOP : 0;
+	const char *name = (arg && (flags & OBJ_POINTER)) ? q2->name : arg;
+
+	if (!ast_strlen_zero(name) && !strcasecmp(q->name, name)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1356,9 +1320,14 @@
 {
 	const struct queue_data *d = obj, *d2 = arg;
 	const char *name = arg;
-	int qhash = (flags & OBJ_POINTER) ? d2->qhash : ast_str_case_hash(name);
-
-	return  (d->qhash == qhash) ? CMP_MATCH | CMP_STOP : 0;
+	int nhash = (ast_strlen_zero(name)) ? 0 : ast_str_case_hash(name);
+	int qhash = (arg && (flags & OBJ_POINTER)) ? d2->qhash : nhash;
+
+	if (qhash && (d->qhash == qhash)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*! \brief Set channel variables of queue */
@@ -1416,7 +1385,6 @@
 			/* if im active and may not place calls when INUSE im actually BUSY */
 			if ((s->reserved || s->active) && !m->callinuse) {
 				ret = AST_DEVICE_BUSY;
-				break;
 			}
 			break;
 		case AST_DEVICE_NOT_INUSE:
@@ -1444,8 +1412,6 @@
 	struct member *member;
 	struct ao2_iterator mem_iter;
 	struct call_queue *q = qe->parent;
-	int max_penalty = qe->max_penalty;
-	int min_penalty = qe->min_penalty;
 	enum empty_conditions conditions;
 
 	conditions = (join) ? q->joinempty : q->leavewhenempty;
@@ -1457,9 +1423,9 @@
 	mem_iter = ao2_iterator_init(q->data->members, 0);
 	while((member = ao2_iterator_next(&mem_iter))) {
 		ao2_lock(member);
-		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
+		if ((qe->max_penalty && (member->penalty > qe->max_penalty)) || (qe->min_penalty && (member->penalty < qe->min_penalty))) {
 			if (conditions & QUEUE_EMPTY_PENALTY) {
-				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
+				ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, qe->min_penalty, qe->max_penalty);
 				ao2_unlock(member);
 				ao2_ref(member, -1);
 				continue;
@@ -1778,9 +1744,13 @@
 {
 	const struct member *mem1 = obj1;
 	const struct member *mem2 = obj2;
-	const char *arg = (flags & OBJ_POINTER) ? mem2->interface : obj2;
-
-	return strcasecmp(mem1->interface, arg) ? 0 : CMP_MATCH | CMP_STOP;
+	const char *iface = (obj2 && (flags & OBJ_POINTER)) ? mem2->interface : obj2;
+
+	if (!ast_strlen_zero(iface) && !strcasecmp(mem1->interface, iface)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1790,9 +1760,9 @@
 {
 	const struct member *mem1 = obj1;
 	const struct member *mem2 = arg;
-	const char *uniqueid = (flags & OBJ_POINTER) ? mem2->rt_uniqueid : arg;
-
-	if (mem1->realtime && !mem1->dead &&
+	const char *uniqueid = (arg && (flags & OBJ_POINTER)) ? mem2->rt_uniqueid : arg;
+
+	if (mem1->realtime && !mem1->dead && !ast_strlen_zero(uniqueid) &&
 	    !strcasecmp(mem1->rt_uniqueid, uniqueid)) {
 		return CMP_MATCH | CMP_STOP;
 	}
@@ -1823,13 +1793,13 @@
 	const struct call_queue *q = data;
 
 	if (m->realtime && m->dead) {
-		ao2_lock(m);
-		if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
+		if (!log_membername_as_agent) {
 			ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
 		} else {
+			ao2_lock(m);
 			ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
-		}
-		ao2_unlock(m);
+			ao2_unlock(m);
+		}
 		return CMP_MATCH;
 	}
 	return 0;
@@ -1868,9 +1838,13 @@
 {
 	const struct mem_state *d = obj;
 	const struct mem_state *d2 = arg;
-	const char *iface = (flags & OBJ_POINTER) ? d2->state_interface : arg;
-
-	return !strcasecmp(d->state_interface, iface) ? CMP_MATCH | CMP_STOP : 0;
+	const char *iface = (arg && (flags & OBJ_POINTER)) ? d2->state_interface : arg;
+
+	if (!ast_strlen_zero(iface) && !strcasecmp(d->state_interface, iface)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1921,9 +1895,13 @@
 {
 	const struct rule_list *rl = obj;
 	const struct rule_list *rl2 = arg;
-	const char *name = (flags & OBJ_POINTER) ? rl2->name : arg;
-
-	return !strcasecmp(rl->name, name) ? CMP_MATCH | CMP_STOP : 0;
+	const char *name = (arg && (flags & OBJ_POINTER)) ? rl2->name : arg;
+
+	if (!ast_strlen_zero(name) && !strcasecmp(rl->name, name)) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
 }
 
 /*!
@@ -1938,6 +1916,21 @@
 	return ast_str_case_hash(interface);
 }
 
+/*!
+ * \brief ao2 callback to find callattempt been watched
+ */
+static int callattempt_watched_cb(void *obj, void *arg, const int flags)
+{
+	const struct callattempt *c = obj;
+	const struct callattempt *c1 = arg;
+	const struct member *mem = (arg) ? c1->member : NULL;
+	const char *interface = (arg && (flags & OBJ_POINTER)) ? mem->interface : arg;
+
+	if (!arg || ast_strlen_zero(interface) || !strcasecmp(interface, c->member->interface)) {
+		return (c->stillgoing && c->chan) ? CMP_MATCH : 0;
+	}
+	return 0;
+}
 
 /*!
  * \brief ao2 callback to obtain the callattempt with best metric
@@ -2001,7 +1994,6 @@
 	q->autopause = QUEUE_AUTOPAUSE_OFF;
 	q->timeoutpriority = TIMEOUT_PRIORITY_APP;
 	q->autopausedelay = 0;
-	q->found = 1;
 
 	ast_string_field_set(q, sound_next, "queue-youarenext");
 	ast_string_field_set(q, sound_thereare, "queue-thereare");
@@ -2375,6 +2367,11 @@
 	char *rt_uniqueid = NULL, *st_dev = NULL;
 	int dead = 0;
 
+	if (ast_strlen_zero(interface)) {
+		ast_log(AST_LOG_ERROR, "Interface was not specified !!\n");
+		return RES_ERROR;
+	}
+
 	if (!(m = ao2_find(q->data->members, (char *)interface, 0))) {
 		if (!(m = ao2_alloc(sizeof(*m), remove_queue_member))) {
 			return RES_OUTOFMEMORY;
@@ -2472,7 +2469,7 @@
 		}
 	}
 
-	if (!dead && !m->device && (!(m->device = create_member_state(st_dev)))) {
+	if (!dead && !m->device && !(m->device = create_member_state(st_dev))) {
 		dead = 1;
 	}
 
@@ -2481,7 +2478,7 @@
 	}
 
 	/*check the uniqueness of the RT uniqueid */
-	if (link && (memtype & QUEUE_ADD_MEMBER_REALTIME) && !dead) {
+	if (!dead && link && (memtype & QUEUE_ADD_MEMBER_REALTIME)) {
 		if (ast_strlen_zero(rt_uniqueid)) {
 			ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(m->membername, interface));
 			dead = 1;
@@ -2502,10 +2499,10 @@
 		int status = get_device_status(m);
 
 		/* i have just been born */
-		if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
-			ast_queue_log(q->name, source, m->interface, "ADDMEMBER", "%s", "");
+		if (!log_membername_as_agent) {
+			ast_queue_log(q->name, source, m->interface, "ADDMEMBER", "%s", m->paused ? "PAUSED" : "");
 		} else {
-			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", "");
+			ast_queue_log(q->name, source, m->membername, "ADDMEMBER", "%s", m->paused ? "PAUSED" : "");
 		}
 		manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
 			"Queue: %s\r\n"
@@ -2532,7 +2529,7 @@
 		}
 		if (!link) {
 			/* thee was a config error remove this member from container now*/
-			if ((ast_strlen_zero(m->membername) || !log_membername_as_agent)) {
+			if (!log_membername_as_agent) {
 				ast_queue_log(q->name, source, m->interface, "REMOVEMEMBER", "%s", "");
 			} else {
 				ast_queue_log(q->name, source, m->membername, "REMOVEMEMBER", "%s", "");
@@ -2646,83 +2643,41 @@
 
 	ast_string_field_set(q, name, queuename);
 	q->realtime = rt;
-	q->weight = 0;
-	q->found = 0;
+
+	/* Ensure defaults for all parameters not set explicitly. */
+	init_queue(q);
 
 	return q;
 }
 
-/*!
- * \brief Reload a single queue via realtime.
+/*
  *
- * Check for statically defined queue first, check if deleted RT queue,
- * check for new RT queue, if queue vars are not defined init them with defaults.
- * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
- * \retval the queue,
- * \retval NULL if it doesn't exist.
-*/
-static struct call_queue *load_realtime_queue(const char *queuename, struct ast_flags *mask)
-{
+ */
+static struct call_queue *config_call_queue(struct call_queue *oldq, struct ast_variable *queue_vars, const char *queuename, int reload_members)
+{
+	int prev_weight = 0;
 	struct ast_variable *v;
+	char *tmp;
 	const char *tmp_name;
-	char *tmp;
 	char tmpbuf[64];	/* Must be longer than the longest queue param name. */
-	int prev_weight = 0;
-	struct ast_variable *queue_vars;
-	struct call_queue *q, *oldq;
-	int found;
-	int reload_queue = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS) : 0;
-	int reload_members = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_MEMBER) : 0;
-	int reload_realtime = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_REALTIME) : 0;
-
-	if ((q = ao2_t_find(queues, (char *)queuename, 0, "Look for queue in memory first")) &&
-	    (!q->realtime || !reload_queue)) {
-		if (reload_members) {
-			rt_load_member_config(q);
-		}
-		return q;
-	}
-
-	if (!reload_realtime && q && !ast_tvzero(q->reload) && ast_tvdiff_sec(ast_tvnow(), q->reload)) {
-		ast_log(AST_LOG_WARNING, "Not reloading queue for next %ld Seconds\n", (long)ast_tvdiff_sec(q->reload, ast_tvnow()));
-		return q;
-	}
-
-	/*! \note The queue is recreated and the existing queue will not change and any
-		users holding a ref to the queue will have no changes applied. */
-
-	/* Check if queue is defined in realtime. */
-	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
-		/* Delete queue from in-core list if it has been deleted in realtime. */
-		if (q) {
-			/*! \note Hmm, can't seem to distinguish a DB failure from a not
-			   found condition... So we might delete an in-core queue
-			   in case of DB failure. */
-			ast_debug(1, "Queue %s not found in realtime.\n", queuename);
-			ao2_t_unlink(queues, q, "Unused; removing from container");
-			ao2_t_ref(q, -1, "Queue is dead; can't return it");
-		}
-		return NULL;
-	}
+	struct call_queue *q;
 
 	/* Create a new queue if an in-core entry does not exist yet. */
-	if (!q && (!(q = alloc_queue(queuename, 1)))) {
+	if (!oldq && !(q = alloc_queue(queuename, 1))) {
 		ast_variables_destroy(queue_vars);
 		return NULL;
-	} else {
-		found = q->found;
-		prev_weight = q->weight ? 1 : 0;
-
-		oldq = q;
+	} else if (oldq) {
+		prev_weight = oldq->weight ? 1 : 0;
+		/*! \note The queue is recreated and the existing queue will not change and any
+		 *users holding a ref to the queue will have no changes applied.
+		 */
 		if (!(q = alloc_queue(queuename, 1))) {
 			/* i could not allocate new structure return the old one*/
 			ast_log(AST_LOG_WARNING, "Failed to assign new queue object returning unchanged object\n");
 			ast_variables_destroy(queue_vars);
-			return oldq;
-		}
-	}
-
-	init_queue(q);		/* Ensure defaults for all parameters not set explicitly. */
+			return NULL;
+		}
+	}
 
 	memset(tmpbuf, 0, sizeof(tmpbuf));
 	for (v = queue_vars; v; v = v->next) {
@@ -2752,7 +2707,6 @@
 	}
 
 	/* update the use_weight value if the queue's has gained or lost a weight */
-	/* Other cases will end up with the proper value for use_weight */
 	if (!q->weight && prev_weight) {
 		ast_atomic_fetchadd_int(&use_weight, -1);
 	} else if (q->weight && !prev_weight) {
@@ -2760,7 +2714,7 @@
 	}
 
 	/* add persistent members to new queue*/
-	if (!found && queue_persistent_members) {
+	if (!oldq && queue_persistent_members) {
 		pm_load_member_config(q);
 	}
 
@@ -2778,7 +2732,61 @@
 	} else {
 		ao2_link(queues, q);
 	}
+
 	return q;
+}
+
+/*!
+ * \brief Reload a single queue via realtime.
+ *
+ * Check for statically defined queue first, check if deleted RT queue,
+ * check for new RT queue, if queue vars are not defined init them with defaults.
+ * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
+ * \retval the queue,
+ * \retval NULL if it doesn't exist.
+*/
+static struct call_queue *load_realtime_queue(const char *queuename, struct ast_flags *mask)
+{
+	struct ast_variable *queue_vars;
+	struct call_queue *oldq;
+
+	int reload_queue = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS) : 0;
+	int reload_members = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_MEMBER) : 0;
+	int reload_realtime = (mask) ? ast_test_flag(mask, QUEUE_RELOAD_REALTIME) : 0;
+
+	/* return if im not realtime or not reloading the queue possibly checking members */
+	if ((oldq = ao2_t_find(queues, (char *)queuename, 0, "Look for queue in memory first")) &&
+	    (!oldq->realtime || !(reload_queue || reload_realtime))) {
+		if (reload_members) {
+			rt_load_member_config(oldq);
+		}
+		return oldq;
+	} else if (!oldq && !(reload_queue || reload_realtime)) {
+		ast_debug(1, "Not loading queue %s at this time\n",queuename);
+		return NULL;
+	}
+
+	/* if im reloading realtime (CLI/AMI) i ignore cache timer */
+	if (!reload_realtime && oldq && !ast_tvzero(oldq->reload) &&
+	    (ast_tvcmp(ast_tvnow(), oldq->reload) < 0)) {
+		ast_debug(1, "Not reloading queue %s for next %ld Seconds\n", oldq->name, (long)ast_tvdiff_sec(oldq->reload, ast_tvnow()));
+		return oldq;
+	}
+
+	/* Check if queue is defined in realtime if im reloading */
+	if (!(queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL))) {
+		/* Delete queue from in-core list if it has been deleted in realtime.
+		 * ! \note On DB failure the queue will be removed as i cant distinguish a DB failure
+		 */
+		if (oldq) {
+			ast_debug(1, "Queue %s not found in realtime.\n", queuename);
+			ao2_t_unlink(queues, oldq, "Unused; removing from container");
+			ao2_t_ref(oldq, -1, "Queue is dead; can't return it");
+		}
+		return NULL;
+	}
+
+	return config_call_queue(oldq, queue_vars, queuename, reload_members);
 }
 
 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
@@ -2798,18 +2806,23 @@
 
 static void load_all_realtime_queues(struct ast_flags *mask)
 {
-	char *queuename;
+	const char *queuename;
 	struct ast_config *cfg;
 	struct call_queue *queue;
+	struct ast_category *cat;
+	struct ast_variable *var;
 
 	/* load realtime queues. */
 	if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
 		for (queuename = ast_category_browse(cfg, NULL);
 				!ast_strlen_zero(queuename);
 				queuename = ast_category_browse(cfg, queuename)) {
-			if ((queue = load_realtime_queue(queuename, mask))) {
-				ao2_ref(queue, -1);
-			}
+			cat = ast_category_get(cfg, queuename);
+			var = ast_category_detach_variables(cat);
+			queue = ao2_find(queues, (char *)queuename, 0);
+			queue = config_call_queue(queue, var, queuename, 1);
+			ao2_ref(queue, -1);
+
 		}
 		ast_config_destroy(cfg);
 	}
@@ -2817,36 +2830,34 @@
 
 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 {
-	struct call_queue *q;
 	struct queue_ent *cur;
 	int res = -1;
 	int pos = 0;
 	int inserted = 0;
 	struct ast_flags qflags = {QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER};
 
-	if (!(q = load_realtime_queue(queuename, &qflags))) {
+	/*obtain a ref for the queue reload realtime settings/members*/
+	if (!(qe->parent = load_realtime_queue(queuename, &qflags))) {
 		return res;
 	}
 
-	qe->parent = q;
-
 	/* This is our one */
-	if ((get_member_status(qe, 1))) {
+	if (get_member_status(qe, 1)) {
 		*reason = QUEUE_JOINEMPTY;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 		return res;
 	}
 
-	ao2_lock(q->data);
-	if ((*reason == QUEUE_UNKNOWN && q->maxlen && (q->data->count >= q->maxlen)) ||
+	ao2_lock(qe->parent->data);
+	if ((*reason == QUEUE_UNKNOWN && qe->parent->maxlen && (qe->parent->data->count >= qe->parent->maxlen)) ||
 	    (*reason != QUEUE_UNKNOWN)) {
-		ao2_unlock(q->data);
+		ao2_unlock(qe->parent->data);
 		*reason = QUEUE_FULL;
-		ao2_t_ref(q, -1, "Done with realtime queue");
+		ao2_t_ref(qe->parent, -1, "Done with realtime queue");
 
 		return res;
 	}
-	ao2_unlock(q->data);
+	ao2_unlock(qe->parent->data);
 
 
 	/* There's space for us, put us at the right position inside
@@ -2854,12 +2865,12 @@
 	 * Take into account the priority of the calling user */
 	inserted = 0;
 
-	AST_LIST_LOCK(q->data->head);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(q->data->head, cur, next) {
+	AST_LIST_LOCK(qe->parent->data->head);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(qe->parent->data->head, cur, next) {
 		/* We have higher priority than the current user, enter
 		 * before him, after all the other users with priority
 		 * higher or equal to our priority. */
-		if ((!inserted) && qe && (qe->prio > cur->prio)) {
+		if (!inserted && qe && (qe->prio > cur->prio)) {
 			AST_LIST_INSERT_BEFORE_CURRENT(qe, next);
 			insert_entry(qe, &pos);
 			inserted = 1;
@@ -2882,20 +2893,20 @@
 
 	/* No luck, join at the end of the queue */
 	if (!inserted && qe) {
-		AST_LIST_INSERT_TAIL(q->data->head, qe, next);
+		AST_LIST_INSERT_TAIL(qe->parent->data->head, qe, next);
 		insert_entry(qe, &pos);
 	}
-	AST_LIST_UNLOCK(q->data->head);
+	AST_LIST_UNLOCK(qe->parent->data->head);
 
 	/* pass a ref to the queue rules or this queue*/
 	qe->pr = NULL;
-	if ((qe->rules = ao2_find(rules, (char *)q->defaultrule, 0))) {
+	if ((qe->rules = ao2_find(rules, (char *)qe->parent->defaultrule, 0))) {
 		int time = 0;
 		ao2_callback_data(qe->rules->rules, OBJ_NODATA | OBJ_MULTIPLE, get_best_rule_cb, &time, &qe->pr);
 	}
 
 	res = 0;
-	ao2_lock(q->data);
+	ao2_lock(qe->parent->data);
 	ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
 		"Channel: %s\r\n"
 		"CallerIDNum: %s\r\n"
@@ -2911,9 +2922,9 @@
 		S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
 		S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
 		S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
-		q->name, qe->pos, q->data->count, qe->chan->uniqueid );
-	ao2_unlock(q->data);
-	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
+		qe->parent->name, qe->pos, qe->parent->data->count, qe->chan->uniqueid );
+	ao2_unlock(qe->parent->data);
+	ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", qe->parent->name, qe->chan->name, qe->pos );
 
 	return res;
 }
@@ -3306,43 +3317,35 @@
 {
 	struct call_queue *q;
 	struct member *mem;
-	int found = 0;
 	int count;
-	int rcount;
+	int res = 0;
 	struct ao2_iterator queue_iter;
-
-	ao2_lock(rq->data);
-	rcount = rq->data->count;
-	ao2_unlock(rq->data);
 
 	queue_iter = ao2_iterator_init(queues, 0);
 	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
-		if (q == rq) { /* don't check myself, could deadlock */
-			ao2_t_ref(q, -1, "Done with iterator");
+		/* don't check myself or queues with  lower weight*/
+		if ((q == rq) || (q->weight <= rq->weight)) {
+			ao2_ref(q, -1);
 			continue;
 		}
-
-		if (count && (mem = interface_exists(q, interface))) {
-			ao2_lock(q->data);
-			count = q->data->count;
-			ao2_unlock(q->data);
-
-			ao2_lock(mem);
-			ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
-			if (q->weight > rq->weight && count >= num_available_members(q)) {
-				ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, count, rq->name, rq->weight, rcount);
-				found = 1;
-			}
-			ao2_unlock(mem);
+		ao2_lock(q->data);
+		count = q->data->count;
+		ao2_unlock(q->data);
+		if (count && (mem = interface_exists(q, interface)) &&
+		    (count >= num_available_members(q))) {
 			ao2_ref(mem, -1);
+			ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d)\n",
+					q->name, q->weight, count, rq->name, rq->weight);
+			ao2_ref(q, -1);
+			res = 1;
+			break;
+		} else if (mem) {
+			ao2_ref(mem, -1);
 		}
 		ao2_ref(q, -1);
-		if (found) {
-			break;
-		}
 	}
 	ao2_iterator_destroy(&queue_iter);
-	return found;
+	return res;
 }
 
 /*! \brief common hangup actions */
@@ -3391,15 +3394,15 @@
 	return vars;
 }
 
-/*! 
+/*!
  * \brief Part 2 of ring_one
  *
  * Does error checking before attempting to request a channel and call a member.
  * This function is only called from ring_one().
  * Failure can occur if:
  * - Priority by another queue
+ * - Member is paused
  * - Wrapup time not expired
- * - Member is paused
  * - Member on call / or is not available for a call
  * - Channel cannot be created by driver
  * - Channel cannot be called by driver
@@ -3414,7 +3417,6 @@
 	char tech[256];
 	char *location;
 	const char *macrocontext, *macroexten;
-	struct mem_state *s;
 	int dstat;
 
 	/* we cannot take this call there is a more urgent call we qualify for */
@@ -3429,8 +3431,7 @@
 	}
 
 	ao2_lock(tmp->member);
-	s = tmp->member->device;
-
+	/* im paused i cannot take this call */
 	if (tmp->member->paused) {
 		ao2_unlock(tmp->member);
 		ast_debug(1, "%s paused, can't receive call\n", tmp->member->interface);
@@ -3472,6 +3473,7 @@
 
 	/* mark device and call entry reserved */
 	if (!tmp->reserved) {
+		struct mem_state *s = tmp->member->device;
 		ao2_lock(s);
 		s->reserved++;
 		ao2_unlock(s);
@@ -3487,17 +3489,16 @@
 	}
 
 	/* Request the peer */
-	tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
-	if (!tmp->chan) {			/* If we can't, just go on to the next call */
+	if (!(tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status))) {
 		if (qe->chan->cdr) {
 			ast_cdr_busy(qe->chan->cdr);
 		}
 		tmp->stillgoing = 0;
 
 		set_queue_member_status(tmp->member);
-		ao2_lock(qe->parent->data->members);
+		ao2_lock(qe->parent->data);
 		qe->parent->data->rrpos++;
-		ao2_unlock(qe->parent->data->members);
+		ao2_unlock(qe->parent->data);
 		qe->linpos++;
 
 		(*busies)++;
@@ -3837,11 +3838,9 @@
 	ao2_unlock(call->member);
 
 	if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
-		if (qe->parent->autopausedelay > 0) {
-			if (!ast_tvzero(call->member->lastcall) &&
-			    (ast_tvdiff_sec(ast_tvnow(), call->member->lastcall) < qe->parent->autopausedelay)) {
-				return;
-			}
+		if ((qe->parent->autopausedelay > 0) && !ast_tvzero(call->member->lastcall) &&
+		    (ast_tvdiff_sec(ast_tvnow(), call->member->lastcall) < qe->parent->autopausedelay)) {
+			return;
 		}
 		if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
 			ao2_lock(call->member);
@@ -3897,8 +3896,7 @@
 	struct ast_channel *in = qe->chan;
 	long starttime = 0;
 	long endtime = 0;
-	struct ao2_iterator aiter;
-	struct ao2_container *calls;
+	struct ao2_iterator aiter, *calls;
 #ifdef HAVE_EPOLL
 	struct callattempt *epollo;
 #endif
@@ -3923,8 +3921,6 @@
 	ao2_iterator_destroy(&aiter);
 #endif
 
-	calls = ao2_container_alloc(MAX_QUEUE_BUCKETS, callattempt_hash_fn, NULL);
-
 	while (*to && !peer) {
 		int numlines, retry, pos = 1;
 		struct ast_channel *watchers[AST_MAX_WATCHERS];
@@ -3936,13 +3932,9 @@
 			while ((o = ao2_iterator_next(&aiter))) {
 				if (o->stillgoing) {	/* Keep track of important channels */
 					stillgoing = 1;
-					if (o->chan) {
-						if (pos < AST_MAX_WATCHERS) {
-							watchers[pos++] = o->chan;
-						}
-						if (!retry) {
-							ao2_link(calls, o);
-						}
+					if (o->chan && !o->watching && (pos < AST_MAX_WATCHERS)) {
+						watchers[pos++] = o->chan;
+						o->watching = 1;
 					}
 				}
 				numlines++;
@@ -3965,8 +3957,6 @@
 				ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
 			}
 			*to = 0;
-			ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-			ao2_ref(calls, -1);
 			return NULL;
 		}
 
@@ -3974,18 +3964,27 @@
 		winner = ast_waitfor_n(watchers, pos, to);
 
 		/* Service all of the outgoing channels */
-		aiter = ao2_iterator_init(calls, 0);
-		while ((o = ao2_iterator_next(&aiter))) {
+		calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+		while (calls && (o = ao2_iterator_next(calls))) {
 			/* We go with a static buffer here instead of using ast_strdupa. Using
 			 * ast_strdupa in a loop like this one can cause a stack overflow
 			 */
 			char ochan_name[AST_CHANNEL_NAME];
+
+			/* i need to be re added to the watchers */
+			if (!o->watching) {
+				ao2_ref(o, -1);
+				continue;
+			} else {
+				o->watching = 0;
+			}
+
 			if (o->chan) {
 				ast_channel_lock(o->chan);
 				ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
 				ast_channel_unlock(o->chan);
 			}
-			if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
+			if (o->stillgoing && o->chan &&  (o->chan->_state == AST_STATE_UP)) {
 				if (!peer) {
 					ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
 					if (update_connectedline) {
@@ -4058,7 +4057,6 @@
 						struct ast_party_redirecting redirecting;
 
 						ast_channel_lock_both(o->chan, in);
-
 						ast_channel_inherit_variables(in, o->chan);
 						ast_channel_datastore_inherit(in, o->chan);
 
@@ -4266,7 +4264,9 @@
 			}
 			ao2_ref(o, -1);
 		}
-		ao2_iterator_destroy(&aiter);
+		if (calls) {
+			ao2_iterator_destroy(calls);
+		}
 
 		/* If we received an event from the caller, deal with it. */
 		if (winner == in) {
@@ -4280,8 +4280,6 @@
 					}
 					ast_frfree(f);
 				}
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4291,8 +4289,6 @@
 				ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 				*to = 0;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4303,8 +4299,6 @@
 				*to = 0;
 				*digit = f->subclass.integer;
 				ast_frfree(f);
-				ao2_callback(calls, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-				ao2_ref(calls, -1);
 				if (peer) {
 					ao2_ref(peer, -1);
 				}
@@ -4313,17 +4307,16 @@
 			ast_frfree(f);
 		}
 		if (!*to) {
-			aiter = ao2_iterator_init(calls, AO2_ITERATOR_UNLINK);
-			while ((o = ao2_iterator_next(&aiter))) {
+			calls = ao2_find(qe->attempts, NULL, OBJ_MULTIPLE);
+			while (calls && (o = ao2_iterator_next(calls))) {
 				rna(orig, qe, o, 1);
 				ao2_ref(o, -1);
 			}
-			ao2_iterator_destroy(&aiter);
-		}
-

[... 911 lines stripped ...]



More information about the svn-commits mailing list