[MINOR] tcp: add support for the defer_accept bind option

This can ensure that data is readily available on a socket when
we accept it, but a bug in the kernel ignores the timeout so the
socket can remain pending as long as the client does not talk.
Use with care.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ace9931..fd5c626 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1143,6 +1143,24 @@
 				goto out;
 #endif
 			}
+
+			if (!strcmp(args[cur_arg], "defer-accept")) { /* wait for some data for 1 second max before doing accept */
+#ifdef TCP_DEFER_ACCEPT
+				struct listener *l;
+
+				for (l = curproxy->listen; l != last_listen; l = l->next)
+					l->options |= LI_O_DEF_ACCEPT;
+
+				cur_arg ++;
+				continue;
+#else
+				Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
+				      file, linenum, args[0], args[cur_arg]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+#endif
+			}
+
 			if (!strcmp(args[cur_arg], "transparent")) { /* transparently bind to these addresses */
 #ifdef CONFIG_HAP_LINUX_TPROXY
 				struct listener *l;
@@ -1212,7 +1230,7 @@
 				continue;
 			}
 
-			Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'name', 'id', 'mss' and 'interface' options.\n",
+			Alert("parsing [%s:%d] : '%s' only supports the 'transparent', 'defer-accept', 'name', 'id', 'mss' and 'interface' options.\n",
 			      file, linenum, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 7bb5d7e..884016f 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -520,6 +520,16 @@
 		}
 	}
 #endif
+#if defined(TCP_DEFER_ACCEPT)
+	if (listener->options & LI_O_DEF_ACCEPT) {
+		/* defer accept by up to one second */
+		int accept_delay = 1;
+		if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_delay, sizeof(accept_delay)) == -1) {
+			msg = "cannot enable DEFER_ACCEPT";
+			err |= ERR_WARN;
+		}
+	}
+#endif
 	if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
 		err |= ERR_RETRYABLE | ERR_ALERT;
 		msg = "cannot bind socket";