From 82a91eb54ed0c6561050a0ae01661ea6302445ba Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sat, 29 Mar 2003 11:31:52 +0000
Subject: [PATCH] Simplify the socket handling code by supplying a replacement
 getaddrinfo() function if the OS doesn't provide one.

---
 configure                         | 112 +++++++++++++------------
 configure.in                      |  16 ++--
 src/Makefile.global.in            |   3 +-
 src/backend/libpq/ip.c            |  49 ++---------
 src/backend/libpq/pqcomm.c        |  61 ++------------
 src/include/getaddrinfo.h         |  43 ++++++++++
 src/include/libpq/ip.h            |  13 ++-
 src/include/pg_config.h.in        |   5 +-
 src/interfaces/libpq/Makefile     |   8 +-
 src/interfaces/libpq/fe-connect.c | 121 ++++-----------------------
 src/port/getaddrinfo.c            | 132 ++++++++++++++++++++++++++++++
 11 files changed, 283 insertions(+), 280 deletions(-)
 create mode 100644 src/include/getaddrinfo.h
 create mode 100644 src/port/getaddrinfo.c

diff --git a/configure b/configure
index 2c673fc1a86..72f9dc3f133 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 <assert.h>
-/* 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 <netinet/in.h>
 
 #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 <netinet/in.h>
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char inet_ntop (); below.  */
+#include <assert.h>
+/* 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 99a8d9d9713..a7d961ecb14 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 <unistd.h>])
 
-# 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 <netinet/in.h>])])
-AC_SUBST(HAVE_IPV6)
+#include <netinet/in.h>])
 
 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 c0d2d202c25..29e48ca17bd 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 20f5df311a8..3c3b872c1de 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 <nkukard@lbsd.net>, 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 8c6e1dc6d0b..20954a4ecf1 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 00000000000..7933f93d705
--- /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 <netdb.h>
+
+
+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 c9d1b0e4667..ac782a03364 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 <sys/socket.h>
 #include <netdb.h>
 #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 3c8e0b5d507..f515c6cff1a 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 c431ca44b7f..16a5ff5ad14 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 78d0e20188e..141c80e2765 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 00000000000..aa3d3ab6b87
--- /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 <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+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);
+}
-- 
GitLab