c885adef54ca8af26b69888cb375c98bc7898c41
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / asyn-ares.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 /***********************************************************************
26  * Only for ares-enabled builds
27  * And only for functions that fulfill the asynch resolver backend API
28  * as defined in asyn.h, nothing else belongs in this file!
29  **********************************************************************/
30
31 #ifdef CURLRES_ARES
32
33 #include <limits.h>
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_NETDB_H
38 #include <netdb.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43 #ifdef __VMS
44 #include <in.h>
45 #include <inet.h>
46 #endif
47
48 #ifdef HAVE_PROCESS_H
49 #include <process.h>
50 #endif
51
52 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
53 #undef in_addr_t
54 #define in_addr_t unsigned long
55 #endif
56
57 #include "urldata.h"
58 #include "sendf.h"
59 #include "hostip.h"
60 #include "hash.h"
61 #include "share.h"
62 #include "url.h"
63 #include "multiif.h"
64 #include "inet_pton.h"
65 #include "connect.h"
66 #include "select.h"
67 #include "progress.h"
68 #include "timediff.h"
69
70 #  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
71   defined(WIN32)
72 #    define CARES_STATICLIB
73 #  endif
74 #  include <ares.h>
75 #  include <ares_version.h> /* really old c-ares didn't include this by
76                                itself */
77
78 #if ARES_VERSION >= 0x010500
79 /* c-ares 1.5.0 or later, the callback proto is modified */
80 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
81 #endif
82
83 #if ARES_VERSION >= 0x010601
84 /* IPv6 supported since 1.6.1 */
85 #define HAVE_CARES_IPV6 1
86 #endif
87
88 #if ARES_VERSION >= 0x010704
89 #define HAVE_CARES_SERVERS_CSV 1
90 #define HAVE_CARES_LOCAL_DEV 1
91 #define HAVE_CARES_SET_LOCAL 1
92 #endif
93
94 #if ARES_VERSION >= 0x010b00
95 #define HAVE_CARES_PORTS_CSV 1
96 #endif
97
98 #if ARES_VERSION >= 0x011000
99 /* 1.16.0 or later has ares_getaddrinfo */
100 #define HAVE_CARES_GETADDRINFO 1
101 #endif
102
103 /* The last 3 #include files should be in this order */
104 #include "curl_printf.h"
105 #include "curl_memory.h"
106 #include "memdebug.h"
107
108 struct thread_data {
109   int num_pending; /* number of outstanding c-ares requests */
110   struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
111                                     parts */
112   int last_status;
113 #ifndef HAVE_CARES_GETADDRINFO
114   struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
115 #endif
116 };
117
118 /* How long we are willing to wait for additional parallel responses after
119    obtaining a "definitive" one.
120
121    This is intended to equal the c-ares default timeout.  cURL always uses that
122    default value.  Unfortunately, c-ares doesn't expose its default timeout in
123    its API, but it is officially documented as 5 seconds.
124
125    See query_completed_cb() for an explanation of how this is used.
126  */
127 #define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
128
129 /*
130  * Curl_resolver_global_init() - the generic low-level asynchronous name
131  * resolve API.  Called from curl_global_init() to initialize global resolver
132  * environment.  Initializes ares library.
133  */
134 int Curl_resolver_global_init(void)
135 {
136 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
137   if(ares_library_init(ARES_LIB_INIT_ALL)) {
138     return CURLE_FAILED_INIT;
139   }
140 #endif
141   return CURLE_OK;
142 }
143
144 /*
145  * Curl_resolver_global_cleanup()
146  *
147  * Called from curl_global_cleanup() to destroy global resolver environment.
148  * Deinitializes ares library.
149  */
150 void Curl_resolver_global_cleanup(void)
151 {
152 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
153   ares_library_cleanup();
154 #endif
155 }
156
157
158 static void sock_state_cb(void *data, ares_socket_t socket_fd,
159                           int readable, int writable)
160 {
161   struct Curl_easy *easy = data;
162   if(!readable && !writable) {
163     DEBUGASSERT(easy);
164     Curl_multi_closed(easy, socket_fd);
165   }
166 }
167
168 /*
169  * Curl_resolver_init()
170  *
171  * Called from curl_easy_init() -> Curl_open() to initialize resolver
172  * URL-state specific environment ('resolver' member of the UrlState
173  * structure).  Fills the passed pointer by the initialized ares_channel.
174  */
175 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
176 {
177   int status;
178   struct ares_options options;
179   int optmask = ARES_OPT_SOCK_STATE_CB;
180   options.sock_state_cb = sock_state_cb;
181   options.sock_state_cb_data = easy;
182   status = ares_init_options((ares_channel*)resolver, &options, optmask);
183   if(status != ARES_SUCCESS) {
184     if(status == ARES_ENOMEM)
185       return CURLE_OUT_OF_MEMORY;
186     else
187       return CURLE_FAILED_INIT;
188   }
189   return CURLE_OK;
190   /* make sure that all other returns from this function should destroy the
191      ares channel before returning error! */
192 }
193
194 /*
195  * Curl_resolver_cleanup()
196  *
197  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
198  * URL-state specific environment ('resolver' member of the UrlState
199  * structure).  Destroys the ares channel.
200  */
201 void Curl_resolver_cleanup(void *resolver)
202 {
203   ares_destroy((ares_channel)resolver);
204 }
205
206 /*
207  * Curl_resolver_duphandle()
208  *
209  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
210  * environment ('resolver' member of the UrlState structure).  Duplicates the
211  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
212  */
213 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
214 {
215   (void)from;
216   /*
217    * it would be better to call ares_dup instead, but right now
218    * it is not possible to set 'sock_state_cb_data' outside of
219    * ares_init_options
220    */
221   return Curl_resolver_init(easy, to);
222 }
223
224 static void destroy_async_data(struct Curl_async *async);
225
226 /*
227  * Cancel all possibly still on-going resolves for this connection.
228  */
229 void Curl_resolver_cancel(struct Curl_easy *data)
230 {
231   DEBUGASSERT(data);
232   if(data->state.async.resolver)
233     ares_cancel((ares_channel)data->state.async.resolver);
234   destroy_async_data(&data->state.async);
235 }
236
237 /*
238  * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
239  * never block.
240  */
241 void Curl_resolver_kill(struct Curl_easy *data)
242 {
243   /* We don't need to check the resolver state because we can be called safely
244      at any time and we always do the same thing. */
245   Curl_resolver_cancel(data);
246 }
247
248 /*
249  * destroy_async_data() cleans up async resolver data.
250  */
251 static void destroy_async_data(struct Curl_async *async)
252 {
253   free(async->hostname);
254
255   if(async->tdata) {
256     struct thread_data *res = async->tdata;
257     if(res) {
258       if(res->temp_ai) {
259         Curl_freeaddrinfo(res->temp_ai);
260         res->temp_ai = NULL;
261       }
262       free(res);
263     }
264     async->tdata = NULL;
265   }
266
267   async->hostname = NULL;
268 }
269
270 /*
271  * Curl_resolver_getsock() is called when someone from the outside world
272  * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
273  * with ares. The caller must make sure that this function is only called when
274  * we have a working ares channel.
275  *
276  * Returns: sockets-in-use-bitmap
277  */
278
279 int Curl_resolver_getsock(struct Curl_easy *data,
280                           curl_socket_t *socks)
281 {
282   struct timeval maxtime;
283   struct timeval timebuf;
284   struct timeval *timeout;
285   long milli;
286   int max = ares_getsock((ares_channel)data->state.async.resolver,
287                          (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
288
289   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
290   maxtime.tv_usec = 0;
291
292   timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
293                          &timebuf);
294   milli = (long)curlx_tvtoms(timeout);
295   if(milli == 0)
296     milli += 10;
297   Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
298
299   return max;
300 }
301
302 /*
303  * waitperform()
304  *
305  * 1) Ask ares what sockets it currently plays with, then
306  * 2) wait for the timeout period to check for action on ares' sockets.
307  * 3) tell ares to act on all the sockets marked as "with action"
308  *
309  * return number of sockets it worked on
310  */
311
312 static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
313 {
314   int nfds;
315   int bitmask;
316   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
317   struct pollfd pfd[ARES_GETSOCK_MAXNUM];
318   int i;
319   int num = 0;
320
321   bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
322                          ARES_GETSOCK_MAXNUM);
323
324   for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
325     pfd[i].events = 0;
326     pfd[i].revents = 0;
327     if(ARES_GETSOCK_READABLE(bitmask, i)) {
328       pfd[i].fd = socks[i];
329       pfd[i].events |= POLLRDNORM|POLLIN;
330     }
331     if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
332       pfd[i].fd = socks[i];
333       pfd[i].events |= POLLWRNORM|POLLOUT;
334     }
335     if(pfd[i].events)
336       num++;
337     else
338       break;
339   }
340
341   if(num)
342     nfds = Curl_poll(pfd, num, timeout_ms);
343   else
344     nfds = 0;
345
346   if(!nfds)
347     /* Call ares_process() unconditionally here, even if we simply timed out
348        above, as otherwise the ares name resolve won't timeout! */
349     ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
350                     ARES_SOCKET_BAD);
351   else {
352     /* move through the descriptors and ask for processing on them */
353     for(i = 0; i < num; i++)
354       ares_process_fd((ares_channel)data->state.async.resolver,
355                       (pfd[i].revents & (POLLRDNORM|POLLIN))?
356                       pfd[i].fd:ARES_SOCKET_BAD,
357                       (pfd[i].revents & (POLLWRNORM|POLLOUT))?
358                       pfd[i].fd:ARES_SOCKET_BAD);
359   }
360   return nfds;
361 }
362
363 /*
364  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
365  * name resolve request has completed. It should also make sure to time-out if
366  * the operation seems to take too long.
367  *
368  * Returns normal CURLcode errors.
369  */
370 CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
371                                    struct Curl_dns_entry **dns)
372 {
373   struct thread_data *res = data->state.async.tdata;
374   CURLcode result = CURLE_OK;
375
376   DEBUGASSERT(dns);
377   *dns = NULL;
378
379   waitperform(data, 0);
380
381 #ifndef HAVE_CARES_GETADDRINFO
382   /* Now that we've checked for any last minute results above, see if there are
383      any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
384      expires. */
385   if(res
386      && res->num_pending
387      /* This is only set to non-zero if the timer was started. */
388      && (res->happy_eyeballs_dns_time.tv_sec
389          || res->happy_eyeballs_dns_time.tv_usec)
390      && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
391          >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
392     /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
393        running. */
394     memset(
395       &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
396
397     /* Cancel the raw c-ares request, which will fire query_completed_cb() with
398        ARES_ECANCELLED synchronously for all pending responses.  This will
399        leave us with res->num_pending == 0, which is perfect for the next
400        block. */
401     ares_cancel((ares_channel)data->state.async.resolver);
402     DEBUGASSERT(res->num_pending == 0);
403   }
404 #endif
405
406   if(res && !res->num_pending) {
407     (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
408     /* temp_ai ownership is moved to the connection, so we need not free-up
409        them */
410     res->temp_ai = NULL;
411
412     if(!data->state.async.dns)
413       result = Curl_resolver_error(data);
414     else
415       *dns = data->state.async.dns;
416
417     destroy_async_data(&data->state.async);
418   }
419
420   return result;
421 }
422
423 /*
424  * Curl_resolver_wait_resolv()
425  *
426  * Waits for a resolve to finish. This function should be avoided since using
427  * this risk getting the multi interface to "hang".
428  *
429  * 'entry' MUST be non-NULL.
430  *
431  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
432  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
433  */
434 CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
435                                    struct Curl_dns_entry **entry)
436 {
437   CURLcode result = CURLE_OK;
438   timediff_t timeout;
439   struct curltime now = Curl_now();
440
441   DEBUGASSERT(entry);
442   *entry = NULL; /* clear on entry */
443
444   timeout = Curl_timeleft(data, &now, TRUE);
445   if(timeout < 0) {
446     /* already expired! */
447     connclose(data->conn, "Timed out before name resolve started");
448     return CURLE_OPERATION_TIMEDOUT;
449   }
450   if(!timeout)
451     timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
452
453   /* Wait for the name resolve query to complete. */
454   while(!result) {
455     struct timeval *tvp, tv, store;
456     int itimeout;
457     timediff_t timeout_ms;
458
459 #if TIMEDIFF_T_MAX > INT_MAX
460     itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
461 #else
462     itimeout = (int)timeout;
463 #endif
464
465     store.tv_sec = itimeout/1000;
466     store.tv_usec = (itimeout%1000)*1000;
467
468     tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
469
470     /* use the timeout period ares returned to us above if less than one
471        second is left, otherwise just use 1000ms to make sure the progress
472        callback gets called frequent enough */
473     if(!tvp->tv_sec)
474       timeout_ms = (timediff_t)(tvp->tv_usec/1000);
475     else
476       timeout_ms = 1000;
477
478     waitperform(data, timeout_ms);
479     result = Curl_resolver_is_resolved(data, entry);
480
481     if(result || data->state.async.done)
482       break;
483
484     if(Curl_pgrsUpdate(data))
485       result = CURLE_ABORTED_BY_CALLBACK;
486     else {
487       struct curltime now2 = Curl_now();
488       timediff_t timediff = Curl_timediff(now2, now); /* spent time */
489       if(timediff <= 0)
490         timeout -= 1; /* always deduct at least 1 */
491       else if(timediff > timeout)
492         timeout = -1;
493       else
494         timeout -= timediff;
495       now = now2; /* for next loop */
496     }
497     if(timeout < 0)
498       result = CURLE_OPERATION_TIMEDOUT;
499   }
500   if(result)
501     /* failure, so we cancel the ares operation */
502     ares_cancel((ares_channel)data->state.async.resolver);
503
504   /* Operation complete, if the lookup was successful we now have the entry
505      in the cache. */
506   if(entry)
507     *entry = data->state.async.dns;
508
509   if(result)
510     /* close the connection, since we can't return failure here without
511        cleaning up this connection properly. */
512     connclose(data->conn, "c-ares resolve failed");
513
514   return result;
515 }
516
517 #ifndef HAVE_CARES_GETADDRINFO
518
519 /* Connects results to the list */
520 static void compound_results(struct thread_data *res,
521                              struct Curl_addrinfo *ai)
522 {
523   if(!ai)
524     return;
525
526 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
527   if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
528     /* We have results already, put the new IPv6 entries at the head of the
529        list. */
530     struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
531
532     while(temp_ai_tail->ai_next)
533       temp_ai_tail = temp_ai_tail->ai_next;
534
535     temp_ai_tail->ai_next = ai;
536   }
537   else
538 #endif /* CURLRES_IPV6 */
539   {
540     /* Add the new results to the list of old results. */
541     struct Curl_addrinfo *ai_tail = ai;
542     while(ai_tail->ai_next)
543       ai_tail = ai_tail->ai_next;
544
545     ai_tail->ai_next = res->temp_ai;
546     res->temp_ai = ai;
547   }
548 }
549
550 /*
551  * ares_query_completed_cb() is the callback that ares will call when
552  * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
553  * when using ares, is completed either successfully or with failure.
554  */
555 static void query_completed_cb(void *arg,  /* (struct connectdata *) */
556                                int status,
557 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
558                                int timeouts,
559 #endif
560                                struct hostent *hostent)
561 {
562   struct Curl_easy *data = (struct Curl_easy *)arg;
563   struct thread_data *res;
564
565 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
566   (void)timeouts; /* ignored */
567 #endif
568
569   if(ARES_EDESTRUCTION == status)
570     /* when this ares handle is getting destroyed, the 'arg' pointer may not
571        be valid so only defer it when we know the 'status' says its fine! */
572     return;
573
574   res = data->state.async.tdata;
575   if(res) {
576     res->num_pending--;
577
578     if(CURL_ASYNC_SUCCESS == status) {
579       struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
580       if(ai) {
581         compound_results(res, ai);
582       }
583     }
584     /* A successful result overwrites any previous error */
585     if(res->last_status != ARES_SUCCESS)
586       res->last_status = status;
587
588     /* If there are responses still pending, we presume they must be the
589        complementary IPv4 or IPv6 lookups that we started in parallel in
590        Curl_resolver_getaddrinfo() (for Happy Eyeballs).  If we've got a
591        "definitive" response from one of a set of parallel queries, we need to
592        think about how long we're willing to wait for more responses. */
593     if(res->num_pending
594        /* Only these c-ares status values count as "definitive" for these
595           purposes.  For example, ARES_ENODATA is what we expect when there is
596           no IPv6 entry for a domain name, and that's not a reason to get more
597           aggressive in our timeouts for the other response.  Other errors are
598           either a result of bad input (which should affect all parallel
599           requests), local or network conditions, non-definitive server
600           responses, or us cancelling the request. */
601        && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
602       /* Right now, there can only be up to two parallel queries, so don't
603          bother handling any other cases. */
604       DEBUGASSERT(res->num_pending == 1);
605
606       /* It's possible that one of these parallel queries could succeed
607          quickly, but the other could always fail or timeout (when we're
608          talking to a pool of DNS servers that can only successfully resolve
609          IPv4 address, for example).
610
611          It's also possible that the other request could always just take
612          longer because it needs more time or only the second DNS server can
613          fulfill it successfully.  But, to align with the philosophy of Happy
614          Eyeballs, we don't want to wait _too_ long or users will think
615          requests are slow when IPv6 lookups don't actually work (but IPv4 ones
616          do).
617
618          So, now that we have a usable answer (some IPv4 addresses, some IPv6
619          addresses, or "no such domain"), we start a timeout for the remaining
620          pending responses.  Even though it is typical that this resolved
621          request came back quickly, that needn't be the case.  It might be that
622          this completing request didn't get a result from the first DNS server
623          or even the first round of the whole DNS server pool.  So it could
624          already be quite some time after we issued the DNS queries in the
625          first place.  Without modifying c-ares, we can't know exactly where in
626          its retry cycle we are.  We could guess based on how much time has
627          gone by, but it doesn't really matter.  Happy Eyeballs tells us that,
628          given usable information in hand, we simply don't want to wait "too
629          much longer" after we get a result.
630
631          We simply wait an additional amount of time equal to the default
632          c-ares query timeout.  That is enough time for a typical parallel
633          response to arrive without being "too long".  Even on a network
634          where one of the two types of queries is failing or timing out
635          constantly, this will usually mean we wait a total of the default
636          c-ares timeout (5 seconds) plus the round trip time for the successful
637          request, which seems bearable.  The downside is that c-ares might race
638          with us to issue one more retry just before we give up, but it seems
639          better to "waste" that request instead of trying to guess the perfect
640          timeout to prevent it.  After all, we don't even know where in the
641          c-ares retry cycle each request is.
642       */
643       res->happy_eyeballs_dns_time = Curl_now();
644       Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
645                   EXPIRE_HAPPY_EYEBALLS_DNS);
646     }
647   }
648 }
649 #else
650 /* c-ares 1.16.0 or later */
651
652 /*
653  * ares2addr() converts an address list provided by c-ares to an internal
654  * libcurl compatible list
655  */
656 static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
657 {
658   /* traverse the ares_addrinfo_node list */
659   struct ares_addrinfo_node *ai;
660   struct Curl_addrinfo *cafirst = NULL;
661   struct Curl_addrinfo *calast = NULL;
662   int error = 0;
663
664   for(ai = node; ai != NULL; ai = ai->ai_next) {
665     size_t ss_size;
666     struct Curl_addrinfo *ca;
667     /* ignore elements with unsupported address family, */
668     /* settle family-specific sockaddr structure size.  */
669     if(ai->ai_family == AF_INET)
670       ss_size = sizeof(struct sockaddr_in);
671 #ifdef ENABLE_IPV6
672     else if(ai->ai_family == AF_INET6)
673       ss_size = sizeof(struct sockaddr_in6);
674 #endif
675     else
676       continue;
677
678     /* ignore elements without required address info */
679     if(!ai->ai_addr || !(ai->ai_addrlen > 0))
680       continue;
681
682     /* ignore elements with bogus address size */
683     if((size_t)ai->ai_addrlen < ss_size)
684       continue;
685
686     ca = malloc(sizeof(struct Curl_addrinfo) + ss_size);
687     if(!ca) {
688       error = EAI_MEMORY;
689       break;
690     }
691
692     /* copy each structure member individually, member ordering, */
693     /* size, or padding might be different for each platform.    */
694
695     ca->ai_flags     = ai->ai_flags;
696     ca->ai_family    = ai->ai_family;
697     ca->ai_socktype  = ai->ai_socktype;
698     ca->ai_protocol  = ai->ai_protocol;
699     ca->ai_addrlen   = (curl_socklen_t)ss_size;
700     ca->ai_addr      = NULL;
701     ca->ai_canonname = NULL;
702     ca->ai_next      = NULL;
703
704     ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
705     memcpy(ca->ai_addr, ai->ai_addr, ss_size);
706
707     /* if the return list is empty, this becomes the first element */
708     if(!cafirst)
709       cafirst = ca;
710
711     /* add this element last in the return list */
712     if(calast)
713       calast->ai_next = ca;
714     calast = ca;
715   }
716
717   /* if we failed, destroy the Curl_addrinfo list */
718   if(error) {
719     Curl_freeaddrinfo(cafirst);
720     cafirst = NULL;
721   }
722
723   return cafirst;
724 }
725
726 static void addrinfo_cb(void *arg, int status, int timeouts,
727                         struct ares_addrinfo *result)
728 {
729   struct Curl_easy *data = (struct Curl_easy *)arg;
730   struct thread_data *res = data->state.async.tdata;
731   (void)timeouts;
732   if(ARES_SUCCESS == status) {
733     res->temp_ai = ares2addr(result->nodes);
734     res->last_status = CURL_ASYNC_SUCCESS;
735     ares_freeaddrinfo(result);
736   }
737   res->num_pending--;
738 }
739
740 #endif
741 /*
742  * Curl_resolver_getaddrinfo() - when using ares
743  *
744  * Returns name information about the given hostname and port number. If
745  * successful, the 'hostent' is returned and the forth argument will point to
746  * memory we need to free after use. That memory *MUST* be freed with
747  * Curl_freeaddrinfo(), nothing else.
748  */
749 struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
750                                                 const char *hostname,
751                                                 int port,
752                                                 int *waitp)
753 {
754   char *bufp;
755
756   *waitp = 0; /* default to synchronous response */
757
758   bufp = strdup(hostname);
759   if(bufp) {
760     struct thread_data *res = NULL;
761     free(data->state.async.hostname);
762     data->state.async.hostname = bufp;
763     data->state.async.port = port;
764     data->state.async.done = FALSE;   /* not done */
765     data->state.async.status = 0;     /* clear */
766     data->state.async.dns = NULL;     /* clear */
767     res = calloc(sizeof(struct thread_data), 1);
768     if(!res) {
769       free(data->state.async.hostname);
770       data->state.async.hostname = NULL;
771       return NULL;
772     }
773     data->state.async.tdata = res;
774
775     /* initial status - failed */
776     res->last_status = ARES_ENOTFOUND;
777
778 #ifdef HAVE_CARES_GETADDRINFO
779     {
780       struct ares_addrinfo_hints hints;
781       char service[12];
782       int pf = PF_INET;
783       memset(&hints, 0, sizeof(hints));
784 #ifdef CURLRES_IPV6
785       if(Curl_ipv6works(data))
786         /* The stack seems to be IPv6-enabled */
787         pf = PF_UNSPEC;
788 #endif /* CURLRES_IPV6 */
789       hints.ai_family = pf;
790       hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
791         SOCK_STREAM : SOCK_DGRAM;
792       msnprintf(service, sizeof(service), "%d", port);
793       res->num_pending = 1;
794       ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
795                        service, &hints, addrinfo_cb, data);
796     }
797 #else
798
799 #ifdef HAVE_CARES_IPV6
800     if(Curl_ipv6works(data)) {
801       /* The stack seems to be IPv6-enabled */
802       res->num_pending = 2;
803
804       /* areschannel is already setup in the Curl_open() function */
805       ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
806                           PF_INET, query_completed_cb, data);
807       ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
808                           PF_INET6, query_completed_cb, data);
809     }
810     else
811 #endif
812     {
813       res->num_pending = 1;
814
815       /* areschannel is already setup in the Curl_open() function */
816       ares_gethostbyname((ares_channel)data->state.async.resolver,
817                          hostname, PF_INET,
818                          query_completed_cb, data);
819     }
820 #endif
821     *waitp = 1; /* expect asynchronous response */
822   }
823   return NULL; /* no struct yet */
824 }
825
826 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
827                               char *servers)
828 {
829   CURLcode result = CURLE_NOT_BUILT_IN;
830   int ares_result;
831
832   /* If server is NULL or empty, this would purge all DNS servers
833    * from ares library, which will cause any and all queries to fail.
834    * So, just return OK if none are configured and don't actually make
835    * any changes to c-ares.  This lets c-ares use it's defaults, which
836    * it gets from the OS (for instance from /etc/resolv.conf on Linux).
837    */
838   if(!(servers && servers[0]))
839     return CURLE_OK;
840
841 #ifdef HAVE_CARES_SERVERS_CSV
842 #ifdef HAVE_CARES_PORTS_CSV
843   ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
844                                            servers);
845 #else
846   ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
847 #endif
848   switch(ares_result) {
849   case ARES_SUCCESS:
850     result = CURLE_OK;
851     break;
852   case ARES_ENOMEM:
853     result = CURLE_OUT_OF_MEMORY;
854     break;
855   case ARES_ENOTINITIALIZED:
856   case ARES_ENODATA:
857   case ARES_EBADSTR:
858   default:
859     result = CURLE_BAD_FUNCTION_ARGUMENT;
860     break;
861   }
862 #else /* too old c-ares version! */
863   (void)data;
864   (void)(ares_result);
865 #endif
866   return result;
867 }
868
869 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
870                                 const char *interf)
871 {
872 #ifdef HAVE_CARES_LOCAL_DEV
873   if(!interf)
874     interf = "";
875
876   ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
877
878   return CURLE_OK;
879 #else /* c-ares version too old! */
880   (void)data;
881   (void)interf;
882   return CURLE_NOT_BUILT_IN;
883 #endif
884 }
885
886 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
887                                 const char *local_ip4)
888 {
889 #ifdef HAVE_CARES_SET_LOCAL
890   struct in_addr a4;
891
892   if((!local_ip4) || (local_ip4[0] == 0)) {
893     a4.s_addr = 0; /* disabled: do not bind to a specific address */
894   }
895   else {
896     if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
897       return CURLE_BAD_FUNCTION_ARGUMENT;
898     }
899   }
900
901   ares_set_local_ip4((ares_channel)data->state.async.resolver,
902                      ntohl(a4.s_addr));
903
904   return CURLE_OK;
905 #else /* c-ares version too old! */
906   (void)data;
907   (void)local_ip4;
908   return CURLE_NOT_BUILT_IN;
909 #endif
910 }
911
912 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
913                                 const char *local_ip6)
914 {
915 #if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
916   unsigned char a6[INET6_ADDRSTRLEN];
917
918   if((!local_ip6) || (local_ip6[0] == 0)) {
919     /* disabled: do not bind to a specific address */
920     memset(a6, 0, sizeof(a6));
921   }
922   else {
923     if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
924       return CURLE_BAD_FUNCTION_ARGUMENT;
925     }
926   }
927
928   ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
929
930   return CURLE_OK;
931 #else /* c-ares version too old! */
932   (void)data;
933   (void)local_ip6;
934   return CURLE_NOT_BUILT_IN;
935 #endif
936 }
937 #endif /* CURLRES_ARES */