From: Willem Toorop Date: Tue, 18 Oct 2016 22:47:04 +0000 (-0500) Subject: bugfix #678: Use poll to support > 1024 fds X-Git-Tag: release-1.7.0-rc1~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2462faeafc733c6535aefcdfcaf999b5175c103;p=thirdparty%2Fldns.git bugfix #678: Use poll to support > 1024 fds Thanks William King --- diff --git a/Changelog b/Changelog index 2ca00c64..b8c180c9 100644 --- a/Changelog +++ b/Changelog @@ -92,6 +92,8 @@ TBD Thanks Harald Jenny * bugfix #680: ldns fails to reject invalidly formatted RFC 7553 URI RRs. Thanks Robert Edmonds + * bugfix #678: Use poll i.s.o. select to support > 1024 fds + Thanks William King 1.6.17 2014-01-10 * Fix ldns_dnssec_zone_new_frm_fp_l to allow the last parsed line of a diff --git a/configure.ac b/configure.ac index b542b244..ed6aa572 100644 --- a/configure.ac +++ b/configure.ac @@ -181,6 +181,13 @@ case "$enable_stderr_msgs" in ;; esac +AX_HAVE_POLL( + [AX_CONFIG_FEATURE_ENABLE(poll)], + [AX_CONFIG_FEATURE_DISABLE(poll)]) +AX_CONFIG_FEATURE( + [poll], [This platform supports poll(7)], + [HAVE_POLL], [This platform supports poll(7).]) + # check for python PYTHON_X_CFLAGS="" ldns_with_pyldns=no @@ -832,6 +839,15 @@ void *memmove(void *dest, const void *src, size_t n); #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif + +#ifdef USE_WINSOCK +#define SOCK_INVALID INVALID_SOCKET +#define close_socket(_s) if (_s > SOCK_INVALID) {closesocket(_s); _s = SOCK_INVALID;} +#else +#define SOCK_INVALID -1 +#define close_socket(_s) if (_s > SOCK_INVALID) {close(_s); _s = SOCK_INVALID;} +#endif + #ifdef __cplusplus } #endif diff --git a/m4/ax_config_feature.m4 b/m4/ax_config_feature.m4 new file mode 100644 index 00000000..e205723e --- /dev/null +++ b/m4/ax_config_feature.m4 @@ -0,0 +1,156 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_config_feature.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CONFIG_FEATURE(FEATURE-NAME, FEATURE-DESCRIPTION, DEFINE, DEFINE-DESCRIPTION, [ACTION-IF-ENABLED [, ACTION-IF-NOT-ENABLED]]) +# +# DESCRIPTION +# +# AX_CONFIG_FEATURE is a simple wrapper for AC_ARG_ENABLE, it enables the +# feature FEATURE-NAME and AC_DEFINEs the passed DEFINE, depending on the +# user choice. DESCRIPTION will be used for AC_DEFINEs. ACTION-IF-ENABLED +# and ACTION-IF-NOT-ENABLED are the actions that will be run. A feature is +# enabled by default, in order to change this behaviour use the +# AX_CONFIG_FEATURE_DEFAULT_ENABLED and AX_CONFIG_FEATURE_DEFAULT_DISABLED +# macros. +# +# A simple example: +# +# AX_CONFIG_FEATURE_DEFAULT_ENABLED +# AX_CONFIG_FEATURE(feature_xxxxx, [turns on/off XXXXX support], +# HAVE_XXXXX, [Define if you want XXXXX support]) +# +# ... +# +# AX_CONFIG_FEATURE_DEFAULT_DISABLED +# AX_CONFIG_FEATURE(feature_yyyyy, [turns on/off YYYYY support], +# HAVE_YYYYY, [Define if you want YYYYY support], +# [enable_yyyyy="yes"], [enable_yyyyy="no"]) +# AM_CONDITIONAL(YYYYY, [test "$enable_yyyyy" = "yes"]) +# +# AX_CONFIG_FEATURE_DEFAULT_ENABLED +# AX_CONFIG_FEATURE(...) +# +# ... +# +# If you have lot of features and you want a verbose dumping of each user +# selection use AX_CONFIG_FEATURE_VERBOSE. Use AX_CONFIG_FEATURE_SILENT in +# order to remove a previously AX_CONFIG_FEATURE_VERBOSE. By default +# features are silent. +# +# Use AX_CONFIG_FEATURE_ENABLE or AX_CONFIG_FEATURE_DISABLE in order to +# enable or disable a specific feature. +# +# Another simple example: +# +# AS_IF([some_test_here],[AX_CONFIG_FEATURE_ENABLE(feature_xxxxx)],[]) +# +# AX_CONFIG_FEATURE(feature_xxxxx, [turns on/off XXXXX support], +# HAVE_XXXXX, [Define if you want XXXXX support]) +# AX_CONFIG_FEATURE(feature_yyyyy, [turns on/off YYYYY support], +# HAVE_YYYYY, [Define if you want YYYYY support], +# [enable_yyyyy="yes"], [enable_yyyyy="no"]) +# +# ... +# +# NOTE: AX_CONFIG_FEATURE_ENABLE() must be placed first of the relative +# AX_CONFIG_FEATURE() macro ... +# +# LICENSE +# +# Copyright (c) 2008 Francesco Salvestrini +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 10 + +AC_DEFUN([AX_CONFIG_FEATURE],[ dnl +m4_pushdef([FEATURE], patsubst([$1], -, _))dnl + +AC_ARG_ENABLE([$1],AS_HELP_STRING([--enable-$1],[$2]),[ +case "${enableval}" in + yes) + ax_config_feature_[]FEATURE[]="yes" + ;; + no) + ax_config_feature_[]FEATURE[]="no" + ;; + *) + AC_MSG_ERROR([bad value ${enableval} for feature --$1]) + ;; +esac +]) + +AS_IF([test "$ax_config_feature_[]FEATURE[]" = yes],[ dnl + AC_DEFINE([$3]) + $5 + AS_IF([test "$ax_config_feature_verbose" = yes],[ dnl + AC_MSG_NOTICE([Feature $1 is enabled]) + ]) +],[ dnl + $6 + AS_IF([test "$ax_config_feature_verbose" = yes],[ dnl + AC_MSG_NOTICE([Feature $1 is disabled]) + ]) +]) + +AH_TEMPLATE([$3],[$4]) + +m4_popdef([FEATURE])dnl +]) + +dnl Feature global +AC_DEFUN([AX_CONFIG_FEATURE_VERBOSE],[ dnl + ax_config_feature_verbose=yes +]) + +dnl Feature global +AC_DEFUN([AX_CONFIG_FEATURE_SILENT],[ dnl + ax_config_feature_verbose=no +]) + +dnl Feature specific +AC_DEFUN([AX_CONFIG_FEATURE_DEFAULT_ENABLED], [ + ax_config_feature_[]FEATURE[]_default=yes +]) + +dnl Feature specific +AC_DEFUN([AX_CONFIG_FEATURE_DEFAULT_DISABLED], [ + ax_config_feature_[]FEATURE[]_default=no +]) + +dnl Feature specific +AC_DEFUN([AX_CONFIG_FEATURE_ENABLE],[ dnl + ax_config_feature_[]patsubst([$1], -, _)[]=yes +]) + +dnl Feature specific +AC_DEFUN([AX_CONFIG_FEATURE_DISABLE],[ dnl + ax_config_feature_[]patsubst([$1], -, _)[]=no +]) diff --git a/m4/ax_have_poll.m4 b/m4/ax_have_poll.m4 new file mode 100644 index 00000000..14d3d4b3 --- /dev/null +++ b/m4/ax_have_poll.m4 @@ -0,0 +1,72 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_have_poll.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_HAVE_POLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# AX_HAVE_PPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# This macro determines whether the system supports the poll I/O event +# interface. A neat usage example would be: +# +# AX_HAVE_POLL( +# [AX_CONFIG_FEATURE_ENABLE(poll)], +# [AX_CONFIG_FEATURE_DISABLE(poll)]) +# AX_CONFIG_FEATURE( +# [poll], [This platform supports poll(7)], +# [HAVE_POLL], [This platform supports poll(7).]) +# +# Some systems -- most notably Linux kernel 2.6.16 and later -- also have +# the variant ppoll(). The availability of that function can be tested +# with the second macro. Generally speaking, it is safe to assume that +# AX_HAVE_POLL would succeed if AX_HAVE_PPOLL has, but not the other way +# round. +# +# LICENSE +# +# Copyright (c) 2009 Peter Simons +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_HAVE_POLL], [dnl + AC_MSG_CHECKING([for poll(2)]) + AC_CACHE_VAL([ax_cv_have_poll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [#include ], + [int rc; rc = poll((struct pollfd *)(0), 0, 0);])], + [ax_cv_have_poll=yes], + [ax_cv_have_poll=no])]) + AS_IF([test "${ax_cv_have_poll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_PPOLL], [dnl + AC_MSG_CHECKING([for ppoll(2)]) + AC_CACHE_VAL([ax_cv_have_ppoll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [dnl +#include +#include ], + [dnl +int rc; +rc = poll((struct pollfd *)(0), 0, 0); +rc = ppoll((struct pollfd *)(0), 0, (struct timespec const *)(0), (sigset_t const *)(0));])], + [ax_cv_have_ppoll=yes], + [ax_cv_have_ppoll=no])]) + AS_IF([test "${ax_cv_have_ppoll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +]) diff --git a/net.c b/net.c index 14f7c89a..4657d75d 100644 --- a/net.c +++ b/net.c @@ -30,6 +30,9 @@ #include #include #include +#ifdef HAVE_POLL +#include +#endif ldns_status ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt) @@ -150,6 +153,7 @@ static int ldns_sock_wait(int sockfd, struct timeval timeout, int write) { int ret; +#ifndef HAVE_POLL #ifndef S_SPLINT_S fd_set fds; FD_ZERO(&fds); @@ -158,6 +162,20 @@ ldns_sock_wait(int sockfd, struct timeval timeout, int write) ret = select(sockfd+1, NULL, &fds, NULL, &timeout); else ret = select(sockfd+1, &fds, NULL, NULL, &timeout); +#endif +#else + struct pollfd pfds[2]; + + memset(&pfds[0], 0, sizeof(pfds[0]) * 2); + + pfds[0].fd = sockfd; + pfds[0].events = POLLIN|POLLERR; + + if (write) { + pfds[0].events |= POLLOUT; + } + + ret = poll(pfds, 1, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); #endif if(ret == 0) /* timeout expired */ @@ -178,30 +196,30 @@ ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, #ifndef S_SPLINT_S if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, - IPPROTO_TCP)) == -1) { + IPPROTO_TCP)) == SOCK_INVALID) { return 0; } #endif - if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ + if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){ return 0; } /* perform nonblocking connect, to be able to wait with select() */ ldns_sock_nonblock(sockfd); - if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) { + if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) { #ifndef USE_WINSOCK #ifdef EINPROGRESS if(errno != EINPROGRESS) { #else if(1) { #endif - close(sockfd); + close_socket(sockfd); return 0; } #else /* USE_WINSOCK */ if(WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) { - closesocket(sockfd); + close_socket(sockfd); return 0; } #endif @@ -214,11 +232,7 @@ ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, socklen_t len = (socklen_t)sizeof(error); if(!ldns_sock_wait(sockfd, timeout, 1)) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); return 0; } @@ -237,7 +251,7 @@ ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, continue; /* try again */ #endif else if(error != 0) { - close(sockfd); + close_socket(sockfd); /* error in errno for our user */ errno = error; return 0; @@ -248,7 +262,7 @@ ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, else if(error == WSAEWOULDBLOCK) continue; else if(error != 0) { - closesocket(sockfd); + close_socket(sockfd); errno = error; return 0; } @@ -285,11 +299,7 @@ ldns_tcp_bgsend_from(ldns_buffer *qbin, } if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); return 0; } @@ -324,11 +334,7 @@ ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin, } answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); if (*answer_size == 0) { /* oops */ @@ -387,11 +393,7 @@ ldns_udp_bgsend_from(ldns_buffer *qbin, } if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); return 0; } return sockfd; @@ -422,11 +424,7 @@ ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, /* wait for an response*/ if(!ldns_sock_wait(sockfd, timeout, 0)) { -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); return LDNS_STATUS_NETWORK_ERR; } @@ -436,11 +434,7 @@ ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, ldns_sock_nonblock(sockfd); answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); -#ifndef USE_WINSOCK - close(sockfd); -#else - closesocket(sockfd); -#endif + close_socket(sockfd); if (*answer_size == 0) { /* oops */ @@ -892,7 +886,7 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c * @hostname is used */ for (ns_i = 0; ns_i < ldns_resolver_nameserver_count(resolver) && - resolver->_socket == 0; + resolver->_socket == SOCK_INVALID; ns_i++) { if (ns != NULL) { LDNS_FREE(ns); @@ -924,7 +918,7 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c ldns_resolver_timeout(resolver)); } - if (resolver->_socket == 0) { + if (resolver->_socket == SOCK_INVALID) { ldns_pkt_free(query); LDNS_FREE(ns); return LDNS_STATUS_NETWORK_ERR; @@ -939,11 +933,7 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c if (status != LDNS_STATUS_OK) { /* to prevent problems on subsequent calls to * ldns_axfr_start we have to close the socket here! */ -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif + close_socket(resolver->_socket); resolver->_socket = 0; ldns_pkt_free(query); @@ -961,12 +951,8 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c if(!query_wire) { ldns_pkt_free(query); LDNS_FREE(ns); -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif - resolver->_socket = 0; + + close_socket(resolver->_socket); return LDNS_STATUS_MEM_ERR; } @@ -978,11 +964,7 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c /* to prevent problems on subsequent calls to ldns_axfr_start * we have to close the socket here! */ -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif + close_socket(resolver->_socket); resolver->_socket = 0; return status; @@ -997,12 +979,8 @@ ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class c /* to prevent problems on subsequent calls to ldns_axfr_start * we have to close the socket here! */ -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif - resolver->_socket = 0; + + close_socket(resolver->_socket); return LDNS_STATUS_NETWORK_ERR; } diff --git a/resolver.c b/resolver.c index 9c523317..e09b577f 100644 --- a/resolver.c +++ b/resolver.c @@ -650,9 +650,7 @@ ldns_resolver_new(void) r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC; r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC; - /* TODO: fd=0 is actually a valid socket (stdin), - replace with -1 */ - r->_socket = 0; + r->_socket = -1; r->_axfr_soa_count = 0; r->_axfr_i = 0; r->_cur_axfr_pkt = NULL; @@ -1042,6 +1040,8 @@ ldns_resolver_deep_free(ldns_resolver *res) size_t i; if (res) { + close_socket(res->_socket); + if (res->_searchlist) { for (i = 0; i < ldns_resolver_searchlist_count(res); i++) { ldns_rdf_deep_free(res->_searchlist[i]); @@ -1441,7 +1441,7 @@ ldns_axfr_next(ldns_resolver *resolver) ldns_status status; /* check if start() has been called */ - if (!resolver || resolver->_socket == 0) { + if (!resolver || resolver->_socket == -1) { return NULL; } @@ -1458,12 +1458,9 @@ ldns_axfr_next(ldns_resolver *resolver) if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) { resolver->_axfr_soa_count++; if (resolver->_axfr_soa_count >= 2) { -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif - resolver->_socket = 0; + + close_socket(resolver->_socket); + ldns_pkt_free(resolver->_cur_axfr_pkt); resolver->_cur_axfr_pkt = NULL; } @@ -1488,12 +1485,8 @@ ldns_axfr_next(ldns_resolver *resolver) /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif - resolver->_socket = 0; + + close_socket(resolver->_socket); return NULL; } else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) { @@ -1514,12 +1507,8 @@ ldns_axfr_next(ldns_resolver *resolver) /* we must now also close the socket, otherwise subsequent uses of the same resolver structure will fail because the link is still open or in an undefined state */ -#ifndef USE_WINSOCK - close(resolver->_socket); -#else - closesocket(resolver->_socket); -#endif - resolver->_socket = 0; + + close_socket(resolver->_socket); return NULL; } else {