summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TSRM/m4/gethostbyname.m4197
-rw-r--r--TSRM/tsrm.m44
-rw-r--r--ext/sockets/sockaddr_conv.c2
-rw-r--r--ext/sockets/sockets.c4
-rw-r--r--ext/standard/dns.c4
-rw-r--r--ext/standard/file.c5
-rw-r--r--ext/standard/file.h5
-rw-r--r--main/fastcgi.c2
-rw-r--r--main/network.c94
-rw-r--r--main/php_network.h6
10 files changed, 314 insertions, 9 deletions
diff --git a/TSRM/m4/gethostbyname.m4 b/TSRM/m4/gethostbyname.m4
new file mode 100644
index 0000000000..ac3eb06018
--- /dev/null
+++ b/TSRM/m4/gethostbyname.m4
@@ -0,0 +1,197 @@
+# =================================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_func_which_gethostbyname_r.html
+# =================================================================================
+#
+# SYNOPSIS
+#
+# AX_FUNC_WHICH_GETHOSTBYNAME_R
+#
+# DESCRIPTION
+#
+# Determines which historical variant of the gethostbyname_r() call
+# (taking three, five, or six arguments) is available on the system and
+# defines one of the following macros accordingly:
+#
+# HAVE_FUNC_GETHOSTBYNAME_R_6
+# HAVE_FUNC_GETHOSTBYNAME_R_5
+# HAVE_FUNC_GETHOSTBYNAME_R_3
+#
+# as well as
+#
+# HAVE_GETHOSTBYNAME_R
+#
+# If used in conjunction with gethostname.c, the API demonstrated in
+# test.c can be used regardless of which gethostbyname_r() is available.
+# These example files can be found at
+# http://www.csn.ul.ie/~caolan/publink/gethostbyname_r
+#
+# based on David Arnold's autoconf suggestion in the threads faq
+#
+# Originally named "AC_caolan_FUNC_WHICH_GETHOSTBYNAME_R". Rewritten for
+# Autoconf 2.5x, and updated for 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Caolan McNamara <caolan@skynet.ie>
+# Copyright (c) 2008 Daniel Richard G. <skunk@iskunk.org>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# 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 7
+
+AC_DEFUN([AX_FUNC_WHICH_GETHOSTBYNAME_R], [
+
+ AC_LANG_PUSH([C])
+ AC_MSG_CHECKING([how many arguments gethostbyname_r() takes])
+
+ AC_CACHE_VAL([ac_cv_func_which_gethostbyname_r], [
+
+################################################################
+
+ac_cv_func_which_gethostbyname_r=unknown
+
+#
+# ONE ARGUMENT (sanity check)
+#
+
+# This should fail, as there is no variant of gethostbyname_r() that takes
+# a single argument. If it actually compiles, then we can assume that
+# netdb.h is not declaring the function, and the compiler is thereby
+# assuming an implicit prototype. In which case, we're out of luck.
+#
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
+ [
+ char *name = "www.gnu.org";
+ (void)gethostbyname_r(name) /* ; */
+ ])],
+ [ac_cv_func_which_gethostbyname_r=no])
+
+#
+# SIX ARGUMENTS
+# (e.g. Linux)
+#
+
+if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
+ [
+ char *name = "www.gnu.org";
+ struct hostent ret, *retp;
+ char buf@<:@1024@:>@;
+ int buflen = 1024;
+ int my_h_errno;
+ (void)gethostbyname_r(name, &ret, buf, buflen, &retp, &my_h_errno) /* ; */
+ ])],
+ [ac_cv_func_which_gethostbyname_r=six])
+
+fi
+
+#
+# FIVE ARGUMENTS
+# (e.g. Solaris)
+#
+
+if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
+ [
+ char *name = "www.gnu.org";
+ struct hostent ret;
+ char buf@<:@1024@:>@;
+ int buflen = 1024;
+ int my_h_errno;
+ (void)gethostbyname_r(name, &ret, buf, buflen, &my_h_errno) /* ; */
+ ])],
+ [ac_cv_func_which_gethostbyname_r=five])
+
+fi
+
+#
+# THREE ARGUMENTS
+# (e.g. AIX, HP-UX, Tru64)
+#
+
+if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
+ [
+ char *name = "www.gnu.org";
+ struct hostent ret;
+ struct hostent_data data;
+ (void)gethostbyname_r(name, &ret, &data) /* ; */
+ ])],
+ [ac_cv_func_which_gethostbyname_r=three])
+
+fi
+
+################################################################
+
+]) dnl end AC_CACHE_VAL
+
+case "$ac_cv_func_which_gethostbyname_r" in
+ three|five|six)
+ AC_DEFINE([HAVE_GETHOSTBYNAME_R], [1],
+ [Define to 1 if you have some form of gethostbyname_r().])
+ ;;
+esac
+
+case "$ac_cv_func_which_gethostbyname_r" in
+ three)
+ AC_MSG_RESULT([three])
+ AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_3], [1],
+ [Define to 1 if you have the three-argument form of gethostbyname_r().])
+ ;;
+
+ five)
+ AC_MSG_RESULT([five])
+ AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_5], [1],
+ [Define to 1 if you have the five-argument form of gethostbyname_r().])
+ ;;
+
+ six)
+ AC_MSG_RESULT([six])
+ AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_6], [1],
+ [Define to 1 if you have the six-argument form of gethostbyname_r().])
+ ;;
+
+ no)
+ AC_MSG_RESULT([cannot find function declaration in netdb.h])
+ ;;
+
+ unknown)
+ AC_MSG_RESULT([can't tell])
+ ;;
+
+ *)
+ AC_MSG_ERROR([internal error])
+ ;;
+esac
+
+AC_LANG_POP
+
+]) dnl end AC_DEFUN
+
diff --git a/TSRM/tsrm.m4 b/TSRM/tsrm.m4
index b53a4bb805..98aa2b8c91 100644
--- a/TSRM/tsrm.m4
+++ b/TSRM/tsrm.m4
@@ -1,3 +1,4 @@
+m4_include([TSRM/m4/gethostbyname.m4])
dnl TSRM_CHECK_GCC_ARG(ARG, ACTION-IF-FOUND, ACTION-IF-NOT_FOUND)
AC_DEFUN([TSRM_CHECK_GCC_ARG],[
@@ -32,6 +33,8 @@ AC_CHECK_HEADERS(stdarg.h)
AC_CHECK_FUNCS(sigprocmask)
+AX_FUNC_WHICH_GETHOSTBYNAME_R()
+
])
@@ -89,7 +92,6 @@ else
fi
])
-
AC_DEFUN([TSRM_THREADS_CHECKS],[
dnl For the thread implementations, we always use --with-*
diff --git a/ext/sockets/sockaddr_conv.c b/ext/sockets/sockaddr_conv.c
index 73a0085720..1ce109ee8c 100644
--- a/ext/sockets/sockaddr_conv.c
+++ b/ext/sockets/sockaddr_conv.c
@@ -90,7 +90,7 @@ int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_soc
if (inet_aton(string, &tmp)) {
sin->sin_addr.s_addr = tmp.s_addr;
} else {
- if (strlen(string) > MAXFQDNLEN || ! (host_entry = gethostbyname(string))) {
+ if (strlen(string) > MAXFQDNLEN || ! (host_entry = php_network_gethostbyname(string))) {
/* Note: < -10000 indicates a host lookup error */
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index a207225f1c..6039ac65ba 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -425,9 +425,9 @@ static int php_open_listen_sock(php_socket **php_sock, int port, int backlog) /*
*php_sock = sock;
#ifndef PHP_WIN32
- if ((hp = gethostbyname("0.0.0.0")) == NULL) {
+ if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) {
#else
- if ((hp = gethostbyname("localhost")) == NULL) {
+ if ((hp = php_network_gethostbyname("localhost")) == NULL) {
#endif
efree(sock);
return 0;
diff --git a/ext/standard/dns.c b/ext/standard/dns.c
index a3394e0479..de40649e69 100644
--- a/ext/standard/dns.c
+++ b/ext/standard/dns.c
@@ -251,7 +251,7 @@ PHP_FUNCTION(gethostbynamel)
RETURN_FALSE;
}
- hp = gethostbyname(hostname);
+ hp = php_network_gethostbyname(hostname);
if (hp == NULL || hp->h_addr_list == NULL) {
RETURN_FALSE;
}
@@ -272,7 +272,7 @@ static zend_string *php_gethostbyname(char *name)
struct in_addr in;
char *address;
- hp = gethostbyname(name);
+ hp = php_network_gethostbyname(name);
if (!hp || !*(hp->h_addr_list)) {
return zend_string_init(name, strlen(name), 0);
diff --git a/ext/standard/file.c b/ext/standard/file.c
index 26f5c161ce..cefdc4aecb 100644
--- a/ext/standard/file.c
+++ b/ext/standard/file.c
@@ -159,6 +159,11 @@ static void file_globals_ctor(php_file_globals *file_globals_p)
static void file_globals_dtor(php_file_globals *file_globals_p)
{
+#if defined(HAVE_GETHOSTBYNAME_R)
+ if (file_globals_p->tmp_host_buf) {
+ free(file_globals_p->tmp_host_buf);
+ }
+#endif
}
PHP_INI_BEGIN()
diff --git a/ext/standard/file.h b/ext/standard/file.h
index d423475386..a9b96d6b38 100644
--- a/ext/standard/file.h
+++ b/ext/standard/file.h
@@ -129,6 +129,11 @@ typedef struct {
HashTable *stream_filters; /* per-request copy of stream_filters_hash */
HashTable *wrapper_errors; /* key: wrapper address; value: linked list of char* */
int pclose_wait;
+#if defined(HAVE_GETHOSTBYNAME_R)
+ struct hostent tmp_host_info;
+ char *tmp_host_buf;
+ size_t tmp_host_buf_len;
+#endif
} php_file_globals;
#ifdef ZTS
diff --git a/main/fastcgi.c b/main/fastcgi.c
index ce33369045..fbc6f403a0 100644
--- a/main/fastcgi.c
+++ b/main/fastcgi.c
@@ -692,7 +692,7 @@ int fcgi_listen(const char *path, int backlog)
if(strlen(host) > MAXFQDNLEN) {
hep = NULL;
} else {
- hep = gethostbyname(host);
+ hep = php_network_gethostbyname(host);
}
if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host);
diff --git a/main/network.c b/main/network.c
index 138f86b3e4..6d1d97bc82 100644
--- a/main/network.c
+++ b/main/network.c
@@ -176,6 +176,8 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
# endif
struct addrinfo hints, *res, *sai;
#else
+ char *tmp_host_buf = NULL;
+ struct hostent tmp_host_info;
struct hostent *host_info;
struct in_addr in;
#endif
@@ -245,12 +247,11 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
freeaddrinfo(res);
#else
if (!inet_aton(host, &in)) {
- /* XXX NOT THREAD SAFE (is safe under win32) */
if(strlen(host) > MAXFQDNLEN) {
host_info = NULL;
errno = E2BIG;
} else {
- host_info = gethostbyname(host);
+ host_info = php_network_gethostbyname(host, &tmp_host_info, &tmp_host_buf);
}
if (host_info == NULL) {
if (error_string) {
@@ -271,6 +272,9 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
((struct sockaddr_in *)*sap)->sin_addr = in;
sap++;
n = 1;
+ if (tmp_host_buf) {
+ efree(tmp_host_buf);
+ }
#endif
*sap = NULL;
@@ -1257,9 +1261,95 @@ PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
}
return n;
}
+#endif
+
+#if defined(HAVE_GETHOSTBYNAME_R)
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
+struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
+{
+ struct hostent *hp;
+ int herr,res;
+
+ if (*hstbuflen == 0) {
+ *hstbuflen = 1024;
+ *tmphstbuf = (char *)malloc (*hstbuflen);
+ }
+
+ while (( res =
+ gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
+ && (errno == ERANGE)) {
+ /* Enlarge the buffer. */
+ *hstbuflen *= 2;
+ *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
+ }
+
+ if (res != SUCCESS) {
+ return NULL;
+ }
+
+ return hp;
+}
+#endif
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
+struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
+{
+ struct hostent *hp;
+ int herr;
+
+ if (*hstbuflen == 0) {
+ *hstbuflen = 1024;
+ *tmphstbuf = (char *)malloc (*hstbuflen);
+ }
+
+ while ((NULL == ( hp =
+ gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
+ && (errno == ERANGE)) {
+ /* Enlarge the buffer. */
+ *hstbuflen *= 2;
+ *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
+ }
+ return hp;
+}
+#endif
+#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
+struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
+{
+ if (*hstbuflen == 0) {
+ *hstbuflen = sizeof(struct hostent_data);
+ *tmphstbuf = (char *)malloc (*hstbuflen);
+ } else {
+ if (*hstbuflen < sizeof(struct hostent_data)) {
+ *hstbuflen = sizeof(struct hostent_data);
+ *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
+ }
+ }
+ memset((void *)(*tmphstbuf),0,*hstbuflen);
+
+ if (SUCCESS != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
+ return NULL;
+ }
+ return hostbuf;
+}
#endif
+#endif
+
+PHPAPI struct hostent* php_network_gethostbyname(char *name) {
+#if !defined(HAVE_GETHOSTBYNAME_R)
+ return gethostbyname(name);
+#else
+ if (FG(tmp_host_buf)) {
+ free(FG(tmp_host_buf));
+ }
+ FG(tmp_host_buf) = NULL;
+ FG(tmp_host_buf_len) = 0;
+
+ memset(&FG(tmp_host_info), 0, sizeof(struct hostent));
+
+ return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len));
+#endif
+}
/*
* Local variables:
diff --git a/main/php_network.h b/main/php_network.h
index daf9671132..4ddae5cd4c 100644
--- a/main/php_network.h
+++ b/main/php_network.h
@@ -74,6 +74,10 @@ END_EXTERN_C()
#include <sys/socket.h>
#endif
+#ifdef HAVE_GETHOSTBYNAME_R
+#include <netdb.h>
+#endif
+
/* These are here, rather than with the win32 counterparts above,
* since <sys/socket.h> defines them. */
#ifndef SHUT_RD
@@ -309,6 +313,8 @@ PHPAPI void php_network_populate_name_from_sockaddr(
PHPAPI int php_network_parse_network_address_with_port(const char *addr,
zend_long addrlen, struct sockaddr *sa, socklen_t *sl);
+
+PHPAPI struct hostent* php_network_gethostbyname(char *name);
END_EXTERN_C()
#define php_stream_sock_open_from_socket(socket, persistent) _php_stream_sock_open_from_socket((socket), (persistent) STREAMS_CC)