[MINOR] add support for the "backlog" parameter

Add the "backlog" parameter to frontends, to give hints to
the system about the approximate listen backlog desired size.

In order to protect against SYN flood attacks, one solution is
to increase the system's SYN backlog size. Depending on the
system, sometimes it is just tunable via a system parameter,
sometimes it is not adjustable at all, and sometimes the system
relies on hints given by the application at the time of the
listen() syscall. By default, HAProxy passes the frontend's
maxconn value to the listen() syscall. On systems which can
make use of this value, it can sometimes be useful to be able
to specify a different value, hence this backlog parameter.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3f0be93..1c7a058 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -4,7 +4,7 @@
                          ----------------------
                             version 1.3.14.2
                              willy tarreau
-                               2007/12/27
+                               2008/01/05
 
 
 This document covers the configuration language as implemented in the version
@@ -502,6 +502,7 @@
 ----------------------+----------+----------+---------+---------
 acl                         -          X         X         X   
 appsession                  -          -         X         X   
+backlog                     X          X         X         -
 balance                     X          -         X         X   
 bind                        -          X         X         -   
 block                       -          X         X         X
@@ -653,6 +654,31 @@
   See also : "cookie", "capture cookie" and "balance".
 
 
+backlog <conns>
+  Give hints to the system about the approximate listen backlog desired size
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    yes   |   yes  |   no
+  Arguments :
+    <conns>   is the number of pending connections. Depending on the operating
+              system, it may represent the number of already acknowledged
+	      connections, of non-acknowledged ones, or both.
+
+  In order to protect against SYN flood attacks, one solution is to increase
+  the system's SYN backlog size. Depending on the system, sometimes it is just
+  tunable via a system parameter, sometimes it is not adjustable at all, and
+  sometimes the system relies on hints given by the application at the time of
+  the listen() syscall. By default, HAProxy passes the frontend's maxconn value
+  to the listen() syscall. On systems which can make use of this value, it can
+  sometimes be useful to be able to specify a different value, hence this
+  backlog parameter.
+
+  On Linux 2.4, the parameter is ignored by the system. On Linux 2.6, it is
+  used as a hint and the system accepts up to the smallest greater power of
+  two, and never more than some limits (usually 32768).
+
+  See also : "maxconn" and the target operating system's tuning guide.
+
+
 balance <algorithm> [ <arguments> ]
   Define the load balancing algorithm to be used in a backend.
   May be used in sections :   defaults | frontend | listen | backend
diff --git a/include/types/protocols.h b/include/types/protocols.h
index 6c59ce1..f360746 100644
--- a/include/types/protocols.h
+++ b/include/types/protocols.h
@@ -78,6 +78,7 @@
 	struct protocol *proto;		/* protocol this listener belongs to */
 	int nbconn;			/* current number of connections on this listener */
 	int maxconn;			/* maximum connections allowed on this listener */
+	unsigned int backlog;		/* if set, listen backlog */
 	struct listener *next;		/* next address for the same proxy, or NULL */
 	struct list proto_list;         /* list in the protocol header */
 	int (*accept)(int fd);		/* accept() function passed to fdtab[] */
diff --git a/include/types/proxy.h b/include/types/proxy.h
index ef74893..8a72d82 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -228,6 +228,7 @@
 	struct chunk errmsg[HTTP_ERR_SIZE];	/* default or customized error messages for known errors */
 	int uuid;				/* universally unique proxy ID, used for SNMP */
 	int next_svid;				/* next server-id, used for SNMP */
+	unsigned int backlog;			/* force the frontend's listen backlog */
 };
 
 struct switching_rule {
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ae05da0..7b43b7e 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -614,6 +614,7 @@
 
 		if (curproxy->cap & PR_CAP_FE) {
 			curproxy->maxconn = defproxy.maxconn;
+			curproxy->backlog = defproxy.backlog;
 
 			/* initialize error relocations */
 			for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
@@ -1365,6 +1366,16 @@
 		}
 		curproxy->maxconn = atol(args[1]);
 	}
+	else if (!strcmp(args[0], "backlog")) {  /* backlog */
+		if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
+			return 0;
+
+		if (*(args[1]) == 0) {
+			Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+			return -1;
+		}
+		curproxy->backlog = atol(args[1]);
+	}
 	else if (!strcmp(args[0], "fullconn")) {  /* fullconn */
 		if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], " Maybe you want 'maxconn' instead ?"))
 			return 0;
@@ -2865,6 +2876,7 @@
 			if (curproxy->options & PR_O_TCP_NOLING)
 				listener->options |= LI_O_NOLINGER;
 			listener->maxconn = curproxy->maxconn;
+			listener->backlog = curproxy->backlog;
 			listener->timeout = &curproxy->timeout.client;
 			listener->accept = event_accept;
 			listener->private = curproxy;
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 593096d..2da34db 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -160,7 +160,7 @@
 		goto tcp_close_return;
 	}
 	
-	if (listen(fd, listener->maxconn) == -1) {
+	if (listen(fd, listener->backlog ? listener->backlog : listener->maxconn) == -1) {
 		err |= ERR_RETRYABLE | ERR_ALERT;
 		msg = "cannot listen to socket";
 		goto tcp_close_return;
diff --git a/src/proxy.c b/src/proxy.c
index 1b12844..82bb2ae 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -369,7 +369,7 @@
 	struct listener *l;
 	for (l = p->listen; l != NULL; l = l->next) {
 		if (shutdown(l->fd, SHUT_WR) == 0 &&
-		    listen(l->fd, p->maxconn) == 0 &&
+		    listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0 &&
 		    shutdown(l->fd, SHUT_RD) == 0) {
 			EV_FD_CLR(l->fd, DIR_RD);
 			if (p->state != PR_STERROR)
@@ -435,7 +435,7 @@
 			send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
 
 			for (l = p->listen; l != NULL; l = l->next) {
-				if (listen(l->fd, p->maxconn) == 0) {
+				if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) {
 					if (actconn < global.maxconn && p->feconn < p->maxconn) {
 						EV_FD_SET(l->fd, DIR_RD);
 						p->state = PR_STRUN;
diff --git a/tests/test-backlog.cfg b/tests/test-backlog.cfg
new file mode 100644
index 0000000..bc4a71e
--- /dev/null
+++ b/tests/test-backlog.cfg
@@ -0,0 +1,22 @@
+# This is a test configuration.
+# It is used to check that the backlog queue works as expected.
+
+global
+	maxconn    200
+        stats timeout 3s
+
+frontend backlog_def
+        mode       http
+        timeout    client  15s
+        maxconn    100
+        bind       :8000
+        option     httpclose
+
+frontend backlog_max
+        mode       http
+        timeout    client  15s
+        maxconn    100
+	backlog    100000
+        bind       :8001
+        option     httpclose
+