summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Momjian2002-12-06 03:46:37 +0000
committerBruce Momjian2002-12-06 03:46:37 +0000
commit2e110684af6a275cd3df3c621f2d5c921348579f (patch)
tree91eb62cb4018ff3875b844bbcf16ffb104198d09
parent8314213b04ad4e6922d40c32dfe703a183140d68 (diff)
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 <[email protected]> Johan Jordaan <[email protected]>
-rwxr-xr-xconfigure3
-rw-r--r--configure.in1
-rw-r--r--src/backend/libpq/Makefile2
-rw-r--r--src/backend/libpq/auth.c7
-rw-r--r--src/backend/libpq/hba.c25
-rw-r--r--src/backend/libpq/pg_hba.conf.sample5
-rw-r--r--src/backend/libpq/pqcomm.c339
-rw-r--r--src/backend/postmaster/postmaster.c7
-rw-r--r--src/include/libpq/libpq.h1
-rw-r--r--src/include/libpq/pqcomm.h1
-rw-r--r--src/interfaces/libpq/Makefile1
-rw-r--r--src/interfaces/libpq/fe-connect.c191
12 files changed, 318 insertions, 265 deletions
diff --git a/configure b/configure
index bb0a28bb08..87c26d234f 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 6c49f6f1d4..caeadb29af 100644
--- a/configure.in
+++ b/configure.in
@@ -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 b74bc691c0..2ba8b7e7f4 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -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 f4ec041b73..e00ebdfc58 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -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 12f90e9c5f..3835eb4ccf 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -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 5338c79104..4ff29977c6 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 82a5e7856a..eb13ef61ae 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -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 0f1e4c20ec..112404ae86 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -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 a0bd15eed3..60e286b2f4 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -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 d0ad9e8e9f..2c3beef1f8 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -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 8b6473d780..9a4c5bf826 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -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 3e380f2619..f2666932d8 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -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;
}