diff options
Diffstat (limited to 'libs/libcurl/src/asyn-thread.c')
-rw-r--r-- | libs/libcurl/src/asyn-thread.c | 196 |
1 files changed, 76 insertions, 120 deletions
diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c index 1044166e1e..c7db2e1b60 100644 --- a/libs/libcurl/src/asyn-thread.c +++ b/libs/libcurl/src/asyn-thread.c @@ -49,9 +49,9 @@ #endif
#ifdef HAVE_GETADDRINFO
-# define RESOLVER_ENOMEM EAI_MEMORY
+# define RESOLVER_ENOMEM EAI_MEMORY /* = WSA_NOT_ENOUGH_MEMORY on Windows */
#else
-# define RESOLVER_ENOMEM ENOMEM
+# define RESOLVER_ENOMEM SOCKENOMEM
#endif
#include "urldata.h"
@@ -69,7 +69,7 @@ #ifdef USE_ARES
#include <ares.h>
#ifdef USE_HTTPSRR
-#define USE_HTTPSRR_ARES 1 /* the combo */
+#define USE_HTTPSRR_ARES /* the combo */
#endif
#endif
@@ -78,9 +78,6 @@ #include "curl_memory.h"
#include "memdebug.h"
-struct resdata {
- struct curltime start;
-};
/*
* Curl_resolver_global_init()
@@ -110,9 +107,7 @@ void Curl_resolver_global_cleanup(void) CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
(void)easy;
- *resolver = calloc(1, sizeof(struct resdata));
- if(!*resolver)
- return CURLE_OUT_OF_MEMORY;
+ (void)resolver;
return CURLE_OK;
}
@@ -124,7 +119,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) */
void Curl_resolver_cleanup(void *resolver)
{
- free(resolver);
+ (void)resolver;
}
/*
@@ -156,17 +151,14 @@ static bool init_resolve_thread(struct Curl_easy *data, static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
- return &(data->state.async.tdata->tsd);
+ return &(data->state.async.thdata.tsd);
}
/* Destroy resolver thread synchronization data */
static
void destroy_thread_sync_data(struct thread_sync_data *tsd)
{
- if(tsd->mtx) {
- Curl_mutex_destroy(tsd->mtx);
- free(tsd->mtx);
- }
+ Curl_mutex_destroy(&tsd->mutx);
free(tsd->hostname);
@@ -178,7 +170,7 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd) * close one end of the socket pair (may be done in resolver thread);
* the other end (for reading) is always closed in the parent thread.
*/
-#ifndef USE_EVENTFD
+#ifndef HAVE_EVENTFD
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
wakeup_close(tsd->sock_pair[1]);
}
@@ -190,15 +182,15 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd) /* Initialize resolver thread synchronization data */
static
int init_thread_sync_data(struct thread_data *td,
- const char *hostname,
- int port,
- const struct addrinfo *hints)
+ const char *hostname,
+ int port,
+ const struct addrinfo *hints)
{
struct thread_sync_data *tsd = &td->tsd;
memset(tsd, 0, sizeof(*tsd));
- tsd->td = td;
+ td->init = TRUE;
tsd->port = port;
/* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly.
@@ -211,11 +203,7 @@ int init_thread_sync_data(struct thread_data *td, (void) hints;
#endif
- tsd->mtx = malloc(sizeof(curl_mutex_t));
- if(!tsd->mtx)
- goto err_exit;
-
- Curl_mutex_init(tsd->mtx);
+ Curl_mutex_init(&tsd->mutx);
#ifndef CURL_DISABLE_SOCKETPAIR
/* create socket pair or pipe */
@@ -271,15 +259,15 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data) * and wait on it.
*/
static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
DWORD
#else
unsigned int
#endif
CURL_STDCALL getaddrinfo_thread(void *arg)
{
- struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
- struct thread_data *td = tsd->td;
+ struct thread_data *td = arg;
+ struct thread_sync_data *tsd = &td->tsd;
char service[12];
int rc;
@@ -296,17 +284,16 @@ CURL_STDCALL getaddrinfo_thread(void *arg) Curl_addrinfo_set_port(tsd->res, tsd->port);
}
- Curl_mutex_acquire(tsd->mtx);
+ Curl_mutex_acquire(&tsd->mutx);
if(tsd->done) {
/* too late, gotta clean up the mess */
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
destroy_thread_sync_data(tsd);
- free(td);
}
else {
#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-#ifdef USE_EVENTFD
+#ifdef HAVE_EVENTFD
const uint64_t buf[1] = { 1 };
#else
const char buf[1] = { 1 };
@@ -319,7 +306,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg) }
#endif
tsd->done = TRUE;
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
}
return 0;
@@ -331,15 +318,15 @@ CURL_STDCALL getaddrinfo_thread(void *arg) * gethostbyname_thread() resolves a name and then exits.
*/
static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
DWORD
#else
unsigned int
#endif
CURL_STDCALL gethostbyname_thread(void *arg)
{
- struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
- struct thread_data *td = tsd->td;
+ struct thread_data *td = arg;
+ struct thread_sync_data *tsd = &td->tsd;
tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
@@ -349,16 +336,15 @@ CURL_STDCALL gethostbyname_thread(void *arg) tsd->sock_error = RESOLVER_ENOMEM;
}
- Curl_mutex_acquire(tsd->mtx);
+ Curl_mutex_acquire(&tsd->mutx);
if(tsd->done) {
/* too late, gotta clean up the mess */
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
destroy_thread_sync_data(tsd);
- free(td);
}
else {
tsd->done = TRUE;
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
}
return 0;
@@ -371,29 +357,28 @@ CURL_STDCALL gethostbyname_thread(void *arg) */
static void destroy_async_data(struct Curl_easy *data)
{
- struct Curl_async *async;
- DEBUGASSERT(data);
- async = &data->state.async;
- DEBUGASSERT(async);
- if(async->tdata) {
- struct thread_data *td = async->tdata;
+ struct Curl_async *async = &data->state.async;
+ struct thread_data *td = &async->thdata;
+ if(td->init) {
bool done;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
#endif
#ifdef USE_HTTPSRR_ARES
- if(data->state.async.tdata->channel)
- ares_destroy(data->state.async.tdata->channel);
+ if(td->channel) {
+ ares_destroy(td->channel);
+ td->channel = NULL;
+ }
#endif
/*
* if the thread is still blocking in the resolve syscall, detach it and
* let the thread do the cleanup...
*/
- Curl_mutex_acquire(td->tsd.mtx);
+ Curl_mutex_acquire(&td->tsd.mutx);
done = td->tsd.done;
td->tsd.done = TRUE;
- Curl_mutex_release(td->tsd.mtx);
+ Curl_mutex_release(&td->tsd.mutx);
if(!done) {
Curl_thread_destroy(td->thread_hnd);
@@ -403,35 +388,33 @@ static void destroy_async_data(struct Curl_easy *data) Curl_thread_join(&td->thread_hnd);
destroy_thread_sync_data(&td->tsd);
-
- free(async->tdata);
}
#ifndef CURL_DISABLE_SOCKETPAIR
/*
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
*/
- Curl_multi_closed(data, sock_rd);
+ Curl_multi_will_close(data, sock_rd);
wakeup_close(sock_rd);
#endif
+
+ td->init = FALSE;
}
- async->tdata = NULL;
- free(async->hostname);
- async->hostname = NULL;
}
#ifdef USE_HTTPSRR_ARES
static CURLcode resolve_httpsrr(struct Curl_easy *data,
- struct Curl_async *asp)
+ struct Curl_async *async)
{
- int status = ares_init_options(&asp->tdata->channel, NULL, 0);
+ int status = ares_init_options(&async->thdata.channel, NULL, 0);
if(status != ARES_SUCCESS)
return CURLE_FAILED_INIT;
- memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
- ares_query_dnsrec(asp->tdata->channel,
- asp->hostname, ARES_CLASS_IN,
+ memset(&async->thdata.hinfo, 0, sizeof(struct Curl_https_rrinfo));
+ async->thdata.hinfo.port = -1;
+ ares_query_dnsrec(async->thdata.channel,
+ data->conn->host.name, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL);
@@ -449,38 +432,28 @@ static bool init_resolve_thread(struct Curl_easy *data, const char *hostname, int port,
const struct addrinfo *hints)
{
- struct thread_data *td = calloc(1, sizeof(struct thread_data));
+ struct thread_data *td = &data->state.async.thdata;
+ /* !checksrc! disable ERRNOVAR 1 */
int err = ENOMEM;
- struct Curl_async *asp = &data->state.async;
-
- data->state.async.tdata = td;
- if(!td)
- goto errno_exit;
+ struct Curl_async *async = &data->state.async;
- asp->port = port;
- asp->done = FALSE;
- asp->status = 0;
- asp->dns = NULL;
+ async->port = port;
+ async->done = FALSE;
+ async->dns = NULL;
td->thread_hnd = curl_thread_t_null;
+ td->start = Curl_now();
if(!init_thread_sync_data(td, hostname, port, hints)) {
- asp->tdata = NULL;
- free(td);
goto errno_exit;
}
- free(asp->hostname);
- asp->hostname = strdup(hostname);
- if(!asp->hostname)
- goto err_exit;
-
/* The thread will set this TRUE when complete. */
td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO
- td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+ td->thread_hnd = Curl_thread_create(getaddrinfo_thread, td);
#else
- td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+ td->thread_hnd = Curl_thread_create(gethostbyname_thread, td);
#endif
if(td->thread_hnd == curl_thread_t_null) {
@@ -490,7 +463,7 @@ static bool init_resolve_thread(struct Curl_easy *data, goto err_exit;
}
#ifdef USE_HTTPSRR_ARES
- if(resolve_httpsrr(data, asp))
+ if(resolve_httpsrr(data, async))
infof(data, "Failed HTTPS RR operation");
#endif
return TRUE;
@@ -499,7 +472,7 @@ err_exit: destroy_async_data(data);
errno_exit:
- errno = err;
+ CURL_SETERRNO(err);
return FALSE;
}
@@ -514,7 +487,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data, CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- td = data->state.async.tdata;
+ td = &data->state.async.thdata;
DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@@ -550,13 +523,12 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data, */
void Curl_resolver_kill(struct Curl_easy *data)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = &data->state.async.thdata;
/* If we are still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
- if(td && td->thread_hnd != curl_thread_t_null
- && (data->set.quick_exit != 1L))
+ if((td->thread_hnd != curl_thread_t_null) && !data->set.quick_exit)
(void)thread_wait_resolv(data, NULL, FALSE);
else
Curl_resolver_cancel(data);
@@ -589,37 +561,34 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = &data->state.async.thdata;
bool done = FALSE;
DEBUGASSERT(entry);
*entry = NULL;
- if(!td) {
- DEBUGASSERT(td);
- return CURLE_COULDNT_RESOLVE_HOST;
- }
#ifdef USE_HTTPSRR_ARES
- if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
- return CURLE_UNRECOVERABLE_POLL;
+ (void)Curl_ares_perform(td->channel, 0); /* ignore errors */
#endif
- Curl_mutex_acquire(td->tsd.mtx);
+ Curl_mutex_acquire(&td->tsd.mutx);
done = td->tsd.done;
- Curl_mutex_release(td->tsd.mtx);
+ Curl_mutex_release(&td->tsd.mutx);
if(done) {
+ CURLcode result = td->result;
getaddrinfo_complete(data);
- if(!data->state.async.dns) {
- CURLcode result = Curl_resolver_error(data);
+ if(!result && !data->state.async.dns)
+ result = Curl_resolver_error(data);
+
+ if(result) {
destroy_async_data(data);
return result;
}
#ifdef USE_HTTPSRR_ARES
{
- struct Curl_https_rrinfo *lhrr =
- Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
+ struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&td->hinfo);
if(!lhrr) {
destroy_async_data(data);
return CURLE_OUT_OF_MEMORY;
@@ -658,12 +627,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
int ret_val = 0;
- timediff_t milli;
- timediff_t ms;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-#ifndef CURL_DISABLE_SOCKETPAIR
- struct thread_data *td = data->state.async.tdata;
-#endif
+ struct thread_data *td = &data->state.async.thdata;
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
int socketi = 0;
#else
@@ -671,8 +635,8 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) #endif
#ifdef USE_HTTPSRR_ARES
- if(data->state.async.tdata && data->state.async.tdata->channel) {
- ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
+ if(td->init && td->channel) {
+ ret_val = Curl_ares_getsock(data, td->channel, socks);
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
@@ -680,14 +644,16 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) }
#endif
#ifndef CURL_DISABLE_SOCKETPAIR
- if(td) {
+ if(td->init) {
/* return read fd to client for polling the DNS resolution status */
socks[socketi] = td->tsd.sock_pair[0];
ret_val |= GETSOCK_READSOCK(socketi);
}
- else {
+ else
#endif
- ms = Curl_timediff(Curl_now(), reslv->start);
+ {
+ timediff_t milli;
+ timediff_t ms = Curl_timediff(Curl_now(), td->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)
@@ -697,10 +663,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks) else
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-#ifndef CURL_DISABLE_SOCKETPAIR
}
-#endif
-
return ret_val;
}
@@ -714,12 +677,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, int port,
int *waitp)
{
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
*waitp = 0; /* default to synchronous response */
- reslv->start = Curl_now();
-
/* fire up a new resolver thread! */
if(init_resolve_thread(data, hostname, port, NULL)) {
*waitp = 1; /* expect asynchronous response */
@@ -743,8 +702,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, {
struct addrinfo hints;
int pf = PF_INET;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
*waitp = 0; /* default to synchronous response */
#ifdef CURLRES_IPV6
@@ -762,7 +719,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
- reslv->start = Curl_now();
/* fire up a new resolver thread! */
if(init_resolve_thread(data, hostname, port, &hints)) {
*waitp = 1; /* expect asynchronous response */
|