From: Peter Eisentraut Date: Sat, 29 Mar 2003 11:31:52 +0000 (+0000) Subject: Simplify the socket handling code by supplying a replacement getaddrinfo() X-Git-Tag: REL7_4_BETA1~808 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=82a91eb54ed0c6561050a0ae01661ea6302445ba;p=postgresql Simplify the socket handling code by supplying a replacement getaddrinfo() function if the OS doesn't provide one. --- diff --git a/configure b/configure index 2c673fc1a8..72f9dc3f13 100755 --- a/configure +++ b/configure @@ -10321,26 +10321,16 @@ fi -# This exports HAVE_IPV6 to both C files and Makefiles -echo "$as_me:$LINENO: checking for getaddrinfo" >&5 -echo $ECHO_N "checking for getaddrinfo... $ECHO_C" >&6 -if test "${ac_cv_func_getaddrinfo+set}" = set; then +echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5 +echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6 +if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" #include "confdefs.h" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char getaddrinfo (); below. */ -#include -/* Override any gcc2 internal prototype to avoid an error. */ -#ifdef __cplusplus -extern "C" -#endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char getaddrinfo (); -char (*f) (); +$ac_includes_default +#include #ifdef F77_DUMMY_MAIN # ifdef __cplusplus @@ -10351,52 +10341,56 @@ char (*f) (); int main () { -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_getaddrinfo) || defined (__stub___getaddrinfo) -choke me -#else -f = getaddrinfo; -#endif - +if ((struct sockaddr_in6 *) 0) + return 0; +if (sizeof (struct sockaddr_in6)) + return 0; ; return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -s conftest$ac_exeext' + { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_getaddrinfo=yes + ac_cv_type_struct_sockaddr_in6=yes else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 -ac_cv_func_getaddrinfo=no +ac_cv_type_struct_sockaddr_in6=no fi -rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_func_getaddrinfo" >&5 -echo "${ECHO_T}$ac_cv_func_getaddrinfo" >&6 -if test $ac_cv_func_getaddrinfo = yes; then - echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5 -echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6 -if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then +echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5 +echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6 +if test $ac_cv_type_struct_sockaddr_in6 = yes; then + echo "$as_me:$LINENO: checking for inet_ntop" >&5 +echo $ECHO_N "checking for inet_ntop... $ECHO_C" >&6 +if test "${ac_cv_func_inet_ntop+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" #include "confdefs.h" -$ac_includes_default -#include +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char inet_ntop (); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char inet_ntop (); +char (*f) (); #ifdef F77_DUMMY_MAIN # ifdef __cplusplus @@ -10407,38 +10401,43 @@ $ac_includes_default int main () { -if ((struct sockaddr_in6 *) 0) - return 0; -if (sizeof (struct sockaddr_in6)) - return 0; +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_inet_ntop) || defined (__stub___inet_ntop) +choke me +#else +f = inet_ntop; +#endif + ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_struct_sockaddr_in6=yes + ac_cv_func_inet_ntop=yes else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 -ac_cv_type_struct_sockaddr_in6=no +ac_cv_func_inet_ntop=no fi -rm -f conftest.$ac_objext conftest.$ac_ext +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5 -echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6 -if test $ac_cv_type_struct_sockaddr_in6 = yes; then - HAVE_IPV6="yes"; cat >>confdefs.h <<\_ACEOF +echo "$as_me:$LINENO: result: $ac_cv_func_inet_ntop" >&5 +echo "${ECHO_T}$ac_cv_func_inet_ntop" >&6 +if test $ac_cv_func_inet_ntop = yes; then + cat >>confdefs.h <<\_ACEOF #define HAVE_IPV6 1 _ACEOF @@ -10447,7 +10446,6 @@ fi fi - echo "$as_me:$LINENO: checking for PS_STRINGS" >&5 echo $ECHO_N "checking for PS_STRINGS... $ECHO_C" >&6 if test "${pgac_cv_var_PS_STRINGS+set}" = set; then @@ -10952,7 +10950,8 @@ fi -for ac_func in fseeko gethostname getopt_long getrusage inet_aton random srandom strcasecmp strdup strerror strtol strtoul + +for ac_func in fseeko getaddrinfo gethostname getopt_long getrusage inet_aton random srandom strcasecmp strdup strerror strtol strtoul do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -17013,7 +17012,6 @@ s,@python_moduleexecdir@,$python_moduleexecdir,;t t s,@python_includespec@,$python_includespec,;t t s,@python_libspec@,$python_libspec,;t t s,@LIBOBJS@,$LIBOBJS,;t t -s,@HAVE_IPV6@,$HAVE_IPV6,;t t s,@HPUXMATHLIB@,$HPUXMATHLIB,;t t s,@HAVE_POSIX_SIGNALS@,$HAVE_POSIX_SIGNALS,;t t s,@MSGFMT@,$MSGFMT,;t t diff --git a/configure.in b/configure.in index 99a8d9d971..a7d961ecb1 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $Header: /cvsroot/pgsql/configure.in,v 1.239 2003/03/21 17:18:34 petere Exp $ +dnl $Header: /cvsroot/pgsql/configure.in,v 1.240 2003/03/29 11:31:51 petere Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -791,14 +791,12 @@ AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat setproc AC_CHECK_DECLS(fdatasync, [], [], [#include ]) -# This exports HAVE_IPV6 to both C files and Makefiles -AC_CHECK_FUNC(getaddrinfo, - [AC_CHECK_TYPE(struct sockaddr_in6, - [HAVE_IPV6="yes"; AC_DEFINE(HAVE_IPV6, 1)], - [], +AC_CHECK_TYPE([struct sockaddr_in6], + [AC_CHECK_FUNC(inet_ntop, + [AC_DEFINE(HAVE_IPV6, 1)])], + [], [$ac_includes_default -#include ])]) -AC_SUBST(HAVE_IPV6) +#include ]) AC_CACHE_CHECK([for PS_STRINGS], [pgac_cv_var_PS_STRINGS], [AC_TRY_LINK( @@ -849,7 +847,7 @@ else AC_CHECK_FUNCS([fpclass fp_class fp_class_d class], [break]) fi -AC_REPLACE_FUNCS([fseeko gethostname getopt_long getrusage inet_aton random srandom strcasecmp strdup strerror strtol strtoul]) +AC_REPLACE_FUNCS([fseeko getaddrinfo gethostname getopt_long getrusage inet_aton random srandom strcasecmp strdup strerror strtol strtoul]) # BSD/OS & NetBSD use a custom fseeko/ftello built on fsetpos/fgetpos # We override the previous test that said fseeko/ftello didn't exist diff --git a/src/Makefile.global.in b/src/Makefile.global.in index c0d2d202c2..29e48ca17b 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -1,5 +1,5 @@ # -*-makefile-*- -# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.159 2003/01/06 03:18:26 momjian Exp $ +# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.160 2003/03/29 11:31:51 petere Exp $ #------------------------------------------------------------------------------ # All PostgreSQL makefiles include this file and use the variables it sets, @@ -277,7 +277,6 @@ ifeq ($(enable_rpath), yes) LDFLAGS += $(rpath) endif -HAVE_IPV6 = @HAVE_IPV6@ ########################################################################## # diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c index 20f5df311a..3c3b872c1d 100644 --- a/src/backend/libpq/ip.c +++ b/src/backend/libpq/ip.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.2 2003/01/09 14:35:03 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.3 2003/03/29 11:31:51 petere Exp $ * * This file and the IPV6 implementation were initially provided by * Nigel Kukard , Linux Based Systems Design @@ -44,9 +44,9 @@ #define LOG stderr #endif -#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6) +#if defined(HAVE_UNIX_SOCKETS) static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, - struct addrinfo **result); + struct addrinfo **result); #endif /* HAVE_UNIX_SOCKETS */ /* @@ -54,48 +54,17 @@ static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, */ int getaddrinfo2(const char *hostname, const char *servname, -#ifdef HAVE_IPV6 const struct addrinfo *hintp, struct addrinfo **result) -#else - int family, SockAddr *result) -#endif { #ifdef HAVE_UNIX_SOCKETS -#ifdef HAVE_IPV6 if (hintp != NULL && hintp->ai_family == AF_UNIX) return getaddrinfo_unix(servname, hintp, result); -#else - if (family == AF_UNIX) - return 0; -#endif else { #endif /* HAVE_UNIX_SOCKETS */ -#ifdef HAVE_IPV6 /* NULL has special meaning to getaddrinfo */ return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname, servname, hintp, result); -#else - if (hostname[0] == '\0') - result->in.sin_addr.s_addr = htonl(INADDR_ANY); - else - { - struct hostent *hp; - - hp = gethostbyname(hostname); - if ((hp == NULL) || (hp->h_addrtype != AF_INET)) - { - elog(LOG, "getaddrinfo2: gethostbyname(%s) failed\n", hostname); - return STATUS_ERROR; - } - memmove((char *) &(result->in.sin_addr), (char *) hp->h_addr, - hp->h_length); - } - - result->in.sin_port = htons((unsigned short)atoi(servname)); - return 0; -#endif /* HAVE_IPV6 */ - #ifdef HAVE_UNIX_SOCKETS } #endif /* HAVE_UNIX_SOCKETS */ @@ -105,7 +74,6 @@ getaddrinfo2(const char *hostname, const char *servname, /* * freeaddrinfo2 - free IPv6 addrinfo structures */ -#ifdef HAVE_IPV6 void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai) { @@ -126,10 +94,9 @@ freeaddrinfo2(int hint_ai_family, struct addrinfo *ai) #endif /* HAVE_UNIX_SOCKETS */ freeaddrinfo(ai); } -#endif -#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6) +#if defined(HAVE_UNIX_SOCKETS) /* ------- * getaddrinfo_unix - get unix socket info using IPv6 * @@ -140,7 +107,7 @@ freeaddrinfo2(int hint_ai_family, struct addrinfo *ai) */ static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, - struct addrinfo **result) + struct addrinfo **result) { struct addrinfo hints; struct addrinfo *aip; @@ -159,9 +126,9 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, if (hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; - if (!(hints.ai_family == AF_UNIX)) + if (hints.ai_family != AF_UNIX) { - elog(LOG, "hints.ai_family is invalied getaddrinfo_unix()\n"); + elog(LOG, "hints.ai_family is invalid in getaddrinfo_unix()\n"); return EAI_ADDRFAMILY; } @@ -197,7 +164,7 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp, return 0; } -#endif /* HAVE_UNIX_SOCKETS && HAVE_IPV6 */ +#endif /* HAVE_UNIX_SOCKETS */ /* ---------- * SockAddr_ntop - set IP address string from SockAddr diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 8c6e1dc6d0..20954a4ecf 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -29,7 +29,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.c,v 1.147 2003/01/25 05:19:46 tgl Exp $ + * $Id: pqcomm.c,v 1.148 2003/03/29 11:31:51 petere Exp $ * *------------------------------------------------------------------------- */ @@ -96,13 +96,6 @@ static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName); static int Setup_AF_UNIX(void); #endif /* HAVE_UNIX_SOCKETS */ -#ifdef HAVE_IPV6 -#define FREEADDRINFO2(family, addrs) freeaddrinfo2((family), (addrs)) -#else -/* do nothing */ -#define FREEADDRINFO2(family, addrs) do {} while (0) -#endif - /* * Configuration options @@ -208,13 +201,6 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, int ret; char portNumberStr[64]; char *service; - - /* - * IPv6 address lookups use a hint structure, while IPv4 creates an - * address structure directly. - */ - -#ifdef HAVE_IPV6 struct addrinfo *addrs = NULL; struct addrinfo hint; @@ -225,16 +211,6 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, hint.ai_family = family; hint.ai_flags = AI_PASSIVE; hint.ai_socktype = SOCK_STREAM; -#else - SockAddr saddr; - size_t len; - - Assert(family == AF_INET || family == AF_UNIX); - - /* Initialize address structure */ - MemSet((char *) &saddr, 0, sizeof(saddr)); - saddr.sa.sa_family = family; -#endif /* HAVE_IPV6 */ #ifdef HAVE_UNIX_SOCKETS if (family == AF_UNIX) @@ -242,38 +218,21 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK) return STATUS_ERROR; service = sock_path; -#ifndef HAVE_IPV6 - UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName); - len = UNIXSOCK_LEN(saddr.un); -#endif } else #endif /* HAVE_UNIX_SOCKETS */ { snprintf(portNumberStr, sizeof(portNumberStr), "%d", portNumber); service = portNumberStr; -#ifndef HAVE_IPV6 - len = sizeof(saddr.in); -#endif } - /* Look up name using IPv6 or IPv4 routines */ -#ifdef HAVE_IPV6 ret = getaddrinfo2(hostName, service, &hint, &addrs); if (ret || addrs == NULL) -#else - ret = getaddrinfo2(hostName, service, family, &saddr); - if (ret) -#endif { elog(LOG, "server socket failure: getaddrinfo2()%s: %s", -#ifdef HAVE_IPV6 (family == AF_INET6) ? " using IPv6" : "", gai_strerror(ret)); if (addrs != NULL) - FREEADDRINFO2(hint.ai_family, addrs); -#else - "", hostName); -#endif + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } @@ -281,7 +240,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, { elog(LOG, "server socket failure: socket(): %s", strerror(errno)); - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } @@ -292,17 +251,13 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, { elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s", strerror(errno)); - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } } -#ifdef HAVE_IPV6 Assert(addrs->ai_next == NULL && addrs->ai_family == family); err = bind(fd, addrs->ai_addr, addrs->ai_addrlen); -#else - err = bind(fd, (struct sockaddr *) &saddr.sa, len); -#endif if (err < 0) { elog(LOG, "server socket failure: bind(): %s\n" @@ -313,7 +268,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, sock_path); else elog(LOG, "\tIf not, wait a few seconds and retry."); - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } @@ -322,7 +277,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, { if (Setup_AF_UNIX() != STATUS_OK) { - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } } @@ -342,12 +297,12 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber, { elog(LOG, "server socket failure: listen(): %s", strerror(errno)); - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_ERROR; } *fdP = fd; - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); return STATUS_OK; } diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h new file mode 100644 index 0000000000..7933f93d70 --- /dev/null +++ b/src/include/getaddrinfo.h @@ -0,0 +1,43 @@ +/* $Header: /cvsroot/pgsql/src/include/getaddrinfo.h,v 1.1 2003/03/29 11:31:51 petere Exp $ */ + +#ifndef GETADDRINFO_H +#define GETADDRINFO_H + +#include "c.h" +#include + + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + + +int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +void freeaddrinfo(struct addrinfo *res); +const char *gai_strerror(int errcode); + + +#define EAI_BADFLAGS -1 +#define EAI_NONAME -2 +#define EAI_AGAIN -3 +#define EAI_FAIL -4 +#define EAI_NODATA -5 +#define EAI_FAMILY -6 +#define EAI_SOCKTYPE -7 +#define EAI_SERVICE -8 +#define EAI_ADDRFAMILY -9 +#define EAI_MEMORY -10 +#define EAI_SYSTEM -11 + +#define AI_PASSIVE 0x0001 +#define AI_NUMERICHOST 0x0004 + +#endif /* GETADDRINFO_H */ diff --git a/src/include/libpq/ip.h b/src/include/libpq/ip.h index c9d1b0e466..ac782a0336 100644 --- a/src/include/libpq/ip.h +++ b/src/include/libpq/ip.h @@ -1,17 +1,16 @@ #ifndef IP_H #define IP_H +#include "c.h" #include #include #include "libpq/pqcomm.h" +#ifndef HAVE_GETADDRINFO +#include "getaddrinfo.h" +#endif -#ifdef HAVE_IPV6 -void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai); int getaddrinfo2(const char *hostname, const char *servname, - const struct addrinfo *hintp, struct addrinfo **result); -#else -int getaddrinfo2(const char *hostname, const char *servname, - int family, SockAddr *result); -#endif + const struct addrinfo *hintp, struct addrinfo **result); +void freeaddrinfo2(int hint_ai_family, struct addrinfo *ai); char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv); int SockAddr_pton(SockAddr *sa, const char *src); diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 3c8e0b5d50..f515c6cff1 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -8,7 +8,7 @@ * or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your * changes will be overwritten the next time you run configure. * - * $Id: pg_config.h.in,v 1.41 2003/03/06 03:16:55 tgl Exp $ + * $Id: pg_config.h.in,v 1.42 2003/03/29 11:31:51 petere Exp $ */ #ifndef PG_CONFIG_H @@ -459,6 +459,9 @@ #undef HAVE_FP_CLASS_D #undef HAVE_CLASS +/* Set to 1 if you have getaddrinfo() */ +#undef HAVE_GETADDRINFO + /* Set to 1 if you have gethostname() */ #undef HAVE_GETHOSTNAME diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index c431ca44b7..16a5ff5ad1 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.73 2003/02/03 14:24:07 momjian Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.74 2003/03/29 11:31:51 petere Exp $ # #------------------------------------------------------------------------- @@ -23,7 +23,7 @@ override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconf OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ pqexpbuffer.o dllist.o pqsignal.o fe-secure.o wchar.o encnames.o ip.o \ md5.o \ - $(filter inet_aton.o snprintf.o strerror.o, $(LIBOBJS)) + $(filter getaddrinfo.o inet_aton.o snprintf.o strerror.o, $(LIBOBJS)) # Add libraries that libpq depends (or might depend) on into the @@ -54,7 +54,7 @@ ip.c: $(backend_src)/libpq/ip.c # symlink the source files in here and build our own object file. # this only gets done if configure finds system doesn't have inet_aton() -inet_aton.c snprintf.c strerror.c: %.c : $(top_srcdir)/src/port/%.c +getaddrinfo.c inet_aton.c snprintf.c strerror.c: %.c : $(top_srcdir)/src/port/%.c rm -f $@ && $(LN_S) $< . encnames.c wchar.c : % : $(backend_src)/utils/mb/% @@ -75,4 +75,4 @@ uninstall: uninstall-lib clean distclean maintainer-clean: clean-lib rm -f $(OBJS) dllist.c md5.c ip.c wchar.c encnames.c - rm -f $(OBJS) inet_aton.c snprintf.c strerror.c + rm -f $(OBJS) getaddrinfo.c inet_aton.c snprintf.c strerror.c diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 78d0e20188..141c80e276 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.228 2003/03/20 06:23:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.229 2003/03/29 11:31:51 petere Exp $ * *------------------------------------------------------------------------- */ @@ -50,13 +50,6 @@ #include "mb/pg_wchar.h" -#ifdef HAVE_IPV6 -#define FREEADDRINFO2(family, addrs) freeaddrinfo2((family), (addrs)) -#else -/* do nothing */ -#define FREEADDRINFO2(family, addrs) do {} while (0) -#endif - #ifdef WIN32 static int inet_aton(const char *cp, struct in_addr * inp) @@ -803,7 +796,6 @@ connectDBStart(PGconn *conn) StartupPacket np; /* Used to negotiate SSL connection */ char SSLok; #endif -#ifdef HAVE_IPV6 struct addrinfo *addrs = NULL; struct addrinfo *addr_cur = NULL; struct addrinfo hint; @@ -814,9 +806,6 @@ connectDBStart(PGconn *conn) /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; -#else - int family = -1; -#endif if (!conn) return 0; @@ -835,11 +824,6 @@ connectDBStart(PGconn *conn) /* * Set up the connection to postmaster/backend. - * - * This code is confusing because IPv6 creates a hint structure - * that is passed to getaddrinfo2(), which returns a list of address - * structures that are looped through, while IPv4 creates an address - * structure directly. */ MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr)); @@ -853,73 +837,23 @@ connectDBStart(PGconn *conn) if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') { -#ifdef HAVE_IPV6 + /* Using pghostaddr avoids a hostname lookup */ node = conn->pghostaddr; hint.ai_family = AF_UNSPEC; -#else - /* Using pghostaddr avoids a hostname lookup */ - struct in_addr addr; - - if (!inet_aton(conn->pghostaddr, &addr)) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid host address: %s\n"), - conn->pghostaddr); - goto connect_errReturn; - } - - family = AF_INET; - - memcpy((char *) &(conn->raddr.in.sin_addr), - (char *) &addr, sizeof(addr)); -#endif + hint.ai_flags = AI_NUMERICHOST; } else if (conn->pghost != NULL && conn->pghost[0] != '\0') { -#ifdef HAVE_IPV6 + /* Using pghost, so we have to look-up the hostname */ node = conn->pghost; hint.ai_family = AF_UNSPEC; -#else - /* Using pghost, so we have to look-up the hostname */ - if (getaddrinfo2(conn->pghost, portstr, family, &conn->raddr) != 0) - goto connect_errReturn; - - family = AF_INET; -#endif } else { + /* pghostaddr and pghost are NULL, so use Unix domain socket */ #ifdef HAVE_UNIX_SOCKETS -#ifdef HAVE_IPV6 node = unix_node; hint.ai_family = AF_UNIX; -#else - /* pghostaddr and pghost are NULL, so use Unix domain socket */ - family = AF_UNIX; -#endif -#endif /* HAVE_UNIX_SOCKETS */ - } - -#ifndef HAVE_IPV6 - /* Set family */ - conn->raddr.sa.sa_family = family; -#endif - -#ifdef HAVE_IPV6 - if (hint.ai_family == AF_UNSPEC) - { - /* do nothing */ - } -#else - if (family == AF_INET) - { - conn->raddr.in.sin_port = htons((unsigned short) (portnum)); - conn->raddr_len = sizeof(struct sockaddr_in); - } -#endif - else - { -#ifdef HAVE_UNIX_SOCKETS UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket); conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un); StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr)); @@ -931,7 +865,6 @@ connectDBStart(PGconn *conn) #endif /* HAVE_UNIX_SOCKETS */ } -#ifdef HAVE_IPV6 /* Use getaddrinfo2() to resolve the address */ ret = getaddrinfo2(node, portstr, &hint, &addrs); if (ret || addrs == NULL) @@ -941,40 +874,27 @@ connectDBStart(PGconn *conn) gai_strerror(ret)); goto connect_errReturn; } -#endif /* - * For IPV6 we loop over the possible addresses returned by - * getaddrinfo2(), and fail only when they all fail (reporting the - * error returned for the *last* alternative, which may not be what - * users expect :-(). Otherwise, there is no true loop here. + * We loop over the possible addresses returned by getaddrinfo2(), + * and fail only when they all fail (reporting the error returned + * for the *last* alternative, which may not be what users expect + * :-(). * * In either case, we never actually fall out of the loop; the * only exits are via "break" or "goto connect_errReturn". Thus, * there is no exit test in the for(). */ - for ( -#ifdef HAVE_IPV6 - addr_cur = addrs; ; addr_cur = addr_cur->ai_next -#else - ;; -#endif - ) + for (addr_cur = addrs; ; addr_cur = addr_cur->ai_next) { /* Open a socket */ -#ifdef HAVE_IPV6 conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, addr_cur->ai_protocol); -#else - conn->sock = socket(family, SOCK_STREAM, 0); -#endif if (conn->sock < 0) { -#ifdef HAVE_IPV6 /* ignore socket() failure if we have more addrs to try */ if (addr_cur->ai_next != NULL) continue; -#endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO)); @@ -987,11 +907,7 @@ connectDBStart(PGconn *conn) * using SSL, then we need the blocking I/O (XXX Can this be fixed?). */ -#ifdef HAVE_IPV6 if (isAF_INETx(addr_cur->ai_family)) -#else - if (isAF_INETx(family)) -#endif { if (!connectNoDelay(conn)) goto connect_errReturn; @@ -1012,11 +928,7 @@ connectDBStart(PGconn *conn) * ---------- */ retry1: -#ifdef HAVE_IPV6 if (connect(conn->sock, addr_cur->ai_addr, addr_cur->ai_addrlen) < 0) -#else - if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0) -#endif { if (SOCK_ERRNO == EINTR) /* Interrupted system call - we'll just try again */ @@ -1043,7 +955,6 @@ retry1: * This connection failed. We need to close the socket, * and either loop to try the next address or report an error. */ -#ifdef HAVE_IPV6 /* ignore connect() failure if we have more addrs to try */ if (addr_cur->ai_next != NULL) { @@ -1051,19 +962,19 @@ retry1: conn->sock = -1; continue; } -#endif + /* copy failed address for error report */ + memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); + conn->raddr_len = addr_cur->ai_addrlen; connectFailureMessage(conn, SOCK_ERRNO); goto connect_errReturn; } /* loop over addrs */ -#ifdef HAVE_IPV6 /* Remember the successfully opened address alternative */ memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); conn->raddr_len = addr_cur->ai_addrlen; /* and release the address list */ - FREEADDRINFO2(hint.ai_family, addrs); + freeaddrinfo2(hint.ai_family, addrs); addrs = NULL; -#endif #ifdef USE_SSL /* Attempt to negotiate SSL usage */ @@ -1153,10 +1064,8 @@ connect_errReturn: conn->sock = -1; } conn->status = CONNECTION_BAD; -#ifdef HAVE_IPV6 if (addrs != NULL) - FREEADDRINFO2(hint.ai_family, addrs); -#endif + freeaddrinfo2(hint.ai_family, addrs); return 0; } diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c new file mode 100644 index 0000000000..aa3d3ab6b8 --- /dev/null +++ b/src/port/getaddrinfo.c @@ -0,0 +1,132 @@ +/* $Header: /cvsroot/pgsql/src/port/getaddrinfo.c,v 1.1 2003/03/29 11:31:52 petere Exp $ */ + +#include "c.h" +#include "getaddrinfo.h" +#include +#include +#include +#include + + +int +getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct addrinfo *ai; + struct sockaddr_in sin, *psin; + + if (!hints || (hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)) + return EAI_FAMILY; + + if (hints->ai_socktype != SOCK_STREAM) + return EAI_SOCKTYPE; + + if (!node && !service) + return EAI_NONAME; + + if (node) + { + if (node[0] == '\0') + sin.sin_addr.s_addr = htonl(INADDR_ANY); + else if (hints->ai_flags & AI_NUMERICHOST) + { + inet_aton(node, &sin.sin_addr); + } + else + { + struct hostent *hp; + + hp = gethostbyname(node); + if (hp == NULL) + { + switch (h_errno) + { + case HOST_NOT_FOUND: + return EAI_NONAME; + case NO_DATA: + return EAI_NODATA; + case TRY_AGAIN: + return EAI_AGAIN; + case NO_RECOVERY: + default: + return EAI_FAIL; + } + } + if (hp->h_addrtype != AF_INET) + return EAI_ADDRFAMILY; + + memmove(&(sin.sin_addr), hp->h_addr, hp->h_length); + } + } + else + { + if (hints->ai_flags & AI_PASSIVE) + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + if (service) + sin.sin_port = htons((unsigned short)atoi(service)); + + ai = malloc(sizeof(*ai)); + if (!ai) + return EAI_MEMORY; + psin = malloc(sizeof(*psin)); + if (!psin) + { + free(ai); + return EAI_MEMORY; + } + + memcpy(psin, &sin, sizeof(sin)); + + ai->ai_family = hints->ai_family; + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + ai->ai_addrlen = sizeof(*psin); + ai->ai_addr = (struct sockaddr *) psin; + ai->ai_canonname = NULL; + ai->ai_next = NULL; + + *res = ai; + + return 0; +} + + +void +freeaddrinfo(struct addrinfo *res) +{ + if (res) + { + if (res->ai_addr) + free(res->ai_addr); + free(res); + } +} + + +const char* +gai_strerror(int errcode) +{ + int hcode; + + switch (errcode) + { + case EAI_NONAME: + hcode = HOST_NOT_FOUND; + break; + case EAI_NODATA: + hcode = NO_DATA; + break; + case EAI_AGAIN: + hcode = TRY_AGAIN; + break; + case EAI_FAIL: + default: + hcode = NO_RECOVERY; + break; + } + + return hstrerror(hcode); +}