From: Witold Kręcicki Date: Thu, 23 Aug 2018 07:42:30 +0000 (+0200) Subject: Add runtime detection of SO_REUSEPORT, use it instead of dup() if available. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68d5614a8d1208026cbd14871ac82f6c2520d8a0;p=thirdparty%2Fbind9.git Add runtime detection of SO_REUSEPORT, use it instead of dup() if available. --- diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 9c440d370e9..a3e27e62c30 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1677,7 +1677,7 @@ open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, result = isc_socket_open(sock); if (result != ISC_R_SUCCESS) return (result); - } else if (dup_socket != NULL) { + } else if (dup_socket != NULL && !isc_socket_hasreuseport()) { result = isc_socket_dup(dup_socket, &sock); if (result != ISC_R_SUCCESS) return (result); diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index d9738af4f64..98fa51bfd6c 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -1010,6 +1010,12 @@ isc_socketmgr_maxudp(isc_socketmgr_t *mgr, int maxudp); * Test interface. Drop UDP packet > 'maxudp'. */ +bool +isc_socket_hasreuseport(void); +/*%< + * Return true if there is SO_REUSEPORT support + */ + #ifdef HAVE_LIBXML2 int isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer); diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 400d87244d1..e3952ba3720 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -4580,13 +4580,21 @@ isc_socket_bind(isc_socket_t *sock0, const isc_sockaddr_t *sockaddr, goto bind_socket; #endif if ((options & ISC_SOCKET_REUSEADDRESS) != 0 && - isc_sockaddr_getport(sockaddr) != (in_port_t)0 && - setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + isc_sockaddr_getport(sockaddr) != (in_port_t)0) { + if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) < 0) { - UNEXPECTED_ERROR(__FILE__, __LINE__, + UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d) %s", sock->fd, isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); + } + if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, + sizeof(on)) < 0) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d) %s", sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + } /* Press on... */ } #ifdef AF_UNIX @@ -5445,6 +5453,38 @@ isc_socket_getfd(isc_socket_t *socket0) { return ((short) sock->fd); } +static isc_once_t hasreuseport_once = ISC_ONCE_INIT; +static bool hasreuseport = false; + +static void +init_hasreuseport() { +#ifdef SO_REUSEPORT + int sock, yes = 1; + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + close(sock); + return; + } else if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, + sizeof(yes)) < 0) { + close(sock); + return; + } else if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, + sizeof(yes)) < 0) { + close(sock); + return; + } + hasreuseport = true; +#endif +} + +bool +isc_socket_hasreuseport() { + RUNTIME_CHECK(isc_once_do(&hasreuseport_once, init_hasreuseport) + == ISC_R_SUCCESS); + return (hasreuseport); +} + + #if defined(HAVE_LIBXML2) || defined(HAVE_JSON) static const char * _socktype(isc_sockettype_t type) diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index e323f54d04e..13d4ba58fae 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -78,6 +78,7 @@ isc_socket_getpeername isc_socket_getsockname isc_socket_gettag isc_socket_gettype +isc_socket_hasreuseport isc_socket_ipv6only isc_socket_listen isc_socket_open diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index 8be28bfc0da..026b4da765b 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -3691,6 +3691,11 @@ isc_socket_socketevent(isc_mem_t *mctx, void *sender, return (allocate_socketevent(mctx, sender, eventtype, action, arg)); } +bool +isc_socket_hasreuseport() { + return (false); +} + #ifdef HAVE_LIBXML2 static const char *