[MINOR] acl: add fe_conn, be_conn, queue, avg_queue

These ACLs are used to check the number of active connections on the
frontend, backend or in a backend's queue. The avg_queue returns the
average number of queued connections per server, and for this, divides
the total number of queued connections by the number of alive servers.

The dst_conn ACL has been slightly changed to more reflect its name and
original usage, which is to return the number of connections on the
destination address/port (the socket) and not the whole frontend.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index fecab81..7e96594 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -5041,10 +5041,30 @@
   to a different backend for some alternative ports.
 
 dst_conn <integer>
-  Applies to the number of currently established connections on the frontend,
+  Applies to the number of currently established connections on the same socket
   including the one being evaluated. It can be used to either return a sorry
   page before hard-blocking, or to use a specific backend to drain new requests
-  when the farm is considered saturated.
+  when the socket is considered saturated. This offers the ability to assign
+  different limits to different listening ports or addresses. See also the
+  "fe_conn" and "be_conn" criteria.
+
+fe_conn <integer>
+fe_conn(frontend) <integer>
+  Applies to the number of currently established connections on the frontend,
+  possibly including the connection being evaluated. If no frontend name is
+  specified, the current one is used. But it is also possible to check another
+  frontend. It can be used to either return a sorry page before hard-blocking,
+  or to use a specific backend to drain new requests when the farm is
+  considered saturated. See also the "dst_conn", "be_conn" and "fe_sess_rate"
+  criteria.
+
+be_conn <integer>
+be_conn(frontend) <integer>
+  Applies to the number of currently established connections on the backend,
+  possibly including the connection being evaluated. If no backend name is
+  specified, the current one is used. But it is also possible to check another
+  backend. It can be used to use a specific farm when the nominal one is full.
+  See also the "fe_conn", "queue" and "be_sess_rate" criteria.
 
 nbsrv <integer>
 nbsrv(backend) <integer>
@@ -5063,19 +5083,43 @@
   'connslots' = number of available server connection slots, + number of
   available server queue slots.
 
-  Note that while "dst_conn" may be used, "connslots" comes in especially
+  Note that while "fe_conn" may be used, "connslots" comes in especially
   useful when you have a case of traffic going to one single ip, splitting into
   multiple backends (perhaps using acls to do name-based load balancing) and
   you want to be able to differentiate between different backends, and their
   available "connslots".  Also, whereas "nbsrv" only measures servers that are
   actually *down*, this acl is more fine-grained and looks into the number of
-  available connection slots as well.
+  available connection slots as well. See also "queue" and "avg_queue".
 
   OTHER CAVEATS AND NOTES: at this point in time, the code does not take care
   of dynamic connections. Also, if any of the server maxconn, or maxqueue is 0,
   then this acl clearly does not make sense, in which case the value returned
   will be -1.
 
+queue <integer>
+queue(frontend) <integer>
+  Returns the total number of queued connections of the designated backend,
+  including all the connections in server queues. If no backend name is
+  specified, the current one is used, but it is also possible to check another
+  one. This can be used to take actions when queuing goes above a known level,
+  generally indicating a surge of traffic or a massive slowdown on the servers.
+  One possible action could be to reject new users but still accept old ones.
+  See also the "avg_queue", "be_conn", and "be_sess_rate" criteria.
+
+avg_queue <integer>
+avg_queue(frontend) <integer>
+  Returns the total number of queued connections of the designated backend
+  divided by the number of active servers. This is very similar to "queue"
+  except that the size of the farm is considered, in order to give a more
+  accurate measurement of the time it may take for a new connection to be
+  processed. The main usage is to return a sorry page to new users when it
+  becomes certain they will get a degraded service. Note that in the event
+  there would not be any active server anymore, we would consider twice the
+  number of queued connections as the measured value. This is a fair estimate,
+  as we expect one server to get back soon anyway, but we still prefer to send
+  new traffic to another backend if in better shape. See also the "queue",
+  "be_conn", and "be_sess_rate" criteria.
+
 fe_sess_rate <integer>
 fe_sess_rate(frontend) <integer>
   Returns true when the session creation rate on the current or the named
diff --git a/src/backend.c b/src/backend.c
index 77c5a92..f4e6110 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1188,7 +1188,7 @@
 	test->i = 0;
 	iterator = px->srv;
 	while (iterator) {
-		if ((iterator->state & 1) == 0) {
+		if ((iterator->state & SRV_RUNNING) == 0) {
 			iterator = iterator->next;
 			continue;
 		}
@@ -1243,6 +1243,99 @@
 	return 1;
 }
 
+/* set test->i to the number of concurrent connections on the frontend */
+static int
+acl_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, int dir,
+		  struct acl_expr *expr, struct acl_test *test)
+{
+	test->flags = ACL_TEST_F_VOL_TEST;
+	if (expr->arg_len) {
+		/* another proxy was designated, we must look for it */
+		for (px = proxy; px; px = px->next)
+			if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str))
+				break;
+	}
+	if (!px)
+		return 0;
+
+	test->i = px->feconn;
+	return 1;
+}
+
+/* set test->i to the number of concurrent connections on the backend */
+static int
+acl_fetch_be_conn(struct proxy *px, struct session *l4, void *l7, int dir,
+		  struct acl_expr *expr, struct acl_test *test)
+{
+	test->flags = ACL_TEST_F_VOL_TEST;
+	if (expr->arg_len) {
+		/* another proxy was designated, we must look for it */
+		for (px = proxy; px; px = px->next)
+			if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
+				break;
+	}
+	if (!px)
+		return 0;
+
+	test->i = px->beconn;
+	return 1;
+}
+
+/* set test->i to the total number of queued connections on the backend */
+static int
+acl_fetch_queue_size(struct proxy *px, struct session *l4, void *l7, int dir,
+		   struct acl_expr *expr, struct acl_test *test)
+{
+	test->flags = ACL_TEST_F_VOL_TEST;
+	if (expr->arg_len) {
+		/* another proxy was designated, we must look for it */
+		for (px = proxy; px; px = px->next)
+			if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
+				break;
+	}
+	if (!px)
+		return 0;
+
+	test->i = px->totpend;
+	return 1;
+}
+
+/* set test->i to the total number of queued connections on the backend divided
+ * by the number of running servers and rounded up. If there is no running
+ * server, we return twice the total, just as if we had half a running server.
+ * This is more or less correct anyway, since we expect the last server to come
+ * back soon.
+ */
+static int
+acl_fetch_avg_queue_size(struct proxy *px, struct session *l4, void *l7, int dir,
+		   struct acl_expr *expr, struct acl_test *test)
+{
+	int nbsrv;
+
+	test->flags = ACL_TEST_F_VOL_TEST;
+	if (expr->arg_len) {
+		/* another proxy was designated, we must look for it */
+		for (px = proxy; px; px = px->next)
+			if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str))
+				break;
+	}
+	if (!px)
+		return 0;
+
+	if (px->srv_act)
+		nbsrv = px->srv_act;
+	else if (px->lbprm.fbck)
+		nbsrv = 1;
+	else
+		nbsrv = px->srv_bck;
+
+	if (nbsrv > 0)
+		test->i = (px->totpend + nbsrv - 1) / nbsrv;
+	else
+		test->i = px->totpend * 2;
+
+	return 1;
+}
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct acl_kw_list acl_kws = {{ },{
@@ -1250,6 +1343,10 @@
 	{ "connslots", acl_parse_int,   acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING },
 	{ "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING },
 	{ "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING },
+	{ "fe_conn", acl_parse_int, acl_fetch_fe_conn, acl_match_int, ACL_USE_NOTHING },
+	{ "be_conn", acl_parse_int, acl_fetch_be_conn, acl_match_int, ACL_USE_NOTHING },
+	{ "queue", acl_parse_int, acl_fetch_queue_size, acl_match_int, ACL_USE_NOTHING },
+	{ "avg_queue", acl_parse_int, acl_fetch_avg_queue_size, acl_match_int, ACL_USE_NOTHING },
 	{ NULL, NULL, NULL, NULL },
 }};
 
diff --git a/src/client.c b/src/client.c
index 3bd31cf..b9e304a 100644
--- a/src/client.c
+++ b/src/client.c
@@ -593,12 +593,12 @@
 }
 
 
-/* set test->i to the number of connexions to the proxy */
+/* set test->i to the number of connexions to the same listening socket */
 static int
 acl_fetch_dconn(struct proxy *px, struct session *l4, void *l7, int dir,
                 struct acl_expr *expr, struct acl_test *test)
 {
-	test->i = px->feconn;
+	test->i = l4->listener->nbconn;
 	return 1;
 }