1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

Gisle Vanem's improved verbose output and timeout handling when connecting to

a host name that resolves to multiple IP addresses.
This commit is contained in:
Daniel Stenberg 2004-06-10 11:06:21 +00:00
parent 2098871509
commit 9f341f9ce5
6 changed files with 116 additions and 92 deletions

View File

@ -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)

View File

@ -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>
@ -167,6 +168,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).

View File

@ -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);
/*

View File

@ -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

View File

@ -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()));

View File

@ -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];
char addrbuf[256] = "";
#ifdef ENABLE_IPV6
const Curl_ipconnect *addr = conn->serv_addr;
#else
const Curl_ipconnect *addr = &conn->serv_addr.sin_addr;
#endif
/* Get a printable version of the network address. */
#ifdef ENABLE_IPV6
struct addrinfo *ai = conn->serv_addr;
host = Curl_printable_address(ai->ai_family, ai->ai_addr,
addrbuf, sizeof(addrbuf));
#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));
#endif
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);
}
/*