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 68123ae74c..fbc22aabbc 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $Header: /cvsroot/pgsql/configure.in,v 1.219 2002/12/03 21:50:43 momjian Exp $ +dnl $Header: /cvsroot/pgsql/configure.in,v 1.220 2002/12/06 03:46:24 momjian Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -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 cc4f750a7d..6e7c1561b4 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 0e0b64555b..dfd6d1e93f 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 396347945e..5cdf60da96 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 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 62e8bd44cd..757a8a72ce 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); - } + 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; + } - 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; - } + + /** 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); + if (family == AF_UNIX){ + if(StreamServerPortSubAFUNIX2() != STATUS_OK){ + freeaddrinfo2(hint.ai_family, addrs); + return STATUS_ERROR; + } + } +#endif - /* - * 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; + /* + * 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; - val = strtoul(Unix_socket_group, &endptr, 10); - if (*endptr == '\0') - { - /* numeric group id */ - gid = val; - } - else - { - /* convert group name to id */ - struct group *gr; + 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; + } - 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; - } - } + *fdP = fd; + freeaddrinfo2(hint.ai_family, addrs); + return STATUS_OK; - 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, "StreamServerPort: listen() failed: %m"); - return STATUS_ERROR; - } - - *fdP = fd; - - return STATUS_OK; } +#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; +} + + +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 8f34a3fd2d..0778784490 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 5e4db4d243..b0b1041be1 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 4066c23e0e..a84978c570 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 6537f86074..a91611cd30 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 7cdd246662..36782ecf70 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 #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 - { - /* pghostaddr and pghost are NULL, so use Unix domain socket */ - family = AF_UNIX; - } - - /* Set family */ - conn->raddr.sa.sa_family = family; - - /* Set port number */ - if (conn->pgport != NULL && conn->pgport[0] != '\0') - 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); + else if (conn->pghost != NULL && conn->pghost[0] != '\0'){ + node = conn->pghost; + hint.ai_family = AF_UNSPEC; } #ifdef HAVE_UNIX_SOCKETS + else { + node = unix_node; + hint.ai_family = AF_UNIX; + } +#endif /* HAVE_UNIX_SOCKETS */ + + if (conn->pgport != NULL && conn->pgport[0] != '\0') + portno = atoi(conn->pgport); else - { - UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket); - conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un); + 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); + 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 +#endif /* HAVE_UNIX_SOCKETS */ - /* 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; + 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; } - - /* - * 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; - } - + 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; }