summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/asyn-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/asyn-thread.c')
-rw-r--r--libs/libcurl/src/asyn-thread.c145
1 files changed, 88 insertions, 57 deletions
diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c
index 11b317b283..1044166e1e 100644
--- a/libs/libcurl/src/asyn-thread.c
+++ b/libs/libcurl/src/asyn-thread.c
@@ -64,6 +64,15 @@
#include "inet_ntop.h"
#include "curl_threads.h"
#include "connect.h"
+#include "strdup.h"
+
+#ifdef USE_ARES
+#include <ares.h>
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1 /* the combo */
+#endif
+#endif
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -129,14 +138,14 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
return Curl_resolver_init(easy, to);
}
-static void destroy_async_data(struct Curl_async *);
+static void destroy_async_data(struct Curl_easy *);
/*
* Cancel all possibly still on-going resolves for this connection.
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
- destroy_async_data(&data->state.async);
+ destroy_async_data(data);
}
/* This function is used to init a threaded resolve */
@@ -145,32 +154,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
const struct addrinfo *hints);
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
- curl_mutex_t *mtx;
- int done;
- int port;
- char *hostname; /* hostname to resolve, Curl_async.hostname
- duplicate */
-#ifndef CURL_DISABLE_SOCKETPAIR
- struct Curl_easy *data;
- curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
-#endif
- int sock_error;
- struct Curl_addrinfo *res;
-#ifdef HAVE_GETADDRINFO
- struct addrinfo hints;
-#endif
- struct thread_data *td; /* for thread-self cleanup */
-};
-
-struct thread_data {
- curl_thread_t thread_hnd;
- unsigned int poll_interval;
- timediff_t interval_end;
- struct thread_sync_data tsd;
-};
-
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
return &(data->state.async.tdata->tsd);
@@ -195,10 +178,12 @@ 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
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
wakeup_close(tsd->sock_pair[1]);
}
#endif
+#endif
memset(tsd, 0, sizeof(*tsd));
}
@@ -218,7 +203,7 @@ int init_thread_sync_data(struct thread_data *td,
/* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly.
*/
- tsd->done = 1;
+ tsd->done = TRUE;
#ifdef HAVE_GETADDRINFO
DEBUGASSERT(hints);
tsd->hints = *hints;
@@ -297,14 +282,6 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
struct thread_data *td = tsd->td;
char service[12];
int rc;
-#ifndef CURL_DISABLE_SOCKETPAIR
-#ifdef USE_EVENTFD
- const void *buf;
- const uint64_t val = 1;
-#else
- char buf[1];
-#endif
-#endif
msnprintf(service, sizeof(service), "%d", tsd->port);
@@ -330,9 +307,9 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
#ifdef USE_EVENTFD
- buf = &val;
+ const uint64_t buf[1] = { 1 };
#else
- buf[0] = 1;
+ const char buf[1] = { 1 };
#endif
/* DNS has been resolved, signal client task */
if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
@@ -341,7 +318,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
}
}
#endif
- tsd->done = 1;
+ tsd->done = TRUE;
Curl_mutex_release(tsd->mtx);
}
@@ -380,7 +357,7 @@ CURL_STDCALL gethostbyname_thread(void *arg)
free(td);
}
else {
- tsd->done = 1;
+ tsd->done = TRUE;
Curl_mutex_release(tsd->mtx);
}
@@ -392,23 +369,30 @@ CURL_STDCALL gethostbyname_thread(void *arg)
/*
* destroy_async_data() cleans up async resolver data and thread handle.
*/
-static void destroy_async_data(struct Curl_async *async)
+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;
- int done;
+ bool done;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
- struct Curl_easy *data = td->tsd.data;
#endif
+#ifdef USE_HTTPSRR_ARES
+ if(data->state.async.tdata->channel)
+ ares_destroy(data->state.async.tdata->channel);
+#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);
done = td->tsd.done;
- td->tsd.done = 1;
+ td->tsd.done = TRUE;
Curl_mutex_release(td->tsd.mtx);
if(!done) {
@@ -437,6 +421,24 @@ static void destroy_async_data(struct Curl_async *async)
async->hostname = NULL;
}
+#ifdef USE_HTTPSRR_ARES
+static CURLcode resolve_httpsrr(struct Curl_easy *data,
+ struct Curl_async *asp)
+{
+ int status = ares_init_options(&asp->tdata->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,
+ ARES_REC_TYPE_HTTPS,
+ Curl_dnsrec_done_cb, data, NULL);
+
+ return CURLE_OK;
+}
+#endif
+
/*
* init_resolve_thread() starts a new thread that performs the actual
* resolve. This function returns before the resolve is done.
@@ -472,8 +474,8 @@ static bool init_resolve_thread(struct Curl_easy *data,
if(!asp->hostname)
goto err_exit;
- /* The thread will set this to 1 when complete. */
- td->tsd.done = 0;
+ /* 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);
@@ -483,15 +485,18 @@ static bool init_resolve_thread(struct Curl_easy *data,
if(td->thread_hnd == curl_thread_t_null) {
/* The thread never started, so mark it as done here for proper cleanup. */
- td->tsd.done = 1;
+ td->tsd.done = TRUE;
err = errno;
goto err_exit;
}
-
+#ifdef USE_HTTPSRR_ARES
+ if(resolve_httpsrr(data, asp))
+ infof(data, "Failed HTTPS RR operation");
+#endif
return TRUE;
err_exit:
- destroy_async_data(asp);
+ destroy_async_data(data);
errno_exit:
errno = err;
@@ -530,7 +535,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
/* a name was not resolved, report error */
result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(data);
if(!data->state.async.dns && report)
connclose(data->conn, "asynch resolve failed");
@@ -585,7 +590,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
struct thread_data *td = data->state.async.tdata;
- int done = 0;
+ bool done = FALSE;
DEBUGASSERT(entry);
*entry = NULL;
@@ -594,6 +599,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
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;
+#endif
Curl_mutex_acquire(td->tsd.mtx);
done = td->tsd.done;
@@ -604,10 +613,21 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(!data->state.async.dns) {
CURLcode result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(data);
return result;
}
- destroy_async_data(&data->state.async);
+#ifdef USE_HTTPSRR_ARES
+ {
+ struct Curl_https_rrinfo *lhrr =
+ Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
+ if(!lhrr) {
+ destroy_async_data(data);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->state.async.dns->hinfo = lhrr;
+ }
+#endif
+ destroy_async_data(data);
*entry = data->state.async.dns;
}
else {
@@ -643,16 +663,27 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata;
+#endif
+#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
+ int socketi = 0;
#else
(void)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);
+ for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
+ if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
+ !ARES_GETSOCK_WRITABLE(ret_val, socketi))
+ break;
+ }
+#endif
#ifndef CURL_DISABLE_SOCKETPAIR
if(td) {
/* return read fd to client for polling the DNS resolution status */
- socks[0] = td->tsd.sock_pair[0];
- td->tsd.data = data;
- ret_val = GETSOCK_READSOCK(0);
+ socks[socketi] = td->tsd.sock_pair[0];
+ ret_val |= GETSOCK_READSOCK(socketi);
}
else {
#endif