Fix some of the breakage from the IPV6 patch.

This commit is contained in:
Tom Lane 2003-02-14 01:24:26 +00:00
parent 874e8cef99
commit e8a10dc7e9
1 changed files with 88 additions and 52 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.222 2003/01/30 19:49:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.223 2003/02/14 01:24:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -800,7 +800,6 @@ static int
connectDBStart(PGconn *conn) connectDBStart(PGconn *conn)
{ {
int portnum; int portnum;
int sockfd;
char portstr[64]; char portstr[64];
#ifdef USE_SSL #ifdef USE_SSL
StartupPacket np; /* Used to negotiate SSL connection */ StartupPacket np; /* Used to negotiate SSL connection */
@ -837,19 +836,17 @@ connectDBStart(PGconn *conn)
conn->outCount = 0; conn->outCount = 0;
/* /*
* Set up the connection to postmaster/backend. Note that this * Set up the connection to postmaster/backend.
* supports IPv4 and UDP only. *
*/
MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
/*
* This code is confusing because IPv6 creates a hint structure * This code is confusing because IPv6 creates a hint structure
* that is passed to getaddrinfo2(), which returns a list of address * that is passed to getaddrinfo2(), which returns a list of address
* structures that are looped through, while IPv4 creates an address * structures that are looped through, while IPv4 creates an address
* structure directly. * structure directly.
*/ */
MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
/* Set port number */
if (conn->pgport != NULL && conn->pgport[0] != '\0') if (conn->pgport != NULL && conn->pgport[0] != '\0')
portnum = atoi(conn->pgport); portnum = atoi(conn->pgport);
else else
@ -875,8 +872,8 @@ connectDBStart(PGconn *conn)
family = AF_INET; family = AF_INET;
memmove((char *) &(conn->raddr.in.sin_addr), memcpy((char *) &(conn->raddr.in.sin_addr),
(char *) &addr, sizeof(addr)); (char *) &addr, sizeof(addr));
#endif #endif
} }
else if (conn->pghost != NULL && conn->pghost[0] != '\0') else if (conn->pghost != NULL && conn->pghost[0] != '\0')
@ -892,9 +889,9 @@ connectDBStart(PGconn *conn)
family = AF_INET; family = AF_INET;
#endif #endif
} }
#ifdef HAVE_UNIX_SOCKETS
else else
{ {
#ifdef HAVE_UNIX_SOCKETS
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
node = unix_node; node = unix_node;
hint.ai_family = AF_UNIX; hint.ai_family = AF_UNIX;
@ -902,16 +899,19 @@ connectDBStart(PGconn *conn)
/* pghostaddr and pghost are NULL, so use Unix domain socket */ /* pghostaddr and pghost are NULL, so use Unix domain socket */
family = AF_UNIX; family = AF_UNIX;
#endif #endif
}
#endif /* HAVE_UNIX_SOCKETS */ #endif /* HAVE_UNIX_SOCKETS */
}
#ifndef HAVE_IPV6 #ifndef HAVE_IPV6
/* Set family */
conn->raddr.sa.sa_family = family; conn->raddr.sa.sa_family = family;
#endif #endif
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (hint.ai_family == AF_UNSPEC) if (hint.ai_family == AF_UNSPEC)
{/* do nothing*/} {
/* do nothing */
}
#else #else
if (family == AF_INET) if (family == AF_INET)
{ {
@ -919,9 +919,9 @@ connectDBStart(PGconn *conn)
conn->raddr_len = sizeof(struct sockaddr_in); conn->raddr_len = sizeof(struct sockaddr_in);
} }
#endif #endif
#ifdef HAVE_UNIX_SOCKETS
else else
{ {
#ifdef HAVE_UNIX_SOCKETS
UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket); UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket);
conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un); conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr)); StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr));
@ -930,10 +930,11 @@ connectDBStart(PGconn *conn)
conn->allow_ssl_try = false; conn->allow_ssl_try = false;
conn->require_ssl = false; conn->require_ssl = false;
#endif #endif
}
#endif /* HAVE_UNIX_SOCKETS */ #endif /* HAVE_UNIX_SOCKETS */
}
#if HAVE_IPV6 #ifdef HAVE_IPV6
/* Use getaddrinfo2() to resolve the address */
ret = getaddrinfo2(node, portstr, &hint, &addrs); ret = getaddrinfo2(node, portstr, &hint, &addrs);
if (ret || addrs == NULL) if (ret || addrs == NULL)
{ {
@ -942,21 +943,52 @@ connectDBStart(PGconn *conn)
gai_strerror(ret)); gai_strerror(ret));
goto connect_errReturn; goto connect_errReturn;
} }
addr_cur = addrs;
#endif #endif
do /*
{ * For IPV6 we loop over the possible addresses returned by
* getaddrinfo2(), and fail only when they all fail (reporting the
* error returned for the *last* alternative, which may not be what
* users expect :-(). Otherwise, there is no true loop here.
*
* In either case, we never actually fall out of the loop; the
* only exits are via "break" or "goto connect_errReturn". Thus,
* there is no exit test in the for().
*/
for (
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
sockfd = socket(addr_cur->ai_family, SOCK_STREAM, addr_cur = addrs; ; addr_cur = addr_cur->ai_next
addr_cur->ai_protocol);
#else #else
sockfd = socket(family, SOCK_STREAM, 0); ;;
#endif #endif
if (sockfd < 0) )
continue; {
/* Open a socket */
#ifdef HAVE_IPV6
conn->sock = socket(addr_cur->ai_family, SOCK_STREAM,
addr_cur->ai_protocol);
#else
conn->sock = socket(family, SOCK_STREAM, 0);
#endif
if (conn->sock < 0)
{
#ifdef HAVE_IPV6
/* ignore socket() failure if we have more addrs to try */
if (addr_cur->ai_next != NULL)
continue;
#endif
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?).
*/
conn->sock = sockfd;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (isAF_INETx(addr_cur->ai_family)) if (isAF_INETx(addr_cur->ai_family))
#else #else
@ -966,6 +998,7 @@ connectDBStart(PGconn *conn)
if (!connectNoDelay(conn)) if (!connectNoDelay(conn))
goto connect_errReturn; goto connect_errReturn;
} }
#if !defined(USE_SSL) #if !defined(USE_SSL)
if (connectMakeNonblocking(conn) == 0) if (connectMakeNonblocking(conn) == 0)
goto connect_errReturn; goto connect_errReturn;
@ -982,16 +1015,10 @@ connectDBStart(PGconn *conn)
*/ */
retry1: retry1:
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (connect(sockfd, addr_cur->ai_addr, addr_cur->ai_addrlen) == 0) if (connect(conn->sock, addr_cur->ai_addr, addr_cur->ai_addrlen) < 0)
#else #else
if (connect(sockfd, &conn->raddr.sa, conn->raddr_len) == 0) if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
#endif #endif
{
/* We're connected already */
conn->status = CONNECTION_MADE;
break;
}
else
{ {
if (SOCK_ERRNO == EINTR) if (SOCK_ERRNO == EINTR)
/* Interrupted system call - we'll just try again */ /* Interrupted system call - we'll just try again */
@ -1006,30 +1033,39 @@ retry1:
conn->status = CONNECTION_STARTED; conn->status = CONNECTION_STARTED;
break; break;
} }
/* otherwise, trouble */
} }
close(sockfd); else
{
/* We're connected already */
conn->status = CONNECTION_MADE;
break;
}
/*
* This connection failed. We need to close the socket,
* and either loop to try the next address or report an error.
*/
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
} while ((addr_cur = addr_cur->ai_next) != NULL); /* ignore connect() failure if we have more addrs to try */
if (addr_cur == NULL) if (addr_cur->ai_next != NULL)
#else {
} while (0); close(conn->sock);
if (sockfd < 0) conn->sock = -1;
continue;
}
#endif #endif
{ connectFailureMessage(conn, SOCK_ERRNO);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not create socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO));
goto connect_errReturn; goto connect_errReturn;
} } /* loop over addrs */
else
{
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
memmove(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen); /* Remember the successfully opened address alternative */
conn->raddr_len = addr_cur->ai_addrlen; memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen);
FREEADDRINFO2(hint.ai_family, addrs); conn->raddr_len = addr_cur->ai_addrlen;
addrs = NULL; /* and release the address list */
FREEADDRINFO2(hint.ai_family, addrs);
addrs = NULL;
#endif #endif
}
#ifdef USE_SSL #ifdef USE_SSL
/* Attempt to negotiate SSL usage */ /* Attempt to negotiate SSL usage */