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