mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
ares awareness/usage/support added. If configure --enable-ares is used, we
build libcurl to use ares for asynch name resolves.
This commit is contained in:
parent
f85935f0f9
commit
b73612392d
@ -12,10 +12,16 @@ EXTRA_DIST = getdate.y Makefile.b32 Makefile.b32.resp Makefile.m32 \
|
|||||||
|
|
||||||
lib_LTLIBRARIES = libcurl.la
|
lib_LTLIBRARIES = libcurl.la
|
||||||
|
|
||||||
|
if ARES
|
||||||
|
ARESINC = -I$(top_srcdir)/ares
|
||||||
|
endif
|
||||||
|
|
||||||
# we use srcdir/include for the static global include files
|
# we use srcdir/include for the static global include files
|
||||||
# we use builddir/lib for the generated lib/config.h file to get found
|
# we use builddir/lib for the generated lib/config.h file to get found
|
||||||
# we use srcdir/lib for the lib-private header files
|
# we use srcdir/lib for the lib-private header files
|
||||||
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/lib -I$(top_srcdir)/lib
|
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/lib -I$(top_srcdir)/lib $(ARESINC)
|
||||||
|
|
||||||
|
LDFLAGS = -L$(top_srcdir)/lib
|
||||||
|
|
||||||
VERSION=-version-info 2:2:0
|
VERSION=-version-info 2:2:0
|
||||||
|
|
||||||
@ -48,15 +54,18 @@ VERSION=-version-info 2:2:0
|
|||||||
#
|
#
|
||||||
|
|
||||||
if NO_UNDEFINED
|
if NO_UNDEFINED
|
||||||
# The -no-undefined flag is CRUCIAL for this to build fine on Cygwin. If we
|
# The -no-undefined flag is CRUCIAL for this to build fine on Cygwin.
|
||||||
# find a case in which we need to remove this flag, we should most likely
|
UNDEF = -no-undefined
|
||||||
# write a configure check that detects when this flag is needed and when its
|
|
||||||
# not.
|
|
||||||
libcurl_la_LDFLAGS = -no-undefined $(VERSION)
|
|
||||||
else
|
else
|
||||||
libcurl_la_LDFLAGS = $(VERSION)
|
UNDEF =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ARES
|
||||||
|
ARESLIB = -lares -L$(top_builddir)/ares
|
||||||
|
endif
|
||||||
|
|
||||||
|
libcurl_la_LDFLAGS = $(UNDEF) $(VERSION) $(ARESLIB)
|
||||||
|
|
||||||
libcurl_la_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c \
|
libcurl_la_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c \
|
||||||
base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c \
|
base64.c file.h hostip.c progress.c timeval.h base64.h formdata.c \
|
||||||
hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c \
|
hostip.h progress.h cookie.c formdata.h http.c sendf.c cookie.h ftp.c \
|
||||||
|
@ -208,6 +208,7 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
size_t size;
|
size_t size;
|
||||||
char myhost[256] = "";
|
char myhost[256] = "";
|
||||||
in_addr_t in;
|
in_addr_t in;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* First check if the given name is an IP address */
|
/* First check if the given name is an IP address */
|
||||||
in=inet_addr(data->set.device);
|
in=inet_addr(data->set.device);
|
||||||
@ -217,7 +218,10 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
/*
|
/*
|
||||||
* We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
|
* We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
|
||||||
*/
|
*/
|
||||||
h = Curl_resolv(data, myhost, 0);
|
rc = Curl_resolv(conn, myhost, 0, &h);
|
||||||
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &h);
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(strlen(data->set.device)>1) {
|
if(strlen(data->set.device)>1) {
|
||||||
@ -225,11 +229,14 @@ static CURLcode bindlocal(struct connectdata *conn,
|
|||||||
* This was not an interface, resolve the name as a host name
|
* This was not an interface, resolve the name as a host name
|
||||||
* or IP number
|
* or IP number
|
||||||
*/
|
*/
|
||||||
h = Curl_resolv(data, data->set.device, 0);
|
rc = Curl_resolv(conn, data->set.device, 0, &h);
|
||||||
if(h) {
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &h);
|
||||||
|
|
||||||
|
if(h)
|
||||||
/* we know data->set.device is shorter than the myhost array */
|
/* we know data->set.device is shorter than the myhost array */
|
||||||
strcpy(myhost, data->set.device);
|
strcpy(myhost, data->set.device);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
lib/ftp.c
23
lib/ftp.c
@ -1231,18 +1231,24 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
|
|
||||||
if(data->set.ftpport) {
|
if(data->set.ftpport) {
|
||||||
in_addr_t in;
|
in_addr_t in;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* First check if the given name is an IP address */
|
/* First check if the given name is an IP address */
|
||||||
in=inet_addr(data->set.ftpport);
|
in=inet_addr(data->set.ftpport);
|
||||||
|
|
||||||
if((in == CURL_INADDR_NONE) &&
|
if((in == CURL_INADDR_NONE) &&
|
||||||
Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
|
Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
|
||||||
h = Curl_resolv(data, myhost, 0);
|
rc = Curl_resolv(conn, myhost, 0, &h);
|
||||||
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &h);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int len = strlen(data->set.ftpport);
|
int len = strlen(data->set.ftpport);
|
||||||
if(len>1)
|
if(len>1) {
|
||||||
h = Curl_resolv(data, data->set.ftpport, 0);
|
rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
|
||||||
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &h);
|
||||||
|
}
|
||||||
if(h)
|
if(h)
|
||||||
strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
|
strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
|
||||||
}
|
}
|
||||||
@ -1381,6 +1387,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct Curl_dns_entry *addr=NULL;
|
struct Curl_dns_entry *addr=NULL;
|
||||||
Curl_ipconnect *conninfo;
|
Curl_ipconnect *conninfo;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Here's the excecutive summary on what to do:
|
Here's the excecutive summary on what to do:
|
||||||
@ -1505,14 +1512,20 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
* We don't want to rely on a former host lookup that might've expired
|
* We don't want to rely on a former host lookup that might've expired
|
||||||
* now, instead we remake the lookup here and now!
|
* now, instead we remake the lookup here and now!
|
||||||
*/
|
*/
|
||||||
addr = Curl_resolv(data, conn->proxyhost, conn->port);
|
rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr);
|
||||||
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &addr);
|
||||||
|
|
||||||
connectport =
|
connectport =
|
||||||
(unsigned short)conn->port; /* we connect to the proxy's port */
|
(unsigned short)conn->port; /* we connect to the proxy's port */
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* normal, direct, ftp connection */
|
/* normal, direct, ftp connection */
|
||||||
addr = Curl_resolv(data, newhostp, newport);
|
rc = Curl_resolv(conn, newhostp, newport, &addr);
|
||||||
|
if(rc == 1)
|
||||||
|
rc = Curl_wait_for_resolv(conn, &addr);
|
||||||
|
|
||||||
if(!addr) {
|
if(!addr) {
|
||||||
failf(data, "Can't resolve new host %s:%d", newhostp, newport);
|
failf(data, "Can't resolve new host %s:%d", newhostp, newport);
|
||||||
return CURLE_FTP_CANT_GET_HOST;
|
return CURLE_FTP_CANT_GET_HOST;
|
||||||
|
471
lib/hostip.c
471
lib/hostip.c
@ -65,6 +65,7 @@
|
|||||||
#include "hostip.h"
|
#include "hostip.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "share.h"
|
#include "share.h"
|
||||||
|
#include "url.h"
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
@ -81,10 +82,13 @@
|
|||||||
static curl_hash hostname_cache;
|
static curl_hash hostname_cache;
|
||||||
static int host_cache_initialized;
|
static int host_cache_initialized;
|
||||||
|
|
||||||
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
int port,
|
int port,
|
||||||
char **bufp);
|
int *waitp);
|
||||||
|
#if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES)
|
||||||
|
static struct hostent* pack_hostent(char** buf, struct hostent* orig);
|
||||||
|
#endif
|
||||||
|
|
||||||
void Curl_global_host_cache_init(void)
|
void Curl_global_host_cache_init(void)
|
||||||
{
|
{
|
||||||
@ -135,15 +139,14 @@ create_hostcache_id(char *server, int port, ssize_t *entry_len)
|
|||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
|
|
||||||
/* Get the length of the new entry id */
|
/* Get the length of the new entry id */
|
||||||
*entry_len = *entry_len + /* Hostname length */
|
*entry_len = *entry_len + /* Hostname length */
|
||||||
1 + /* The ':' seperator */
|
1 + /* ':' seperator */
|
||||||
_num_chars(port); /* The number of characters the port will take up */
|
_num_chars(port); /* number of characters the port will take up */
|
||||||
|
|
||||||
/* Allocate the new entry id */
|
/* Allocate the new entry id */
|
||||||
id = malloc(*entry_len + 1);
|
id = malloc(*entry_len + 1);
|
||||||
if (!id) {
|
if (!id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the new entry */
|
/* Create the new entry */
|
||||||
/* If sprintf() doesn't return the entry length, that signals failure */
|
/* If sprintf() doesn't return the entry length, that signals failure */
|
||||||
@ -192,57 +195,26 @@ hostcache_prune(curl_hash *hostcache, int cache_timeout, int now)
|
|||||||
hostcache_timestamp_remove);
|
hostcache_timestamp_remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
|
|
||||||
/* Called from Curl_done() to check that there's no DNS cache entry with
|
|
||||||
a non-zero counter left. */
|
|
||||||
void Curl_scan_cache_used(void *user, void *ptr)
|
|
||||||
{
|
|
||||||
struct Curl_dns_entry *e = ptr;
|
|
||||||
(void)user; /* prevent compiler warning */
|
|
||||||
if(e->inuse) {
|
|
||||||
fprintf(stderr, "*** WARNING: locked DNS cache entry detected: %s\n",
|
|
||||||
e->entry_id);
|
|
||||||
/* perform a segmentation fault to draw attention */
|
|
||||||
*(void **)0 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Macro to save redundant free'ing of entry_id */
|
|
||||||
#define HOSTCACHE_RETURN(dns) \
|
|
||||||
{ \
|
|
||||||
free(entry_id); \
|
|
||||||
if(data->share) \
|
|
||||||
{ \
|
|
||||||
Curl_share_unlock(data, CURL_LOCK_DATA_DNS); \
|
|
||||||
} \
|
|
||||||
return dns; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_SIGSETJMP
|
#ifdef HAVE_SIGSETJMP
|
||||||
/* Beware this is a global and unique instance */
|
/* Beware this is a global and unique instance */
|
||||||
sigjmp_buf curl_jmpenv;
|
sigjmp_buf curl_jmpenv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
|
|
||||||
char *hostname,
|
|
||||||
int port)
|
|
||||||
{
|
|
||||||
char *entry_id = NULL;
|
|
||||||
struct Curl_dns_entry *dns = NULL;
|
|
||||||
ssize_t entry_len;
|
|
||||||
time_t now;
|
|
||||||
char *bufp;
|
|
||||||
|
|
||||||
#ifdef HAVE_SIGSETJMP
|
/* When calling Curl_resolv() has resulted in a response with a returned
|
||||||
/* this allows us to time-out from the name resolver, as the timeout
|
address, we call this function to store the information in the dns
|
||||||
will generate a signal and we will siglongjmp() from that here */
|
cache etc */
|
||||||
if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
|
|
||||||
/* this is coming from a siglongjmp() */
|
static struct Curl_dns_entry *
|
||||||
failf(data, "name lookup timed out");
|
cache_resolv_response(struct SessionHandle *data,
|
||||||
return NULL;
|
Curl_addrinfo *addr,
|
||||||
}
|
char *hostname,
|
||||||
#endif
|
int port)
|
||||||
|
{
|
||||||
|
char *entry_id;
|
||||||
|
int entry_len;
|
||||||
|
struct Curl_dns_entry *dns;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
/* Create an entry id, based upon the hostname and port */
|
/* Create an entry id, based upon the hostname and port */
|
||||||
entry_len = strlen(hostname);
|
entry_len = strlen(hostname);
|
||||||
@ -251,45 +223,112 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
|
|||||||
if (!entry_id)
|
if (!entry_id)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/* Create a new cache entry */
|
||||||
|
dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
|
||||||
|
if (!dns) {
|
||||||
|
Curl_freeaddrinfo(addr);
|
||||||
|
free(entry_id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns->inuse = 0;
|
||||||
|
dns->addr = addr;
|
||||||
|
|
||||||
|
/* Store it in our dns cache */
|
||||||
|
Curl_hash_add(data->hostcache, entry_id, entry_len+1,
|
||||||
|
(const void *) dns);
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
dns->timestamp = now;
|
||||||
|
dns->inuse++; /* mark entry as in-use */
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove outdated and unused entries from the hostcache */
|
||||||
|
hostcache_prune(data->hostcache,
|
||||||
|
data->set.dns_cache_timeout,
|
||||||
|
now);
|
||||||
|
|
||||||
|
/* free the allocated entry_id again */
|
||||||
|
free(entry_id);
|
||||||
|
|
||||||
|
return dns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve a name and return a pointer in the 'entry' argument if one
|
||||||
|
is available.
|
||||||
|
|
||||||
|
Return codes:
|
||||||
|
|
||||||
|
-1 = error, no pointer
|
||||||
|
0 = OK, pointer provided
|
||||||
|
1 = waiting for response, no pointer
|
||||||
|
*/
|
||||||
|
int Curl_resolv(struct connectdata *conn,
|
||||||
|
char *hostname,
|
||||||
|
int port,
|
||||||
|
struct Curl_dns_entry **entry)
|
||||||
|
{
|
||||||
|
char *entry_id = NULL;
|
||||||
|
struct Curl_dns_entry *dns = NULL;
|
||||||
|
ssize_t entry_len;
|
||||||
|
int wait;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
/* default to failure */
|
||||||
|
int rc = -1;
|
||||||
|
*entry = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGSETJMP
|
||||||
|
/* this allows us to time-out from the name resolver, as the timeout
|
||||||
|
will generate a signal and we will siglongjmp() from that here */
|
||||||
|
if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
|
||||||
|
/* this is coming from a siglongjmp() */
|
||||||
|
failf(data, "name lookup timed out");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Create an entry id, based upon the hostname and port */
|
||||||
|
entry_len = strlen(hostname);
|
||||||
|
entry_id = create_hostcache_id(hostname, port, &entry_len);
|
||||||
|
/* If we can't create the entry id, fail */
|
||||||
|
if (!entry_id)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(data->share)
|
if(data->share)
|
||||||
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
|
||||||
|
|
||||||
/* See if its already in our dns cache */
|
/* See if its already in our dns cache */
|
||||||
dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
|
dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
|
||||||
|
|
||||||
|
/* free the allocated entry_id again */
|
||||||
|
free(entry_id);
|
||||||
|
|
||||||
if (!dns) {
|
if (!dns) {
|
||||||
Curl_addrinfo *addr = my_getaddrinfo(data, hostname, port, &bufp);
|
/* The entry was not in the cache. Resolve it to IP address */
|
||||||
|
|
||||||
|
/* If my_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
|
||||||
|
value indicating that we need to wait for the response to the resolve
|
||||||
|
call */
|
||||||
|
Curl_addrinfo *addr = my_getaddrinfo(conn, hostname, port, &wait);
|
||||||
|
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
HOSTCACHE_RETURN(NULL);
|
if(wait)
|
||||||
|
/* the response to our resolve call will come asynchronously at
|
||||||
|
a later time, good or bad */
|
||||||
|
rc = 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* Create a new cache entry */
|
/* we got a response, store it in the cache */
|
||||||
dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
|
dns = cache_resolv_response(data, addr, hostname, port);
|
||||||
if (!dns) {
|
|
||||||
Curl_freeaddrinfo(addr);
|
|
||||||
HOSTCACHE_RETURN(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
dns->inuse = 0;
|
|
||||||
dns->addr = addr;
|
|
||||||
/* Save it in our host cache */
|
|
||||||
Curl_hash_add(data->hostcache, entry_id, entry_len+1, (const void *) dns);
|
|
||||||
}
|
}
|
||||||
time(&now);
|
|
||||||
|
|
||||||
dns->timestamp = now;
|
if(data->share)
|
||||||
dns->inuse++; /* mark entry as in-use */
|
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
|
||||||
#ifdef CURLDEBUG
|
|
||||||
dns->entry_id = entry_id;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Remove outdated and unused entries from the hostcache */
|
*entry = dns;
|
||||||
hostcache_prune(data->hostcache,
|
|
||||||
data->set.dns_cache_timeout,
|
|
||||||
now);
|
|
||||||
|
|
||||||
HOSTCACHE_RETURN(dns);
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
|
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
|
||||||
@ -314,7 +353,7 @@ void Curl_freeaddrinfo(Curl_addrinfo *p)
|
|||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
freeaddrinfo(p);
|
freeaddrinfo(p);
|
||||||
#else
|
#else
|
||||||
free(p);
|
free(p); /* works fine for the ARES case too */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +371,203 @@ void Curl_freednsinfo(void *freethis)
|
|||||||
|
|
||||||
/* --- resolve name or IP-number --- */
|
/* --- resolve name or IP-number --- */
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
/* Allocate enough memory to hold the full name information structs and
|
||||||
|
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
||||||
|
* required for storing all possible aliases and IP numbers is according to
|
||||||
|
* Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
|
||||||
|
*/
|
||||||
|
#define CURL_NAMELOOKUP_SIZE 9000
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
|
||||||
|
CURLcode Curl_multi_ares_fdset(struct connectdata *conn,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
int *max_fdp)
|
||||||
|
|
||||||
|
{
|
||||||
|
int max = ares_fds(conn->data->state.areschannel,
|
||||||
|
read_fd_set, write_fd_set);
|
||||||
|
*max_fdp = max;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called to check if the name is resolved now */
|
||||||
|
CURLcode Curl_is_resolved(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
fd_set read_fds, write_fds;
|
||||||
|
static const struct timeval tv={0,0};
|
||||||
|
int count;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
int nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
|
||||||
|
|
||||||
|
count = select(nfds, &read_fds, &write_fds, NULL,
|
||||||
|
(struct timeval *)&tv);
|
||||||
|
|
||||||
|
if(count)
|
||||||
|
ares_process(data->state.areschannel, &read_fds, &write_fds);
|
||||||
|
|
||||||
|
if(conn->async.done) {
|
||||||
|
*done = TRUE;
|
||||||
|
|
||||||
|
if(!conn->async.dns)
|
||||||
|
return CURLE_COULDNT_RESOLVE_HOST;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*done = FALSE;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a function that locks and waits until the name resolve operation
|
||||||
|
has completed.
|
||||||
|
|
||||||
|
If 'entry' is non-NULL, make it point to the resolved dns entry
|
||||||
|
|
||||||
|
Return CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
|
||||||
|
CURLE_OPERATION_TIMEDOUT if a time-out occurred.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||||
|
struct Curl_dns_entry **entry)
|
||||||
|
{
|
||||||
|
CURLcode rc=CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
/* Wait for the name resolve query to complete. */
|
||||||
|
while (1) {
|
||||||
|
int nfds=0;
|
||||||
|
fd_set read_fds, write_fds;
|
||||||
|
struct timeval *tvp, tv;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_ZERO(&write_fds);
|
||||||
|
nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
|
||||||
|
if (nfds == 0)
|
||||||
|
break;
|
||||||
|
tvp = ares_timeout(data->state.areschannel,
|
||||||
|
NULL, /* pass in our maximum time here */
|
||||||
|
&tv);
|
||||||
|
count = select(nfds, &read_fds, &write_fds, NULL, tvp);
|
||||||
|
if (count < 0 && errno != EINVAL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ares_process(data->state.areschannel, &read_fds, &write_fds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operation complete, if the lookup was successful we now have the entry
|
||||||
|
in the cache. */
|
||||||
|
|
||||||
|
/* this destroys the channel and we cannot use it anymore after this */
|
||||||
|
ares_destroy(data->state.areschannel);
|
||||||
|
|
||||||
|
if(entry)
|
||||||
|
*entry = conn->async.dns;
|
||||||
|
|
||||||
|
if(!conn->async.dns) {
|
||||||
|
/* a name was not resolved */
|
||||||
|
if(conn->async.done)
|
||||||
|
rc = CURLE_COULDNT_RESOLVE_HOST;
|
||||||
|
else
|
||||||
|
rc = CURLE_OPERATION_TIMEDOUT;
|
||||||
|
|
||||||
|
/* close the connection, since we can't return failure here without
|
||||||
|
cleaning up this connection properly */
|
||||||
|
Curl_disconnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this function gets called by ares when we got the name resolved */
|
||||||
|
static void host_callback(void *arg, /* "struct connectdata *" */
|
||||||
|
int status,
|
||||||
|
struct hostent *hostent)
|
||||||
|
{
|
||||||
|
struct connectdata *conn = (struct connectdata *)arg;
|
||||||
|
struct Curl_dns_entry *dns = NULL;
|
||||||
|
|
||||||
|
conn->async.done = TRUE;
|
||||||
|
conn->async.status = status;
|
||||||
|
|
||||||
|
if(ARES_SUCCESS == status) {
|
||||||
|
/* we got a resolved name in 'hostent' */
|
||||||
|
char *bufp = (char *)malloc(CURL_NAMELOOKUP_SIZE);
|
||||||
|
if(bufp) {
|
||||||
|
|
||||||
|
/* pack_hostent() copies to and shrinks the target buffer */
|
||||||
|
struct hostent *he = pack_hostent(&bufp, hostent);
|
||||||
|
|
||||||
|
dns = cache_resolv_response(conn->data, he,
|
||||||
|
conn->async.hostname, conn->async.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->async.dns = dns;
|
||||||
|
|
||||||
|
/* The input hostent struct will be freed by ares when we return from this
|
||||||
|
function */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return name information about the given hostname and port number. If
|
||||||
|
* successful, the 'hostent' is returned and the forth argument will point to
|
||||||
|
* memory we need to free after use. That meory *MUST* be freed with
|
||||||
|
* Curl_freeaddrinfo(), nothing else.
|
||||||
|
*/
|
||||||
|
static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
|
||||||
|
char *hostname,
|
||||||
|
int port,
|
||||||
|
int *waitp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char *bufp;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
rc = ares_init(&data->state.areschannel);
|
||||||
|
|
||||||
|
*waitp = FALSE;
|
||||||
|
|
||||||
|
if(!rc) {
|
||||||
|
/* only if success */
|
||||||
|
|
||||||
|
bufp = strdup(hostname);
|
||||||
|
|
||||||
|
if(bufp) {
|
||||||
|
Curl_safefree(conn->async.hostname);
|
||||||
|
conn->async.hostname = bufp;
|
||||||
|
conn->async.port = port;
|
||||||
|
conn->async.done = FALSE; /* not done */
|
||||||
|
conn->async.status = 0; /* clear */
|
||||||
|
conn->async.dns = NULL; /* clear */
|
||||||
|
|
||||||
|
ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
|
||||||
|
host_callback, conn);
|
||||||
|
|
||||||
|
*waitp = TRUE; /* please wait for the response */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ares_destroy(data->state.areschannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; /* no struct yet */
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* For builds without ARES, Curl_resolv() can never return wait==TRUE,
|
||||||
|
so this function will never be called. If it still gets called, we
|
||||||
|
return failure at once. */
|
||||||
|
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||||
|
struct Curl_dns_entry **entry)
|
||||||
|
{
|
||||||
|
(void)conn;
|
||||||
|
*entry=NULL;
|
||||||
|
return CURLE_COULDNT_RESOLVE_HOST;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_IPV6) && !defined(USE_ARES)
|
||||||
|
|
||||||
#ifdef CURLDEBUG
|
#ifdef CURLDEBUG
|
||||||
/* These two are strictly for memory tracing and are using the same
|
/* These two are strictly for memory tracing and are using the same
|
||||||
@ -377,15 +612,16 @@ void curl_freeaddrinfo(struct addrinfo *freethis,
|
|||||||
* memory we need to free after use. That meory *MUST* be freed with
|
* memory we need to free after use. That meory *MUST* be freed with
|
||||||
* Curl_freeaddrinfo(), nothing else.
|
* Curl_freeaddrinfo(), nothing else.
|
||||||
*/
|
*/
|
||||||
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
int port,
|
int port,
|
||||||
char **bufp)
|
int *waitp)
|
||||||
{
|
{
|
||||||
struct addrinfo hints, *res;
|
struct addrinfo hints, *res;
|
||||||
int error;
|
int error;
|
||||||
char sbuf[NI_MAXSERV];
|
char sbuf[NI_MAXSERV];
|
||||||
int s, pf = PF_UNSPEC;
|
int s, pf = PF_UNSPEC;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
/* see if we have an IPv6 stack */
|
/* see if we have an IPv6 stack */
|
||||||
s = socket(PF_INET6, SOCK_DGRAM, 0);
|
s = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||||
@ -410,20 +646,18 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
|
infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*bufp=(char *)res; /* make it point to the result struct */
|
*waitp=0; /* don't wait, we have the response now */
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
#else /* following code is IPv4-only */
|
#else /* following code is IPv4-only */
|
||||||
|
|
||||||
#ifndef HAVE_GETHOSTBYNAME_R
|
#if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES)
|
||||||
static void hostcache_fixoffset(struct hostent *h, int offset);
|
static void hostcache_fixoffset(struct hostent *h, int offset);
|
||||||
/**
|
/*
|
||||||
* Performs a "deep" copy of a hostent into a buffer (returns a pointer to the
|
* Performs a "deep" copy of a hostent into a buffer (returns a pointer to the
|
||||||
* copy). Make absolutely sure the destination buffer is big enough!
|
* copy). Make absolutely sure the destination buffer is big enough!
|
||||||
*
|
*/
|
||||||
* Keith McGuigan
|
|
||||||
* 10/3/2001 */
|
|
||||||
static struct hostent* pack_hostent(char** buf, struct hostent* orig)
|
static struct hostent* pack_hostent(char** buf, struct hostent* orig)
|
||||||
{
|
{
|
||||||
char *bufptr;
|
char *bufptr;
|
||||||
@ -512,6 +746,25 @@ static struct hostent* pack_hostent(char** buf, struct hostent* orig)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void hostcache_fixoffset(struct hostent *h, int offset)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
h->h_name=(char *)((long)h->h_name+offset);
|
||||||
|
h->h_aliases=(char **)((long)h->h_aliases+offset);
|
||||||
|
while(h->h_aliases[i]) {
|
||||||
|
h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
h->h_addr_list=(char **)((long)h->h_addr_list+offset);
|
||||||
|
i=0;
|
||||||
|
while(h->h_addr_list[i]) {
|
||||||
|
h->h_addr_list[i]=(char *)((long)h->h_addr_list[i]+offset);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USE_ARES
|
||||||
|
|
||||||
static char *MakeIP(unsigned long num, char *addr, int addr_len)
|
static char *MakeIP(unsigned long num, char *addr, int addr_len)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
|
#if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
|
||||||
@ -533,43 +786,24 @@ static char *MakeIP(unsigned long num, char *addr, int addr_len)
|
|||||||
return (addr);
|
return (addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hostcache_fixoffset(struct hostent *h, int offset)
|
|
||||||
{
|
|
||||||
int i=0;
|
|
||||||
h->h_name=(char *)((long)h->h_name+offset);
|
|
||||||
h->h_aliases=(char **)((long)h->h_aliases+offset);
|
|
||||||
while(h->h_aliases[i]) {
|
|
||||||
h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
h->h_addr_list=(char **)((long)h->h_addr_list+offset);
|
|
||||||
i=0;
|
|
||||||
while(h->h_addr_list[i]) {
|
|
||||||
h->h_addr_list[i]=(char *)((long)h->h_addr_list[i]+offset);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The original code to this function was once stolen from the Dancer source
|
/* The original code to this function was once stolen from the Dancer source
|
||||||
code, written by Bjorn Reese, it has since been patched and modified
|
code, written by Bjorn Reese, it has since been patched and modified
|
||||||
considerably. */
|
considerably. */
|
||||||
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
static Curl_addrinfo *my_getaddrinfo(struct connectdata *conn,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
int port,
|
int port,
|
||||||
char **bufp)
|
int *waitp)
|
||||||
{
|
{
|
||||||
struct hostent *h = NULL;
|
struct hostent *h = NULL;
|
||||||
in_addr_t in;
|
in_addr_t in;
|
||||||
int ret; /* this variable is unused on several platforms but used on some */
|
int ret; /* this variable is unused on several platforms but used on some */
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
#define CURL_NAMELOOKUP_SIZE 9000
|
(void)port; /* unused in IPv4 code */
|
||||||
/* Allocate enough memory to hold the full name information structs and
|
|
||||||
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
|
||||||
* required for storing all possible aliases and IP numbers is according to
|
|
||||||
* Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */
|
|
||||||
port=0; /* unused in IPv4 code */
|
|
||||||
ret = 0; /* to prevent the compiler warning */
|
ret = 0; /* to prevent the compiler warning */
|
||||||
|
|
||||||
|
*waitp = 0; /* don't wait, we act synchronously */
|
||||||
|
|
||||||
in=inet_addr(hostname);
|
in=inet_addr(hostname);
|
||||||
if (in != CURL_INADDR_NONE) {
|
if (in != CURL_INADDR_NONE) {
|
||||||
struct in_addr *addrentry;
|
struct in_addr *addrentry;
|
||||||
@ -581,7 +815,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
} *buf = (struct namebuf *)malloc(sizeof(struct namebuf));
|
} *buf = (struct namebuf *)malloc(sizeof(struct namebuf));
|
||||||
if(!buf)
|
if(!buf)
|
||||||
return NULL; /* major failure */
|
return NULL; /* major failure */
|
||||||
*bufp = (char *)buf;
|
|
||||||
|
|
||||||
h = &buf->hostentry;
|
h = &buf->hostentry;
|
||||||
h->h_addr_list = &buf->h_addr_list[0];
|
h->h_addr_list = &buf->h_addr_list[0];
|
||||||
@ -602,7 +835,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
|
int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
|
||||||
if(!buf)
|
if(!buf)
|
||||||
return NULL; /* major failure */
|
return NULL; /* major failure */
|
||||||
*bufp=(char *)buf;
|
|
||||||
|
|
||||||
/* Workaround for gethostbyname_r bug in qnx nto. It is also _required_
|
/* Workaround for gethostbyname_r bug in qnx nto. It is also _required_
|
||||||
for some of these functions. */
|
for some of these functions. */
|
||||||
@ -638,7 +870,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
offset=(long)h-(long)buf;
|
offset=(long)h-(long)buf;
|
||||||
hostcache_fixoffset(h, offset);
|
hostcache_fixoffset(h, offset);
|
||||||
buf=(int *)h;
|
buf=(int *)h;
|
||||||
*bufp=(char *)buf;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -687,7 +918,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
offset=(long)h-(long)buf;
|
offset=(long)h-(long)buf;
|
||||||
hostcache_fixoffset(h, offset);
|
hostcache_fixoffset(h, offset);
|
||||||
buf=(int *)h;
|
buf=(int *)h;
|
||||||
*bufp=(char *)buf;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -730,13 +960,11 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
|
infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
|
||||||
h = NULL; /* set return code to NULL */
|
h = NULL; /* set return code to NULL */
|
||||||
free(buf);
|
free(buf);
|
||||||
*bufp=NULL;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
else {
|
else {
|
||||||
if ((h = gethostbyname(hostname)) == NULL ) {
|
if ((h = gethostbyname(hostname)) == NULL ) {
|
||||||
infof(data, "gethostbyname(2) failed for %s\n", hostname);
|
infof(data, "gethostbyname(2) failed for %s\n", hostname);
|
||||||
*bufp=NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -745,7 +973,6 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
static one we got a pointer to might get removed when we don't
|
static one we got a pointer to might get removed when we don't
|
||||||
want/expect that */
|
want/expect that */
|
||||||
h = pack_hostent(&buf, h);
|
h = pack_hostent(&buf, h);
|
||||||
*bufp=(char *)buf;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -753,3 +980,5 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* end of IPv4-specific code */
|
#endif /* end of IPv4-specific code */
|
||||||
|
|
||||||
|
#endif /* end of !USE_ARES */
|
||||||
|
18
lib/hostip.h
18
lib/hostip.h
@ -29,6 +29,7 @@
|
|||||||
struct addrinfo;
|
struct addrinfo;
|
||||||
struct hostent;
|
struct hostent;
|
||||||
struct SessionHandle;
|
struct SessionHandle;
|
||||||
|
struct connectdata;
|
||||||
|
|
||||||
void Curl_global_host_cache_init(void);
|
void Curl_global_host_cache_init(void);
|
||||||
void Curl_global_host_cache_dtor(void);
|
void Curl_global_host_cache_dtor(void);
|
||||||
@ -41,9 +42,6 @@ struct Curl_dns_entry {
|
|||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
long inuse; /* use-counter, make very sure you decrease this
|
long inuse; /* use-counter, make very sure you decrease this
|
||||||
when you're done using the address you received */
|
when you're done using the address you received */
|
||||||
#ifdef CURLDEBUG
|
|
||||||
char *entry_id;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -54,10 +52,18 @@ struct Curl_dns_entry {
|
|||||||
* use, or we'll leak memory!
|
* use, or we'll leak memory!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
|
int Curl_resolv(struct connectdata *conn,
|
||||||
char *hostname,
|
char *hostname,
|
||||||
int port);
|
int port,
|
||||||
|
struct Curl_dns_entry **dnsentry);
|
||||||
|
|
||||||
|
CURLcode Curl_is_resolved(struct connectdata *conn, bool *done);
|
||||||
|
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||||
|
struct Curl_dns_entry **dnsentry);
|
||||||
|
CURLcode Curl_multi_ares_fdset(struct connectdata *conn,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
int *max_fdp);
|
||||||
/* unlock a previously resolved dns entry */
|
/* unlock a previously resolved dns entry */
|
||||||
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
|
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
|
||||||
|
|
||||||
|
51
lib/multi.c
51
lib/multi.c
@ -56,7 +56,8 @@ struct Curl_message {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CURLM_STATE_INIT,
|
CURLM_STATE_INIT,
|
||||||
CURLM_STATE_CONNECT, /* connect has been sent off */
|
CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
|
||||||
|
CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
|
||||||
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
|
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
|
||||||
CURLM_STATE_DO, /* send off the request (part 1) */
|
CURLM_STATE_DO, /* send off the request (part 1) */
|
||||||
CURLM_STATE_DO_MORE, /* send off the request (part 2) */
|
CURLM_STATE_DO_MORE, /* send off the request (part 2) */
|
||||||
@ -239,6 +240,14 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
|||||||
switch(easy->state) {
|
switch(easy->state) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
case CURLM_STATE_WAITRESOLVE:
|
||||||
|
/* waiting for a resolve to complete */
|
||||||
|
Curl_multi_ares_fdset(easy->easy_conn, read_fd_set, write_fd_set,
|
||||||
|
&this_max_fd);
|
||||||
|
if(this_max_fd > *max_fd)
|
||||||
|
*max_fd = this_max_fd;
|
||||||
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
case CURLM_STATE_WAITCONNECT:
|
||||||
case CURLM_STATE_DO_MORE:
|
case CURLM_STATE_DO_MORE:
|
||||||
{
|
{
|
||||||
@ -293,6 +302,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
CURLMcode result=CURLM_OK;
|
CURLMcode result=CURLM_OK;
|
||||||
struct Curl_message *msg = NULL;
|
struct Curl_message *msg = NULL;
|
||||||
bool connected;
|
bool connected;
|
||||||
|
bool async;
|
||||||
|
|
||||||
*running_handles = 0; /* bump this once for every living handle */
|
*running_handles = 0; /* bump this once for every living handle */
|
||||||
|
|
||||||
@ -320,6 +330,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
easy->easy_handle->state.used_interface = Curl_if_multi;
|
easy->easy_handle->state.used_interface = Curl_if_multi;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_CONNECT:
|
case CURLM_STATE_CONNECT:
|
||||||
if (Curl_global_host_cache_use(easy->easy_handle)) {
|
if (Curl_global_host_cache_use(easy->easy_handle)) {
|
||||||
easy->easy_handle->hostcache = Curl_global_host_cache_get();
|
easy->easy_handle->hostcache = Curl_global_host_cache_get();
|
||||||
@ -333,16 +344,46 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
|
|
||||||
/* Connect. We get a connection identifier filled in. */
|
/* Connect. We get a connection identifier filled in. */
|
||||||
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
|
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
|
||||||
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
|
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, &async);
|
||||||
|
|
||||||
/* after the connect has been sent off, go WAITCONNECT */
|
|
||||||
if(CURLE_OK == easy->result) {
|
if(CURLE_OK == easy->result) {
|
||||||
easy->state = CURLM_STATE_WAITCONNECT;
|
if(async)
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
/* We're now waiting for an asynchronous name lookup */
|
||||||
|
easy->state = CURLM_STATE_WAITRESOLVE;
|
||||||
|
else {
|
||||||
|
/* after the connect has been sent off, go WAITCONNECT */
|
||||||
|
easy->state = CURLM_STATE_WAITCONNECT;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_WAITRESOLVE:
|
||||||
|
/* awaiting an asynch name resolve to complete */
|
||||||
|
{
|
||||||
|
bool done;
|
||||||
|
|
||||||
|
/* check if we have the name resolved by now */
|
||||||
|
easy->result = Curl_is_resolved(easy->easy_conn, &done);
|
||||||
|
|
||||||
|
if(done) {
|
||||||
|
/* Perform the next step in the connection phase, and then move on
|
||||||
|
to the WAITCONNECT state */
|
||||||
|
easy->result = Curl_async_resolved(easy->easy_conn);
|
||||||
|
|
||||||
|
easy->state = CURLM_STATE_WAITCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CURLE_OK != easy->result) {
|
||||||
|
/* failure detected */
|
||||||
|
easy->easy_conn = NULL; /* no more connection */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
case CURLM_STATE_WAITCONNECT:
|
||||||
|
/* awaiting a completion of an asynch connect */
|
||||||
{
|
{
|
||||||
bool connected;
|
bool connected;
|
||||||
easy->result = Curl_is_connected(easy->easy_conn,
|
easy->result = Curl_is_connected(easy->easy_conn,
|
||||||
|
@ -185,7 +185,7 @@ int fileno( FILE *stream);
|
|||||||
* Information regarding a single IP witin a Curl_addrinfo MUST be stored in
|
* Information regarding a single IP witin a Curl_addrinfo MUST be stored in
|
||||||
* a Curl_ipconnect struct.
|
* a Curl_ipconnect struct.
|
||||||
*/
|
*/
|
||||||
#ifdef ENABLE_IPV6
|
#if defined(ENABLE_IPV6) && !defined(USE_ARES)
|
||||||
typedef struct addrinfo Curl_addrinfo;
|
typedef struct addrinfo Curl_addrinfo;
|
||||||
typedef struct addrinfo Curl_ipconnect;
|
typedef struct addrinfo Curl_ipconnect;
|
||||||
#else
|
#else
|
||||||
|
@ -605,8 +605,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
len = end-start+1;
|
len = end-start+1;
|
||||||
|
|
||||||
/* allocate memory of a cloned copy */
|
/* allocate memory of a cloned copy */
|
||||||
if(data->info.contenttype)
|
Curl_safefree(data->info.contenttype);
|
||||||
free(data->info.contenttype);
|
|
||||||
|
|
||||||
data->info.contenttype = malloc(len + 1);
|
data->info.contenttype = malloc(len + 1);
|
||||||
if (NULL == data->info.contenttype)
|
if (NULL == data->info.contenttype)
|
||||||
@ -1903,10 +1902,22 @@ CURLcode Curl_perform(struct SessionHandle *data)
|
|||||||
do {
|
do {
|
||||||
int urlchanged = FALSE;
|
int urlchanged = FALSE;
|
||||||
do {
|
do {
|
||||||
|
bool async;
|
||||||
Curl_pgrsTime(data, TIMER_STARTSINGLE);
|
Curl_pgrsTime(data, TIMER_STARTSINGLE);
|
||||||
data->change.url_changed = FALSE;
|
data->change.url_changed = FALSE;
|
||||||
res = Curl_connect(data, &conn);
|
res = Curl_connect(data, &conn, &async);
|
||||||
|
|
||||||
|
if((CURLE_OK == res) && async) {
|
||||||
|
/* Now, if async is TRUE here, we need to wait for the name
|
||||||
|
to resolve */
|
||||||
|
res = Curl_wait_for_resolv(conn, NULL);
|
||||||
|
if(CURLE_OK == res)
|
||||||
|
/* Resolved, continue with the connection */
|
||||||
|
res = Curl_async_resolved(conn);
|
||||||
|
}
|
||||||
|
if(res)
|
||||||
|
break;
|
||||||
|
|
||||||
/* If a callback (or something) has altered the URL we should use within
|
/* If a callback (or something) has altered the URL we should use within
|
||||||
the Curl_connect(), we detect it here and act as if we are redirected
|
the Curl_connect(), we detect it here and act as if we are redirected
|
||||||
to the new URL */
|
to the new URL */
|
||||||
|
164
lib/url.c
164
lib/url.c
@ -147,7 +147,11 @@ static unsigned int ConnectionStore(struct SessionHandle *data,
|
|||||||
struct connectdata *conn);
|
struct connectdata *conn);
|
||||||
static bool safe_strequal(char* str1, char* str2);
|
static bool safe_strequal(char* str1, char* str2);
|
||||||
|
|
||||||
#if !defined(WIN32)||defined(__CYGWIN32__)
|
#ifndef USE_ARES
|
||||||
|
/* not for Win32, unless it is cygwin
|
||||||
|
not for ares builds */
|
||||||
|
#if !defined(WIN32) || defined(__CYGWIN32__)
|
||||||
|
|
||||||
#ifndef RETSIGTYPE
|
#ifndef RETSIGTYPE
|
||||||
#define RETSIGTYPE void
|
#define RETSIGTYPE void
|
||||||
#endif
|
#endif
|
||||||
@ -165,6 +169,7 @@ RETSIGTYPE alarmfunc(int signal)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* USE_ARES */
|
||||||
|
|
||||||
void Curl_safefree(void *ptr)
|
void Curl_safefree(void *ptr)
|
||||||
{
|
{
|
||||||
@ -1286,7 +1291,11 @@ CURLcode Curl_disconnect(struct connectdata *conn)
|
|||||||
Curl_safefree(conn->allocptr.host);
|
Curl_safefree(conn->allocptr.host);
|
||||||
Curl_safefree(conn->allocptr.cookiehost);
|
Curl_safefree(conn->allocptr.cookiehost);
|
||||||
Curl_safefree(conn->proxyhost);
|
Curl_safefree(conn->proxyhost);
|
||||||
|
#ifdef USE_ARES
|
||||||
|
/* possible left-overs from the async name resolve */
|
||||||
|
Curl_safefree(conn->async.hostname);
|
||||||
|
#endif
|
||||||
|
|
||||||
Curl_free_ssl_config(&conn->ssl_config);
|
Curl_free_ssl_config(&conn->ssl_config);
|
||||||
|
|
||||||
free(conn); /* free all the connection oriented data */
|
free(conn); /* free all the connection oriented data */
|
||||||
@ -1632,7 +1641,15 @@ static int handleSock5Proxy(
|
|||||||
#ifndef ENABLE_IPV6
|
#ifndef ENABLE_IPV6
|
||||||
struct Curl_dns_entry *dns;
|
struct Curl_dns_entry *dns;
|
||||||
Curl_addrinfo *hp=NULL;
|
Curl_addrinfo *hp=NULL;
|
||||||
dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
|
int rc = Curl_resolv(conn, conn->hostname, conn->remote_port, &dns);
|
||||||
|
|
||||||
|
if(rc == -1)
|
||||||
|
return CURLE_COULDNT_RESOLVE_HOST;
|
||||||
|
|
||||||
|
if(rc == 1)
|
||||||
|
/* this requires that we're in "wait for resolve" state */
|
||||||
|
rc = Curl_wait_for_resolv(conn, &dns);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
|
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
|
||||||
* returns a Curl_addrinfo pointer that may not always look the same.
|
* returns a Curl_addrinfo pointer that may not always look the same.
|
||||||
@ -1841,8 +1858,19 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
|
|||||||
return result; /* pass back status */
|
return result; /* pass back status */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CreateConnection() sets up a new connectdata struct, or re-uses an already
|
||||||
|
* existing one, and resolves host name.
|
||||||
|
*
|
||||||
|
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
|
||||||
|
* response will be coming asynchronously. If *async is FALSE, the name is
|
||||||
|
* already resolved.
|
||||||
|
*/
|
||||||
|
|
||||||
static CURLcode CreateConnection(struct SessionHandle *data,
|
static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
struct connectdata **in_connect)
|
struct connectdata **in_connect,
|
||||||
|
struct Curl_dns_entry **addr,
|
||||||
|
bool *async)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
CURLcode result=CURLE_OK;
|
CURLcode result=CURLE_OK;
|
||||||
@ -1859,7 +1887,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
char passwd[MAX_CURL_PASSWORD_LENGTH];
|
char passwd[MAX_CURL_PASSWORD_LENGTH];
|
||||||
bool passwdgiven=FALSE; /* set TRUE if an application-provided password has
|
bool passwdgiven=FALSE; /* set TRUE if an application-provided password has
|
||||||
been set */
|
been set */
|
||||||
|
int rc;
|
||||||
|
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
struct sigaction keep_sigact; /* store the old struct here */
|
struct sigaction keep_sigact; /* store the old struct here */
|
||||||
@ -1870,6 +1898,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
*addr = NULL; /* nothing yet */
|
||||||
|
*async = FALSE;
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check input data
|
* Check input data
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
@ -2875,8 +2906,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
/* else, no chunky upload */
|
/* else, no chunky upload */
|
||||||
FALSE;
|
FALSE;
|
||||||
|
|
||||||
|
#ifndef USE_ARES
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Set timeout if that is being used
|
* Set timeout if that is being used, and we're not using an asynchronous
|
||||||
|
* name resolve.
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
|
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@ -2919,7 +2952,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
has been done since then until now. */
|
has been done since then until now. */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Resolve the name of the server or proxy
|
* Resolve the name of the server or proxy
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
@ -2935,9 +2969,11 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->port = conn->remote_port; /* it is the same port */
|
conn->port = conn->remote_port; /* it is the same port */
|
||||||
|
|
||||||
/* Resolve target host right on */
|
/* Resolve target host right on */
|
||||||
hostaddr = Curl_resolv(data, conn->name, conn->port);
|
rc = Curl_resolv(conn, conn->name, conn->port, &hostaddr);
|
||||||
|
if(rc == 1)
|
||||||
|
*async = TRUE;
|
||||||
|
|
||||||
if(!hostaddr) {
|
else if(!hostaddr) {
|
||||||
failf(data, "Couldn't resolve host '%s'", conn->name);
|
failf(data, "Couldn't resolve host '%s'", conn->name);
|
||||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||||
/* don't return yet, we need to clean up the timeout first */
|
/* don't return yet, we need to clean up the timeout first */
|
||||||
@ -2947,15 +2983,19 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
/* This is a proxy that hasn't been resolved yet. */
|
/* This is a proxy that hasn't been resolved yet. */
|
||||||
|
|
||||||
/* resolve proxy */
|
/* resolve proxy */
|
||||||
hostaddr = Curl_resolv(data, conn->proxyhost, conn->port);
|
rc = Curl_resolv(conn, conn->proxyhost, conn->port, &hostaddr);
|
||||||
|
|
||||||
if(!hostaddr) {
|
if(rc == 1)
|
||||||
|
*async = TRUE;
|
||||||
|
|
||||||
|
else if(!hostaddr) {
|
||||||
failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
|
failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
|
||||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||||
/* don't return yet, we need to clean up the timeout first */
|
/* don't return yet, we need to clean up the timeout first */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
*addr = hostaddr;
|
||||||
|
|
||||||
#ifdef HAVE_ALARM
|
#ifdef HAVE_ALARM
|
||||||
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
|
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
@ -2995,7 +3035,25 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
alarm(0); /* just shut it off */
|
alarm(0); /* just shut it off */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(result)
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SetupConnection() should be called after the name resolve initiated in
|
||||||
|
* CreateConnection() is all done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static CURLcode SetupConnection(struct connectdata *conn,
|
||||||
|
struct Curl_dns_entry *hostaddr)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
|
||||||
|
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||||
|
|
||||||
|
if(conn->protocol & PROT_FILE)
|
||||||
|
/* There's nothing in this function to setup if we're only doing
|
||||||
|
a file:// transfer */
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@ -3007,8 +3065,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->proxyuser, conn->proxypasswd);
|
conn->proxyuser, conn->proxypasswd);
|
||||||
if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
|
if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
|
||||||
&authorization) >= 0) {
|
&authorization) >= 0) {
|
||||||
if(conn->allocptr.proxyuserpwd)
|
Curl_safefree(conn->allocptr.proxyuserpwd);
|
||||||
free(conn->allocptr.proxyuserpwd);
|
|
||||||
conn->allocptr.proxyuserpwd =
|
conn->allocptr.proxyuserpwd =
|
||||||
aprintf("Proxy-authorization: Basic %s\015\012", authorization);
|
aprintf("Proxy-authorization: Basic %s\015\012", authorization);
|
||||||
free(authorization);
|
free(authorization);
|
||||||
@ -3022,16 +3079,14 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
if((conn->protocol&PROT_HTTP) ||
|
if((conn->protocol&PROT_HTTP) ||
|
||||||
(data->change.proxy && *data->change.proxy)) {
|
(data->change.proxy && *data->change.proxy)) {
|
||||||
if(data->set.useragent) {
|
if(data->set.useragent) {
|
||||||
if(conn->allocptr.uagent)
|
Curl_safefree(conn->allocptr.uagent);
|
||||||
free(conn->allocptr.uagent);
|
|
||||||
conn->allocptr.uagent =
|
conn->allocptr.uagent =
|
||||||
aprintf("User-Agent: %s\015\012", data->set.useragent);
|
aprintf("User-Agent: %s\015\012", data->set.useragent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->set.encoding) {
|
if(data->set.encoding) {
|
||||||
if(conn->allocptr.accept_encoding)
|
Curl_safefree(conn->allocptr.accept_encoding);
|
||||||
free(conn->allocptr.accept_encoding);
|
|
||||||
conn->allocptr.accept_encoding =
|
conn->allocptr.accept_encoding =
|
||||||
aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
|
aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
|
||||||
}
|
}
|
||||||
@ -3083,26 +3138,60 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_connect(struct SessionHandle *data,
|
CURLcode Curl_connect(struct SessionHandle *data,
|
||||||
struct connectdata **in_connect)
|
struct connectdata **in_connect,
|
||||||
|
bool *asyncp)
|
||||||
{
|
{
|
||||||
CURLcode code;
|
CURLcode code;
|
||||||
struct connectdata *conn;
|
struct Curl_dns_entry *dns;
|
||||||
|
|
||||||
|
*asyncp = FALSE; /* assume synchronous resolves by default */
|
||||||
|
|
||||||
/* call the stuff that needs to be called */
|
/* call the stuff that needs to be called */
|
||||||
code = CreateConnection(data, in_connect);
|
code = CreateConnection(data, in_connect, &dns, asyncp);
|
||||||
|
|
||||||
|
if(CURLE_OK == code) {
|
||||||
|
/* no error */
|
||||||
|
if(dns || !*asyncp)
|
||||||
|
/* If an address is available it means that we already have the name
|
||||||
|
resolved, OR it isn't async.
|
||||||
|
If so => continue connecting from here */
|
||||||
|
code = SetupConnection(*in_connect, dns);
|
||||||
|
/* else
|
||||||
|
response will be received and treated async wise */
|
||||||
|
}
|
||||||
|
|
||||||
if(CURLE_OK != code) {
|
if(CURLE_OK != code) {
|
||||||
/* We're not allowed to return failure with memory left allocated
|
/* We're not allowed to return failure with memory left allocated
|
||||||
in the connectdata struct, free those here */
|
in the connectdata struct, free those here */
|
||||||
conn = (struct connectdata *)*in_connect;
|
if(*in_connect) {
|
||||||
if(conn) {
|
Curl_disconnect(*in_connect); /* close the connection */
|
||||||
Curl_disconnect(conn); /* close the connection */
|
*in_connect = NULL; /* return a NULL */
|
||||||
*in_connect = NULL; /* return a NULL */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Call this function after Curl_connect() has returned async=TRUE and
|
||||||
|
then a successful name resolve has been received */
|
||||||
|
CURLcode Curl_async_resolved(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
#ifdef USE_ARES
|
||||||
|
CURLcode code = SetupConnection(conn, conn->async.dns);
|
||||||
|
|
||||||
|
if(code)
|
||||||
|
/* We're not allowed to return failure with memory left allocated
|
||||||
|
in the connectdata struct, free those here */
|
||||||
|
Curl_disconnect(conn); /* close the connection */
|
||||||
|
|
||||||
|
return code;
|
||||||
|
#else
|
||||||
|
(void)conn;
|
||||||
|
return CURLE_OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CURLcode Curl_done(struct connectdata *conn)
|
CURLcode Curl_done(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data=conn->data;
|
struct SessionHandle *data=conn->data;
|
||||||
@ -3179,11 +3268,28 @@ CURLcode Curl_do(struct connectdata **connp)
|
|||||||
conn->bits.close = TRUE; /* enforce close of this connetion */
|
conn->bits.close = TRUE; /* enforce close of this connetion */
|
||||||
result = Curl_done(conn); /* we are so done with this */
|
result = Curl_done(conn); /* we are so done with this */
|
||||||
if(CURLE_OK == result) {
|
if(CURLE_OK == result) {
|
||||||
|
bool async;
|
||||||
/* Now, redo the connect and get a new connection */
|
/* Now, redo the connect and get a new connection */
|
||||||
result = Curl_connect(data, connp);
|
result = Curl_connect(data, connp, &async);
|
||||||
if(CURLE_OK == result)
|
if(CURLE_OK == result) {
|
||||||
|
/* We have connected or sent away a name resolve query fine */
|
||||||
|
|
||||||
|
if(async) {
|
||||||
|
/* Now, if async is TRUE here, we need to wait for the name
|
||||||
|
to resolve */
|
||||||
|
result = Curl_wait_for_resolv(conn, NULL);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* Resolved, continue with the connection */
|
||||||
|
result = Curl_async_resolved(conn);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* ... finally back to actually retry the DO phase */
|
/* ... finally back to actually retry the DO phase */
|
||||||
result = conn->curl_do(*connp);
|
result = conn->curl_do(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
CURLcode Curl_open(struct SessionHandle **curl);
|
CURLcode Curl_open(struct SessionHandle **curl);
|
||||||
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
|
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
|
||||||
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
|
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
|
||||||
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
|
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
|
||||||
|
bool *async);
|
||||||
|
CURLcode Curl_async_resolved(struct connectdata *conn);
|
||||||
CURLcode Curl_do(struct connectdata **);
|
CURLcode Curl_do(struct connectdata **);
|
||||||
CURLcode Curl_do_more(struct connectdata *);
|
CURLcode Curl_do_more(struct connectdata *);
|
||||||
CURLcode Curl_done(struct connectdata *);
|
CURLcode Curl_done(struct connectdata *);
|
||||||
|
@ -90,6 +90,10 @@
|
|||||||
#include <gssapi.h>
|
#include <gssapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
#include <ares.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Download buffer size, keep it fairly big for speed reasons */
|
/* Download buffer size, keep it fairly big for speed reasons */
|
||||||
#define BUFSIZE CURL_MAX_WRITE_SIZE
|
#define BUFSIZE CURL_MAX_WRITE_SIZE
|
||||||
|
|
||||||
@ -364,6 +368,16 @@ struct Curl_transfer_keeper {
|
|||||||
bool ignorebody; /* we read a response-body but we ignore it! */
|
bool ignorebody; /* we read a response-body but we ignore it! */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
struct Curl_async {
|
||||||
|
char *hostname;
|
||||||
|
int port;
|
||||||
|
struct Curl_dns_entry *dns;
|
||||||
|
bool done; /* set TRUE when the lookup is complete */
|
||||||
|
int status; /* if done is TRUE, this is the status from the callback */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The connectdata struct contains all fields and variables that should be
|
* The connectdata struct contains all fields and variables that should be
|
||||||
* unique for an entire connection.
|
* unique for an entire connection.
|
||||||
@ -538,6 +552,11 @@ struct connectdata {
|
|||||||
because it authenticates connections, not
|
because it authenticates connections, not
|
||||||
single requests! */
|
single requests! */
|
||||||
struct ntlmdata proxyntlm; /* NTLM data for proxy */
|
struct ntlmdata proxyntlm; /* NTLM data for proxy */
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
/* data used for the asynch name resolve callback */
|
||||||
|
struct Curl_async async;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The end of connectdata. */
|
/* The end of connectdata. */
|
||||||
@ -669,6 +688,10 @@ struct UrlState {
|
|||||||
|
|
||||||
long authwant; /* inherited from what the user set with CURLOPT_HTTPAUTH */
|
long authwant; /* inherited from what the user set with CURLOPT_HTTPAUTH */
|
||||||
long authavail; /* what the server reports */
|
long authavail; /* what the server reports */
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
ares_channel areschannel; /* for name resolves */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user