done
+# 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 $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. */
+/* 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) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+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
+
+ ;
+ 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
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { 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_func_getaddrinfo=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func_getaddrinfo=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext 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
+ HAVE_IPV6="yes"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+fi
+
+
+
if test "$with_readline" = yes; then
for ac_header in readline/readline.h
s,@python_moduleexecdir@,$python_moduleexecdir,;t t
s,@python_includespec@,$python_includespec,;t t
s,@python_libspec@,$python_libspec,;t t
+s,@HAVE_IPV6@,$HAVE_IPV6,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@HPUXMATHLIB@,$HPUXMATHLIB,;t t
s,@HAVE_POSIX_SIGNALS@,$HAVE_POSIX_SIGNALS,;t t
dnl Process this file with autoconf to produce a configure script.
-dnl $Header: /cvsroot/pgsql/configure.in,v 1.224 2002/12/30 17:19:49 tgl Exp $
+dnl $Header: /cvsroot/pgsql/configure.in,v 1.225 2003/01/06 03:18:25 momjian Exp $
dnl
dnl Developers, please strive to achieve this order:
dnl
#endif
])
+# This exports HAVE_IPV6 to both C files and Makefiles
+AC_CHECK_FUNC(getaddrinfo,
+ [HAVE_IPV6="yes"; AC_DEFINE(HAVE_IPV6, 1, [])], [])
+AC_SUBST(HAVE_IPV6)
+
if test "$with_readline" = yes; then
AC_CHECK_HEADERS(readline/readline.h, [],
[AC_CHECK_HEADERS(readline.h, [],
# Check for one of atexit() or on_exit()
AC_CHECK_FUNCS(atexit, [],
[AC_CHECK_FUNCS(on_exit, [],
- [AC_MSG_ERROR([neither atexit() nor on_exit() found])])])
+ [AC_MSG_ERROR([neither atexit() nor on_exit() found])])])
AC_FUNC_FSEEKO
must be zero for the record to match. (Of course IP addresses
can be spoofed but this consideration is beyond the scope of
+
PostgreSQL.) If you machine supports
+ IPv6, the default pg_hba.conf> will have an IPv6
+ entry for localhost>. You can add your own IPv6
+ entries to the file. IPv6 entries are used only for IPv6
+ connections.
# -*-makefile-*-
-# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.158 2003/01/05 13:45:47 petere Exp $
+# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.159 2003/01/06 03:18:26 momjian Exp $
#------------------------------------------------------------------------------
# All PostgreSQL makefiles include this file and use the variables it sets,
LDFLAGS += $(rpath)
endif
+HAVE_IPV6 = @HAVE_IPV6@
##########################################################################
#
#
# Copyright (c) 1994, Regents of the University of California
#
-# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.89 2002/12/14 00:24:23 petere Exp $
+# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.90 2003/01/06 03:18:26 momjian Exp $
#
#-------------------------------------------------------------------------
endif
endif
$(MAKE) -C catalog install-data
+ifdef HAVE_IPV6
$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample $(DESTDIR)$(datadir)/pg_hba.conf.sample
+else
+ grep -v '^host.*::1.*ffff:ffff:ffff:ffff:ffff:ffff' \
+ $(srcdir)/libpq/pg_hba.conf.sample \
+ > $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6
+ $(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6 $(DESTDIR)$(datadir)/pg_hba.conf.sample
+endif
$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample $(DESTDIR)$(datadir)/pg_ident.conf.sample
$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample $(DESTDIR)$(datadir)/postgresql.conf.sample
rm -f postgres$(X) $(POSTGRES_IMP) \
$(top_srcdir)/src/include/parser/parse.h \
$(top_builddir)/src/include/utils/fmgroids.h
+ifndef HAVE_IPV6
+ rm -f $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6
+endif
ifeq ($(PORTNAME), win)
rm -f postgres.dll postgres.def libpostgres.a
endif
# Makefile for libpq subsystem (backend half of libpq interface)
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.35 2002/12/06 04:37:02 momjian Exp $
+# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.36 2003/01/06 03:18:26 momjian Exp $
#
#-------------------------------------------------------------------------
# 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
+OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \
+ pqformat.o pqsignal.o
all: SUBSYS.o
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.94 2002/12/06 04:37:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.95 2003/01/06 03:18:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*/
{
const char *hostinfo = "localhost";
+#ifdef HAVE_IPV6
+ char ip_hostinfo[INET6_ADDRSTRLEN];
+#else
+ char ip_hostinfo[INET_ADDRSTRLEN];
+#endif
+ if (isAF_INETx(port->raddr.sa.sa_family) )
+ hostinfo = SockAddr_ntop(&port->raddr, ip_hostinfo,
+ sizeof(ip_hostinfo), 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);
+ "No pg_hba.conf entry for host %s, user %s, database %s",
+ hostinfo, port->user, port->database);
break;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.92 2002/12/14 18:49:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.93 2003/01/06 03:18:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
}
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)
{
if (!line)
goto hba_syntax;
token = lfirst(line);
- if (!inet_aton(token, &file_ip_addr))
+
+ if(SockAddr_pton(&file_ip_addr, token) < 0)
goto hba_syntax;
/* Read the mask field. */
if (!line)
goto hba_syntax;
token = lfirst(line);
- if (!inet_aton(token, &mask))
+
+ if(SockAddr_pton(&mask, 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. */
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.sa.sa_family) ||
+ !rangeSockAddr(&port->raddr, &file_ip_addr, &mask))
return;
}
else
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * ip.c
+ * Handles IPv6
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.1 2003/01/06 03:18:26 momjian Exp $
+ *
+ * This file and the IPV6 implementation were initially provided by
+ * Nigel Kukard , Linux Based Systems Design
+ * http://www.lbsd.net.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_NETINET_TCP_H
+#include
+#endif
+#include
+
+#include "libpq/libpq.h"
+#include "miscadmin.h"
+
+#ifdef FRONTEND
+#define elog fprintf
+#define LOG stderr
+#endif
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+ struct addrinfo **result);
+#endif /* HAVE_UNIX_SOCKETS */
+
+/*
+ * getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
+ */
+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 */
+}
+
+
+/*
+ * freeaddrinfo2 - free IPv6 addrinfo structures
+ */
+#ifdef HAVE_IPV6
+void
+freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
+{
+#ifdef HAVE_UNIX_SOCKETS
+ if (hint_ai_family == AF_UNIX)
+ {
+ struct addrinfo *p;
+
+ while (ai != NULL)
+ {
+ p = ai;
+ ai = ai->ai_next;
+ free(p->ai_addr);
+ free(p);
+ }
+ }
+ else
+#endif /* HAVE_UNIX_SOCKETS */
+ freeaddrinfo(ai);
+}
+#endif
+
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+/* -------
+ * getaddrinfo_unix - get unix socket info using IPv6
+ *
+ * Bug: only one addrinfo is set even though hintsp is NULL or
+ * ai_socktype is 0
+ * AI_CANNONNAME does not support.
+ * -------
+ */
+static int
+getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+ struct addrinfo **result)
+{
+ struct addrinfo hints;
+ struct addrinfo *aip;
+ struct sockaddr_un *unp;
+
+ MemSet(&hints, 0, sizeof(hints));
+
+ if (hintsp == NULL)
+ {
+ hints.ai_family = AF_UNIX;
+ hints.ai_socktype = SOCK_STREAM;
+ }
+ else
+ memcpy(&hints, hintsp, sizeof(hints));
+
+ if (hints.ai_socktype == 0)
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (!(hints.ai_family == AF_UNIX))
+ {
+ elog(LOG, "hints.ai_family is invalied getaddrinfo_unix()\n");
+ return EAI_ADDRFAMILY;
+ }
+
+ aip = calloc(1, sizeof(struct addrinfo));
+ if (aip == NULL)
+ return EAI_MEMORY;
+
+ aip->ai_family = AF_UNIX;
+ aip->ai_socktype = hints.ai_socktype;
+ aip->ai_protocol = hints.ai_protocol;
+ aip->ai_next = NULL;
+ aip->ai_canonname = NULL;
+ *result = aip;
+
+ unp = calloc(1, sizeof(struct sockaddr_un));
+ if (aip == NULL)
+ return EAI_MEMORY;
+
+ unp->sun_family = AF_UNIX;
+ aip->ai_addr = (struct sockaddr *) unp;
+ aip->ai_addrlen = sizeof(struct sockaddr_un);
+
+ if (strlen(path) >= sizeof(unp->sun_path))
+ return EAI_SERVICE;
+ strcpy(unp->sun_path, path);
+
+#if SALEN
+ unp->sun_len = sizeof(struct sockaddr_un);
+#endif /* SALEN */
+
+ if (hints.ai_flags & AI_PASSIVE)
+ unlink(unp->sun_path);
+
+ return 0;
+}
+#endif /* HAVE_UNIX_SOCKETS && HAVE_IPV6 */
+
+/* ----------
+ * SockAddr_ntop - set IP address string from SockAddr
+ *
+ * parameters... sa : SockAddr union
+ * dst : buffer for address string
+ * cnt : sizeof dst
+ * v4conv: non-zero: if address is IPv4 mapped IPv6 address then
+ * convert to IPv4 address.
+ * returns... pointer to dst
+ * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string.
+ * ----------
+ */
+char *
+SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
+{
+ switch (sa->sa.sa_family)
+ {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
+#else
+ StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
+#endif
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt);
+ if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr))
+ strcpy(dst, dst + 7);
+ break;
+#endif
+ default:
+ dst[0] = '\0';
+ break;
+ }
+ return dst;
+}
+
+
+/*
+ * SockAddr_pton - IPv6 pton
+ */
+int
+SockAddr_pton(SockAddr *sa, const char *src)
+{
+ int family = AF_INET;
+#ifdef HAVE_IPV6
+ const char *ch;
+
+ for (ch = src; *ch != '\0'; ch++)
+ {
+ if (*ch == ':')
+ {
+ family = AF_INET6;
+ break;
+ }
+ }
+#endif
+
+ sa->sa.sa_family = family;
+
+ switch (family)
+ {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ return inet_pton(AF_INET, src, &sa->in.sin_addr);
+#else
+ return inet_aton(src, &sa->in.sin_addr);
+#endif
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
+ break;
+#endif
+ default:
+ return -1;
+ }
+}
+
+
+
+
+/*
+ * isAF_INETx - check to see if sa is AF_INET or AF_INET6
+ */
+int
+isAF_INETx(const int family)
+{
+ if (family == AF_INET
+#ifdef HAVE_IPV6
+ || family == AF_INET6
+#endif
+ )
+ return 1;
+ else
+ return 0;
+}
+
+
+int
+rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
+{
+ if (addr->sa.sa_family == AF_INET)
+ return rangeSockAddrAF_INET(addr, netaddr, netmask);
+#ifdef HAVE_IPV6
+ else if (addr->sa.sa_family == AF_INET6)
+ return rangeSockAddrAF_INET6(addr, netaddr, netmask);
+#endif
+ else
+ return 0;
+}
+
+int
+rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask)
+{
+ if (addr->sa.sa_family != AF_INET ||
+ netaddr->sa.sa_family != AF_INET ||
+ netmask->sa.sa_family != AF_INET)
+ return 0;
+ if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
+ netmask->in.sin_addr.s_addr) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask)
+{
+ int i;
+
+ if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
+ {
+ SockAddr addr4;
+
+ convSockAddr6to4(addr, &addr4);
+ if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
+ return 1;
+ }
+
+ if (netaddr->sa.sa_family != AF_INET6 ||
+ netmask->sa.sa_family != AF_INET6)
+ return 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) &
+ netmask->in6.sin6_addr.s6_addr[i]) != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+convSockAddr6to4(const SockAddr *src, SockAddr *dst)
+{
+ char addr_str[INET6_ADDRSTRLEN];
+
+ dst->in.sin_family = AF_INET;
+ dst->in.sin_port = src->in6.sin6_port;
+
+ dst->in.sin_addr.s_addr = src->in6.sin6_addr.s6_addr32[3];
+ SockAddr_ntop(src, addr_str, INET6_ADDRSTRLEN, 0);
+}
+#endif
# 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:ffff:ffff:ffff trust
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqcomm.c,v 1.143 2002/12/06 04:37:02 momjian Exp $
+ * $Id: pqcomm.c,v 1.144 2003/01/06 03:18:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
static void pq_close(void);
+#ifdef HAVE_UNIX_SOCKETS
+int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
+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
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 ret;
+ char portNumberStr[64];
+ char *service;
- Assert(family == AF_INET || family == AF_UNIX);
+ /*
+ * IPv6 address lookups use a hint structure, while IPv4 creates an
+ * address structure directly.
+ */
- if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
- {
- elog(LOG, "StreamServerPort: socket() failed: %m");
- return STATUS_ERROR;
- }
+#ifdef HAVE_IPV6
+ struct addrinfo *addrs = NULL;
+ struct addrinfo hint;
- 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;
- }
- }
+ Assert(family == AF_INET6 || family == AF_INET || family == AF_UNIX);
+
+ /* Initialize hint structure */
+ MemSet(&hint, 0, sizeof(hint));
+ 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)
{
+ 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);
- 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);
+#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
+ return STATUS_ERROR;
+ }
- if (family == AF_INET)
+ if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
{
- /* TCP/IP socket */
- if (hostName[0] == '\0')
- saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
- else
- {
- struct hostent *hp;
+ elog(LOG, "server socket failure: socket(): %s",
+ strerror(errno));
+ FREEADDRINFO2(hint.ai_family, addrs);
+ return STATUS_ERROR;
+ }
- 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);
+ if (isAF_INETx(family))
+ {
+ if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+ sizeof(one))) == -1)
+ {
+ elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s",
+ strerror(errno));
+ FREEADDRINFO2(hint.ai_family, addrs);
+ return STATUS_ERROR;
}
-
- saddr.in.sin_port = htons(portNumber);
- len = sizeof(struct sockaddr_in);
}
- err = bind(fd, (struct sockaddr *) & saddr.sa, len);
+#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"
+ "\tIs another postmaster already running on port %d?",
+ strerror(errno), (int) portNumber);
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);
+ elog(LOG, "\tIf not, remove socket node (%s) and retry.",
+ 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);
+ elog(LOG, "\tIf not, wait a few seconds and retry.");
+ 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')
+ if (Setup_AF_UNIX() != STATUS_OK)
{
- 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 (chmod(sock_path, Unix_socket_permissions) == -1)
- {
- elog(LOG, "Could not set permissions on %s: %m",
- sock_path);
+ FREEADDRINFO2(hint.ai_family, addrs);
return STATUS_ERROR;
}
}
-#endif /* HAVE_UNIX_SOCKETS */
+#endif
/*
* Select appropriate accept-queue length limit. PG_SOMAXCONN is only
err = listen(fd, maxconn);
if (err < 0)
{
- elog(LOG, "StreamServerPort: listen() failed: %m");
+ elog(LOG, "server socket failure: listen(): %s",
+ strerror(errno));
+ FREEADDRINFO2(hint.ai_family, addrs);
return STATUS_ERROR;
}
*fdP = fd;
+ FREEADDRINFO2(hint.ai_family, addrs);
+ return STATUS_OK;
+
+}
+
+/*
+ * Lock_AF_UNIX -- configure unix socket file path
+ */
+
+#ifdef HAVE_UNIX_SOCKETS
+int
+Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
+{
+ SockAddr saddr; /* just used to get socket path */
+
+ UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
+ 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;
+}
+
+
+/*
+ * Setup_AF_UNIX -- configure unix socket permissions
+ */
+int
+Setup_AF_UNIX(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, "server socket failure: no such group '%s'",
+ Unix_socket_group);
+ return STATUS_ERROR;
+ }
+ gid = gr->gr_gid;
+ }
+ if (chown(sock_path, -1, gid) == -1)
+ {
+ elog(LOG, "server socket failure: could not set group of %s: %s",
+ sock_path, strerror(errno));
+ return STATUS_ERROR;
+ }
+ }
+
+ if (chmod(sock_path, Unix_socket_permissions) == -1)
+ {
+ elog(LOG, "server socket failure: could not set permissions on %s: %s",
+ sock_path, strerror(errno));
+ return STATUS_ERROR;
+ }
return STATUS_OK;
}
+#endif /* HAVE_UNIX_SOCKETS */
+
/*
* StreamConnection -- create a new connection with client using
/* accept connection (and fill in the client (remote) address) */
addrlen = sizeof(port->raddr);
if ((port->sock = accept(server_fd,
- (struct sockaddr *) & port->raddr,
+ (struct sockaddr *) &port->raddr,
&addrlen)) < 0)
{
elog(LOG, "StreamConnection: accept() failed: %m");
}
#ifdef SCO_ACCEPT_BUG
-
/*
* UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it
* shouldn't hurt to catch it for all versions of those platforms.
}
/* select NODELAY and KEEPALIVE options if it's a TCP connection */
- if (port->laddr.sa.sa_family == AF_INET)
+ if (isAF_INETx(port->laddr.sa.sa_family))
{
int on = 1;
*
* If maxlen is not zero, it is an upper limit on the length of the
* string we are willing to accept. We abort the connection (by
- * returning EOF) if client tries to send more than that. Note that
+ * returning EOF) if client tries to send more than that. Note that
* since we test maxlen in the outer per-bufferload loop, the limit
* is fuzzy: we might accept up to PQ_BUFFER_SIZE more bytes than
- * specified. This is fine for the intended purpose, which is just
+ * specified. This is fine for the intended purpose, which is just
* to prevent DoS attacks from not-yet-authenticated clients.
*
* NOTE: this routine does not do any character set conversion,
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.301 2002/12/06 04:37:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.302 2003/01/06 03:18:27 momjian Exp $
*
* NOTES
*
*/
if (NetServer)
{
- status = StreamServerPort(AF_INET, VirtualHost,
+#ifdef HAVE_IPV6
+ /* Try INET6 first. May fail if kernel doesn't support IP6 */
+ status = StreamServerPort(AF_INET6, VirtualHost,
(unsigned short) PostPortNumber,
UnixSocketDir,
&ServerSock_INET);
if (status != STATUS_OK)
{
- postmaster_error("cannot create INET stream port");
- ExitPostmaster(1);
+ elog(LOG, "IPv6 support disabled --- perhaps the kernel does not support IPv6");
+#endif
+ status = StreamServerPort(AF_INET, VirtualHost,
+ (unsigned short) PostPortNumber,
+ UnixSocketDir,
+ &ServerSock_INET);
+ if (status != STATUS_OK)
+ {
+ postmaster_error("cannot create INET stream port");
+ ExitPostmaster(1);
+ }
+#ifdef HAVE_IPV6
+ else
+ elog(LOG, "IPv4 socket created");
}
+#endif
}
#ifdef HAVE_UNIX_SOCKETS
/*
* 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.sa.sa_family))
{
unsigned short remote_port;
char *host_addr;
+#ifdef HAVE_IPV6
+ char ip_hostinfo[INET6_ADDRSTRLEN];
+#else
+ char ip_hostinfo[INET_ADDRSTRLEN];
+#endif
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,
+ sizeof(ip_hostinfo), 1);
remote_host = NULL;
--- /dev/null
+#ifndef IP_H
+#define IP_H
+#include
+#include
+#include "libpq/pqcomm.h"
+
+#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
+
+char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv);
+int SockAddr_pton(SockAddr *sa, const char *src);
+int isAF_INETx(const int family);
+int rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask);
+int rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask);
+#ifdef HAVE_IPV6
+int rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask);
+void convSockAddr6to4(const SockAddr *src, SockAddr *dst);
+#endif
+
+#endif /* IP_H */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq.h,v 1.54 2002/12/06 04:37:05 momjian Exp $
+ * $Id: libpq.h,v 1.55 2003/01/06 03:18:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "lib/stringinfo.h"
#include "libpq/libpq-be.h"
+#include "libpq/ip.h"
/* ----------------
* PQArgBlock
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqcomm.h,v 1.72 2002/12/06 04:37:05 momjian Exp $
+ * $Id: pqcomm.h,v 1.73 2003/01/06 03:18:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
{
struct sockaddr sa;
struct sockaddr_in in;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 in6;
+#endif
struct sockaddr_un un;
} SockAddr;
* 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.34 2002/11/10 00:38:21 momjian Exp $
+ * $Id: pg_config.h.in,v 1.35 2003/01/06 03:18:27 momjian Exp $
*/
#ifndef PG_CONFIG_H
/* Set to 1 if you have */
#undef HAVE_SYS_SHM_H
+/* Set to 1 if you have for IPv6 */
+#undef HAVE_IPV6
+
/* Set to 1 if you have */
#undef HAVE_KERNEL_OS_H
#
# Copyright (c) 1994, Regents of the University of California
#
-# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.70 2002/12/13 22:17:57 momjian Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.71 2003/01/06 03:18:27 momjian Exp $
#
#-------------------------------------------------------------------------
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
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 \
+ 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))
md5.c: $(backend_src)/libpq/md5.c
rm -f $@ && $(LN_S) $< .
+ip.c: $(backend_src)/libpq/ip.c
+ rm -f $@ && $(LN_S) $< .
+
# We use several backend modules verbatim, but since we need to
# compile with appropriate options to build a shared lib, we can't
# necessarily use the same object files as the backend uses. Instead,
rm -f $(DESTDIR)$(includedir)/libpq-fe.h $(DESTDIR)$(includedir_internal)/libpq-int.h $(includedir_internal)/pqexpbuffer.h
clean distclean maintainer-clean: clean-lib
- rm -f $(OBJS) dllist.c md5.c wchar.c encnames.c
+ rm -f $(OBJS) dllist.c md5.c v6util.c wchar.c encnames.c
rm -f $(OBJS) inet_aton.c snprintf.c strerror.c
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.216 2002/12/19 19:30:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.217 2003/01/06 03:18:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#endif
+#include "libpq/ip.h"
+
+
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif
#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)
static int
connectDBStart(PGconn *conn)
{
- int portno,
- family;
-
+ int portnum;
+ int sockfd;
+ char portstr[64];
#ifdef USE_SSL
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;
+ const char *node = NULL;
+ const char *unix_node = "unix";
+ int ret;
+
+ /* Initialize hint structure */
+ MemSet(&hint, 0, sizeof(hint));
+ hint.ai_socktype = SOCK_STREAM;
+#else
+ int family = -1;
+#endif
if (!conn)
return 0;
#ifdef NOT_USED
-
/*
* parse dbName to get all additional info in it, if any
*/
MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
+ /*
+ * 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.
+ */
+
+ if (conn->pgport != NULL && conn->pgport[0] != '\0')
+ portnum = atoi(conn->pgport);
+ else
+ portnum = DEF_PGPORT;
+ snprintf(portstr, sizeof(portstr), "%d", portnum);
+
if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
{
+#ifdef HAVE_IPV6
+ node = conn->pghostaddr;
+ hint.ai_family = AF_UNSPEC;
+#else
/* Using pghostaddr avoids a hostname lookup */
- /* Note that this supports IPv4 only */
struct in_addr addr;
if (!inet_aton(conn->pghostaddr, &addr))
memmove((char *) &(conn->raddr.in.sin_addr),
(char *) &addr, sizeof(addr));
+#endif
}
else if (conn->pghost != NULL && conn->pghost[0] != '\0')
{
+#ifdef HAVE_IPV6
+ node = conn->pghost;
+ hint.ai_family = AF_UNSPEC;
+#else
/* 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);
+ if (getaddrinfo2(conn->pghost, portstr, family, &conn->raddr) != 0)
goto connect_errReturn;
- }
- family = AF_INET;
- memmove((char *) &(conn->raddr.in.sin_addr),
- (char *) hp->h_addr,
- hp->h_length);
+ family = AF_INET;
+#endif
}
+#ifdef HAVE_UNIX_SOCKETS
else
{
+#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 */
- /* Set family */
+#ifndef HAVE_IPV6
conn->raddr.sa.sa_family = family;
+#endif
- /* Set port number */
- if (conn->pgport != NULL && conn->pgport[0] != '\0')
- portno = atoi(conn->pgport);
- else
- portno = DEF_PGPORT;
-
+#ifdef HAVE_IPV6
+ if (hint.ai_family == AF_UNSPEC)
+ {/* do nothing*/}
+#else
if (family == AF_INET)
{
- conn->raddr.in.sin_port = htons((unsigned short) (portno));
+ conn->raddr.in.sin_port = htons((unsigned short) (portnum));
conn->raddr_len = sizeof(struct sockaddr_in);
}
+#endif
#ifdef HAVE_UNIX_SOCKETS
else
{
- UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
+ 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));
#ifdef USE_SSL
/* Don't bother requesting SSL over a Unix socket */
conn->allow_ssl_try = false;
conn->require_ssl = false;
#endif
}
-#endif
+#endif /* HAVE_UNIX_SOCKETS */
- /* Open a socket */
- if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
+#if HAVE_IPV6
+ ret = getaddrinfo2(node, portstr, &hint, &addrs);
+ if (ret || addrs == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not create socket: %s\n"),
- SOCK_STRERROR(SOCK_ERRNO));
+ libpq_gettext("failed to getaddrinfo(): %s\n"),
+ gai_strerror(ret));
goto connect_errReturn;
}
+ addr_cur = addrs;
+#endif
- /*
- * 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)
+ do
{
- if (!connectNoDelay(conn))
- goto connect_errReturn;
- }
+#ifdef HAVE_IPV6
+ sockfd = socket(addr_cur->ai_family, SOCK_STREAM,
+ addr_cur->ai_protocol);
+#else
+ sockfd = socket(family, SOCK_STREAM, 0);
+#endif
+ if (sockfd < 0)
+ continue;
+ conn->sock = sockfd;
+#ifdef HAVE_IPV6
+ if (isAF_INETx(addr_cur->ai_family))
+#else
+ if (isAF_INETx(family))
+#endif
+ {
+ 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
- /* ----------
- * Start / make connection. We are hopefully in non-blocking mode
- * now, but it is possible that:
- * 1. Older systems will still block on connect, despite the
- * non-blocking flag. (Anyone know if this is true?)
- * 2. We are using SSL.
- * Thus, we have to make arrangements for all eventualities.
- * ----------
- */
+ /* ----------
+ * Start / make connection. We are hopefully in non-blocking mode
+ * now, but it is possible that:
+ * 1. Older systems will still block on connect, despite the
+ * non-blocking flag. (Anyone know if this is true?)
+ * 2. We are using SSL.
+ * Thus, we have to make arrangements for all eventualities.
+ * ----------
+ */
retry1:
- if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
- {
- if (SOCK_ERRNO == EINTR)
- /* Interrupted system call - we'll just try again */
- goto retry1;
-
- if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == 0)
+#ifdef HAVE_IPV6
+ if (connect(sockfd, addr_cur->ai_addr, addr_cur->ai_addrlen) == 0)
+#else
+ if (connect(sockfd, &conn->raddr.sa, conn->raddr_len) == 0)
+#endif
{
- /*
- * This is fine - we're in non-blocking mode, and the
- * connection is in progress.
- */
- conn->status = CONNECTION_STARTED;
+ /* We're connected already */
+ conn->status = CONNECTION_MADE;
+ break;
}
else
{
- /* Something's gone wrong */
- connectFailureMessage(conn, SOCK_ERRNO);
- goto connect_errReturn;
+ 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;
+ break;
+ }
}
+ close(sockfd);
+#ifdef HAVE_IPV6
+ } while ((addr_cur = addr_cur->ai_next) != NULL);
+ if (addr_cur == NULL)
+#else
+ } while (0);
+ if (sockfd < 0)
+#endif
+ {
+ 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;
+#ifdef HAVE_IPV6
+ 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;
+#endif
}
#ifdef USE_SSL
}
#endif
-
/*
* This makes the connection non-blocking, for all those cases which
* forced us not to do it above.
conn->sock = -1;
}
conn->status = CONNECTION_BAD;
-
+#ifdef HAVE_IPV6
+ if (addrs != NULL)
+ FREEADDRINFO2(hint.ai_family, addrs);
+#endif
return 0;
}