ENH: typo
[cmake.git] / Utilities / cmcurl / hostthre.c
blob8e22ee1f0ea2a14b7e2b819d64a3c336cfa65c9f
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: hostthre.c,v 1.2 2007-03-15 19:22:13 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 #include <string.h>
27 #include <errno.h>
29 #ifdef NEED_MALLOC_H
30 #include <malloc.h>
31 #endif
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
46 #endif
47 #ifdef HAVE_STDLIB_H
48 #include <stdlib.h> /* required for free() prototypes */
49 #endif
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h> /* for the close() proto */
52 #endif
53 #ifdef VMS
54 #include <in.h>
55 #include <inet.h>
56 #include <stdlib.h>
57 #endif
59 #ifdef HAVE_SETJMP_H
60 #include <setjmp.h>
61 #endif
63 #ifdef HAVE_PROCESS_H
64 #include <process.h>
65 #endif
67 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
68 #undef in_addr_t
69 #define in_addr_t unsigned long
70 #endif
72 #include "urldata.h"
73 #include "sendf.h"
74 #include "hostip.h"
75 #include "hash.h"
76 #include "share.h"
77 #include "strerror.h"
78 #include "url.h"
79 #include "multiif.h"
81 #define _MPRINTF_REPLACE /* use our functions only */
82 #include <curl/mprintf.h>
84 #include "inet_ntop.h"
86 #include "memory.h"
87 /* The last #include file should be: */
88 #include "memdebug.h"
90 #if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
91 #pragma message ("No _beginthreadex() available in this RTL")
92 #endif
94 /***********************************************************************
95 * Only for Windows threaded name resolves builds
96 **********************************************************************/
97 #ifdef CURLRES_THREADED
99 /* This function is used to init a threaded resolve */
100 static bool init_resolve_thread(struct connectdata *conn,
101 const char *hostname, int port,
102 const Curl_addrinfo *hints);
104 #ifdef CURLRES_IPV4
105 #define THREAD_FUNC gethostbyname_thread
106 #define THREAD_NAME "gethostbyname_thread"
107 #else
108 #define THREAD_FUNC getaddrinfo_thread
109 #define THREAD_NAME "getaddrinfo_thread"
110 #endif
112 #if defined(DEBUG_THREADING_GETHOSTBYNAME) || \
113 defined(DEBUG_THREADING_GETADDRINFO)
114 /* If this is defined, provide tracing */
115 #define TRACE(args) \
116 do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
118 static void trace_it (const char *fmt, ...)
120 static int do_trace = -1;
121 va_list args;
123 if (do_trace == -1) {
124 const char *env = getenv("CURL_TRACE");
125 do_trace = (env && atoi(env) > 0);
127 if (!do_trace)
128 return;
129 va_start (args, fmt);
130 vfprintf (stderr, fmt, args);
131 fflush (stderr);
132 va_end (args);
134 #else
135 #define TRACE(x)
136 #endif
138 #ifdef DEBUG_THREADING_GETADDRINFO
139 static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
141 TRACE(("dump_addrinfo:\n"));
142 for ( ; ai; ai = ai->ai_next) {
143 char buf [INET6_ADDRSTRLEN];
145 trace_it(" fam %2d, CNAME %s, ",
146 ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
147 if (Curl_printable_address(ai, buf, sizeof(buf)))
148 trace_it("%s\n", buf);
149 else
150 trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
153 #endif
155 struct thread_data {
156 HANDLE thread_hnd;
157 unsigned thread_id;
158 DWORD thread_status;
159 curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
160 HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
161 HANDLE event_resolved; /* marks that the thread obtained the information */
162 HANDLE event_thread_started; /* marks that the thread has initialized and
163 started */
164 HANDLE mutex_terminate; /* serializes access to flag_terminate */
165 HANDLE event_terminate; /* flag for thread to terminate instead of calling
166 callbacks */
167 #ifdef CURLRES_IPV6
168 struct addrinfo hints;
169 #endif
172 /* Data for synchronization between resolver thread and its parent */
173 struct thread_sync_data {
174 HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */
175 HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
176 HANDLE event_terminate; /* thread_data.event_terminate duplicate */
177 char * hostname; /* hostname to resolve, Curl_async.hostname
178 duplicate */
181 /* Destroy resolver thread synchronization data */
182 static
183 void destroy_thread_sync_data(struct thread_sync_data * tsd)
185 if (tsd->hostname) {
186 free(tsd->hostname);
187 tsd->hostname = NULL;
189 if (tsd->event_terminate) {
190 CloseHandle(tsd->event_terminate);
191 tsd->event_terminate = NULL;
193 if (tsd->mutex_terminate) {
194 CloseHandle(tsd->mutex_terminate);
195 tsd->mutex_terminate = NULL;
197 if (tsd->mutex_waiting) {
198 CloseHandle(tsd->mutex_waiting);
199 tsd->mutex_waiting = NULL;
203 /* Initialize resolver thread synchronization data */
204 static
205 BOOL init_thread_sync_data(struct thread_data * td,
206 char * hostname,
207 struct thread_sync_data * tsd)
209 HANDLE curr_proc = GetCurrentProcess();
211 memset(tsd, 0, sizeof(*tsd));
212 if (!DuplicateHandle(curr_proc, td->mutex_waiting,
213 curr_proc, &tsd->mutex_waiting, 0, FALSE,
214 DUPLICATE_SAME_ACCESS)) {
215 /* failed to duplicate the mutex, no point in continuing */
216 destroy_thread_sync_data(tsd);
217 return FALSE;
219 if (!DuplicateHandle(curr_proc, td->mutex_terminate,
220 curr_proc, &tsd->mutex_terminate, 0, FALSE,
221 DUPLICATE_SAME_ACCESS)) {
222 /* failed to duplicate the mutex, no point in continuing */
223 destroy_thread_sync_data(tsd);
224 return FALSE;
226 if (!DuplicateHandle(curr_proc, td->event_terminate,
227 curr_proc, &tsd->event_terminate, 0, FALSE,
228 DUPLICATE_SAME_ACCESS)) {
229 /* failed to duplicate the event, no point in continuing */
230 destroy_thread_sync_data(tsd);
231 return FALSE;
233 /* Copying hostname string because original can be destroyed by parent
234 * thread during gethostbyname execution.
236 tsd->hostname = strdup(hostname);
237 if (!tsd->hostname) {
238 /* Memory allocation failed */
239 destroy_thread_sync_data(tsd);
240 return FALSE;
242 return TRUE;
245 /* acquire resolver thread synchronization */
246 static
247 BOOL acquire_thread_sync(struct thread_sync_data * tsd)
249 /* is the thread initiator still waiting for us ? */
250 if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
251 /* yes, it is */
253 /* Waiting access to event_terminate */
254 if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
255 /* Something went wrong - now just ignoring */
257 else {
258 if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
259 /* Parent thread signaled us to terminate.
260 * This means that all data in conn->async is now destroyed
261 * and we cannot use it.
264 else {
265 return TRUE;
269 return FALSE;
272 /* release resolver thread synchronization */
273 static
274 void release_thread_sync(struct thread_sync_data * tsd)
276 ReleaseMutex(tsd->mutex_terminate);
279 #if defined(CURLRES_IPV4)
281 * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
282 * and then exits.
284 * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
285 * it.
287 static unsigned __stdcall gethostbyname_thread (void *arg)
289 struct connectdata *conn = (struct connectdata*) arg;
290 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
291 struct hostent *he;
292 int rc = 0;
294 /* Duplicate the passed mutex and event handles.
295 * This allows us to use it even after the container gets destroyed
296 * due to a resolver timeout.
298 struct thread_sync_data tsd = { 0,0,0,NULL };
299 if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
300 /* thread synchronization data initialization failed */
301 return (unsigned)-1;
304 WSASetLastError (conn->async.status = NO_DATA); /* pending status */
306 /* Signaling that we have initialized all copies of data and handles we
307 need */
308 SetEvent(td->event_thread_started);
310 he = gethostbyname (tsd.hostname);
312 /* is parent thread waiting for us and are we able to access conn members? */
313 if (acquire_thread_sync(&tsd)) {
314 /* Mark that we have obtained the information, and that we are calling
315 * back with it. */
316 SetEvent(td->event_resolved);
317 if (he) {
318 rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
320 else {
321 rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
323 TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
324 he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
325 release_thread_sync(&tsd);
328 /* clean up */
329 destroy_thread_sync_data(&tsd);
331 return (rc);
332 /* An implicit _endthreadex() here */
335 #elif defined(CURLRES_IPV6)
338 * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
339 * exits.
341 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
342 * and wait on it.
344 static unsigned __stdcall getaddrinfo_thread (void *arg)
346 struct connectdata *conn = (struct connectdata*) arg;
347 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
348 struct addrinfo *res;
349 char service [NI_MAXSERV];
350 int rc;
351 struct addrinfo hints = td->hints;
353 /* Duplicate the passed mutex handle.
354 * This allows us to use it even after the container gets destroyed
355 * due to a resolver timeout.
357 struct thread_sync_data tsd = { 0,0,0,NULL };
358 if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
359 /* thread synchronization data initialization failed */
360 return -1;
363 itoa(conn->async.port, service, 10);
365 WSASetLastError(conn->async.status = NO_DATA); /* pending status */
367 /* Signaling that we have initialized all copies of data and handles we
368 need */
369 SetEvent(td->event_thread_started);
371 rc = getaddrinfo(tsd.hostname, service, &hints, &res);
373 /* is parent thread waiting for us and are we able to access conn members? */
374 if (acquire_thread_sync(&tsd)) {
375 /* Mark that we have obtained the information, and that we are calling
376 back with it. */
377 SetEvent(td->event_resolved);
379 if (rc == 0) {
380 #ifdef DEBUG_THREADING_GETADDRINFO
381 dump_addrinfo (conn, res);
382 #endif
383 rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
385 else {
386 rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
387 TRACE(("Winsock-error %d, no address\n", conn->async.status));
389 release_thread_sync(&tsd);
392 /* clean up */
393 destroy_thread_sync_data(&tsd);
395 return (rc);
396 /* An implicit _endthreadex() here */
398 #endif
401 * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
402 * Complementary of ares_destroy.
404 void Curl_destroy_thread_data (struct Curl_async *async)
406 if (async->hostname)
407 free(async->hostname);
409 if (async->os_specific) {
410 struct thread_data *td = (struct thread_data*) async->os_specific;
411 curl_socket_t sock = td->dummy_sock;
413 if (td->mutex_terminate && td->event_terminate) {
414 /* Signaling resolver thread to terminate */
415 if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
416 SetEvent(td->event_terminate);
417 ReleaseMutex(td->mutex_terminate);
419 else {
420 /* Something went wrong - just ignoring it */
424 if (td->mutex_terminate)
425 CloseHandle(td->mutex_terminate);
426 if (td->event_terminate)
427 CloseHandle(td->event_terminate);
428 if (td->event_thread_started)
429 CloseHandle(td->event_thread_started);
431 if (sock != CURL_SOCKET_BAD)
432 sclose(sock);
434 /* destroy the synchronization objects */
435 if (td->mutex_waiting)
436 CloseHandle(td->mutex_waiting);
437 td->mutex_waiting = NULL;
438 if (td->event_resolved)
439 CloseHandle(td->event_resolved);
441 if (td->thread_hnd)
442 CloseHandle(td->thread_hnd);
444 free(async->os_specific);
446 async->hostname = NULL;
447 async->os_specific = NULL;
451 * init_resolve_thread() starts a new thread that performs the actual
452 * resolve. This function returns before the resolve is done.
454 * Returns FALSE in case of failure, otherwise TRUE.
456 static bool init_resolve_thread (struct connectdata *conn,
457 const char *hostname, int port,
458 const Curl_addrinfo *hints)
460 struct thread_data *td = calloc(sizeof(*td), 1);
461 HANDLE thread_and_event[2] = {0};
463 if (!td) {
464 SetLastError(ENOMEM);
465 return FALSE;
468 Curl_safefree(conn->async.hostname);
469 conn->async.hostname = strdup(hostname);
470 if (!conn->async.hostname) {
471 free(td);
472 SetLastError(ENOMEM);
473 return FALSE;
476 conn->async.port = port;
477 conn->async.done = FALSE;
478 conn->async.status = 0;
479 conn->async.dns = NULL;
480 conn->async.os_specific = (void*) td;
481 td->dummy_sock = CURL_SOCKET_BAD;
483 /* Create the mutex used to inform the resolver thread that we're
484 * still waiting, and take initial ownership.
486 td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
487 if (td->mutex_waiting == NULL) {
488 Curl_destroy_thread_data(&conn->async);
489 SetLastError(EAGAIN);
490 return FALSE;
493 /* Create the event that the thread uses to inform us that it's
494 * done resolving. Do not signal it.
496 td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
497 if (td->event_resolved == NULL) {
498 Curl_destroy_thread_data(&conn->async);
499 SetLastError(EAGAIN);
500 return FALSE;
502 /* Create the mutex used to serialize access to event_terminated
503 * between us and resolver thread.
505 td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
506 if (td->mutex_terminate == NULL) {
507 Curl_destroy_thread_data(&conn->async);
508 SetLastError(EAGAIN);
509 return FALSE;
511 /* Create the event used to signal thread that it should terminate.
513 td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
514 if (td->event_terminate == NULL) {
515 Curl_destroy_thread_data(&conn->async);
516 SetLastError(EAGAIN);
517 return FALSE;
519 /* Create the event used by thread to inform it has initialized its own data.
521 td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
522 if (td->event_thread_started == NULL) {
523 Curl_destroy_thread_data(&conn->async);
524 SetLastError(EAGAIN);
525 return FALSE;
528 #ifdef _WIN32_WCE
529 td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
530 (LPTHREAD_START_ROUTINE) THREAD_FUNC,
531 conn, 0, &td->thread_id);
532 #else
533 td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
534 conn, 0, &td->thread_id);
535 #endif
537 #ifdef CURLRES_IPV6
538 curlassert(hints);
539 td->hints = *hints;
540 #else
541 (void) hints;
542 #endif
544 if (!td->thread_hnd) {
545 #ifdef _WIN32_WCE
546 TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn,GetLastError())));
547 #else
548 SetLastError(errno);
549 TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
550 #endif
551 Curl_destroy_thread_data(&conn->async);
552 return FALSE;
554 /* Waiting until the thread will initialize its data or it will exit due errors.
556 thread_and_event[0] = td->thread_hnd;
557 thread_and_event[1] = td->event_thread_started;
558 if (WaitForMultipleObjects(sizeof(thread_and_event) /
559 sizeof(thread_and_event[0]),
560 (const HANDLE*)thread_and_event, FALSE,
561 INFINITE) == WAIT_FAILED) {
562 /* The resolver thread has been created,
563 * most probably it works now - ignoring this "minor" error
566 /* This socket is only to keep Curl_resolv_fdset() and select() happy;
567 * should never become signalled for read/write since it's unbound but
568 * Windows needs atleast 1 socket in select().
570 td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
571 return TRUE;
576 * Curl_wait_for_resolv() waits for a resolve to finish. This function should
577 * be avoided since using this risk getting the multi interface to "hang".
579 * If 'entry' is non-NULL, make it point to the resolved dns entry
581 * This is the version for resolves-in-a-thread.
583 CURLcode Curl_wait_for_resolv(struct connectdata *conn,
584 struct Curl_dns_entry **entry)
586 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
587 struct SessionHandle *data = conn->data;
588 long timeout;
589 DWORD status, ticks;
590 CURLcode rc;
592 curlassert (conn && td);
594 /* now, see if there's a connect timeout or a regular timeout to
595 use instead of the default one */
596 timeout =
597 conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
598 conn->data->set.timeout ? conn->data->set.timeout :
599 CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
600 ticks = GetTickCount();
602 /* wait for the thread to resolve the name */
603 status = WaitForSingleObject(td->event_resolved, 1000UL*timeout);
605 /* mark that we are now done waiting */
606 ReleaseMutex(td->mutex_waiting);
608 /* close our handle to the mutex, no point in hanging on to it */
609 CloseHandle(td->mutex_waiting);
610 td->mutex_waiting = NULL;
612 /* close the event handle, it's useless now */
613 CloseHandle(td->event_resolved);
614 td->event_resolved = NULL;
616 /* has the resolver thread succeeded in resolving our query ? */
617 if (status == WAIT_OBJECT_0) {
618 /* wait for the thread to exit, it's in the callback sequence */
619 if (WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
620 TerminateThread(td->thread_hnd, 0);
621 conn->async.done = TRUE;
622 td->thread_status = (DWORD)-1;
623 TRACE(("%s() thread stuck?!, ", THREAD_NAME));
625 else {
626 /* Thread finished before timeout; propagate Winsock error to this
627 * thread. 'conn->async.done = TRUE' is set in
628 * Curl_addrinfo4/6_callback().
630 WSASetLastError(conn->async.status);
631 GetExitCodeThread(td->thread_hnd, &td->thread_status);
632 TRACE(("%s() status %lu, thread retval %lu, ",
633 THREAD_NAME, status, td->thread_status));
636 else {
637 conn->async.done = TRUE;
638 td->thread_status = (DWORD)-1;
639 TRACE(("%s() timeout, ", THREAD_NAME));
642 TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
644 if(entry)
645 *entry = conn->async.dns;
647 rc = CURLE_OK;
649 if (!conn->async.dns) {
650 /* a name was not resolved */
651 if (td->thread_status == CURLE_OUT_OF_MEMORY) {
652 rc = CURLE_OUT_OF_MEMORY;
653 failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
655 else if(conn->async.done) {
656 if(conn->bits.httpproxy) {
657 failf(data, "Could not resolve proxy: %s; %s",
658 conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
659 rc = CURLE_COULDNT_RESOLVE_PROXY;
661 else {
662 failf(data, "Could not resolve host: %s; %s",
663 conn->host.name, Curl_strerror(conn, conn->async.status));
664 rc = CURLE_COULDNT_RESOLVE_HOST;
667 else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
668 failf(data, "Resolving host timed out: %s", conn->host.name);
669 rc = CURLE_OPERATION_TIMEDOUT;
671 else
672 rc = CURLE_OPERATION_TIMEDOUT;
675 Curl_destroy_thread_data(&conn->async);
677 if(!conn->async.dns)
678 conn->bits.close = TRUE;
680 return (rc);
684 * Curl_is_resolved() is called repeatedly to check if a previous name resolve
685 * request has completed. It should also make sure to time-out if the
686 * operation seems to take too long.
688 CURLcode Curl_is_resolved(struct connectdata *conn,
689 struct Curl_dns_entry **entry)
691 *entry = NULL;
693 if (conn->async.done) {
694 /* we're done */
695 Curl_destroy_thread_data(&conn->async);
696 if (!conn->async.dns) {
697 TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
698 return CURLE_COULDNT_RESOLVE_HOST;
700 *entry = conn->async.dns;
701 TRACE(("resolved okay, dns %p\n", *entry));
703 return CURLE_OK;
706 int Curl_resolv_getsock(struct connectdata *conn,
707 curl_socket_t *socks,
708 int numsocks)
710 const struct thread_data *td =
711 (const struct thread_data *) conn->async.os_specific;
713 if (td && td->dummy_sock != CURL_SOCKET_BAD) {
714 if(numsocks) {
715 /* return one socket waiting for writable, even though this is just
716 a dummy */
717 socks[0] = td->dummy_sock;
718 return GETSOCK_WRITESOCK(0);
721 return 0;
724 #ifdef CURLRES_IPV4
726 * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
728 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
729 const char *hostname,
730 int port,
731 int *waitp)
733 struct hostent *h = NULL;
734 struct SessionHandle *data = conn->data;
735 in_addr_t in;
737 *waitp = 0; /* don't wait, we act synchronously */
739 in = inet_addr(hostname);
740 if (in != CURL_INADDR_NONE)
741 /* This is a dotted IP address 123.123.123.123-style */
742 return Curl_ip2addr(in, hostname, port);
744 /* fire up a new resolver thread! */
745 if (init_resolve_thread(conn, hostname, port, NULL)) {
746 *waitp = TRUE; /* please wait for the response */
747 return NULL;
750 /* fall-back to blocking version */
751 infof(data, "init_resolve_thread() failed for %s; %s\n",
752 hostname, Curl_strerror(conn,GetLastError()));
754 h = gethostbyname(hostname);
755 if (!h) {
756 infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
757 hostname, port, Curl_strerror(conn,WSAGetLastError()));
758 return NULL;
760 return Curl_he2ai(h, port);
762 #endif /* CURLRES_IPV4 */
764 #ifdef CURLRES_IPV6
766 * Curl_getaddrinfo() - for Windows threading IPv6 enabled
768 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
769 const char *hostname,
770 int port,
771 int *waitp)
773 struct addrinfo hints, *res;
774 int error;
775 char sbuf[NI_MAXSERV];
776 curl_socket_t s;
777 int pf;
778 struct SessionHandle *data = conn->data;
780 *waitp = FALSE; /* default to synch response */
782 /* see if we have an IPv6 stack */
783 s = socket(PF_INET6, SOCK_DGRAM, 0);
784 if (s == CURL_SOCKET_BAD) {
785 /* Some non-IPv6 stacks have been found to make very slow name resolves
786 * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
787 * the stack seems to be a non-ipv6 one. */
789 pf = PF_INET;
791 else {
792 /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
793 * possible checks. And close the socket again.
795 sclose(s);
798 * Check if a more limited name resolve has been requested.
800 switch(data->set.ip_version) {
801 case CURL_IPRESOLVE_V4:
802 pf = PF_INET;
803 break;
804 case CURL_IPRESOLVE_V6:
805 pf = PF_INET6;
806 break;
807 default:
808 pf = PF_UNSPEC;
809 break;
813 memset(&hints, 0, sizeof(hints));
814 hints.ai_family = pf;
815 hints.ai_socktype = conn->socktype;
816 #if 0 /* removed nov 8 2005 before 7.15.1 */
817 hints.ai_flags = AI_CANONNAME;
818 #endif
819 itoa(port, sbuf, 10);
821 /* fire up a new resolver thread! */
822 if (init_resolve_thread(conn, hostname, port, &hints)) {
823 *waitp = TRUE; /* please wait for the response */
824 return NULL;
827 /* fall-back to blocking version */
828 infof(data, "init_resolve_thread() failed for %s; %s\n",
829 hostname, Curl_strerror(conn,GetLastError()));
831 error = getaddrinfo(hostname, sbuf, &hints, &res);
832 if (error) {
833 infof(data, "getaddrinfo() failed for %s:%d; %s\n",
834 hostname, port, Curl_strerror(conn,WSAGetLastError()));
835 return NULL;
837 return res;
839 #endif /* CURLRES_IPV6 */
840 #endif /* CURLRES_THREADED */