From: Mark Ellzey Date: Tue, 14 Feb 2012 23:04:52 +0000 (-0500) Subject: Support TCP_DEFER_ACCEPT sockopts for listeners X-Git-Tag: release-2.1.1-alpha~90 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5880e4a1fc41908b8750662c69b1c59639898149;p=libevent Support TCP_DEFER_ACCEPT sockopts for listeners A listening socket can be enabled with the sockopt TCP_DEFER_ACCEPT. This informs the kernel to not call the user-land accept() until real data has been written to the socket. A new flag LEV_OPT_DEFERRED_ACCEPT has been introduced to automatically set this option. Optionally evutil_make_tcp_listen_socket_deferred() can be called manually. (Tweaked slightly by nickm.) --- diff --git a/configure.in b/configure.in index 0bf5b5c6..fce6ff52 100644 --- a/configure.in +++ b/configure.in @@ -192,6 +192,7 @@ AC_CHECK_HEADERS([ \ netdb.h \ netinet/in.h \ netinet/in6.h \ + netinet/tcp.h \ poll.h \ port.h \ stdarg.h \ diff --git a/evutil.c b/evutil.c index bc81a093..c340b54a 100644 --- a/evutil.c +++ b/evutil.c @@ -64,6 +64,9 @@ #ifdef _EVENT_HAVE_NETINET_IN6_H #include #endif +#ifdef _EVENT_HAVE_NETINET_TCP_H +#include +#endif #ifdef _EVENT_HAVE_ARPA_INET_H #include #endif @@ -364,6 +367,20 @@ evutil_make_listen_socket_reuseable(evutil_socket_t sock) #endif } +int +evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock) +{ +#if defined(_EVENT_HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT) + int one = 1; + + /* TCP_DEFER_ACCEPT tells the kernel to call defer accept() only after data + * has arrived and ready to read */ + return setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, + (ev_socklen_t)sizeof(one)); +#endif + return 0; +} + int evutil_make_socket_closeonexec(evutil_socket_t fd) { diff --git a/include/event2/listener.h b/include/event2/listener.h index 14d1aec1..6c3bd775 100644 --- a/include/event2/listener.h +++ b/include/event2/listener.h @@ -72,6 +72,12 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *); /** Flag: Indicates that the listener should be created in disabled * state. Use evconnlistener_enable() to enable it later. */ #define LEV_OPT_DISABLED (1u<<5) +/** Flag: Indicates that the listener should defer accept() until data is + * available, if possible. Ignored on platforms that do not support this. + * + * This option can help performance for protocols where the client transmits + * immediately after connecting. */ +#define LEV_OPT_DEFERRED_ACCEPT (1u<<6) /** Allocate a new evconnlistener object to listen for incoming TCP connections diff --git a/include/event2/util.h b/include/event2/util.h index e5e0bc47..d56e7446 100644 --- a/include/event2/util.h +++ b/include/event2/util.h @@ -336,6 +336,18 @@ int evutil_make_socket_closeonexec(evutil_socket_t sock); int evutil_closesocket(evutil_socket_t sock); #define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s) +/** Do platform-specific operations, if possible, to make a tcp listener + * socket defer accept()s until there is data to read. + * + * Not all platforms support this. You don't want to do this for every + * listener socket: only the ones that implement a protocol where the + * client transmits before the server needs to respond. + * + * @param sock The listening socket to to make deferred + * @return 0 on success (whether the operation is supported or not), + * -1 on failure +*/ +int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock); #ifdef _WIN32 /** Return the most recent socket error. Not idempotent on all platforms. */ diff --git a/listener.c b/listener.c index a24ba073..3f6b44f9 100644 --- a/listener.c +++ b/listener.c @@ -232,6 +232,10 @@ evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, evutil_make_listen_socket_reuseable(fd); } + if (flags & LEV_OPT_DEFERRED_ACCEPT) { + evutil_make_tcp_listen_socket_deferred(fd); + } + if (sa) { if (bind(fd, sa, socklen)<0) { evutil_closesocket(fd);