• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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 #include "socketpair.h"
27 
28 /***********************************************************************
29  * Only for threaded name resolves builds
30  **********************************************************************/
31 #ifdef CURLRES_THREADED
32 
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
35 #endif
36 #ifdef HAVE_NETDB_H
37 #include <netdb.h>
38 #endif
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
41 #endif
42 #ifdef __VMS
43 #include <in.h>
44 #include <inet.h>
45 #endif
46 
47 #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
48 #  include <pthread.h>
49 #endif
50 
51 #ifdef HAVE_GETADDRINFO
52 #  define RESOLVER_ENOMEM  EAI_MEMORY
53 #else
54 #  define RESOLVER_ENOMEM  ENOMEM
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_ntop.h"
65 #include "curl_threads.h"
66 #include "connect.h"
67 #include "strdup.h"
68 
69 #ifdef USE_ARES
70 #include <ares.h>
71 #ifdef USE_HTTPSRR
72 #define USE_HTTPSRR_ARES 1 /* the combo */
73 #endif
74 #endif
75 
76 /* The last 3 #include files should be in this order */
77 #include "curl_printf.h"
78 #include "curl_memory.h"
79 #include "memdebug.h"
80 
81 struct resdata {
82   struct curltime start;
83 };
84 
85 /*
86  * Curl_resolver_global_init()
87  * Called from curl_global_init() to initialize global resolver environment.
88  * Does nothing here.
89  */
Curl_resolver_global_init(void)90 int Curl_resolver_global_init(void)
91 {
92   return CURLE_OK;
93 }
94 
95 /*
96  * Curl_resolver_global_cleanup()
97  * Called from curl_global_cleanup() to destroy global resolver environment.
98  * Does nothing here.
99  */
Curl_resolver_global_cleanup(void)100 void Curl_resolver_global_cleanup(void)
101 {
102 }
103 
104 /*
105  * Curl_resolver_init()
106  * Called from curl_easy_init() -> Curl_open() to initialize resolver
107  * URL-state specific environment ('resolver' member of the UrlState
108  * structure).
109  */
Curl_resolver_init(struct Curl_easy * easy,void ** resolver)110 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
111 {
112   (void)easy;
113   *resolver = calloc(1, sizeof(struct resdata));
114   if(!*resolver)
115     return CURLE_OUT_OF_MEMORY;
116   return CURLE_OK;
117 }
118 
119 /*
120  * Curl_resolver_cleanup()
121  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
122  * URL-state specific environment ('resolver' member of the UrlState
123  * structure).
124  */
Curl_resolver_cleanup(void * resolver)125 void Curl_resolver_cleanup(void *resolver)
126 {
127   free(resolver);
128 }
129 
130 /*
131  * Curl_resolver_duphandle()
132  * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
133  * environment ('resolver' member of the UrlState structure).
134  */
Curl_resolver_duphandle(struct Curl_easy * easy,void ** to,void * from)135 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
136 {
137   (void)from;
138   return Curl_resolver_init(easy, to);
139 }
140 
141 static void destroy_async_data(struct Curl_async *);
142 
143 /*
144  * Cancel all possibly still on-going resolves for this connection.
145  */
Curl_resolver_cancel(struct Curl_easy * data)146 void Curl_resolver_cancel(struct Curl_easy *data)
147 {
148   destroy_async_data(&data->state.async);
149 }
150 
151 /* This function is used to init a threaded resolve */
152 static bool init_resolve_thread(struct Curl_easy *data,
153                                 const char *hostname, int port,
154                                 const struct addrinfo *hints);
155 
156 
conn_thread_sync_data(struct Curl_easy * data)157 static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
158 {
159   return &(data->state.async.tdata->tsd);
160 }
161 
162 /* Destroy resolver thread synchronization data */
163 static
destroy_thread_sync_data(struct thread_sync_data * tsd)164 void destroy_thread_sync_data(struct thread_sync_data *tsd)
165 {
166   if(tsd->mtx) {
167     Curl_mutex_destroy(tsd->mtx);
168     free(tsd->mtx);
169   }
170 
171   free(tsd->hostname);
172 
173   if(tsd->res)
174     Curl_freeaddrinfo(tsd->res);
175 
176 #ifndef CURL_DISABLE_SOCKETPAIR
177   /*
178    * close one end of the socket pair (may be done in resolver thread);
179    * the other end (for reading) is always closed in the parent thread.
180    */
181 #ifndef USE_EVENTFD
182   if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
183     wakeup_close(tsd->sock_pair[1]);
184   }
185 #endif
186 #endif
187   memset(tsd, 0, sizeof(*tsd));
188 }
189 
190 /* Initialize resolver thread synchronization data */
191 static
init_thread_sync_data(struct thread_data * td,const char * hostname,int port,const struct addrinfo * hints)192 int init_thread_sync_data(struct thread_data *td,
193                            const char *hostname,
194                            int port,
195                            const struct addrinfo *hints)
196 {
197   struct thread_sync_data *tsd = &td->tsd;
198 
199   memset(tsd, 0, sizeof(*tsd));
200 
201   tsd->td = td;
202   tsd->port = port;
203   /* Treat the request as done until the thread actually starts so any early
204    * cleanup gets done properly.
205    */
206   tsd->done = TRUE;
207 #ifdef HAVE_GETADDRINFO
208   DEBUGASSERT(hints);
209   tsd->hints = *hints;
210 #else
211   (void) hints;
212 #endif
213 
214   tsd->mtx = malloc(sizeof(curl_mutex_t));
215   if(!tsd->mtx)
216     goto err_exit;
217 
218   Curl_mutex_init(tsd->mtx);
219 
220 #ifndef CURL_DISABLE_SOCKETPAIR
221   /* create socket pair or pipe */
222   if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
223     tsd->sock_pair[0] = CURL_SOCKET_BAD;
224     tsd->sock_pair[1] = CURL_SOCKET_BAD;
225     goto err_exit;
226   }
227 #endif
228   tsd->sock_error = CURL_ASYNC_SUCCESS;
229 
230   /* Copying hostname string because original can be destroyed by parent
231    * thread during gethostbyname execution.
232    */
233   tsd->hostname = strdup(hostname);
234   if(!tsd->hostname)
235     goto err_exit;
236 
237   return 1;
238 
239 err_exit:
240 #ifndef CURL_DISABLE_SOCKETPAIR
241   if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
242     wakeup_close(tsd->sock_pair[0]);
243     tsd->sock_pair[0] = CURL_SOCKET_BAD;
244   }
245 #endif
246   destroy_thread_sync_data(tsd);
247   return 0;
248 }
249 
getaddrinfo_complete(struct Curl_easy * data)250 static CURLcode getaddrinfo_complete(struct Curl_easy *data)
251 {
252   struct thread_sync_data *tsd = conn_thread_sync_data(data);
253   CURLcode result;
254 
255   result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
256   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
257      cache. Set our copy to NULL so destroy_thread_sync_data does not free it.
258   */
259   tsd->res = NULL;
260 
261   return result;
262 }
263 
264 
265 #ifdef HAVE_GETADDRINFO
266 
267 /*
268  * getaddrinfo_thread() resolves a name and then exits.
269  *
270  * For builds without ARES, but with USE_IPV6, create a resolver thread
271  * and wait on it.
272  */
273 static
274 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
275 DWORD
276 #else
277 unsigned int
278 #endif
getaddrinfo_thread(void * arg)279 CURL_STDCALL getaddrinfo_thread(void *arg)
280 {
281   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
282   struct thread_data *td = tsd->td;
283   char service[12];
284   int rc;
285 #ifndef CURL_DISABLE_SOCKETPAIR
286 #ifdef USE_EVENTFD
287   const void *buf;
288   const uint64_t val = 1;
289 #else
290   char buf[1];
291 #endif
292 #endif
293 
294   msnprintf(service, sizeof(service), "%d", tsd->port);
295 
296   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
297 
298   if(rc) {
299     tsd->sock_error = SOCKERRNO ? SOCKERRNO : rc;
300     if(tsd->sock_error == 0)
301       tsd->sock_error = RESOLVER_ENOMEM;
302   }
303   else {
304     Curl_addrinfo_set_port(tsd->res, tsd->port);
305   }
306 
307   Curl_mutex_acquire(tsd->mtx);
308   if(tsd->done) {
309     /* too late, gotta clean up the mess */
310     Curl_mutex_release(tsd->mtx);
311     destroy_thread_sync_data(tsd);
312     free(td);
313   }
314   else {
315 #ifndef CURL_DISABLE_SOCKETPAIR
316     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
317 #ifdef USE_EVENTFD
318       buf = &val;
319 #else
320       buf[0] = 1;
321 #endif
322       /* DNS has been resolved, signal client task */
323       if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
324         /* update sock_erro to errno */
325         tsd->sock_error = SOCKERRNO;
326       }
327     }
328 #endif
329     tsd->done = TRUE;
330     Curl_mutex_release(tsd->mtx);
331   }
332 
333   return 0;
334 }
335 
336 #else /* HAVE_GETADDRINFO */
337 
338 /*
339  * gethostbyname_thread() resolves a name and then exits.
340  */
341 static
342 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
343 DWORD
344 #else
345 unsigned int
346 #endif
gethostbyname_thread(void * arg)347 CURL_STDCALL gethostbyname_thread(void *arg)
348 {
349   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
350   struct thread_data *td = tsd->td;
351 
352   tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
353 
354   if(!tsd->res) {
355     tsd->sock_error = SOCKERRNO;
356     if(tsd->sock_error == 0)
357       tsd->sock_error = RESOLVER_ENOMEM;
358   }
359 
360   Curl_mutex_acquire(tsd->mtx);
361   if(tsd->done) {
362     /* too late, gotta clean up the mess */
363     Curl_mutex_release(tsd->mtx);
364     destroy_thread_sync_data(tsd);
365     free(td);
366   }
367   else {
368     tsd->done = TRUE;
369     Curl_mutex_release(tsd->mtx);
370   }
371 
372   return 0;
373 }
374 
375 #endif /* HAVE_GETADDRINFO */
376 
377 /*
378  * destroy_async_data() cleans up async resolver data and thread handle.
379  */
destroy_async_data(struct Curl_async * async)380 static void destroy_async_data(struct Curl_async *async)
381 {
382   if(async->tdata) {
383     struct thread_data *td = async->tdata;
384     bool done;
385 #ifndef CURL_DISABLE_SOCKETPAIR
386     curl_socket_t sock_rd = td->tsd.sock_pair[0];
387     struct Curl_easy *data = td->tsd.data;
388 #endif
389 
390 #ifdef USE_HTTPSRR_ARES
391     ares_destroy(data->state.async.tdata->channel);
392 #endif
393     /*
394      * if the thread is still blocking in the resolve syscall, detach it and
395      * let the thread do the cleanup...
396      */
397     Curl_mutex_acquire(td->tsd.mtx);
398     done = td->tsd.done;
399     td->tsd.done = TRUE;
400     Curl_mutex_release(td->tsd.mtx);
401 
402     if(!done) {
403       Curl_thread_destroy(td->thread_hnd);
404     }
405     else {
406       if(td->thread_hnd != curl_thread_t_null)
407         Curl_thread_join(&td->thread_hnd);
408 
409       destroy_thread_sync_data(&td->tsd);
410 
411       free(async->tdata);
412     }
413 #ifndef CURL_DISABLE_SOCKETPAIR
414     /*
415      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
416      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
417      */
418     Curl_multi_closed(data, sock_rd);
419     wakeup_close(sock_rd);
420 #endif
421   }
422   async->tdata = NULL;
423 
424   free(async->hostname);
425   async->hostname = NULL;
426 }
427 
428 #ifdef USE_HTTPSRR_ARES
resolve_httpsrr(struct Curl_easy * data,struct Curl_async * asp)429 static CURLcode resolve_httpsrr(struct Curl_easy *data,
430                                 struct Curl_async *asp)
431 {
432   int status = ares_init_options(&asp->tdata->channel, NULL, 0);
433   if(status != ARES_SUCCESS)
434     return CURLE_FAILED_INIT;
435 
436   memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
437   ares_query_dnsrec(asp->tdata->channel,
438                     asp->hostname, ARES_CLASS_IN,
439                     ARES_REC_TYPE_HTTPS,
440                     Curl_dnsrec_done_cb, data, NULL);
441 
442   return CURLE_OK;
443 }
444 #endif
445 
446 /*
447  * init_resolve_thread() starts a new thread that performs the actual
448  * resolve. This function returns before the resolve is done.
449  *
450  * Returns FALSE in case of failure, otherwise TRUE.
451  */
init_resolve_thread(struct Curl_easy * data,const char * hostname,int port,const struct addrinfo * hints)452 static bool init_resolve_thread(struct Curl_easy *data,
453                                 const char *hostname, int port,
454                                 const struct addrinfo *hints)
455 {
456   struct thread_data *td = calloc(1, sizeof(struct thread_data));
457   int err = ENOMEM;
458   struct Curl_async *asp = &data->state.async;
459 
460   data->state.async.tdata = td;
461   if(!td)
462     goto errno_exit;
463 
464   asp->port = port;
465   asp->done = FALSE;
466   asp->status = 0;
467   asp->dns = NULL;
468   td->thread_hnd = curl_thread_t_null;
469 
470   if(!init_thread_sync_data(td, hostname, port, hints)) {
471     asp->tdata = NULL;
472     free(td);
473     goto errno_exit;
474   }
475 
476   free(asp->hostname);
477   asp->hostname = strdup(hostname);
478   if(!asp->hostname)
479     goto err_exit;
480 
481   /* The thread will set this TRUE when complete. */
482   td->tsd.done = FALSE;
483 
484 #ifdef HAVE_GETADDRINFO
485   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
486 #else
487   td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
488 #endif
489 
490   if(td->thread_hnd == curl_thread_t_null) {
491     /* The thread never started, so mark it as done here for proper cleanup. */
492     td->tsd.done = TRUE;
493     err = errno;
494     goto err_exit;
495   }
496 #ifdef USE_HTTPSRR_ARES
497   if(resolve_httpsrr(data, asp))
498     goto err_exit;
499 #endif
500   return TRUE;
501 
502 err_exit:
503   destroy_async_data(asp);
504 
505 errno_exit:
506   errno = err;
507   return FALSE;
508 }
509 
510 /*
511  * 'entry' may be NULL and then no data is returned
512  */
thread_wait_resolv(struct Curl_easy * data,struct Curl_dns_entry ** entry,bool report)513 static CURLcode thread_wait_resolv(struct Curl_easy *data,
514                                    struct Curl_dns_entry **entry,
515                                    bool report)
516 {
517   struct thread_data *td;
518   CURLcode result = CURLE_OK;
519 
520   DEBUGASSERT(data);
521   td = data->state.async.tdata;
522   DEBUGASSERT(td);
523   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
524 
525   /* wait for the thread to resolve the name */
526   if(Curl_thread_join(&td->thread_hnd)) {
527     if(entry)
528       result = getaddrinfo_complete(data);
529   }
530   else
531     DEBUGASSERT(0);
532 
533   data->state.async.done = TRUE;
534 
535   if(entry)
536     *entry = data->state.async.dns;
537 
538   if(!data->state.async.dns && report)
539     /* a name was not resolved, report error */
540     result = Curl_resolver_error(data);
541 
542   destroy_async_data(&data->state.async);
543 
544   if(!data->state.async.dns && report)
545     connclose(data->conn, "asynch resolve failed");
546 
547   return result;
548 }
549 
550 
551 /*
552  * Until we gain a way to signal the resolver threads to stop early, we must
553  * simply wait for them and ignore their results.
554  */
Curl_resolver_kill(struct Curl_easy * data)555 void Curl_resolver_kill(struct Curl_easy *data)
556 {
557   struct thread_data *td = data->state.async.tdata;
558 
559   /* If we are still resolving, we must wait for the threads to fully clean up,
560      unfortunately. Otherwise, we can simply cancel to clean up any resolver
561      data. */
562   if(td && td->thread_hnd != curl_thread_t_null
563      && (data->set.quick_exit != 1L))
564     (void)thread_wait_resolv(data, NULL, FALSE);
565   else
566     Curl_resolver_cancel(data);
567 }
568 
569 /*
570  * Curl_resolver_wait_resolv()
571  *
572  * Waits for a resolve to finish. This function should be avoided since using
573  * this risk getting the multi interface to "hang".
574  *
575  * If 'entry' is non-NULL, make it point to the resolved dns entry
576  *
577  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
578  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
579  *
580  * This is the version for resolves-in-a-thread.
581  */
Curl_resolver_wait_resolv(struct Curl_easy * data,struct Curl_dns_entry ** entry)582 CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
583                                    struct Curl_dns_entry **entry)
584 {
585   return thread_wait_resolv(data, entry, TRUE);
586 }
587 
588 /*
589  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
590  * name resolve request has completed. It should also make sure to time-out if
591  * the operation seems to take too long.
592  */
Curl_resolver_is_resolved(struct Curl_easy * data,struct Curl_dns_entry ** entry)593 CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
594                                    struct Curl_dns_entry **entry)
595 {
596   struct thread_data *td = data->state.async.tdata;
597   bool done = FALSE;
598 
599   DEBUGASSERT(entry);
600   *entry = NULL;
601 
602   if(!td) {
603     DEBUGASSERT(td);
604     return CURLE_COULDNT_RESOLVE_HOST;
605   }
606 #ifdef USE_HTTPSRR_ARES
607   if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
608     return CURLE_UNRECOVERABLE_POLL;
609 #endif
610 
611   Curl_mutex_acquire(td->tsd.mtx);
612   done = td->tsd.done;
613   Curl_mutex_release(td->tsd.mtx);
614 
615   if(done) {
616     getaddrinfo_complete(data);
617 
618     if(!data->state.async.dns) {
619       CURLcode result = Curl_resolver_error(data);
620       destroy_async_data(&data->state.async);
621       return result;
622     }
623 #ifdef USE_HTTPSRR_ARES
624     {
625       struct Curl_https_rrinfo *lhrr =
626         Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
627       if(!lhrr) {
628         destroy_async_data(&data->state.async);
629         return CURLE_OUT_OF_MEMORY;
630       }
631       data->state.async.dns->hinfo = lhrr;
632     }
633 #endif
634     destroy_async_data(&data->state.async);
635     *entry = data->state.async.dns;
636   }
637   else {
638     /* poll for name lookup done with exponential backoff up to 250ms */
639     /* should be fine even if this converts to 32-bit */
640     timediff_t elapsed = Curl_timediff(Curl_now(),
641                                        data->progress.t_startsingle);
642     if(elapsed < 0)
643       elapsed = 0;
644 
645     if(td->poll_interval == 0)
646       /* Start at 1ms poll interval */
647       td->poll_interval = 1;
648     else if(elapsed >= td->interval_end)
649       /* Back-off exponentially if last interval expired  */
650       td->poll_interval *= 2;
651 
652     if(td->poll_interval > 250)
653       td->poll_interval = 250;
654 
655     td->interval_end = elapsed + td->poll_interval;
656     Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
657   }
658 
659   return CURLE_OK;
660 }
661 
Curl_resolver_getsock(struct Curl_easy * data,curl_socket_t * socks)662 int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
663 {
664   int ret_val = 0;
665   timediff_t milli;
666   timediff_t ms;
667   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
668   int socketi = 0;
669 #ifndef CURL_DISABLE_SOCKETPAIR
670   struct thread_data *td = data->state.async.tdata;
671 #else
672   (void)socks;
673 #endif
674 
675 #ifdef USE_HTTPSRR_ARES
676   if(data->state.async.tdata) {
677     ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
678     for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
679       if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
680          !ARES_GETSOCK_WRITABLE(ret_val, socketi))
681         break;
682   }
683 #endif
684 #ifndef CURL_DISABLE_SOCKETPAIR
685   if(td) {
686     /* return read fd to client for polling the DNS resolution status */
687     socks[socketi] = td->tsd.sock_pair[0];
688     td->tsd.data = data;
689     ret_val = GETSOCK_READSOCK(socketi);
690   }
691   else {
692 #endif
693     ms = Curl_timediff(Curl_now(), reslv->start);
694     if(ms < 3)
695       milli = 0;
696     else if(ms <= 50)
697       milli = ms/3;
698     else if(ms <= 250)
699       milli = 50;
700     else
701       milli = 200;
702     Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
703 #ifndef CURL_DISABLE_SOCKETPAIR
704   }
705 #endif
706 
707 
708   return ret_val;
709 }
710 
711 #ifndef HAVE_GETADDRINFO
712 /*
713  * Curl_getaddrinfo() - for platforms without getaddrinfo
714  */
Curl_resolver_getaddrinfo(struct Curl_easy * data,const char * hostname,int port,int * waitp)715 struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
716                                                 const char *hostname,
717                                                 int port,
718                                                 int *waitp)
719 {
720   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
721 
722   *waitp = 0; /* default to synchronous response */
723 
724   reslv->start = Curl_now();
725 
726   /* fire up a new resolver thread! */
727   if(init_resolve_thread(data, hostname, port, NULL)) {
728     *waitp = 1; /* expect asynchronous response */
729     return NULL;
730   }
731 
732   failf(data, "getaddrinfo() thread failed");
733 
734   return NULL;
735 }
736 
737 #else /* !HAVE_GETADDRINFO */
738 
739 /*
740  * Curl_resolver_getaddrinfo() - for getaddrinfo
741  */
Curl_resolver_getaddrinfo(struct Curl_easy * data,const char * hostname,int port,int * waitp)742 struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
743                                                 const char *hostname,
744                                                 int port,
745                                                 int *waitp)
746 {
747   struct addrinfo hints;
748   int pf = PF_INET;
749   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
750 
751   *waitp = 0; /* default to synchronous response */
752 
753 #ifdef CURLRES_IPV6
754   if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
755     /* The stack seems to be IPv6-enabled */
756     if(data->conn->ip_version == CURL_IPRESOLVE_V6)
757       pf = PF_INET6;
758     else
759       pf = PF_UNSPEC;
760   }
761 #endif /* CURLRES_IPV6 */
762 
763   memset(&hints, 0, sizeof(hints));
764   hints.ai_family = pf;
765   hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
766     SOCK_STREAM : SOCK_DGRAM;
767 
768   reslv->start = Curl_now();
769   /* fire up a new resolver thread! */
770   if(init_resolve_thread(data, hostname, port, &hints)) {
771     *waitp = 1; /* expect asynchronous response */
772     return NULL;
773   }
774 
775   failf(data, "getaddrinfo() thread failed to start");
776   return NULL;
777 
778 }
779 
780 #endif /* !HAVE_GETADDRINFO */
781 
Curl_set_dns_servers(struct Curl_easy * data,char * servers)782 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
783                               char *servers)
784 {
785   (void)data;
786   (void)servers;
787   return CURLE_NOT_BUILT_IN;
788 
789 }
790 
Curl_set_dns_interface(struct Curl_easy * data,const char * interf)791 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
792                                 const char *interf)
793 {
794   (void)data;
795   (void)interf;
796   return CURLE_NOT_BUILT_IN;
797 }
798 
Curl_set_dns_local_ip4(struct Curl_easy * data,const char * local_ip4)799 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
800                                 const char *local_ip4)
801 {
802   (void)data;
803   (void)local_ip4;
804   return CURLE_NOT_BUILT_IN;
805 }
806 
Curl_set_dns_local_ip6(struct Curl_easy * data,const char * local_ip6)807 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
808                                 const char *local_ip6)
809 {
810   (void)data;
811   (void)local_ip6;
812   return CURLE_NOT_BUILT_IN;
813 }
814 
815 #endif /* CURLRES_THREADED */
816