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:
parent
2098871509
commit
9f341f9ce5
113
lib/connect.c
113
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)
|
||||
|
38
lib/hostip.c
38
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>
|
||||
@ -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).
|
||||
|
12
lib/hostip.h
12
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);
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
22
lib/url.c
22
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];
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user