[MEDIUM] split fe->maxconn into fe->maxconn and be->fullconn

The maxconn argument is used only for the listeners, and the
fullconn is used only for the backends. If unset, it inherits
maxconn's value which itself can inherit the default or the
global value (we might need to change this).
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 8480143..8aaa3a7 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -98,7 +98,8 @@
 	unsigned int feconn, feconn_max;	/* # of active frontend sessions */
 	unsigned int beconn, beconn_max;	/* # of active backend sessions */
 	unsigned int cum_feconn, cum_beconn;	/* cumulated number of processed sessions */
-	unsigned int maxconn;			/* max # of active sessions */
+	unsigned int maxconn;			/* max # of active sessions on the frontend */
+	unsigned int fullconn;			/* #conns on backend above which servers are used at full load */
 	unsigned failed_conns, failed_resp;	/* failed connect() and responses */
 	unsigned failed_secu;			/* blocked responses because of security concerns */
 	int conn_retries;			/* maximum number of connect retries */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index d707685..42e250b 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -395,6 +395,7 @@
 		/* set default values */
 		curproxy->state = defproxy.state;
 		curproxy->maxconn = defproxy.maxconn;
+		curproxy->fullconn = defproxy.fullconn;
 		curproxy->conn_retries = defproxy.conn_retries;
 		curproxy->options = defproxy.options;
 
@@ -909,6 +910,13 @@
 		}
 		curproxy->maxconn = atol(args[1]);
 	}
+	else if (!strcmp(args[0], "fullconn")) {  /* fullconn */
+		if (*(args[1]) == 0) {
+			Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+			return -1;
+		}
+		curproxy->fullconn = atol(args[1]);
+	}
 	else if (!strcmp(args[0], "grace")) {  /* grace time (ms) */
 		if (*(args[1]) == 0) {
 			Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
@@ -1973,6 +1981,13 @@
 			memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt));
 		}
 
+		/* for backwards compatibility with "listen" instances, if
+		 * fullconn is not set but maxconn is set, then maxconn
+		 * is used.
+		 */
+		if (!curproxy->fullconn)
+			curproxy->fullconn = curproxy->maxconn;
+
 		/* first, we will invert the servers list order */
 		newsrv = NULL;
 		while (curproxy->srv) {
@@ -2035,13 +2050,18 @@
 		 */
 		newsrv = curproxy->srv;
 		while (newsrv != NULL) {
-			if (newsrv->minconn >= newsrv->maxconn) {
+			if (newsrv->minconn > newsrv->maxconn) {
 				/* Only 'minconn' was specified, or it was higher than or equal
 				 * to 'maxconn'. Let's turn this into maxconn and clean it, as
 				 * this will avoid further useless expensive computations.
 				 */
 				newsrv->maxconn = newsrv->minconn;
-				newsrv->minconn = 0;
+			} else if (newsrv->maxconn && !newsrv->minconn) {
+				/* minconn was not specified, so we set it to maxconn */
+				newsrv->minconn = newsrv->maxconn;
+			} else if (!curproxy->fullconn) {
+				Alert("parsing [%s:%d] : fullconn is mandatory when minconn is set on a server.\n", file, linenum);
+				return -1;
 			}
 
 			if (newsrv->maxconn > 0) {
diff --git a/src/queue.c b/src/queue.c
index 8f0474c..611cfe9 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -25,14 +25,21 @@
 void **pool_pendconn = NULL;
 
 /* returns the effective dynamic maxconn for a server, considering the minconn
- * and the proxy's usage relative to its saturation.
+ * and the proxy's usage relative to its dynamic connections limit. It is
+ * expected that 0 < s->minconn <= s->maxconn when this is called.
  */
 unsigned int srv_dynamic_maxconn(const struct server *s)
 {
-	return (s->proxy->beconn >= s->proxy->maxconn) ? s->maxconn :
-		(s->minconn ? 
-		 MAX(s->maxconn * s->proxy->beconn / s->proxy->maxconn, s->minconn)
-		 : s->maxconn);
+	if (s->proxy->beconn >= s->proxy->fullconn)
+		/* no fullconn or proxy is full */
+		return s->maxconn;
+
+	if (s->minconn == s->maxconn)
+		/* static limit */
+		return s->maxconn;
+
+	return MAX(s->minconn,
+		   s->proxy->beconn * s->maxconn / s->proxy->fullconn);
 }