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