From 8fc86dd593b9e9a2b24779e263ad33c37e15c9f9 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 6 Dec 2002 03:46:37 +0000
Subject: [PATCH] We have just finished porting the old KAME IPv6 patch over to
 postgresql version 7.3, but yea... this patch adds full IPv6 support to
 postgres. I've tested it out on 7.2.3 and has been running perfectly stable.

CREDITS:
 The KAME Project  (Initial patch)
 Nigel Kukard  <nkukard@lbsd.net>
 Johan Jordaan  <johanj@lando.co.za>
---
 configure                            |   3 +-
 configure.in                         |   3 +-
 src/backend/libpq/Makefile           |   4 +-
 src/backend/libpq/auth.c             |   9 +-
 src/backend/libpq/hba.c              |  27 ++-
 src/backend/libpq/pg_hba.conf.sample |   5 +-
 src/backend/libpq/pqcomm.c           | 341 +++++++++++++++------------
 src/backend/postmaster/postmaster.c  |   9 +-
 src/include/libpq/libpq.h            |   3 +-
 src/include/libpq/pqcomm.h           |   3 +-
 src/interfaces/libpq/Makefile        |   3 +-
 src/interfaces/libpq/fe-connect.c    | 193 ++++++++-------
 12 files changed, 328 insertions(+), 275 deletions(-)

diff --git a/configure b/configure
index bb0a28bb081..87c26d234f2 100755
--- a/configure
+++ b/configure
@@ -15778,7 +15778,7 @@ fi
 ac_config_files="$ac_config_files GNUmakefile src/Makefile.global"
 
 
-ac_config_links="$ac_config_links src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION} src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION} src/include/dynloader.h:src/backend/port/dynloader/${template}.h src/include/pg_config_os.h:src/include/port/${template}.h src/Makefile.port:src/makefiles/Makefile.${template}"
+ac_config_links="$ac_config_links src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION} src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION} src/include/dynloader.h:src/backend/port/dynloader/${template}.h src/include/pg_config_os.h:src/include/port/${template}.h src/Makefile.port:src/makefiles/Makefile.${template} src/interfaces/libpq/v6util.c:src/backend/libpq/v6util.c"
 
 
 ac_config_headers="$ac_config_headers src/include/pg_config.h"
@@ -16266,6 +16266,7 @@ do
   "src/include/dynloader.h" ) CONFIG_LINKS="$CONFIG_LINKS src/include/dynloader.h:src/backend/port/dynloader/${template}.h" ;;
   "src/include/pg_config_os.h" ) CONFIG_LINKS="$CONFIG_LINKS src/include/pg_config_os.h:src/include/port/${template}.h" ;;
   "src/Makefile.port" ) CONFIG_LINKS="$CONFIG_LINKS src/Makefile.port:src/makefiles/Makefile.${template}" ;;
+  "src/interfaces/libpq/v6util.c" ) CONFIG_LINKS="$CONFIG_LINKS src/interfaces/libpq/v6util.c:src/backend/libpq/v6util.c" ;;
   "src/include/pg_config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/include/pg_config.h" ;;
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
 echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
diff --git a/configure.in b/configure.in
index 68123ae74cc..fbc22aabbc7 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.219 2002/12/03 21:50:43 momjian Exp $
+dnl $Header: /cvsroot/pgsql/configure.in,v 1.220 2002/12/06 03:46:24 momjian Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -1182,6 +1182,7 @@ AC_CONFIG_LINKS([
   src/include/dynloader.h:src/backend/port/dynloader/${template}.h
   src/include/pg_config_os.h:src/include/port/${template}.h
   src/Makefile.port:src/makefiles/Makefile.${template}
+  src/interfaces/libpq/v6util.c:src/backend/libpq/v6util.c
 ])
 
 AC_CONFIG_HEADERS([src/include/pg_config.h],
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index cc4f750a7d6..6e7c1561b4d 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for libpq subsystem (backend half of libpq interface)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.33 2002/06/14 04:23:17 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.34 2002/12/06 03:46:24 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.global
 # be-fsstubs is here for historical reasons, probably belongs elsewhere
 
 OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o md5.o pqcomm.o \
-	pqformat.o pqsignal.o
+	pqformat.o pqsignal.o v6util.o
 
 
 all: SUBSYS.o
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 0e0b64555bc..dfd6d1e93f5 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.92 2002/12/03 22:09:19 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.93 2002/12/06 03:46:24 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -410,9 +410,12 @@ ClientAuthentication(Port *port)
 			 */
 			{
 				const char *hostinfo = "localhost";
+				char ip_hostinfo[INET6_ADDRSTRLEN];
+				if (isAF_INETx(&port->raddr.sa) ){
+				  hostinfo = SockAddr_ntop(&port->raddr, ip_hostinfo,
+							   INET6_ADDRSTRLEN, 1);
+				}
 
-				if (port->raddr.sa.sa_family == AF_INET)
-					hostinfo = inet_ntoa(port->raddr.in.sin_addr);
 				elog(FATAL,
 				"No pg_hba.conf entry for host %s, user %s, database %s",
 					 hostinfo, port->user, port->database);
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 396347945e3..5cdf60da96a 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.88 2002/12/03 21:50:44 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.89 2002/12/06 03:46:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -582,9 +582,8 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 	}
 	else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
 	{
-		struct in_addr file_ip_addr,
-					mask;
-
+      	        SockAddr file_ip_addr, mask;
+		
 		if (strcmp(token, "hostssl") == 0)
 		{
 #ifdef USE_SSL
@@ -619,16 +618,25 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 		if (!line)
 			goto hba_syntax;
 		token = lfirst(line);
-		if (!inet_aton(token, &file_ip_addr))
-			goto hba_syntax;
+
+		if(SockAddr_pton(&file_ip_addr, token, strlen(token)) < 0){
+		  goto hba_syntax;
+		}
 
 		/* Read the mask field. */
 		line = lnext(line);
 		if (!line)
 			goto hba_syntax;
 		token = lfirst(line);
-		if (!inet_aton(token, &mask))
-			goto hba_syntax;
+
+		if(SockAddr_pton(&mask, token, strlen(token)) < 0){
+		  goto hba_syntax;
+		}
+
+
+		if(file_ip_addr.sa.sa_family != mask.sa.sa_family){
+		  goto hba_syntax;
+		}
 
 		/* Read the rest of the line. */
 		line = lnext(line);
@@ -639,8 +647,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 			goto hba_syntax;
 
 		/* Must meet network restrictions */
-		if (port->raddr.sa.sa_family != AF_INET ||
-			((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0)
+		if (!isAF_INETx(&port->raddr) || !rangeSockAddr(&port->raddr, &file_ip_addr, &mask))
 			return;
 	}
 	else
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 5338c79104b..4ff29977c62 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -44,5 +44,6 @@
 
 # TYPE  DATABASE    USER        IP-ADDRESS        IP-MASK           METHOD
 
-local   all         all                                             trust
-host    all         all         127.0.0.1         255.255.255.255   trust
+local   all         all                                                                trust
+host    all         all         127.0.0.1         255.255.255.255                      trust
+host    all         all         ::1               ffff:ffff:ffff:fff:ffff:ffff:ffff    trust
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 62e8bd44cd5..757a8a72ce6 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.141 2002/09/04 23:31:34 tgl Exp $
+ *	$Id: pqcomm.c,v 1.142 2002/12/06 03:46:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -85,6 +85,11 @@ extern ssize_t secure_read(Port *, void *, size_t);
 extern ssize_t secure_write(Port *, const void *, size_t);
 
 static void pq_close(void);
+#ifdef HAVE_UNIX_SOCKETS
+int StreamServerPortSubAFUNIX1(unsigned short portNumber,
+			       char *unixSocketName );
+int StreamServerPortSubAFUNIX2(void);
+#endif /* HAVE_UNIX_SOCKETS */
 
 
 /*
@@ -182,171 +187,199 @@ int
 StreamServerPort(int family, char *hostName, unsigned short portNumber,
 				 char *unixSocketName, int *fdP)
 {
-	SockAddr	saddr;
-	int			fd,
-				err;
-	int			maxconn;
-	size_t		len = 0;
-	int			one = 1;
+  int			fd,
+			err;
+  int			maxconn;
+  int			one = 1;
 
-	Assert(family == AF_INET || family == AF_UNIX);
+  int                   ret;
+  struct addrinfo*      addrs  = NULL;
+  struct addrinfo       hint;
+  char                  portNumberStr[64];
+  char*                 service = portNumberStr;
+  char*                 hostn = (hostName[0] == '\0')? NULL : hostName;
 
-	if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
-	{
-		elog(LOG, "StreamServerPort: socket() failed: %m");
-		return STATUS_ERROR;
-	}
+  Assert(family == AF_INET6 || family == AF_INET || family == AF_UNIX);
 
-	if (family == AF_INET)
-	{
-		if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
-						sizeof(one))) == -1)
-		{
-			elog(LOG, "StreamServerPort: setsockopt(SO_REUSEADDR) failed: %m");
-			return STATUS_ERROR;
-		}
-	}
+  memset(&hint, 0, sizeof(hint));
+  hint.ai_family   = family;
+  hint.ai_flags    = AI_PASSIVE;
+  hint.ai_socktype = SOCK_STREAM;
 
-	MemSet((char *) &saddr, 0, sizeof(saddr));
-	saddr.sa.sa_family = family;
+  snprintf(portNumberStr, sizeof(portNumberStr)/sizeof(char),
+	   "%d", portNumber);
 
 #ifdef HAVE_UNIX_SOCKETS
-	if (family == AF_UNIX)
-	{
-		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
-		len = UNIXSOCK_LEN(saddr.un);
-		strcpy(sock_path, saddr.un.sun_path);
-
-		/*
-		 * Grab an interlock file associated with the socket file.
-		 */
-		if (!CreateSocketLockFile(sock_path, true))
-			return STATUS_ERROR;
-
-		/*
-		 * Once we have the interlock, we can safely delete any
-		 * pre-existing socket file to avoid failure at bind() time.
-		 */
-		unlink(sock_path);
-	}
+  if (family == AF_UNIX) {
+    if(StreamServerPortSubAFUNIX1(portNumber, unixSocketName) != STATUS_OK){
+      return STATUS_ERROR;
+    }
+    service = sock_path;
+  }
 #endif   /* HAVE_UNIX_SOCKETS */
 
-	if (family == AF_INET)
-	{
-		/* TCP/IP socket */
-		if (hostName[0] == '\0')
-			saddr.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, "StreamServerPort: gethostbyname(%s) failed",
-					 hostName);
-				return STATUS_ERROR;
-			}
-			memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr,
-					hp->h_length);
-		}
 
-		saddr.in.sin_port = htons(portNumber);
-		len = sizeof(struct sockaddr_in);
-	}
-
-	err = bind(fd, (struct sockaddr *) & saddr.sa, len);
-	if (err < 0)
-	{
-		if (family == AF_UNIX)
-			elog(LOG, "StreamServerPort: bind() failed: %m\n"
-				 "\tIs another postmaster already running on port %d?\n"
-				 "\tIf not, remove socket node (%s) and retry.",
-				 (int) portNumber, sock_path);
-		else
-			elog(LOG, "StreamServerPort: bind() failed: %m\n"
-				 "\tIs another postmaster already running on port %d?\n"
-				 "\tIf not, wait a few seconds and retry.",
-				 (int) portNumber);
-		return STATUS_ERROR;
-	}
+  ret = getaddrinfo2(hostn, service, &hint, &addrs);
+  if(ret || addrs == NULL){
+    elog(LOG, "FATAL: StreamServerPort: getaddrinfo2() failed: %s\n",
+	     gai_strerror(ret));
+    freeaddrinfo2(hint.ai_family, addrs);
+    return STATUS_ERROR;
+  }
+
+
+  /** YY DEBUG
+  if(addrs->ai_family == AF_UNIX){
+    printf("%s-%s-%s \n", "debug: AF_UNIX!", unixSocketName, hostName);
+  }
+  else {
+    printf("%s", "debug: NOT AF_UNIX!\n");
+  }
+  fflush(stdout);
+  **/
+
+  if( (fd = socket(addrs->ai_family, SOCK_STREAM, 0)) < 0){
+    elog(LOG, "FATAL: StreamServerPort: socket() failed: %s\n",
+	     strerror(errno));
+    freeaddrinfo2(hint.ai_family, addrs);
+    return STATUS_ERROR;
+  }
+
+  if( isAF_INETx2(family) ){
+    if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, 
+		    sizeof(one) )) == -1 ){
+      elog(LOG, "FATAL: StreamServerPort: setsockopt(SO_REUSEADDR) failed: %s\n",
+	       strerror(errno));
+      freeaddrinfo2(hint.ai_family, addrs);
+      return STATUS_ERROR;
+    }
+  }
+
+
+  err = bind(fd, addrs->ai_addr, addrs->ai_addrlen);
+  if(err < 0){
+    elog(LOG, "FATAL: StreamServerPort: bind() failed: %s\n"
+	     "\tIs another postmaster already running on port %d?\n",
+	     strerror(errno), (int) portNumber);
+    if (family == AF_UNIX)
+      elog(LOG, "\tIf not, remove socket node (%s) and retry.\n",
+	       sock_path);
+    else
+      elog(LOG, "\tIf not, wait a few seconds and retry.\n");
+    freeaddrinfo2(hint.ai_family, addrs);
+    return STATUS_ERROR;
+  }
 
 #ifdef HAVE_UNIX_SOCKETS
-	if (family == AF_UNIX)
-	{
-		/* Arrange to unlink the socket file at exit */
-		on_proc_exit(StreamDoUnlink, 0);
-
-		/*
-		 * Fix socket ownership/permission if requested.  Note we must do
-		 * this before we listen() to avoid a window where unwanted
-		 * connections could get accepted.
-		 */
-		Assert(Unix_socket_group);
-		if (Unix_socket_group[0] != '\0')
-		{
-			char	   *endptr;
-			unsigned long int val;
-			gid_t		gid;
-
-			val = strtoul(Unix_socket_group, &endptr, 10);
-			if (*endptr == '\0')
-			{
-				/* numeric group id */
-				gid = val;
-			}
-			else
-			{
-				/* convert group name to id */
-				struct group *gr;
-
-				gr = getgrnam(Unix_socket_group);
-				if (!gr)
-				{
-					elog(LOG, "No such group as '%s'",
-						 Unix_socket_group);
-					return STATUS_ERROR;
-				}
-				gid = gr->gr_gid;
-			}
-			if (chown(sock_path, -1, gid) == -1)
-			{
-				elog(LOG, "Could not set group of %s: %m",
-					 sock_path);
-				return STATUS_ERROR;
-			}
-		}
+  if (family == AF_UNIX){
+    if(StreamServerPortSubAFUNIX2() != STATUS_OK){
+      freeaddrinfo2(hint.ai_family, addrs);
+      return STATUS_ERROR;
+    }
+  }
+#endif
 
-		if (chmod(sock_path, Unix_socket_permissions) == -1)
-		{
-			elog(LOG, "Could not set permissions on %s: %m",
-				 sock_path);
-			return STATUS_ERROR;
-		}
-	}
-#endif   /* HAVE_UNIX_SOCKETS */
+  /*
+   * Select appropriate accept-queue length limit.  PG_SOMAXCONN is only
+   * intended to provide a clamp on the request on platforms where an
+   * overly large request provokes a kernel error (are there any?).
+   */
+  maxconn = MaxBackends * 2;
+  if (maxconn > PG_SOMAXCONN)
+    maxconn = PG_SOMAXCONN;
+
+  err = listen(fd, maxconn);
+  if (err < 0) {
+    elog(LOG, "FATAL: StreamServerPort: listen() failed: %s\n",
+	     strerror(errno));
+    freeaddrinfo2(hint.ai_family, addrs);
+    return STATUS_ERROR;
+  }
+
+  *fdP = fd;
+  freeaddrinfo2(hint.ai_family, addrs);
+  return STATUS_OK;
 
-	/*
-	 * Select appropriate accept-queue length limit.  PG_SOMAXCONN is only
-	 * intended to provide a clamp on the request on platforms where an
-	 * overly large request provokes a kernel error (are there any?).
-	 */
-	maxconn = MaxBackends * 2;
-	if (maxconn > PG_SOMAXCONN)
-		maxconn = PG_SOMAXCONN;
+}
 
-	err = listen(fd, maxconn);
-	if (err < 0)
-	{
-		elog(LOG, "StreamServerPort: listen() failed: %m");
-		return STATUS_ERROR;
-	}
+#ifdef HAVE_UNIX_SOCKETS
+int StreamServerPortSubAFUNIX1(unsigned short portNumber,
+			       char *unixSocketName )
+{
+  SockAddr	saddr;
+  int           len;
+
+  MemSet((char *) &saddr, 0, sizeof(saddr));
+  
+  UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
+  len = UNIXSOCK_LEN(saddr.un);
+  strcpy(sock_path, saddr.un.sun_path);
+  
+  /*
+   * Grab an interlock file associated with the socket file.
+   */
+  if (!CreateSocketLockFile(sock_path, true))
+    return STATUS_ERROR;
+  
+  /*
+   * Once we have the interlock, we can safely delete any
+   * pre-existing socket file to avoid failure at bind() time.
+   */
+  unlink(sock_path);
+
+  return STATUS_OK;
+}
 
-	*fdP = fd;
 
-	return STATUS_OK;
+int StreamServerPortSubAFUNIX2(void)
+{
+  /* Arrange to unlink the socket file at exit */
+  on_proc_exit(StreamDoUnlink, 0);
+  
+  /*
+   * Fix socket ownership/permission if requested.  Note we must do
+   * this before we listen() to avoid a window where unwanted
+   * connections could get accepted.
+   */
+  Assert(Unix_socket_group);
+  if (Unix_socket_group[0] != '\0')  {
+    char	   *endptr;
+    unsigned long int val;
+    gid_t		gid;
+    
+    val = strtoul(Unix_socket_group, &endptr, 10);
+    if (*endptr == '\0'){     /* numeric group id */
+      gid = val;
+    }
+    else {                    /* convert group name to id */
+      struct group *gr;
+      gr = getgrnam(Unix_socket_group);
+      if (!gr) {
+	elog(LOG, "FATAL:  no such group '%s'\n",
+		 Unix_socket_group);
+	return STATUS_ERROR;
+      }
+      gid = gr->gr_gid;
+    }
+    if (chown(sock_path, -1, gid) == -1){
+      elog(LOG, "FATAL:  could not set group of %s: %s\n",
+	       sock_path, strerror(errno));
+      return STATUS_ERROR;
+    }
+  }
+
+  if (chmod(sock_path, Unix_socket_permissions) == -1){
+	elog(LOG, "FATAL:  could not set permissions on %s: %s\n",
+	     sock_path, strerror(errno));
+    return STATUS_ERROR;
+  }
+  return STATUS_OK;
 }
 
+#endif   /* HAVE_UNIX_SOCKETS */
+
+
 /*
  * StreamConnection -- create a new connection with client using
  *		server port.
@@ -391,8 +424,20 @@ StreamConnection(int server_fd, Port *port)
 		return STATUS_ERROR;
 	}
 
+	/* DEBUG YY
+	{ 
+	  char l_hostinfo[INET6_ADDRSTRLEN];
+	  char r_hostinfo[INET6_ADDRSTRLEN];
+	  SockAddr_ntop(&port->laddr, l_hostinfo, INET6_ADDRSTRLEN, 1);
+	  SockAddr_ntop(&port->raddr, r_hostinfo, INET6_ADDRSTRLEN, 1);
+	  printf("StreamConnect() l: %s r: %s\n", l_hostinfo, r_hostinfo);
+	  printf("StreamConnect() l: %d r: %d\n", port->laddr.sa.sa_family, 
+		 port->raddr.sa.sa_family);
+	}
+	*/
+
 	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
-	if (port->laddr.sa.sa_family == AF_INET)
+	if ( isAF_INETx(&port->laddr) )
 	{
 		int			on = 1;
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 8f34a3fd2dc..07787844903 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.299 2002/11/21 06:36:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.300 2002/12/06 03:46:29 momjian Exp $
  *
  * NOTES
  *
@@ -669,7 +669,7 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	if (NetServer)
 	{
-		status = StreamServerPort(AF_INET, VirtualHost,
+		status = StreamServerPort(AF_INET6, VirtualHost,
 								  (unsigned short) PostPortNumber,
 								  UnixSocketDir,
 								  &ServerSock_INET);
@@ -2091,13 +2091,14 @@ DoBackend(Port *port)
 	/*
 	 * Get the remote host name and port for logging and status display.
 	 */
-	if (port->raddr.sa.sa_family == AF_INET)
+	if (isAF_INETx(&port->raddr))
 	{
 		unsigned short remote_port;
 		char	   *host_addr;
+		char	   ip_hostinfo[INET6_ADDRSTRLEN]; 
 
 		remote_port = ntohs(port->raddr.in.sin_port);
-		host_addr = inet_ntoa(port->raddr.in.sin_addr);
+		host_addr = SockAddr_ntop(&port->raddr, ip_hostinfo, INET6_ADDRSTRLEN, 1);
 
 		remote_host = NULL;
 
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 5e4db4d2430..b0b1041be18 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq.h,v 1.52 2002/09/04 23:31:35 tgl Exp $
+ * $Id: libpq.h,v 1.53 2002/12/06 03:46:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 
 #include "lib/stringinfo.h"
 #include "libpq/libpq-be.h"
+#include "libpq/v6util.h"
 
 /* ----------------
  * PQArgBlock
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index 4066c23e0e4..a84978c5705 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqcomm.h,v 1.70 2002/09/04 20:31:42 momjian Exp $
+ * $Id: pqcomm.h,v 1.71 2002/12/06 03:46:33 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,7 @@ typedef union SockAddr
 {
 	struct sockaddr sa;
 	struct sockaddr_in in;
+	struct sockaddr_in6 in6;
 	struct sockaddr_un un;
 } SockAddr;
 
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 6537f86074d..a91611cd306 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.66 2002/12/04 18:14:11 momjian Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.67 2002/12/06 03:46:37 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -23,6 +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 md5.o pqsignal.o fe-secure.o \
       wchar.o encnames.o \
+      v6util.o \
       $(filter inet_aton.o snprintf.o strerror.o, $(LIBOBJS))
 
 
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 7cdd2466624..36782ecf70f 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.213 2002/10/24 23:35:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.214 2002/12/06 03:46:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,9 @@
 #include <arpa/inet.h>
 #endif
 
+#include "libpq/v6util.h"
+
+
 #ifndef HAVE_STRDUP
 #include "strdup.h"
 #endif
@@ -786,6 +789,15 @@ connectDBStart(PGconn *conn)
 {
 	int			portno,
 				family;
+	struct addrinfo*        addrs         = NULL;
+	struct addrinfo*        addr_cur      = NULL;
+	struct addrinfo         hint;
+	const char*             node          = NULL;
+	const char*             unix_node     = "unix";
+	char                    portNoStr[64];
+	int   ret;
+	int   sockfd;
+
 
 #ifdef USE_SSL
 	StartupPacket np;			/* Used to negotiate SSL connection */
@@ -815,101 +827,67 @@ connectDBStart(PGconn *conn)
 
 	MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
 
-	if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
-	{
-		/* Using pghostaddr avoids a hostname lookup */
-		/* Note that this supports IPv4 only */
-		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;
-
-		memmove((char *) &(conn->raddr.in.sin_addr),
-				(char *) &addr, sizeof(addr));
+	MemSet(&hint, 0, sizeof(hint));
+	hint.ai_socktype = SOCK_STREAM;
+	if(conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0'){
+	  node = conn->pghostaddr;
+	  hint.ai_family = AF_UNSPEC;
 	}
-	else if (conn->pghost != NULL && conn->pghost[0] != '\0')
-	{
-		/* Using pghost, so we have to look-up the hostname */
-		struct hostent *hp;
-
-		hp = gethostbyname(conn->pghost);
-		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("unknown host name: %s\n"),
-							  conn->pghost);
-			goto connect_errReturn;
-		}
-		family = AF_INET;
-
-		memmove((char *) &(conn->raddr.in.sin_addr),
-				(char *) hp->h_addr,
-				hp->h_length);
+	else if (conn->pghost != NULL && conn->pghost[0] != '\0'){
+	  node = conn->pghost;
+	  hint.ai_family = AF_UNSPEC;
 	}
-	else
-	{
-		/* pghostaddr and pghost are NULL, so use Unix domain socket */
-		family = AF_UNIX;
+#ifdef HAVE_UNIX_SOCKETS
+	else {
+	  node = unix_node;
+	  hint.ai_family = AF_UNIX;
 	}
+#endif   /* HAVE_UNIX_SOCKETS */
 
-	/* Set family */
-	conn->raddr.sa.sa_family = family;
-
-	/* Set port number */
 	if (conn->pgport != NULL && conn->pgport[0] != '\0')
-		portno = atoi(conn->pgport);
+	  portno = atoi(conn->pgport);
 	else
-		portno = DEF_PGPORT;
-
-	if (family == AF_INET)
-	{
-		conn->raddr.in.sin_port = htons((unsigned short) (portno));
-		conn->raddr_len = sizeof(struct sockaddr_in);
+	  portno = DEF_PGPORT;
+	
+	if(hint.ai_family == AF_UNSPEC){
+	  snprintf(portNoStr, sizeof(portNoStr)/sizeof(char),
+		   "%d", portno);
 	}
 #ifdef HAVE_UNIX_SOCKETS
-	else
-	{
-		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
-		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
+	else {
+	  UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
+	  conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
+	  strcpy(portNoStr, conn->raddr.un.sun_path);
 #ifdef USE_SSL
 		/* Don't bother requesting SSL over a Unix socket */
 		conn->allow_ssl_try = false;
 		conn->require_ssl = false;
 #endif
 	}
-#endif
-
-	/* Open a socket */
-	if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
-	{
-		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("could not create socket: %s\n"),
-						  SOCK_STRERROR(SOCK_ERRNO));
-		goto connect_errReturn;
-	}
-
-	/*
-	 * Set the right options. Normally, we need nonblocking I/O, and we
-	 * don't want delay of outgoing data for AF_INET sockets.  If we are
-	 * using SSL, then we need the blocking I/O (XXX Can this be fixed?).
-	 */
-
-	if (family == AF_INET)
-	{
-		if (!connectNoDelay(conn))
-			goto connect_errReturn;
+#endif   /* HAVE_UNIX_SOCKETS */
+
+	ret = getaddrinfo2(node, portNoStr, &hint, &addrs);
+	if(ret || addrs == NULL){
+	  printfPQExpBuffer(&conn->errorMessage,
+			    libpq_gettext("failed to getaddrinfo(): %s\n"),
+			    gai_strerror(ret) );
+	  goto connect_errReturn;
 	}
-
+	addr_cur = addrs;
+	do {
+	  sockfd = socket(addr_cur->ai_family, addr_cur->ai_socktype, 
+			  addr_cur->ai_protocol);
+	  if(sockfd < 0){
+	    continue;
+	  }
+	  conn->sock = sockfd;
+	  if (isAF_INETx2(addr_cur->ai_family) ){
+	    if (!connectNoDelay(conn))
+	      goto connect_errReturn;
+	  }
 #if !defined(USE_SSL)
-	if (connectMakeNonblocking(conn) == 0)
-		goto connect_errReturn;
+	  if (connectMakeNonblocking(conn) == 0)
+	    goto connect_errReturn;
 #endif
 
 	/* ----------
@@ -922,31 +900,42 @@ connectDBStart(PGconn *conn)
 	 * ----------
 	 */
 retry1:
-	if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
-	{
+	  if(connect(sockfd, addr_cur->ai_addr, addr_cur->ai_addrlen) == 0){
+	    /* We're connected already */
+	    conn->status = CONNECTION_MADE;
+	    break;
+	  }
+	  else {
 		if (SOCK_ERRNO == EINTR)
 			/* Interrupted system call - we'll just try again */
 			goto retry1;
 
-		if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == 0)
-		{
-			/*
-			 * This is fine - we're in non-blocking mode, and the
-			 * connection is in progress.
-			 */
-			conn->status = CONNECTION_STARTED;
-		}
-		else
-		{
-			/* Something's gone wrong */
-			connectFailureMessage(conn, SOCK_ERRNO);
-			goto connect_errReturn;
-		}
+	    if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == 0){
+
+		/*
+		 * This is fine - we're in non-blocking mode, and the
+		 * connection is in progress.
+		 */
+		conn->status = CONNECTION_STARTED;
+		break;
+	    }
+	  }
+	  close(sockfd);
+	} while( (addr_cur = addr_cur->ai_next) != NULL);
+
+	if(addr_cur == NULL){
+	  printfPQExpBuffer(&conn->errorMessage,
+			    libpq_gettext("could not create socket: %s\n"),
+			    SOCK_STRERROR(SOCK_ERRNO));
+
+	  goto connect_errReturn;
 	}
-	else
-	{
-		/* We're connected already */
-		conn->status = CONNECTION_MADE;
+	else {
+	  family = addr_cur->ai_family;
+	  memmove(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen);
+	  conn->raddr_len = addr_cur->ai_addrlen;
+	  freeaddrinfo2(hint.ai_family, addrs);
+	  addrs = NULL;
 	}
 
 #ifdef USE_SSL
@@ -1038,7 +1027,9 @@ connect_errReturn:
 		conn->sock = -1;
 	}
 	conn->status = CONNECTION_BAD;
-
+	if(addrs != NULL){
+	  freeaddrinfo2(hint.ai_family, addrs);
+	}
 	return 0;
 }
 
-- 
GitLab