aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/Makefile4
-rw-r--r--src/backend/libpq/auth.c9
-rw-r--r--src/backend/libpq/hba.c27
-rw-r--r--src/backend/libpq/pg_hba.conf.sample5
-rw-r--r--src/backend/libpq/pqcomm.c341
-rw-r--r--src/backend/postmaster/postmaster.c9
-rw-r--r--src/include/libpq/libpq.h3
-rw-r--r--src/include/libpq/pqcomm.h3
-rw-r--r--src/interfaces/libpq/Makefile3
-rw-r--r--src/interfaces/libpq/fe-connect.c193
10 files changed, 324 insertions, 273 deletions
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;
}