aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/libpq/Makefile11
-rw-r--r--src/interfaces/libpq/fe-connect.c226
2 files changed, 160 insertions, 77 deletions
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 4a31afb3d88..2fbab37e161 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.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 $
#
#-------------------------------------------------------------------------
@@ -21,8 +21,8 @@ SO_MINOR_VERSION= 1
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))
@@ -45,6 +45,9 @@ dllist.c: $(backend_src)/lib/dllist.c
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,
@@ -70,5 +73,5 @@ uninstall: uninstall-lib
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
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 659114f9995..8ce8f197807 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.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 $
*
*-------------------------------------------------------------------------
*/
@@ -39,6 +39,9 @@
#include <arpa/inet.h>
#endif
+#include "libpq/ip.h"
+
+
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif
@@ -48,6 +51,14 @@
#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)
@@ -784,19 +795,32 @@ connectFailureMessage(PGconn *conn, int errorno)
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
*/
@@ -815,10 +839,26 @@ connectDBStart(PGconn *conn)
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))
@@ -833,120 +873,158 @@ connectDBStart(PGconn *conn)
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
@@ -1014,7 +1092,6 @@ retry2:
}
#endif
-
/*
* This makes the connection non-blocking, for all those cases which
* forced us not to do it above.
@@ -1038,7 +1115,10 @@ connect_errReturn:
conn->sock = -1;
}
conn->status = CONNECTION_BAD;
-
+#ifdef HAVE_IPV6
+ if (addrs != NULL)
+ FREEADDRINFO2(hint.ai_family, addrs);
+#endif
return 0;
}