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