diff options
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 193 |
1 files changed, 92 insertions, 101 deletions
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; } |