diff options
Diffstat (limited to 'src/interfaces')
-rw-r--r-- | src/interfaces/libpq/Makefile | 11 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 226 |
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; } |