comparison mupdf-source/thirdparty/curl/lib/asyn-thread.c @ 2:b50eed0cc0ef upstream

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