aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-06-10 11:06:21 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-06-10 11:06:21 +0000
commit9f341f9ce5ff2cc85a4cbdd38cd4b5c68b02504d (patch)
tree6e6c97746450dee34253768bfbba72039fd04d4c
parent20988715093810cde488cabe2b9f52fe5b300450 (diff)
Gisle Vanem's improved verbose output and timeout handling when connecting to
a host name that resolves to multiple IP addresses.
-rw-r--r--lib/connect.c113
-rw-r--r--lib/hostip.c38
-rw-r--r--lib/hostip.h12
-rw-r--r--lib/hostip6.c21
-rw-r--r--lib/hostthre.c2
-rw-r--r--lib/url.c20
6 files changed, 115 insertions, 91 deletions
diff --git a/lib/connect.c b/lib/connect.c
index 26bf28329..a2c5ad612 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -490,8 +490,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
/* check for connect without timeout as we want to return immediately */
rc = waitconnect(sockfd, 0);
- if(0 == rc) {
- if (verifyconnect(sockfd,NULL)) {
+ if(WAITCONN_CONNECTED == rc) {
+ if (verifyconnect(sockfd, NULL)) {
/* we are connected, awesome! */
*connected = TRUE;
return CURLE_OK;
@@ -500,7 +500,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
failf(data, "Connection failed");
return CURLE_COULDNT_CONNECT;
}
- else if(1 != rc) {
+ else if(WAITCONN_TIMEOUT != rc) {
int error = Curl_ourerrno();
failf(data, "Failed connect to %s:%d; %s",
conn->host.name, conn->port, Curl_strerror(conn,error));
@@ -549,22 +549,22 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
bool *connected) /* really connected? */
{
struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = CURL_SOCKET_BAD;
int rc, error;
- curl_socket_t sockfd= CURL_SOCKET_BAD;
- int aliasindex=0;
- char *hostname;
+ int aliasindex;
+ int num_addr;
+ const char *hostname;
+ bool conected;
+ Curl_ipconnect *curr_addr;
struct timeval after;
struct timeval before = Curl_tvnow();
-#ifdef ENABLE_IPV6
- struct addrinfo *ai;
-#endif
-
/*************************************************************
* Figure out what maximum time we have left
*************************************************************/
- long timeout_ms=300000; /* milliseconds, default to five minutes */
+ long timeout_ms=300000; /* milliseconds, default to five minutes total */
+ long timeout_per_addr;
*connected = FALSE; /* default to not connected */
@@ -600,31 +600,38 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
}
+ /* Max time for each address */
+ num_addr = Curl_num_addresses(remotehost->addr);
+ timeout_per_addr = timeout_ms / num_addr;
+
hostname = data->change.proxy?conn->proxy.name:conn->host.name;
+
infof(data, "About to connect() to %s port %d\n",
hostname, port);
+ /* Below is the loop that attempts to connect to all IP-addresses we
+ * know for the given host. One by one until one IP succeedes.
+ */
#ifdef ENABLE_IPV6
/*
* Connecting with a getaddrinfo chain
*/
- for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
- sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (sockfd == CURL_SOCKET_BAD)
+ for (curr_addr = remotehost->addr, aliasindex=0; curr_addr;
+ curr_addr = curr_addr->ai_next, aliasindex++) {
+ sockfd = socket(curr_addr->ai_family, curr_addr->ai_socktype,
+ curr_addr->ai_protocol);
+ if (sockfd == CURL_SOCKET_BAD) {
+ timeout_per_addr += timeout_per_addr / (num_addr - aliasindex);
continue;
+ }
- else if(data->set.tcp_nodelay)
- Curl_setNoDelay(conn, sockfd);
#else
/*
* Connecting with old style IPv4-only support
*/
-
- /* This is the loop that attempts to connect to all IP-addresses we
- know for the given host. One by one. */
- for(rc=-1, aliasindex=0;
- rc && (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
- aliasindex++) {
+ curr_addr = (Curl_ipconnect*)remotehost->addr->h_addr_list[0];
+ for(aliasindex=0; curr_addr;
+ curr_addr=(Curl_ipconnect*)remotehost->addr->h_addr_list[++aliasindex]) {
struct sockaddr_in serv_addr;
/* create an IPv4 TCP socket */
@@ -634,18 +641,24 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_COULDNT_CONNECT; /* big time error */
}
- else if(data->set.tcp_nodelay)
- Curl_setNoDelay(conn, sockfd);
-
/* nasty address work before connect can be made */
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
- memcpy((char *)&(serv_addr.sin_addr),
- (struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
+ memcpy((char *)&(serv_addr.sin_addr), curr_addr,
sizeof(struct in_addr));
serv_addr.sin_family = remotehost->addr->h_addrtype;
serv_addr.sin_port = htons((unsigned short)port);
#endif
+ {
+ char addr_buf[256] = "";
+
+ Curl_printable_address(curr_addr, addr_buf, sizeof(addr_buf));
+ infof(data, " Trying %s... ", addr_buf);
+ }
+
+ if(data->set.tcp_nodelay)
+ Curl_setNoDelay(conn, sockfd);
+
if(conn->data->set.device) {
/* user selected to bind the outgoing socket to a specified "device"
before doing connect */
@@ -661,7 +674,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
a defined macro on some platforms and some compilers don't like to mix
#ifdefs with macro usage! (AmigaOS is one such platform) */
#ifdef ENABLE_IPV6
- rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
+ rc = connect(sockfd, curr_addr->ai_addr, curr_addr->ai_addrlen);
#else
rc = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
#endif
@@ -682,9 +695,9 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* asynchronous connect, wait for connect or timeout */
if(data->state.used_interface == Curl_if_multi)
/* don't hang when doing multi */
- timeout_ms = 0;
+ timeout_per_addr = timeout_ms = 0;
- rc = waitconnect(sockfd, timeout_ms);
+ rc = waitconnect(sockfd, timeout_per_addr);
break;
default:
/* unknown error, fallthrough and try another address! */
@@ -694,26 +707,27 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
}
- /* The '1 == rc' comes from the waitconnect(), and not from connect().
- We can be sure of this since connect() cannot return 1. */
- if((1 == rc) && (data->state.used_interface == Curl_if_multi)) {
+ /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
+ connect(). We can be sure of this since connect() cannot return 1. */
+ if((WAITCONN_TIMEOUT == rc) &&
+ (data->state.used_interface == Curl_if_multi)) {
/* Timeout when running the multi interface, we return here with a
CURLE_OK return code. */
rc = 0;
break;
}
- if(0 == rc) {
- if (verifyconnect(sockfd,NULL)) {
- /* we are connected, awesome! */
- *connected = TRUE; /* this is a true connect */
- break;
- }
- /* nope, not connected for real */
- rc = -1;
+ conected = verifyconnect(sockfd, &error);
+
+ if(!rc && conected) {
+ /* we are connected, awesome! */
+ *connected = TRUE; /* this is a true connect */
+ break;
}
+ if(WAITCONN_TIMEOUT == rc)
+ infof(data, "Timeout\n");
else
- verifyconnect(sockfd,&error); /* get non-blocking error */
+ infof(data, "%s\n", Curl_strerror(conn, error));
/* connect failed or timed out */
sclose(sockfd);
@@ -727,24 +741,19 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_OPERATION_TIMEOUTED;
}
before = after;
- }
+ } /* end of connect-to-each-address loop */
+
if (sockfd == CURL_SOCKET_BAD) {
/* no good connect was made */
- *sockconn = -1;
- failf(data, "Connect failed; %s", Curl_strerror(conn,error));
+ *sockconn = CURL_SOCKET_BAD;
return CURLE_COULDNT_CONNECT;
}
/* leave the socket in non-blocking mode */
/* store the address we use */
- if(addr) {
-#ifdef ENABLE_IPV6
- *addr = ai;
-#else
- *addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
-#endif
- }
+ if(addr)
+ *addr = curr_addr;
/* allow NULL-pointers to get passed in */
if(sockconn)
diff --git a/lib/hostip.c b/lib/hostip.c
index ffc8198ea..2a0367795 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -79,6 +79,7 @@
#include "share.h"
#include "strerror.h"
#include "url.h"
+#include "inet_ntop.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -168,6 +169,43 @@ void Curl_global_host_cache_dtor(void)
}
/*
+ * Return # of adresses in a Curl_addrinfo struct
+ */
+int Curl_num_addresses(const Curl_addrinfo *addr)
+{
+ int i;
+
+#ifdef ENABLE_IPV6
+ for (i = 0; addr; addr = addr->ai_next, i++)
+#else
+ for (i = 0; addr->h_addr_list[i]; i++)
+#endif
+ ;
+ return (i);
+}
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st
+ * address given in the 2nd argument. The result will be stored in
+ * the buf that is bufsize bytes big.
+ *
+ * If the conversion fails, it returns NULL.
+ */
+const char *Curl_printable_address(const Curl_ipconnect *ip,
+ char *buf, size_t bufsize)
+{
+#ifdef CURLRES_IPV6
+ const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
+ const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
+ int af = ip->ai_family;
+
+ return Curl_inet_ntop(af, af == AF_INET6 ? ip6 : ip4, buf, bufsize);
+#else
+ return Curl_inet_ntop(AF_INET, ip, buf, bufsize);
+#endif
+}
+
+/*
* Count the number of characters that an integer would use in a string
* (base 10).
*/
diff --git a/lib/hostip.h b/lib/hostip.h
index 75245e6bd..82aa4d59c 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -102,6 +102,9 @@ curl_hash *Curl_mk_dnscache(void);
/* prune old entries from the DNS cache */
void Curl_hostcache_prune(struct SessionHandle *data);
+/* Return # of adresses in a Curl_addrinfo struct */
+int Curl_num_addresses (const Curl_addrinfo *addr);
+
#ifdef CURLDEBUG
void curl_dofreeaddrinfo(struct addrinfo *freethis,
int line, const char *source);
@@ -133,12 +136,11 @@ void Curl_hostent_relocate(struct hostent *h, long offset);
Curl_addrinfo *Curl_addrinfo_copy(Curl_addrinfo *orig);
/*
- * (IPv6) Curl_printable_address() returns a printable version of the
- * ai->ai_addr address given in the 2nd argument. The first should be the
- * ai->ai_family and the result will be stored in the buf that is bufsize
- * bytes big.
+ * Curl_printable_address() returns a printable version of the
+ * 1st address given in the 2nd argument. The result will be stored
+ * in the buf that is bufsize bytes big.
*/
-const char *Curl_printable_address(int af, void *addr,
+const char *Curl_printable_address(const Curl_ipconnect *ip,
char *buf, size_t bufsize);
/*
diff --git a/lib/hostip6.c b/lib/hostip6.c
index 9698ef3c9..55e273623 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -79,7 +79,6 @@
#include "share.h"
#include "strerror.h"
#include "url.h"
-#include "inet_ntop.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -106,26 +105,6 @@ void Curl_freeaddrinfo(Curl_addrinfo *p)
freeaddrinfo(p);
}
-/*
- * Curl_printable_address() returns a printable version of the ai->ai_addr
- * address given in the 2nd argument. The first should be the ai->ai_family
- * and the result will be stored in the buf that is bufsize bytes big.
- *
- * If the conversion fails, it returns NULL.
- */
-const char *Curl_printable_address(int af, void *addr,
- char *buf, size_t bufsize)
-{
- const struct in_addr *addr4 =
- &((const struct sockaddr_in*)addr)->sin_addr;
- const struct in6_addr *addr6 =
- &((const struct sockaddr_in6*)addr)->sin6_addr;
- return Curl_inet_ntop(af, af == AF_INET6 ?
- (const void *)addr6 :
- (const void *)addr4, buf, bufsize);
-}
-
-
#ifdef CURLRES_ASYNCH
/*
* Curl_addrinfo_copy() is used by the asynch callback to copy a given
diff --git a/lib/hostthre.c b/lib/hostthre.c
index 360cad129..9014b02c9 100644
--- a/lib/hostthre.c
+++ b/lib/hostthre.c
@@ -142,7 +142,7 @@ static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
trace_it(" fam %2d, CNAME %s, ",
ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
- if (Curl_printable_address(ai->ai_family, ai->ai_addr, buf, sizeof(buf)))
+ if (Curl_printable_address(ai, buf, sizeof(buf)))
trace_it("%s\n", buf);
else
trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
diff --git a/lib/url.c b/lib/url.c
index 2bc9e53c6..f83e49435 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1990,22 +1990,18 @@ static CURLcode ConnectPlease(struct connectdata *conn,
static void verboseconnect(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
- const char *host=NULL;
- char addrbuf[256];
-
- /* Get a printable version of the network address. */
+ char addrbuf[256] = "";
#ifdef ENABLE_IPV6
- struct addrinfo *ai = conn->serv_addr;
- host = Curl_printable_address(ai->ai_family, ai->ai_addr,
- addrbuf, sizeof(addrbuf));
+ const Curl_ipconnect *addr = conn->serv_addr;
#else
- struct in_addr in;
- (void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
- host = Curl_inet_ntop(AF_INET, &in, addrbuf, sizeof(addrbuf));
+ const Curl_ipconnect *addr = &conn->serv_addr.sin_addr;
#endif
+
+ /* Get a printable version of the network address. */
+ Curl_printable_address(addr, addrbuf, sizeof(addrbuf));
infof(data, "Connected to %s (%s) port %d\n",
- conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname,
- host?host:"", conn->port);
+ conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
+ addrbuf[0] ? addrbuf : "??", conn->port);
}
/*