[MINOR] tcp: add support for dynamic MSS setting

By passing a negative value to the "mss" argument of "bind" lines, it
becomes possible to subtract this value to the MSS advertised by the
client, which results in segments smaller than advertised. The effect
is useful with some TCP stacks which ACK less often when segments are
not full, because they only ACK every other full segment as suggested
by RFC1122.

NOTE: currently this has no effect on Linux kernel 2.6, a kernel patch
is still required to change the MSS of established connections.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index f20b8b2..daec879 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1463,9 +1463,14 @@
                   connections passing through a VPN. Note that this relies on a
                   kernel feature which is theorically supported under Linux but
                   was buggy in all versions prior to 2.6.28. It may or may not
-                  work on other operating systems. The commonly advertised
-                  value on Ethernet networks is 1460 = 1500(MTU) - 40(IP+TCP).
-                  This parameter is only compatible with TCP sockets.
+                  work on other operating systems. It may also not change the
+                  advertised value but change the effective size of outgoing
+                  segments. The commonly advertised value on Ethernet networks
+                  is 1460 = 1500(MTU) - 40(IP+TCP). If this value is positive,
+                  it will be used as the advertised MSS. If it is negative, it
+                  will indicate by how much to reduce the incoming connection's
+                  advertised MSS for outgoing segments. This parameter is only
+                  compatible with TCP sockets.
 
     <id>          is a persistent value for socket ID. Must be positive and
                   unique in the proxy. An unused value will automatically be
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ddfbe42..a67b348 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1683,9 +1683,9 @@
 					goto out;
 				}
 
-				mss = str2uic(args[cur_arg + 1]);
-				if (mss < 1 || mss > 65535) {
-					Alert("parsing [%s:%d]: %s expects an MSS value between 1 and 65535.\n",
+				mss = atoi(args[cur_arg + 1]);
+				if (!mss || abs(mss) > 65535) {
+					Alert("parsing [%s:%d]: %s expects an MSS with and absolute value between 1 and 65535.\n",
 					      file, linenum, args[0]);
 					err_code |= ERR_ALERT | ERR_FATAL;
 					goto out;
diff --git a/src/frontend.c b/src/frontend.c
index 4fc4460..8842e28 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -20,6 +20,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <netinet/tcp.h>
+
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
@@ -100,6 +102,17 @@
 		if (s->fe->options & PR_O_TCP_NOLING)
 			setsockopt(cfd, SOL_SOCKET, SO_LINGER,
 				   (struct linger *) &nolinger, sizeof(struct linger));
+#if defined(TCP_MAXSEG)
+		if (s->listener->maxseg < 0) {
+			/* we just want to reduce the current MSS by that value */
+			int mss;
+			int mss_len = sizeof(mss);
+			if (getsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &mss_len) == 0) {
+				mss += s->listener->maxseg; /* remember, it's < 0 */
+				setsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss));
+			}
+		}
+#endif
 	}
 
 	if (global.tune.client_sndbuf)
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 5039db8..6328d0a 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -509,7 +509,7 @@
 	}
 #endif
 #if defined(TCP_MAXSEG)
-	if (listener->maxseg) {
+	if (listener->maxseg > 0) {
 		if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
 			       &listener->maxseg, sizeof(listener->maxseg)) == -1) {
 			msg = "cannot set MSS";