diff --git a/CHANGES b/CHANGES index 2e557ae642..f961844ff1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4440. [func] Enable TCP fast open support when available on the + server side. [RT #42866] + 4439. [bug] Address race conditions getting ownernames of nodes. [RT #43005] diff --git a/configure b/configure index 09227423fb..05a64a9600 100755 --- a/configure +++ b/configure @@ -761,6 +761,7 @@ ISC_LWRES_SETHOSTENTINT ISC_LWRES_NEEDRRSETINFO ISC_IRS_NEEDADDRINFO ISC_LWRES_NEEDADDRINFO +ISC_PLATFORM_HAVETFO ISC_PLATFORM_NEEDPORTT ISC_PLATFORM_MSGHDRFLAVOR LWRES_PLATFORM_HAVESALEN @@ -18418,6 +18419,36 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# +# Look for TCP_FASTOPEN +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TCP_FASTOPEN socket option" >&5 +$as_echo_n "checking for TCP_FASTOPEN socket option... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#ifdef TCP_FASTOPEN +int has_tfo() { return (0); } +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "has_tfo" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ISC_PLATFORM_HAVETFO="#define ISC_PLATFORM_HAVETFO 1" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ISC_PLATFORM_HAVETFO="#undef ISC_PLATFORM_HAVETFO" +fi +rm -f conftest* + + + # # Check for addrinfo # diff --git a/configure.in b/configure.in index d3509c0a3b..c3696d0c7b 100644 --- a/configure.in +++ b/configure.in @@ -3107,6 +3107,24 @@ AC_TRY_COMPILE([ ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"]) AC_SUBST(ISC_PLATFORM_NEEDPORTT) +# +# Look for TCP_FASTOPEN +# +AC_MSG_CHECKING(for TCP_FASTOPEN socket option) +AC_EGREP_CPP(has_tfo, [ +#include +#include +#include +#ifdef TCP_FASTOPEN +int has_tfo() { return (0); } +#endif +], + [AC_MSG_RESULT(yes) + ISC_PLATFORM_HAVETFO="#define ISC_PLATFORM_HAVETFO 1"], + [AC_MSG_RESULT(no) + ISC_PLATFORM_HAVETFO="#undef ISC_PLATFORM_HAVETFO"]) +AC_SUBST(ISC_PLATFORM_HAVETFO) + # # Check for addrinfo # diff --git a/doc/misc/tcp-fast-open b/doc/misc/tcp-fast-open new file mode 100644 index 0000000000..a102706907 --- /dev/null +++ b/doc/misc/tcp-fast-open @@ -0,0 +1,27 @@ +Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") + +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Some systems (Linux, FreeBSD, OS X/macOS and Windows 10) support +the TCP Fast Open (RFC 7413) mechanism in their recent versions. + +BIND 9 supports this on the server side. + +When the TCP_FASTOPEN socket option is defined after the listen() +system call the socket code in the libisc set the option with +the half of the listen backlog (so the fast open maximum queue length +is the half of the pending connection queue length). +Any failure is logged and ignored. + +System specific notes: + - FreeBSD doesn't interpret the argument as a queue length but + only as an on/off switch. + + - Apple OS X/macOS allows only 0 or 1 so the code puts 1 for this system. + + - Windows 10 uses a 0/1 char flag and perhaps as not yet server support? + + - the only other system known to support this is Linux. + diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in index 82d02249bf..24b61db1f0 100644 --- a/lib/isc/include/isc/platform.h.in +++ b/lib/isc/include/isc/platform.h.in @@ -125,6 +125,11 @@ */ @ISC_PLATFORM_HAVESOCKADDRSTORAGE@ +/*! \brief + * Define if the system has TCP_FASTOPEN socket option. + */ +@ISC_PLATFORM_HAVETFO@ + /*! \brief * Define if the system supports kqueue multiplexing */ diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index cef85fa86b..dbc981062c 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -91,6 +91,10 @@ #include #endif +#ifdef ISC_PLATFORM_HAVETFO +#include +#endif + /*% * Choose the most preferable multiplex method. */ @@ -5648,6 +5652,24 @@ isc__socket_listen(isc_socket_t *sock0, unsigned int backlog) { return (ISC_R_UNEXPECTED); } +#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN) +#ifdef __APPLE__ + backlog = 1; +#else + backlog = backlog / 2; + if (backlog == 0) + backlog = 1; +#endif + if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN, + (void *)&backlog, sizeof(backlog)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, TCP_FASTOPEN) failed with %s", + sock->fd, strbuf); + /* TCP_FASTOPEN is experimental so ignore failures */ + } +#endif + sock->listener = 1; UNLOCK(&sock->lock); diff --git a/lib/isc/win32/include/isc/platform.h.in b/lib/isc/win32/include/isc/platform.h.in index eea9a3e74e..ac9b5e205d 100644 --- a/lib/isc/win32/include/isc/platform.h.in +++ b/lib/isc/win32/include/isc/platform.h.in @@ -31,6 +31,9 @@ #define ISC_PLATFORM_NEEDNTOP #define ISC_PLATFORM_NEEDPTON #define ISC_PLATFORM_HAVESOCKADDRSTORAGE +#ifdef _MSC_VER >= 1900 +#define ISC_PLATFORM_HAVETFO +#endif #define ISC_PLATFORM_QUADFORMAT "I64" diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index 3eee2f5c99..d4d158d60a 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -3319,6 +3319,9 @@ isc__socket_filter(isc_socket_t *sock, const char *filter) { isc_result_t isc__socket_listen(isc_socket_t *sock, unsigned int backlog) { char strbuf[ISC_STRERRORSIZE]; +#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN) + char on = 1; +#endif REQUIRE(VALID_SOCKET(sock)); @@ -3349,6 +3352,17 @@ isc__socket_listen(isc_socket_t *sock, unsigned int backlog) { return (ISC_R_UNEXPECTED); } +#if defined(ISC_PLATFORM_HAVETFO) && defined(TCP_FASTOPEN) + if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN, + &on, sizeof(on)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, TCP_FASTOPEN) failed with %s", + sock->fd, strbuf); + /* TCP_FASTOPEN is experimental so ignore failures */ + } +#endif + socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening"); sock->listener = 1;