aboutsummaryrefslogtreecommitdiffstats
path: root/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'socket.c')
-rw-r--r--socket.c51
1 files changed, 28 insertions, 23 deletions
diff --git a/socket.c b/socket.c
index c852e641..c0925723 100644
--- a/socket.c
+++ b/socket.c
@@ -152,7 +152,7 @@ int SockOpen(const char *host, int clientPort, const char *options,
#ifndef HAVE_INET_ATON
unsigned long inaddr;
#endif /* HAVE_INET_ATON */
- struct sockaddr_in ad;
+ struct sockaddr_in ad, **pptr;
struct hostent *hp;
#ifdef HAVE_SOCKETPAIR
@@ -195,30 +195,35 @@ int SockOpen(const char *host, int clientPort, const char *options,
return -1;
}
/*
- * FIXME: make this work for multihomed hosts.
- * We're toast if we get back multiple addresses and h_addrs[0]
- * (aka h_addr) is not one we can actually connect to; this happens
- * with multi-homed boxen.
+ * Try all addresses of a possibly multihomed host until we get
+ * a successful connect or until we run out of addresses.
*/
- memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
- }
- ad.sin_port = htons(clientPort);
-
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- {
- h_errno = 0;
- return -1;
- }
- if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
- {
- int olderr = errno;
- close(sock);
- h_errno = 0;
- errno = olderr;
- return -1;
+ pptr = (struct sockaddr_in **)hp->h_addr_list;
+ for(; *pptr != NULL; pptr++)
+ {
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ h_errno = 0;
+ return -1;
+ }
+ ad.sin_port = htons(clientPort);
+ memcpy(&ad.sin_addr, *pptr, sizeof(struct in_addr));
+ if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) == 0)
+ break; /* success */
+ close(sock);
+ memset(&ad, 0, sizeof(ad));
+ ad.sin_family = AF_INET;
+ }
+ if(*pptr == NULL)
+ {
+ int olderr = errno;
+ close(sock);
+ h_errno = 0;
+ errno = olderr;
+ return -1;
+ }
}
-
return(sock);
}
#endif /* INET6 */