summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/asyn-ares.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/asyn-ares.c')
-rw-r--r--libs/libcurl/src/asyn-ares.c261
1 files changed, 154 insertions, 107 deletions
diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c
index 1ce5d78a4f..900c028dca 100644
--- a/libs/libcurl/src/asyn-ares.c
+++ b/libs/libcurl/src/asyn-ares.c
@@ -24,14 +24,14 @@
#include "curl_setup.h"
+#ifdef USE_ARES
+
/***********************************************************************
* Only for ares-enabled builds
* And only for functions that fulfill the asynch resolver backend API
* as defined in asyn.h, nothing else belongs in this file!
**********************************************************************/
-#ifdef CURLRES_ARES
-
#include <limits.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -59,15 +59,104 @@
#include "select.h"
#include "progress.h"
#include "timediff.h"
+#include "httpsrr.h"
+#include "strdup.h"
-#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- defined(_WIN32)
-# define CARES_STATICLIB
-#endif
#include <ares.h>
#include <ares_version.h> /* really old c-ares did not include this by
itself */
+/*
+ * Curl_ares_getsock() is called when the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we are talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_ares_getsock(struct Curl_easy *data,
+ ares_channel channel,
+ curl_socket_t *socks)
+{
+ struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
+ struct timeval timebuf;
+ int max = ares_getsock(channel,
+ (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
+ struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
+ timediff_t milli = curlx_tvtoms(timeout);
+ Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+ return max;
+}
+
+/*
+ * Curl_ares_perform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on, or -1 on error
+ */
+
+int Curl_ares_perform(ares_channel channel,
+ timediff_t timeout_ms)
+{
+ int nfds;
+ int bitmask;
+ ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+ struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+ int i;
+ int num = 0;
+
+ if(!channel)
+ return 0;
+
+ bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
+
+ for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
+ pfd[i].events = 0;
+ pfd[i].revents = 0;
+ if(ARES_GETSOCK_READABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLRDNORM|POLLIN;
+ }
+ if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLWRNORM|POLLOUT;
+ }
+ if(pfd[i].events)
+ num++;
+ else
+ break;
+ }
+
+ if(num) {
+ nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
+ if(nfds < 0)
+ return -1;
+ }
+ else
+ nfds = 0;
+
+ if(!nfds)
+ /* Call ares_process() unconditionally here, even if we simply timed out
+ above, as otherwise the ares name resolve will not timeout! */
+ ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ else {
+ /* move through the descriptors and ask for processing on them */
+ for(i = 0; i < num; i++)
+ ares_process_fd(channel,
+ (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
+ pfd[i].fd : ARES_SOCKET_BAD,
+ (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
+ pfd[i].fd : ARES_SOCKET_BAD);
+ }
+ return nfds;
+}
+
+#ifdef CURLRES_ARES
+
#if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */
#define HAVE_CARES_CALLBACK_TIMEOUTS 1
@@ -93,22 +182,19 @@
#define HAVE_CARES_GETADDRINFO 1
#endif
+#if ARES_VERSION >= 0x011c00
+/* 1.28.0 and later have ares_query_dnsrec */
+#define HAVE_ARES_QUERY_DNSREC 1
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1
+#endif
+#endif
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-struct thread_data {
- int num_pending; /* number of outstanding c-ares requests */
- struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
- parts */
- int last_status;
-#ifndef HAVE_CARES_GETADDRINFO
- struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
-#endif
- char hostname[1];
-};
-
/* How long we are willing to wait for additional parallel responses after
obtaining a "definitive" one. For old c-ares without getaddrinfo.
@@ -280,89 +366,13 @@ static void destroy_async_data(struct Curl_async *async)
/*
* Curl_resolver_getsock() is called when someone from the outside world
- * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking
- * with ares. The caller must make sure that this function is only called when
- * we have a working ares channel.
- *
- * Returns: sockets-in-use-bitmap
+ * (using curl_multi_fdset()) wants to get our fd_set setup.
*/
-int Curl_resolver_getsock(struct Curl_easy *data,
- curl_socket_t *socks)
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
- struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
- struct timeval timebuf;
- int max = ares_getsock((ares_channel)data->state.async.resolver,
- (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
- struct timeval *timeout =
- ares_timeout((ares_channel)data->state.async.resolver, &maxtime, &timebuf);
- timediff_t milli = curlx_tvtoms(timeout);
- Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
- return max;
-}
-
-/*
- * waitperform()
- *
- * 1) Ask ares what sockets it currently plays with, then
- * 2) wait for the timeout period to check for action on ares' sockets.
- * 3) tell ares to act on all the sockets marked as "with action"
- *
- * return number of sockets it worked on, or -1 on error
- */
-
-static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
-{
- int nfds;
- int bitmask;
- ares_socket_t socks[ARES_GETSOCK_MAXNUM];
- struct pollfd pfd[ARES_GETSOCK_MAXNUM];
- int i;
- int num = 0;
-
- bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
- ARES_GETSOCK_MAXNUM);
-
- for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
- pfd[i].events = 0;
- pfd[i].revents = 0;
- if(ARES_GETSOCK_READABLE(bitmask, i)) {
- pfd[i].fd = socks[i];
- pfd[i].events |= POLLRDNORM|POLLIN;
- }
- if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
- pfd[i].fd = socks[i];
- pfd[i].events |= POLLWRNORM|POLLOUT;
- }
- if(pfd[i].events)
- num++;
- else
- break;
- }
-
- if(num) {
- nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
- if(nfds < 0)
- return -1;
- }
- else
- nfds = 0;
-
- if(!nfds)
- /* Call ares_process() unconditionally here, even if we simply timed out
- above, as otherwise the ares name resolve will not timeout! */
- ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
- ARES_SOCKET_BAD);
- else {
- /* move through the descriptors and ask for processing on them */
- for(i = 0; i < num; i++)
- ares_process_fd((ares_channel)data->state.async.resolver,
- (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
- pfd[i].fd : ARES_SOCKET_BAD,
- (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
- pfd[i].fd : ARES_SOCKET_BAD);
- }
- return nfds;
+ return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver,
+ socks);
}
/*
@@ -381,7 +391,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
DEBUGASSERT(dns);
*dns = NULL;
- if(waitperform(data, 0) < 0)
+ if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
return CURLE_UNRECOVERABLE_POLL;
#ifndef HAVE_CARES_GETADDRINFO
@@ -417,8 +427,19 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(!data->state.async.dns)
result = Curl_resolver_error(data);
- else
+ else {
*dns = data->state.async.dns;
+#ifdef USE_HTTPSRR_ARES
+ {
+ struct Curl_https_rrinfo *lhrr =
+ Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
+ if(!lhrr)
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ (*dns)->hinfo = lhrr;
+ }
+#endif
+ }
destroy_async_data(&data->state.async);
}
@@ -481,7 +502,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
else
timeout_ms = 1000;
- if(waitperform(data, timeout_ms) < 0)
+ if(Curl_ares_perform((ares_channel)data->state.async.resolver,
+ timeout_ms) < 0)
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
@@ -745,6 +767,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
}
#endif
+
/*
* Curl_resolver_getaddrinfo() - when using ares
*
@@ -827,6 +850,16 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
query_completed_cb, data);
}
#endif
+#ifdef USE_HTTPSRR_ARES
+ {
+ res->num_pending++; /* one more */
+ memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
+ ares_query_dnsrec((ares_channel)data->state.async.resolver,
+ hostname, ARES_CLASS_IN,
+ ARES_REC_TYPE_HTTPS,
+ Curl_dnsrec_done_cb, data, NULL);
+ }
+#endif
*waitp = 1; /* expect asynchronous response */
}
return NULL; /* no struct yet */
@@ -838,14 +871,26 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
CURLcode result = CURLE_NOT_BUILT_IN;
int ares_result;
- /* If server is NULL or empty, this would purge all DNS servers
- * from ares library, which will cause any and all queries to fail.
- * So, just return OK if none are configured and do not actually make
- * any changes to c-ares. This lets c-ares use its defaults, which
- * it gets from the OS (for instance from /etc/resolv.conf on Linux).
+ /* If server is NULL, this purges all DNS servers from c-ares. Reset it to
+ * default.
*/
- if(!(servers && servers[0]))
- return CURLE_OK;
+ if(!servers) {
+ Curl_resolver_cleanup(data->state.async.resolver);
+ result = Curl_resolver_init(data, &data->state.async.resolver);
+ if(!result) {
+ /* this now needs to restore the other options set to c-ares */
+ if(data->set.str[STRING_DNS_INTERFACE])
+ (void)Curl_set_dns_interface(data,
+ data->set.str[STRING_DNS_INTERFACE]);
+ if(data->set.str[STRING_DNS_LOCAL_IP4])
+ (void)Curl_set_dns_local_ip4(data,
+ data->set.str[STRING_DNS_LOCAL_IP4]);
+ if(data->set.str[STRING_DNS_LOCAL_IP6])
+ (void)Curl_set_dns_local_ip6(data,
+ data->set.str[STRING_DNS_LOCAL_IP6]);
+ }
+ return result;
+ }
#ifdef HAVE_CARES_SERVERS_CSV
#ifdef HAVE_CARES_PORTS_CSV
@@ -947,3 +992,5 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
#endif
}
#endif /* CURLRES_ARES */
+
+#endif /* USE_ARES */