88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.222 2003/01/30 19:49:54 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.223 2003/02/14 01:24:26 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -800,7 +800,6 @@ static int
800800connectDBStart (PGconn * conn )
801801{
802802int portnum ;
803- int sockfd ;
804803char portstr [64 ];
805804#ifdef USE_SSL
806805StartupPacket np ;/* Used to negotiate SSL connection */
@@ -837,19 +836,17 @@ connectDBStart(PGconn *conn)
837836conn -> outCount = 0 ;
838837
839838/*
840- * Set up the connection to postmaster/backend. Note that this
841- * supports IPv4 and UDP only.
842- */
843-
844- MemSet ((char * )& conn -> raddr ,0 ,sizeof (conn -> raddr ));
845-
846- /*
839+ * Set up the connection to postmaster/backend.
840+ *
847841 *This code is confusing because IPv6 creates a hint structure
848842 *that is passed to getaddrinfo2(), which returns a list of address
849843 *structures that are looped through, while IPv4 creates an address
850844 *structure directly.
851845 */
852846
847+ MemSet ((char * )& conn -> raddr ,0 ,sizeof (conn -> raddr ));
848+
849+ /* Set port number */
853850if (conn -> pgport != NULL && conn -> pgport [0 ]!= '\0' )
854851portnum = atoi (conn -> pgport );
855852else
@@ -875,8 +872,8 @@ connectDBStart(PGconn *conn)
875872
876873family = AF_INET ;
877874
878- memmove ((char * )& (conn -> raddr .in .sin_addr ),
879- (char * )& addr ,sizeof (addr ));
875+ memcpy ((char * )& (conn -> raddr .in .sin_addr ),
876+ (char * )& addr ,sizeof (addr ));
880877#endif
881878}
882879else if (conn -> pghost != NULL && conn -> pghost [0 ]!= '\0' )
@@ -892,36 +889,39 @@ connectDBStart(PGconn *conn)
892889family = AF_INET ;
893890#endif
894891}
895- #ifdef HAVE_UNIX_SOCKETS
896892else
897893{
894+ #ifdef HAVE_UNIX_SOCKETS
898895#ifdef HAVE_IPV6
899896node = unix_node ;
900897hint .ai_family = AF_UNIX ;
901898#else
902899/* pghostaddr and pghost are NULL, so use Unix domain socket */
903900family = AF_UNIX ;
904901#endif
905- }
906902#endif /* HAVE_UNIX_SOCKETS */
903+ }
907904
908905#ifndef HAVE_IPV6
906+ /* Set family */
909907conn -> raddr .sa .sa_family = family ;
910908#endif
911909
912910#ifdef HAVE_IPV6
913911if (hint .ai_family == AF_UNSPEC )
914- {/* do nothing*/ }
912+ {
913+ /* do nothing */
914+ }
915915#else
916916if (family == AF_INET )
917917{
918918conn -> raddr .in .sin_port = htons ((unsigned short ) (portnum ));
919919conn -> raddr_len = sizeof (struct sockaddr_in );
920920}
921921#endif
922- #ifdef HAVE_UNIX_SOCKETS
923922else
924923{
924+ #ifdef HAVE_UNIX_SOCKETS
925925UNIXSOCK_PATH (conn -> raddr .un ,portnum ,conn -> pgunixsocket );
926926conn -> raddr_len = UNIXSOCK_LEN (conn -> raddr .un );
927927StrNCpy (portstr ,conn -> raddr .un .sun_path ,sizeof (portstr ));
@@ -930,10 +930,11 @@ connectDBStart(PGconn *conn)
930930conn -> allow_ssl_try = false;
931931conn -> require_ssl = false;
932932#endif
933- }
934933#endif /* HAVE_UNIX_SOCKETS */
934+ }
935935
936- #if HAVE_IPV6
936+ #ifdef HAVE_IPV6
937+ /* Use getaddrinfo2() to resolve the address */
937938ret = getaddrinfo2 (node ,portstr ,& hint ,& addrs );
938939if (ret || addrs == NULL )
939940{
@@ -942,21 +943,52 @@ connectDBStart(PGconn *conn)
942943gai_strerror (ret ));
943944gotoconnect_errReturn ;
944945}
945- addr_cur = addrs ;
946946#endif
947947
948- do
948+ /*
949+ * For IPV6 we loop over the possible addresses returned by
950+ * getaddrinfo2(), and fail only when they all fail (reporting the
951+ * error returned for the *last* alternative, which may not be what
952+ * users expect :-(). Otherwise, there is no true loop here.
953+ *
954+ * In either case, we never actually fall out of the loop; the
955+ * only exits are via "break" or "goto connect_errReturn". Thus,
956+ * there is no exit test in the for().
957+ */
958+ for (
959+ #ifdef HAVE_IPV6
960+ addr_cur = addrs ; ;addr_cur = addr_cur -> ai_next
961+ #else
962+ ;;
963+ #endif
964+ )
949965{
966+ /* Open a socket */
950967#ifdef HAVE_IPV6
951- sockfd = socket (addr_cur -> ai_family ,SOCK_STREAM ,
952- addr_cur -> ai_protocol );
968+ conn -> sock = socket (addr_cur -> ai_family ,SOCK_STREAM ,
969+ addr_cur -> ai_protocol );
953970#else
954- sockfd = socket (family ,SOCK_STREAM ,0 );
971+ conn -> sock = socket (family ,SOCK_STREAM ,0 );
955972#endif
956- if (sockfd < 0 )
957- continue ;
973+ if (conn -> sock < 0 )
974+ {
975+ #ifdef HAVE_IPV6
976+ /* ignore socket() failure if we have more addrs to try */
977+ if (addr_cur -> ai_next != NULL )
978+ continue ;
979+ #endif
980+ printfPQExpBuffer (& conn -> errorMessage ,
981+ libpq_gettext ("could not create socket: %s\n" ),
982+ SOCK_STRERROR (SOCK_ERRNO ));
983+ gotoconnect_errReturn ;
984+ }
985+
986+ /*
987+ * Set the right options. Normally, we need nonblocking I/O, and we
988+ * don't want delay of outgoing data for AF_INET sockets. If we are
989+ * using SSL, then we need the blocking I/O (XXX Can this be fixed?).
990+ */
958991
959- conn -> sock = sockfd ;
960992#ifdef HAVE_IPV6
961993if (isAF_INETx (addr_cur -> ai_family ))
962994#else
@@ -966,6 +998,7 @@ connectDBStart(PGconn *conn)
966998if (!connectNoDelay (conn ))
967999gotoconnect_errReturn ;
9681000}
1001+
9691002#if !defined(USE_SSL )
9701003if (connectMakeNonblocking (conn )== 0 )
9711004gotoconnect_errReturn ;
@@ -982,16 +1015,10 @@ connectDBStart(PGconn *conn)
9821015 */
9831016retry1 :
9841017#ifdef HAVE_IPV6
985- if (connect (sockfd ,addr_cur -> ai_addr ,addr_cur -> ai_addrlen )== 0 )
1018+ if (connect (conn -> sock ,addr_cur -> ai_addr ,addr_cur -> ai_addrlen )< 0 )
9861019#else
987- if (connect (sockfd ,& conn -> raddr .sa ,conn -> raddr_len )== 0 )
1020+ if (connect (conn -> sock ,& conn -> raddr .sa ,conn -> raddr_len )< 0 )
9881021#endif
989- {
990- /* We're connected already */
991- conn -> status = CONNECTION_MADE ;
992- break ;
993- }
994- else
9951022{
9961023if (SOCK_ERRNO == EINTR )
9971024/* Interrupted system call - we'll just try again */
@@ -1006,30 +1033,39 @@ connectDBStart(PGconn *conn)
10061033conn -> status = CONNECTION_STARTED ;
10071034break ;
10081035}
1036+ /* otherwise, trouble */
1037+ }
1038+ else
1039+ {
1040+ /* We're connected already */
1041+ conn -> status = CONNECTION_MADE ;
1042+ break ;
10091043}
1010- close (sockfd );
1044+ /*
1045+ * This connection failed. We need to close the socket,
1046+ * and either loop to try the next address or report an error.
1047+ */
10111048#ifdef HAVE_IPV6
1012- }while ((addr_cur = addr_cur -> ai_next )!= NULL );
1013- if (addr_cur == NULL )
1014- #else
1015- }while (0 );
1016- if (sockfd < 0 )
1049+ /* ignore connect() failure if we have more addrs to try */
1050+ if (addr_cur -> ai_next != NULL )
1051+ {
1052+ close (conn -> sock );
1053+ conn -> sock = -1 ;
1054+ continue ;
1055+ }
10171056#endif
1018- {
1019- printfPQExpBuffer (& conn -> errorMessage ,
1020- libpq_gettext ("could not create socket: %s\n" ),
1021- SOCK_STRERROR (SOCK_ERRNO ));
1057+ connectFailureMessage (conn ,SOCK_ERRNO );
10221058gotoconnect_errReturn ;
1023- }
1024- else
1025- {
1059+ }/* loop over addrs */
1060+
10261061#ifdef HAVE_IPV6
1027- memmove (& conn -> raddr ,addr_cur -> ai_addr ,addr_cur -> ai_addrlen );
1028- conn -> raddr_len = addr_cur -> ai_addrlen ;
1029- FREEADDRINFO2 (hint .ai_family ,addrs );
1030- addrs = NULL ;
1062+ /* Remember the successfully opened address alternative */
1063+ memcpy (& conn -> raddr ,addr_cur -> ai_addr ,addr_cur -> ai_addrlen );
1064+ conn -> raddr_len = addr_cur -> ai_addrlen ;
1065+ /* and release the address list */
1066+ FREEADDRINFO2 (hint .ai_family ,addrs );
1067+ addrs = NULL ;
10311068#endif
1032- }
10331069
10341070#ifdef USE_SSL
10351071/* Attempt to negotiate SSL usage */