diff --git a/doc/configuration.txt b/doc/configuration.txt
index c0131e878..2a34d225d 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1132,6 +1132,7 @@ bind [
]: [, ...] mss
bind []: [, ...] transparent
bind []: [, ...] id
bind []: [, ...] name
+bind []: [, ...] defer_accept
Define one or several listening addresses and/or ports in a frontend.
May be used in sections : defaults | frontend | listen | backend
no | yes | yes | no
@@ -1182,6 +1183,20 @@ bind []: [, ...] name
the specified port. This keyword is available only when
HAProxy is built with USE_LINUX_TPROXY=1.
+ defer_accept is an optional keyword which is supported only on certain
+ Linux kernels. It states that a connection will only be
+ accepted once some data arrive on it, or at worst after the
+ first retransmit. This should be used only on protocols for
+ which the client talks first (eg: HTTP). It can slightly
+ improve performance by ensuring that most of the request is
+ already available when the connection is accepted. On the
+ other hand, it will not be able to detect connections which
+ don't talk. It is important to note that this option is
+ broken in all kernels up to 2.6.31, as the connection is
+ never accepted until the client talks. This can cause issues
+ with front firewalls which would see an established
+ connection while the proxy will only see it in SYN_RECV.
+
It is possible to specify a list of address:port combinations delimited by
commas. The frontend will then listen on all of these addresses. There is no
fixed limit to the number of addresses and ports which can be listened on in
diff --git a/include/types/protocols.h b/include/types/protocols.h
index a776cb339..66c742b09 100644
--- a/include/types/protocols.h
+++ b/include/types/protocols.h
@@ -71,6 +71,7 @@
#define LI_O_NOLINGER 0x0001 /* disable linger on this socket */
#define LI_O_FOREIGN 0x0002 /* permit listening on foreing addresses */
#define LI_O_NOQUICKACK 0x0004 /* disable quick ack of immediate data (linux) */
+#define LI_O_DEF_ACCEPT 0x0008 /* wait up to 1 second for data before accepting */
/* The listener will be directly referenced by the fdtab[] which holds its
* socket. The listener provides the protocol-specific accept() function to
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ace99313b..fd5c626e3 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1143,6 +1143,24 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
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 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
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 7bb5d7e21..884016f5a 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -519,6 +519,16 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
err |= ERR_WARN;
}
}
+#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;