8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -800,7 +800,6 @@ static int
800
800
connectDBStart (PGconn * conn )
801
801
{
802
802
int portnum ;
803
- int sockfd ;
804
803
char portstr [64 ];
805
804
#ifdef USE_SSL
806
805
StartupPacket np ; /* Used to negotiate SSL connection */
@@ -837,19 +836,17 @@ connectDBStart(PGconn *conn)
837
836
conn -> outCount = 0 ;
838
837
839
838
/*
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
+ *
847
841
* This code is confusing because IPv6 creates a hint structure
848
842
* that is passed to getaddrinfo2(), which returns a list of address
849
843
* structures that are looped through, while IPv4 creates an address
850
844
* structure directly.
851
845
*/
852
846
847
+ MemSet ((char * ) & conn -> raddr , 0 , sizeof (conn -> raddr ));
848
+
849
+ /* Set port number */
853
850
if (conn -> pgport != NULL && conn -> pgport [0 ] != '\0' )
854
851
portnum = atoi (conn -> pgport );
855
852
else
@@ -875,8 +872,8 @@ connectDBStart(PGconn *conn)
875
872
876
873
family = AF_INET ;
877
874
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 ));
880
877
#endif
881
878
}
882
879
else if (conn -> pghost != NULL && conn -> pghost [0 ] != '\0' )
@@ -892,36 +889,39 @@ connectDBStart(PGconn *conn)
892
889
family = AF_INET ;
893
890
#endif
894
891
}
895
- #ifdef HAVE_UNIX_SOCKETS
896
892
else
897
893
{
894
+ #ifdef HAVE_UNIX_SOCKETS
898
895
#ifdef HAVE_IPV6
899
896
node = unix_node ;
900
897
hint .ai_family = AF_UNIX ;
901
898
#else
902
899
/* pghostaddr and pghost are NULL, so use Unix domain socket */
903
900
family = AF_UNIX ;
904
901
#endif
905
- }
906
902
#endif /* HAVE_UNIX_SOCKETS */
903
+ }
907
904
908
905
#ifndef HAVE_IPV6
906
+ /* Set family */
909
907
conn -> raddr .sa .sa_family = family ;
910
908
#endif
911
909
912
910
#ifdef HAVE_IPV6
913
911
if (hint .ai_family == AF_UNSPEC )
914
- {/* do nothing*/ }
912
+ {
913
+ /* do nothing */
914
+ }
915
915
#else
916
916
if (family == AF_INET )
917
917
{
918
918
conn -> raddr .in .sin_port = htons ((unsigned short ) (portnum ));
919
919
conn -> raddr_len = sizeof (struct sockaddr_in );
920
920
}
921
921
#endif
922
- #ifdef HAVE_UNIX_SOCKETS
923
922
else
924
923
{
924
+ #ifdef HAVE_UNIX_SOCKETS
925
925
UNIXSOCK_PATH (conn -> raddr .un , portnum , conn -> pgunixsocket );
926
926
conn -> raddr_len = UNIXSOCK_LEN (conn -> raddr .un );
927
927
StrNCpy (portstr , conn -> raddr .un .sun_path , sizeof (portstr ));
@@ -930,10 +930,11 @@ connectDBStart(PGconn *conn)
930
930
conn -> allow_ssl_try = false;
931
931
conn -> require_ssl = false;
932
932
#endif
933
- }
934
933
#endif /* HAVE_UNIX_SOCKETS */
934
+ }
935
935
936
- #if HAVE_IPV6
936
+ #ifdef HAVE_IPV6
937
+ /* Use getaddrinfo2() to resolve the address */
937
938
ret = getaddrinfo2 (node , portstr , & hint , & addrs );
938
939
if (ret || addrs == NULL )
939
940
{
@@ -942,21 +943,52 @@ connectDBStart(PGconn *conn)
942
943
gai_strerror (ret ));
943
944
goto connect_errReturn ;
944
945
}
945
- addr_cur = addrs ;
946
946
#endif
947
947
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
+ )
949
965
{
966
+ /* Open a socket */
950
967
#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 );
953
970
#else
954
- sockfd = socket (family , SOCK_STREAM , 0 );
971
+ conn -> sock = socket (family , SOCK_STREAM , 0 );
955
972
#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
+ goto connect_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
+ */
958
991
959
- conn -> sock = sockfd ;
960
992
#ifdef HAVE_IPV6
961
993
if (isAF_INETx (addr_cur -> ai_family ))
962
994
#else
@@ -966,6 +998,7 @@ connectDBStart(PGconn *conn)
966
998
if (!connectNoDelay (conn ))
967
999
goto connect_errReturn ;
968
1000
}
1001
+
969
1002
#if !defined(USE_SSL )
970
1003
if (connectMakeNonblocking (conn ) == 0 )
971
1004
goto connect_errReturn ;
@@ -982,16 +1015,10 @@ connectDBStart(PGconn *conn)
982
1015
*/
983
1016
retry1 :
984
1017
#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 )
986
1019
#else
987
- if (connect (sockfd , & conn -> raddr .sa , conn -> raddr_len ) == 0 )
1020
+ if (connect (conn -> sock , & conn -> raddr .sa , conn -> raddr_len ) < 0 )
988
1021
#endif
989
- {
990
- /* We're connected already */
991
- conn -> status = CONNECTION_MADE ;
992
- break ;
993
- }
994
- else
995
1022
{
996
1023
if (SOCK_ERRNO == EINTR )
997
1024
/* Interrupted system call - we'll just try again */
@@ -1006,30 +1033,39 @@ connectDBStart(PGconn *conn)
1006
1033
conn -> status = CONNECTION_STARTED ;
1007
1034
break ;
1008
1035
}
1036
+ /* otherwise, trouble */
1037
+ }
1038
+ else
1039
+ {
1040
+ /* We're connected already */
1041
+ conn -> status = CONNECTION_MADE ;
1042
+ break ;
1009
1043
}
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
+ */
1011
1048
#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
+ }
1017
1056
#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 );
1022
1058
goto connect_errReturn ;
1023
- }
1024
- else
1025
- {
1059
+ } /* loop over addrs */
1060
+
1026
1061
#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 ;
1031
1068
#endif
1032
- }
1033
1069
1034
1070
#ifdef USE_SSL
1035
1071
/* Attempt to negotiate SSL usage */
0 commit comments