1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2008, 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 http://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 * $Id: hostthre.c,v 1.57 2008-11-06 17:19:57 yangtse Exp $
22 ***************************************************************************/
23
24 #include "setup.h"
25
26 #include <string.h>
27 #include <errno.h>
28
29 #ifdef NEED_MALLOC_H
30 #include <malloc.h>
31 #endif
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38 #ifdef HAVE_NETDB_H
39 #include <netdb.h>
40 #endif
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif
44 #ifdef HAVE_STDLIB_H
45 #include <stdlib.h> /* required for free() prototypes */
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h> /* for the close() proto */
49 #endif
50 #ifdef VMS
51 #include <in.h>
52 #include <inet.h>
53 #include <stdlib.h>
54 #endif
55
56 #ifdef HAVE_PROCESS_H
57 #include <process.h>
58 #endif
59
60 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
61 #undef in_addr_t
62 #define in_addr_t unsigned long
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
75 #define _MPRINTF_REPLACE /* use our functions only */
76 #include <curl/mprintf.h>
77
78 #include "inet_ntop.h"
79
80 #include "memory.h"
81 /* The last #include file should be: */
82 #include "memdebug.h"
83
84 #if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
85 #pragma message ("No _beginthreadex() available in this RTL")
86 #endif
87
88 /***********************************************************************
89 * Only for Windows threaded name resolves builds
90 **********************************************************************/
91 #ifdef CURLRES_THREADED
92
93 /* This function is used to init a threaded resolve */
94 static bool init_resolve_thread(struct connectdata *conn,
95 const char *hostname, int port,
96 const struct addrinfo *hints);
97
98 #ifdef CURLRES_IPV4
99 #define THREAD_FUNC gethostbyname_thread
100 #define THREAD_NAME "gethostbyname_thread"
101 #else
102 #define THREAD_FUNC getaddrinfo_thread
103 #define THREAD_NAME "getaddrinfo_thread"
104 #endif
105
106 struct thread_data {
107 HANDLE thread_hnd;
108 unsigned thread_id;
109 DWORD thread_status;
110 curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
111 HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
112 HANDLE event_resolved; /* marks that the thread obtained the information */
113 HANDLE event_thread_started; /* marks that the thread has initialized and
114 started */
115 HANDLE mutex_terminate; /* serializes access to flag_terminate */
116 HANDLE event_terminate; /* flag for thread to terminate instead of calling
117 callbacks */
118 #ifdef CURLRES_IPV6
119 struct addrinfo hints;
120 #endif
121 };
122
123 /* Data for synchronization between resolver thread and its parent */
124 struct thread_sync_data {
125 HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */
126 HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
127 HANDLE event_terminate; /* thread_data.event_terminate duplicate */
128 char * hostname; /* hostname to resolve, Curl_async.hostname
129 duplicate */
130 };
131
132 /* Destroy resolver thread synchronization data */
133 static
destroy_thread_sync_data(struct thread_sync_data * tsd)134 void destroy_thread_sync_data(struct thread_sync_data * tsd)
135 {
136 if(tsd->hostname)
137 free(tsd->hostname);
138 if(tsd->event_terminate)
139 CloseHandle(tsd->event_terminate);
140 if(tsd->mutex_terminate)
141 CloseHandle(tsd->mutex_terminate);
142 if(tsd->mutex_waiting)
143 CloseHandle(tsd->mutex_waiting);
144 memset(tsd,0,sizeof(*tsd));
145 }
146
147 /* Initialize resolver thread synchronization data */
148 static
init_thread_sync_data(struct thread_data * td,const char * hostname,struct thread_sync_data * tsd)149 BOOL init_thread_sync_data(struct thread_data * td,
150 const char * hostname,
151 struct thread_sync_data * tsd)
152 {
153 HANDLE curr_proc = GetCurrentProcess();
154
155 memset(tsd, 0, sizeof(*tsd));
156 if(!DuplicateHandle(curr_proc, td->mutex_waiting,
157 curr_proc, &tsd->mutex_waiting, 0, FALSE,
158 DUPLICATE_SAME_ACCESS)) {
159 /* failed to duplicate the mutex, no point in continuing */
160 destroy_thread_sync_data(tsd);
161 return FALSE;
162 }
163 if(!DuplicateHandle(curr_proc, td->mutex_terminate,
164 curr_proc, &tsd->mutex_terminate, 0, FALSE,
165 DUPLICATE_SAME_ACCESS)) {
166 /* failed to duplicate the mutex, no point in continuing */
167 destroy_thread_sync_data(tsd);
168 return FALSE;
169 }
170 if(!DuplicateHandle(curr_proc, td->event_terminate,
171 curr_proc, &tsd->event_terminate, 0, FALSE,
172 DUPLICATE_SAME_ACCESS)) {
173 /* failed to duplicate the event, no point in continuing */
174 destroy_thread_sync_data(tsd);
175 return FALSE;
176 }
177 /* Copying hostname string because original can be destroyed by parent
178 * thread during gethostbyname execution.
179 */
180 tsd->hostname = strdup(hostname);
181 if(!tsd->hostname) {
182 /* Memory allocation failed */
183 destroy_thread_sync_data(tsd);
184 return FALSE;
185 }
186 return TRUE;
187 }
188
189 /* acquire resolver thread synchronization */
190 static
acquire_thread_sync(struct thread_sync_data * tsd)191 BOOL acquire_thread_sync(struct thread_sync_data * tsd)
192 {
193 /* is the thread initiator still waiting for us ? */
194 if(WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
195 /* yes, it is */
196
197 /* Waiting access to event_terminate */
198 if(WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
199 /* Something went wrong - now just ignoring */
200 }
201 else {
202 if(WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
203 /* Parent thread signaled us to terminate.
204 * This means that all data in conn->async is now destroyed
205 * and we cannot use it.
206 */
207 }
208 else {
209 return TRUE;
210 }
211 }
212 }
213 return FALSE;
214 }
215
216 /* release resolver thread synchronization */
217 static
release_thread_sync(struct thread_sync_data * tsd)218 void release_thread_sync(struct thread_sync_data * tsd)
219 {
220 ReleaseMutex(tsd->mutex_terminate);
221 }
222
223 #if defined(CURLRES_IPV4)
224 /*
225 * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
226 * and then exits.
227 *
228 * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
229 * it.
230 */
gethostbyname_thread(void * arg)231 static unsigned __stdcall gethostbyname_thread (void *arg)
232 {
233 struct connectdata *conn = (struct connectdata*) arg;
234 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
235 struct hostent *he;
236 int rc = 0;
237
238 /* Duplicate the passed mutex and event handles.
239 * This allows us to use it even after the container gets destroyed
240 * due to a resolver timeout.
241 */
242 struct thread_sync_data tsd = { 0,0,0,NULL };
243
244 if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
245 /* thread synchronization data initialization failed */
246 return (unsigned)-1;
247 }
248
249 conn->async.status = NO_DATA; /* pending status */
250 SET_SOCKERRNO(conn->async.status);
251
252 /* Signaling that we have initialized all copies of data and handles we
253 need */
254 SetEvent(td->event_thread_started);
255
256 he = gethostbyname (tsd.hostname);
257
258 /* is parent thread waiting for us and are we able to access conn members? */
259 if(acquire_thread_sync(&tsd)) {
260 /* Mark that we have obtained the information, and that we are calling
261 * back with it. */
262 SetEvent(td->event_resolved);
263 if(he) {
264 rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
265 }
266 else {
267 rc = Curl_addrinfo4_callback(conn, SOCKERRNO, NULL);
268 }
269 release_thread_sync(&tsd);
270 }
271
272 /* clean up */
273 destroy_thread_sync_data(&tsd);
274
275 return (rc);
276 /* An implicit _endthreadex() here */
277 }
278
279 #elif defined(CURLRES_IPV6)
280
281 /*
282 * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
283 * exits.
284 *
285 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
286 * and wait on it.
287 */
getaddrinfo_thread(void * arg)288 static unsigned __stdcall getaddrinfo_thread (void *arg)
289 {
290 struct connectdata *conn = (struct connectdata*) arg;
291 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
292 Curl_addrinfo *res;
293 char service [NI_MAXSERV];
294 int rc;
295 struct addrinfo hints = td->hints;
296
297 /* Duplicate the passed mutex handle.
298 * This allows us to use it even after the container gets destroyed
299 * due to a resolver timeout.
300 */
301 struct thread_sync_data tsd = { 0,0,0,NULL };
302
303 if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
304 /* thread synchronization data initialization failed */
305 return -1;
306 }
307
308 itoa(conn->async.port, service, 10);
309
310 conn->async.status = NO_DATA; /* pending status */
311 SET_SOCKERRNO(conn->async.status);
312
313 /* Signaling that we have initialized all copies of data and handles we
314 need */
315 SetEvent(td->event_thread_started);
316
317 rc = Curl_getaddrinfo_ex(tsd.hostname, service, &hints, &res);
318
319 /* is parent thread waiting for us and are we able to access conn members? */
320 if(acquire_thread_sync(&tsd)) {
321 /* Mark that we have obtained the information, and that we are calling
322 back with it. */
323 SetEvent(td->event_resolved);
324
325 if(rc == 0) {
326 rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
327 }
328 else {
329 rc = Curl_addrinfo6_callback(conn, SOCKERRNO, NULL);
330 }
331 release_thread_sync(&tsd);
332 }
333
334 /* clean up */
335 destroy_thread_sync_data(&tsd);
336
337 return (rc);
338 /* An implicit _endthreadex() here */
339 }
340 #endif
341
342 /*
343 * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
344 * Complementary of ares_destroy.
345 */
Curl_destroy_thread_data(struct Curl_async * async)346 void Curl_destroy_thread_data (struct Curl_async *async)
347 {
348 if(async->hostname)
349 free(async->hostname);
350
351 if(async->os_specific) {
352 struct thread_data *td = (struct thread_data*) async->os_specific;
353 curl_socket_t sock = td->dummy_sock;
354
355 if(td->mutex_terminate && td->event_terminate) {
356 /* Signaling resolver thread to terminate */
357 if(WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
358 SetEvent(td->event_terminate);
359 ReleaseMutex(td->mutex_terminate);
360 }
361 else {
362 /* Something went wrong - just ignoring it */
363 }
364 }
365
366 if(td->mutex_terminate)
367 CloseHandle(td->mutex_terminate);
368 if(td->event_terminate)
369 CloseHandle(td->event_terminate);
370 if(td->event_thread_started)
371 CloseHandle(td->event_thread_started);
372
373 if(sock != CURL_SOCKET_BAD)
374 sclose(sock);
375
376 /* destroy the synchronization objects */
377 if(td->mutex_waiting)
378 CloseHandle(td->mutex_waiting);
379 td->mutex_waiting = NULL;
380 if(td->event_resolved)
381 CloseHandle(td->event_resolved);
382
383 if(td->thread_hnd)
384 CloseHandle(td->thread_hnd);
385
386 free(async->os_specific);
387 }
388 async->hostname = NULL;
389 async->os_specific = NULL;
390 }
391
392 /*
393 * init_resolve_thread() starts a new thread that performs the actual
394 * resolve. This function returns before the resolve is done.
395 *
396 * Returns FALSE in case of failure, otherwise TRUE.
397 */
init_resolve_thread(struct connectdata * conn,const char * hostname,int port,const struct addrinfo * hints)398 static bool init_resolve_thread (struct connectdata *conn,
399 const char *hostname, int port,
400 const struct addrinfo *hints)
401 {
402 struct thread_data *td = calloc(sizeof(*td), 1);
403 HANDLE thread_and_event[2] = {0};
404
405 if(!td) {
406 SET_ERRNO(ENOMEM);
407 return FALSE;
408 }
409
410 Curl_safefree(conn->async.hostname);
411 conn->async.hostname = strdup(hostname);
412 if(!conn->async.hostname) {
413 free(td);
414 SET_ERRNO(ENOMEM);
415 return FALSE;
416 }
417
418 conn->async.port = port;
419 conn->async.done = FALSE;
420 conn->async.status = 0;
421 conn->async.dns = NULL;
422 conn->async.os_specific = (void*) td;
423 td->dummy_sock = CURL_SOCKET_BAD;
424
425 /* Create the mutex used to inform the resolver thread that we're
426 * still waiting, and take initial ownership.
427 */
428 td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
429 if(td->mutex_waiting == NULL) {
430 Curl_destroy_thread_data(&conn->async);
431 SET_ERRNO(EAGAIN);
432 return FALSE;
433 }
434
435 /* Create the event that the thread uses to inform us that it's
436 * done resolving. Do not signal it.
437 */
438 td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
439 if(td->event_resolved == NULL) {
440 Curl_destroy_thread_data(&conn->async);
441 SET_ERRNO(EAGAIN);
442 return FALSE;
443 }
444 /* Create the mutex used to serialize access to event_terminated
445 * between us and resolver thread.
446 */
447 td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
448 if(td->mutex_terminate == NULL) {
449 Curl_destroy_thread_data(&conn->async);
450 SET_ERRNO(EAGAIN);
451 return FALSE;
452 }
453 /* Create the event used to signal thread that it should terminate.
454 */
455 td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
456 if(td->event_terminate == NULL) {
457 Curl_destroy_thread_data(&conn->async);
458 SET_ERRNO(EAGAIN);
459 return FALSE;
460 }
461 /* Create the event used by thread to inform it has initialized its own data.
462 */
463 td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
464 if(td->event_thread_started == NULL) {
465 Curl_destroy_thread_data(&conn->async);
466 SET_ERRNO(EAGAIN);
467 return FALSE;
468 }
469
470 #ifdef _WIN32_WCE
471 td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
472 (LPTHREAD_START_ROUTINE) THREAD_FUNC,
473 conn, 0, &td->thread_id);
474 #else
475 td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
476 conn, 0, &td->thread_id);
477 #endif
478
479 #ifdef CURLRES_IPV6
480 DEBUGASSERT(hints);
481 td->hints = *hints;
482 #else
483 (void) hints;
484 #endif
485
486 if(!td->thread_hnd) {
487 #ifndef _WIN32_WCE
488 SET_ERRNO(errno);
489 #endif
490 Curl_destroy_thread_data(&conn->async);
491 return FALSE;
492 }
493 /* Waiting until the thread will initialize its data or it will exit due errors.
494 */
495 thread_and_event[0] = td->thread_hnd;
496 thread_and_event[1] = td->event_thread_started;
497 if(WaitForMultipleObjects(sizeof(thread_and_event) /
498 sizeof(thread_and_event[0]),
499 (const HANDLE*)thread_and_event, FALSE,
500 INFINITE) == WAIT_FAILED) {
501 /* The resolver thread has been created,
502 * most probably it works now - ignoring this "minor" error
503 */
504 }
505 /* This socket is only to keep Curl_resolv_fdset() and select() happy;
506 * should never become signalled for read/write since it's unbound but
507 * Windows needs atleast 1 socket in select().
508 */
509 td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
510 return TRUE;
511 }
512
513
514 /*
515 * Curl_wait_for_resolv() waits for a resolve to finish. This function should
516 * be avoided since using this risk getting the multi interface to "hang".
517 *
518 * If 'entry' is non-NULL, make it point to the resolved dns entry
519 *
520 * This is the version for resolves-in-a-thread.
521 */
Curl_wait_for_resolv(struct connectdata * conn,struct Curl_dns_entry ** entry)522 CURLcode Curl_wait_for_resolv(struct connectdata *conn,
523 struct Curl_dns_entry **entry)
524 {
525 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
526 struct SessionHandle *data = conn->data;
527 long timeout;
528 DWORD status;
529 CURLcode rc;
530
531 DEBUGASSERT(conn && td);
532
533 /* now, see if there's a connect timeout or a regular timeout to
534 use instead of the default one */
535 timeout =
536 conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
537 conn->data->set.timeout ? conn->data->set.timeout :
538 CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
539
540 /* wait for the thread to resolve the name */
541 status = WaitForSingleObject(td->event_resolved, timeout);
542
543 /* mark that we are now done waiting */
544 ReleaseMutex(td->mutex_waiting);
545
546 /* close our handle to the mutex, no point in hanging on to it */
547 CloseHandle(td->mutex_waiting);
548 td->mutex_waiting = NULL;
549
550 /* close the event handle, it's useless now */
551 CloseHandle(td->event_resolved);
552 td->event_resolved = NULL;
553
554 /* has the resolver thread succeeded in resolving our query ? */
555 if(status == WAIT_OBJECT_0) {
556 /* wait for the thread to exit, it's in the callback sequence */
557 if(WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
558 TerminateThread(td->thread_hnd, 0);
559 conn->async.done = TRUE;
560 td->thread_status = (DWORD)-1;
561 }
562 else {
563 /* Thread finished before timeout; propagate Winsock error to this
564 * thread. 'conn->async.done = TRUE' is set in
565 * Curl_addrinfo4/6_callback().
566 */
567 SET_SOCKERRNO(conn->async.status);
568 GetExitCodeThread(td->thread_hnd, &td->thread_status);
569 }
570 }
571 else {
572 conn->async.done = TRUE;
573 td->thread_status = (DWORD)-1;
574 }
575
576 if(entry)
577 *entry = conn->async.dns;
578
579 rc = CURLE_OK;
580
581 if(!conn->async.dns) {
582 /* a name was not resolved */
583 if(td->thread_status == CURLE_OUT_OF_MEMORY) {
584 rc = CURLE_OUT_OF_MEMORY;
585 failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
586 }
587 else if(conn->async.done) {
588 if(conn->bits.httpproxy) {
589 failf(data, "Could not resolve proxy: %s; %s",
590 conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
591 rc = CURLE_COULDNT_RESOLVE_PROXY;
592 }
593 else {
594 failf(data, "Could not resolve host: %s; %s",
595 conn->host.name, Curl_strerror(conn, conn->async.status));
596 rc = CURLE_COULDNT_RESOLVE_HOST;
597 }
598 }
599 else if(td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
600 failf(data, "Resolving host timed out: %s", conn->host.name);
601 rc = CURLE_OPERATION_TIMEDOUT;
602 }
603 else
604 rc = CURLE_OPERATION_TIMEDOUT;
605 }
606
607 Curl_destroy_thread_data(&conn->async);
608
609 if(!conn->async.dns)
610 conn->bits.close = TRUE;
611
612 return (rc);
613 }
614
615 /*
616 * Curl_is_resolved() is called repeatedly to check if a previous name resolve
617 * request has completed. It should also make sure to time-out if the
618 * operation seems to take too long.
619 */
Curl_is_resolved(struct connectdata * conn,struct Curl_dns_entry ** entry)620 CURLcode Curl_is_resolved(struct connectdata *conn,
621 struct Curl_dns_entry **entry)
622 {
623 struct SessionHandle *data = conn->data;
624
625 *entry = NULL;
626
627 if(conn->async.done) {
628 /* we're done */
629 Curl_destroy_thread_data(&conn->async);
630 if(!conn->async.dns) {
631 failf(data, "Could not resolve host: %s; %s",
632 conn->host.name, Curl_strerror(conn, conn->async.status));
633 return CURLE_COULDNT_RESOLVE_HOST;
634 }
635 *entry = conn->async.dns;
636 }
637 return CURLE_OK;
638 }
639
Curl_resolv_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)640 int Curl_resolv_getsock(struct connectdata *conn,
641 curl_socket_t *socks,
642 int numsocks)
643 {
644 const struct thread_data *td =
645 (const struct thread_data *) conn->async.os_specific;
646
647 if(td && td->dummy_sock != CURL_SOCKET_BAD) {
648 if(numsocks) {
649 /* return one socket waiting for writable, even though this is just
650 a dummy */
651 socks[0] = td->dummy_sock;
652 return GETSOCK_WRITESOCK(0);
653 }
654 }
655 return 0;
656 }
657
658 #ifdef CURLRES_IPV4
659 /*
660 * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
661 */
Curl_getaddrinfo(struct connectdata * conn,const char * hostname,int port,int * waitp)662 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
663 const char *hostname,
664 int port,
665 int *waitp)
666 {
667 struct hostent *h = NULL;
668 struct SessionHandle *data = conn->data;
669 struct in_addr in;
670
671 *waitp = 0; /* don't wait, we act synchronously */
672
673 if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
674 /* This is a dotted IP address 123.123.123.123-style */
675 return Curl_ip2addr(AF_INET, &in, hostname, port);
676
677 /* fire up a new resolver thread! */
678 if(init_resolve_thread(conn, hostname, port, NULL)) {
679 *waitp = TRUE; /* please wait for the response */
680 return NULL;
681 }
682
683 /* fall-back to blocking version */
684 infof(data, "init_resolve_thread() failed for %s; %s\n",
685 hostname, Curl_strerror(conn, ERRNO));
686
687 h = gethostbyname(hostname);
688 if(!h) {
689 infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
690 hostname, port, Curl_strerror(conn, SOCKERRNO));
691 return NULL;
692 }
693 return Curl_he2ai(h, port);
694 }
695 #endif /* CURLRES_IPV4 */
696
697 #ifdef CURLRES_IPV6
698 /*
699 * Curl_getaddrinfo() - for Windows threading IPv6 enabled
700 */
Curl_getaddrinfo(struct connectdata * conn,const char * hostname,int port,int * waitp)701 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
702 const char *hostname,
703 int port,
704 int *waitp)
705 {
706 struct addrinfo hints;
707 Curl_addrinfo *res;
708 int error;
709 char sbuf[NI_MAXSERV];
710 int pf;
711 struct SessionHandle *data = conn->data;
712
713 *waitp = FALSE; /* default to synch response */
714
715 /*
716 * Check if a limited name resolve has been requested.
717 */
718 switch(data->set.ip_version) {
719 case CURL_IPRESOLVE_V4:
720 pf = PF_INET;
721 break;
722 case CURL_IPRESOLVE_V6:
723 pf = PF_INET6;
724 break;
725 default:
726 pf = PF_UNSPEC;
727 break;
728 }
729
730 if (pf != PF_INET) {
731 /* see if we have an IPv6 stack */
732 curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
733 if(s == CURL_SOCKET_BAD) {
734 /* Some non-IPv6 stacks have been found to make very slow name resolves
735 * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
736 * the stack seems to be a non-ipv6 one. */
737
738 pf = PF_INET;
739 }
740 else {
741 /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
742 * possible checks. And close the socket again.
743 */
744 sclose(s);
745 }
746 }
747
748 memset(&hints, 0, sizeof(hints));
749 hints.ai_family = pf;
750 hints.ai_socktype = conn->socktype;
751 #if 0 /* removed nov 8 2005 before 7.15.1 */
752 hints.ai_flags = AI_CANONNAME;
753 #endif
754 itoa(port, sbuf, 10);
755
756 /* fire up a new resolver thread! */
757 if(init_resolve_thread(conn, hostname, port, &hints)) {
758 *waitp = TRUE; /* please wait for the response */
759 return NULL;
760 }
761
762 /* fall-back to blocking version */
763 infof(data, "init_resolve_thread() failed for %s; %s\n",
764 hostname, Curl_strerror(conn, ERRNO));
765
766 error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
767 if(error) {
768 infof(data, "getaddrinfo() failed for %s:%d; %s\n",
769 hostname, port, Curl_strerror(conn, SOCKERRNO));
770 return NULL;
771 }
772 return res;
773 }
774 #endif /* CURLRES_IPV6 */
775 #endif /* CURLRES_THREADED */
776