*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
connectDBStart(PGconn *conn)
{
int portnum;
- int sockfd;
char portstr[64];
#ifdef USE_SSL
StartupPacket np; /* Used to negotiate SSL connection */
conn->outCount = 0;
/*
- * Set up the connection to postmaster/backend. Note that this
- * supports IPv4 and UDP only.
- */
-
- MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
-
- /*
+ * Set up the connection to postmaster/backend.
+ *
* This code is confusing because IPv6 creates a hint structure
* that is passed to getaddrinfo2(), which returns a list of address
* structures that are looped through, while IPv4 creates an address
* structure directly.
*/
+ MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
+
+ /* Set port number */
if (conn->pgport != NULL && conn->pgport[0] != '\0')
portnum = atoi(conn->pgport);
else
family = AF_INET;
- memmove((char *) &(conn->raddr.in.sin_addr),
- (char *) &addr, sizeof(addr));
+ memcpy((char *) &(conn->raddr.in.sin_addr),
+ (char *) &addr, sizeof(addr));
#endif
}
else if (conn->pghost != NULL && conn->pghost[0] != '\0')
family = AF_INET;
#endif
}
-#ifdef HAVE_UNIX_SOCKETS
else
{
+#ifdef HAVE_UNIX_SOCKETS
#ifdef HAVE_IPV6
node = unix_node;
hint.ai_family = AF_UNIX;
/* pghostaddr and pghost are NULL, so use Unix domain socket */
family = AF_UNIX;
#endif
- }
#endif /* HAVE_UNIX_SOCKETS */
+ }
#ifndef HAVE_IPV6
+ /* Set family */
conn->raddr.sa.sa_family = family;
#endif
#ifdef HAVE_IPV6
if (hint.ai_family == AF_UNSPEC)
- {/* do nothing*/}
+ {
+ /* do nothing */
+ }
#else
if (family == AF_INET)
{
conn->raddr_len = sizeof(struct sockaddr_in);
}
#endif
-#ifdef HAVE_UNIX_SOCKETS
else
{
+#ifdef HAVE_UNIX_SOCKETS
UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket);
conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr));
conn->allow_ssl_try = false;
conn->require_ssl = false;
#endif
- }
#endif /* HAVE_UNIX_SOCKETS */
+ }
-#if HAVE_IPV6
+#ifdef HAVE_IPV6
+ /* Use getaddrinfo2() to resolve the address */
ret = getaddrinfo2(node, portstr, &hint, &addrs);
if (ret || addrs == NULL)
{
gai_strerror(ret));
goto connect_errReturn;
}
- addr_cur = addrs;
#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
+ addr_cur = addrs; ; addr_cur = addr_cur->ai_next
+#else
+ ;;
+#endif
+ )
{
+ /* Open a socket */
#ifdef HAVE_IPV6
- sockfd = socket(addr_cur->ai_family, SOCK_STREAM,
- addr_cur->ai_protocol);
+ conn->sock = socket(addr_cur->ai_family, SOCK_STREAM,
+ addr_cur->ai_protocol);
#else
- sockfd = socket(family, SOCK_STREAM, 0);
+ conn->sock = socket(family, SOCK_STREAM, 0);
#endif
- if (sockfd < 0)
- continue;
+ 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
if (isAF_INETx(addr_cur->ai_family))
#else
if (!connectNoDelay(conn))
goto connect_errReturn;
}
+
#if !defined(USE_SSL)
if (connectMakeNonblocking(conn) == 0)
goto connect_errReturn;
*/
retry1:
#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
- if (connect(sockfd, &conn->raddr.sa, conn->raddr_len) == 0)
+ if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
#endif
{
- /* We're connected already */
- conn->status = CONNECTION_MADE;
- break;
- }
- else
- {
if (SOCK_ERRNO == EINTR)
/* Interrupted system call - we'll just try again */
goto retry1;
conn->status = CONNECTION_STARTED;
break;
}
+ /* otherwise, trouble */
+ }
+ else
+ {
+ /* We're connected already */
+ conn->status = CONNECTION_MADE;
+ break;
}
- close(sockfd);
+ /*
+ * This connection failed. We need to close the socket,
+ * and either loop to try the next address or report an error.
+ */
#ifdef HAVE_IPV6
- } while ((addr_cur = addr_cur->ai_next) != NULL);
- if (addr_cur == NULL)
-#else
- } while (0);
- if (sockfd < 0)
+ /* ignore connect() failure if we have more addrs to try */
+ if (addr_cur->ai_next != NULL)
+ {
+ close(conn->sock);
+ conn->sock = -1;
+ continue;
+ }
#endif
- {
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not create socket: %s\n"),
- SOCK_STRERROR(SOCK_ERRNO));
+ connectFailureMessage(conn, SOCK_ERRNO);
goto connect_errReturn;
- }
- else
- {
+ } /* loop over addrs */
+
#ifdef HAVE_IPV6
- 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;
+ /* Remember the successfully opened address alternative */
+ memcpy(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen);
+ conn->raddr_len = addr_cur->ai_addrlen;
+ /* and release the address list */
+ FREEADDRINFO2(hint.ai_family, addrs);
+ addrs = NULL;
#endif
- }
#ifdef USE_SSL
/* Attempt to negotiate SSL usage */