OSDN Git Service

Fix some of the breakage from the IPV6 patch.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Feb 2003 01:24:26 +0000 (01:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Feb 2003 01:24:26 +0000 (01:24 +0000)
src/interfaces/libpq/fe-connect.c

index a3368a8..dd651fd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
 {
        int                     portnum;
-       int                     sockfd;
        char            portstr[64];
 #ifdef USE_SSL
        StartupPacket np;                       /* Used to negotiate SSL connection */
@@ -837,19 +836,17 @@ connectDBStart(PGconn *conn)
        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
@@ -875,8 +872,8 @@ connectDBStart(PGconn *conn)
 
                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')
@@ -892,9 +889,9 @@ connectDBStart(PGconn *conn)
                family = AF_INET;
 #endif
        }
-#ifdef HAVE_UNIX_SOCKETS
        else
        {
+#ifdef HAVE_UNIX_SOCKETS
 #ifdef HAVE_IPV6
                node = unix_node;
                hint.ai_family = AF_UNIX;
@@ -902,16 +899,19 @@ connectDBStart(PGconn *conn)
                /* 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)
        {
@@ -919,9 +919,9 @@ connectDBStart(PGconn *conn)
                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));
@@ -930,10 +930,11 @@ connectDBStart(PGconn *conn)
                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)
        {
@@ -942,21 +943,52 @@ connectDBStart(PGconn *conn)
                                                  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
@@ -966,6 +998,7 @@ connectDBStart(PGconn *conn)
                        if (!connectNoDelay(conn))
                                goto connect_errReturn;
                }
+
 #if !defined(USE_SSL)
                if (connectMakeNonblocking(conn) == 0)
                        goto connect_errReturn;
@@ -982,17 +1015,11 @@ connectDBStart(PGconn *conn)
                 */
 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;
@@ -1006,30 +1033,39 @@ 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 */