VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/asyn-thread.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

  • 屬性 svn:eol-style 設為 native
檔案大小: 25.0 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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.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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26#include "socketpair.h"
27
28/***********************************************************************
29 * Only for threaded name resolves builds
30 **********************************************************************/
31#ifdef CURLRES_THREADED
32
33#ifdef HAVE_NETINET_IN_H
34#include <netinet/in.h>
35#endif
36#ifdef HAVE_NETDB_H
37#include <netdb.h>
38#endif
39#ifdef HAVE_ARPA_INET_H
40#include <arpa/inet.h>
41#endif
42#ifdef __VMS
43#include <in.h>
44#include <inet.h>
45#endif
46
47#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
48# include <pthread.h>
49#endif
50
51#ifdef HAVE_GETADDRINFO
52# define RESOLVER_ENOMEM EAI_MEMORY
53#else
54# define RESOLVER_ENOMEM ENOMEM
55#endif
56
57#include "system_win32.h"
58#include "urldata.h"
59#include "sendf.h"
60#include "hostip.h"
61#include "hash.h"
62#include "share.h"
63#include "url.h"
64#include "multiif.h"
65#include "inet_ntop.h"
66#include "curl_threads.h"
67#include "connect.h"
68/* The last 3 #include files should be in this order */
69#include "curl_printf.h"
70#include "curl_memory.h"
71#include "memdebug.h"
72
73struct resdata {
74 struct curltime start;
75};
76
77/*
78 * Curl_resolver_global_init()
79 * Called from curl_global_init() to initialize global resolver environment.
80 * Does nothing here.
81 */
82int Curl_resolver_global_init(void)
83{
84 return CURLE_OK;
85}
86
87/*
88 * Curl_resolver_global_cleanup()
89 * Called from curl_global_cleanup() to destroy global resolver environment.
90 * Does nothing here.
91 */
92void Curl_resolver_global_cleanup(void)
93{
94}
95
96/*
97 * Curl_resolver_init()
98 * Called from curl_easy_init() -> Curl_open() to initialize resolver
99 * URL-state specific environment ('resolver' member of the UrlState
100 * structure).
101 */
102CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
103{
104 (void)easy;
105 *resolver = calloc(1, sizeof(struct resdata));
106 if(!*resolver)
107 return CURLE_OUT_OF_MEMORY;
108 return CURLE_OK;
109}
110
111/*
112 * Curl_resolver_cleanup()
113 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
114 * URL-state specific environment ('resolver' member of the UrlState
115 * structure).
116 */
117void Curl_resolver_cleanup(void *resolver)
118{
119 free(resolver);
120}
121
122/*
123 * Curl_resolver_duphandle()
124 * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
125 * environment ('resolver' member of the UrlState structure).
126 */
127CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
128{
129 (void)from;
130 return Curl_resolver_init(easy, to);
131}
132
133static void destroy_async_data(struct Curl_async *);
134
135/*
136 * Cancel all possibly still on-going resolves for this connection.
137 */
138void Curl_resolver_cancel(struct Curl_easy *data)
139{
140 destroy_async_data(&data->state.async);
141}
142
143/* This function is used to init a threaded resolve */
144static bool init_resolve_thread(struct Curl_easy *data,
145 const char *hostname, int port,
146 const struct addrinfo *hints);
147
148#ifdef _WIN32
149/* Thread sync data used by GetAddrInfoExW for win8+ */
150struct thread_sync_data_w8
151{
152 OVERLAPPED overlapped;
153 ADDRINFOEXW_ *res;
154 HANDLE cancel_ev;
155 ADDRINFOEXW_ hints;
156};
157#endif
158
159/* Data for synchronization between resolver thread and its parent */
160struct thread_sync_data {
161#ifdef _WIN32
162 struct thread_sync_data_w8 w8;
163#endif
164 curl_mutex_t *mtx;
165 int done;
166 int port;
167 char *hostname; /* hostname to resolve, Curl_async.hostname
168 duplicate */
169#ifndef CURL_DISABLE_SOCKETPAIR
170 struct Curl_easy *data;
171 curl_socket_t sock_pair[2]; /* socket pair */
172#endif
173 int sock_error;
174 struct Curl_addrinfo *res;
175#ifdef HAVE_GETADDRINFO
176 struct addrinfo hints;
177#endif
178 struct thread_data *td; /* for thread-self cleanup */
179};
180
181struct thread_data {
182#ifdef _WIN32
183 HANDLE complete_ev;
184#endif
185 curl_thread_t thread_hnd;
186 unsigned int poll_interval;
187 timediff_t interval_end;
188 struct thread_sync_data tsd;
189};
190
191static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
192{
193 return &(data->state.async.tdata->tsd);
194}
195
196/* Destroy resolver thread synchronization data */
197static
198void destroy_thread_sync_data(struct thread_sync_data *tsd)
199{
200 if(tsd->mtx) {
201 Curl_mutex_destroy(tsd->mtx);
202 free(tsd->mtx);
203 }
204
205 free(tsd->hostname);
206
207 if(tsd->res)
208 Curl_freeaddrinfo(tsd->res);
209
210#ifndef CURL_DISABLE_SOCKETPAIR
211 /*
212 * close one end of the socket pair (may be done in resolver thread);
213 * the other end (for reading) is always closed in the parent thread.
214 */
215 if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
216 wakeup_close(tsd->sock_pair[1]);
217 }
218#endif
219 memset(tsd, 0, sizeof(*tsd));
220}
221
222/* Initialize resolver thread synchronization data */
223static
224int init_thread_sync_data(struct thread_data *td,
225 const char *hostname,
226 int port,
227 const struct addrinfo *hints)
228{
229 struct thread_sync_data *tsd = &td->tsd;
230
231 memset(tsd, 0, sizeof(*tsd));
232
233 tsd->td = td;
234 tsd->port = port;
235 /* Treat the request as done until the thread actually starts so any early
236 * cleanup gets done properly.
237 */
238 tsd->done = 1;
239#ifdef HAVE_GETADDRINFO
240 DEBUGASSERT(hints);
241 tsd->hints = *hints;
242#else
243 (void) hints;
244#endif
245
246 tsd->mtx = malloc(sizeof(curl_mutex_t));
247 if(!tsd->mtx)
248 goto err_exit;
249
250 Curl_mutex_init(tsd->mtx);
251
252#ifndef CURL_DISABLE_SOCKETPAIR
253 /* create socket pair or pipe */
254 if(wakeup_create(&tsd->sock_pair[0]) < 0) {
255 tsd->sock_pair[0] = CURL_SOCKET_BAD;
256 tsd->sock_pair[1] = CURL_SOCKET_BAD;
257 goto err_exit;
258 }
259#endif
260 tsd->sock_error = CURL_ASYNC_SUCCESS;
261
262 /* Copying hostname string because original can be destroyed by parent
263 * thread during gethostbyname execution.
264 */
265 tsd->hostname = strdup(hostname);
266 if(!tsd->hostname)
267 goto err_exit;
268
269 return 1;
270
271err_exit:
272#ifndef CURL_DISABLE_SOCKETPAIR
273 if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
274 wakeup_close(tsd->sock_pair[0]);
275 tsd->sock_pair[0] = CURL_SOCKET_BAD;
276 }
277#endif
278 destroy_thread_sync_data(tsd);
279 return 0;
280}
281
282static CURLcode getaddrinfo_complete(struct Curl_easy *data)
283{
284 struct thread_sync_data *tsd = conn_thread_sync_data(data);
285 CURLcode result;
286
287 result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
288 /* The tsd->res structure has been copied to async.dns and perhaps the DNS
289 cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
290 */
291 tsd->res = NULL;
292
293 return result;
294}
295
296#ifdef _WIN32
297static VOID WINAPI
298query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
299{
300 size_t ss_size;
301 const ADDRINFOEXW_ *ai;
302 struct Curl_addrinfo *ca;
303 struct Curl_addrinfo *cafirst = NULL;
304 struct Curl_addrinfo *calast = NULL;
305#ifdef __clang__
306#pragma clang diagnostic push
307#pragma clang diagnostic ignored "-Wcast-align"
308#endif
309 struct thread_sync_data *tsd =
310 CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
311#ifdef __clang__
312#pragma clang diagnostic pop
313#endif
314 struct thread_data *td = tsd->td;
315 const ADDRINFOEXW_ *res = tsd->w8.res;
316 int error = (int)err;
317 (void)bytes;
318
319 if(error == ERROR_SUCCESS) {
320 /* traverse the addrinfo list */
321
322 for(ai = res; ai != NULL; ai = ai->ai_next) {
323 size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
324 /* ignore elements with unsupported address family, */
325 /* settle family-specific sockaddr structure size. */
326 if(ai->ai_family == AF_INET)
327 ss_size = sizeof(struct sockaddr_in);
328#ifdef ENABLE_IPV6
329 else if(ai->ai_family == AF_INET6)
330 ss_size = sizeof(struct sockaddr_in6);
331#endif
332 else
333 continue;
334
335 /* ignore elements without required address info */
336 if(!ai->ai_addr || !(ai->ai_addrlen > 0))
337 continue;
338
339 /* ignore elements with bogus address size */
340 if((size_t)ai->ai_addrlen < ss_size)
341 continue;
342
343 ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
344 if(!ca) {
345 error = EAI_MEMORY;
346 break;
347 }
348
349 /* copy each structure member individually, member ordering, */
350 /* size, or padding might be different for each platform. */
351 ca->ai_flags = ai->ai_flags;
352 ca->ai_family = ai->ai_family;
353 ca->ai_socktype = ai->ai_socktype;
354 ca->ai_protocol = ai->ai_protocol;
355 ca->ai_addrlen = (curl_socklen_t)ss_size;
356 ca->ai_addr = NULL;
357 ca->ai_canonname = NULL;
358 ca->ai_next = NULL;
359
360 ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
361 memcpy(ca->ai_addr, ai->ai_addr, ss_size);
362
363 if(namelen) {
364 size_t i;
365 ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
366 for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
367 ca->ai_canonname[i] = (char)ai->ai_canonname[i];
368 ca->ai_canonname[namelen] = '\0';
369 }
370
371 /* if the return list is empty, this becomes the first element */
372 if(!cafirst)
373 cafirst = ca;
374
375 /* add this element last in the return list */
376 if(calast)
377 calast->ai_next = ca;
378 calast = ca;
379 }
380
381 /* if we failed, also destroy the Curl_addrinfo list */
382 if(error) {
383 Curl_freeaddrinfo(cafirst);
384 cafirst = NULL;
385 }
386 else if(!cafirst) {
387#ifdef EAI_NONAME
388 /* rfc3493 conformant */
389 error = EAI_NONAME;
390#else
391 /* rfc3493 obsoleted */
392 error = EAI_NODATA;
393#endif
394#ifdef USE_WINSOCK
395 SET_SOCKERRNO(error);
396#endif
397 }
398 tsd->res = cafirst;
399 }
400
401 if(tsd->w8.res) {
402 Curl_FreeAddrInfoExW(tsd->w8.res);
403 tsd->w8.res = NULL;
404 }
405
406 if(error) {
407 tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
408 if(tsd->sock_error == 0)
409 tsd->sock_error = RESOLVER_ENOMEM;
410 }
411 else {
412 Curl_addrinfo_set_port(tsd->res, tsd->port);
413 }
414
415 Curl_mutex_acquire(tsd->mtx);
416 if(tsd->done) {
417 /* too late, gotta clean up the mess */
418 Curl_mutex_release(tsd->mtx);
419 destroy_thread_sync_data(tsd);
420 free(td);
421 }
422 else {
423#ifndef CURL_DISABLE_SOCKETPAIR
424 char buf[1];
425 if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
426 /* DNS has been resolved, signal client task */
427 buf[0] = 1;
428 if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
429 /* update sock_erro to errno */
430 tsd->sock_error = SOCKERRNO;
431 }
432 }
433#endif
434 tsd->done = 1;
435 Curl_mutex_release(tsd->mtx);
436 if(td->complete_ev)
437 SetEvent(td->complete_ev); /* Notify caller that the query completed */
438 }
439}
440#endif
441
442#ifdef HAVE_GETADDRINFO
443
444/*
445 * getaddrinfo_thread() resolves a name and then exits.
446 *
447 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
448 * and wait on it.
449 */
450static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
451{
452 struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
453 struct thread_data *td = tsd->td;
454 char service[12];
455 int rc;
456#ifndef CURL_DISABLE_SOCKETPAIR
457 char buf[1];
458#endif
459
460 msnprintf(service, sizeof(service), "%d", tsd->port);
461
462 rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
463
464 if(rc) {
465 tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
466 if(tsd->sock_error == 0)
467 tsd->sock_error = RESOLVER_ENOMEM;
468 }
469 else {
470 Curl_addrinfo_set_port(tsd->res, tsd->port);
471 }
472
473 Curl_mutex_acquire(tsd->mtx);
474 if(tsd->done) {
475 /* too late, gotta clean up the mess */
476 Curl_mutex_release(tsd->mtx);
477 destroy_thread_sync_data(tsd);
478 free(td);
479 }
480 else {
481#ifndef CURL_DISABLE_SOCKETPAIR
482 if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
483 /* DNS has been resolved, signal client task */
484 buf[0] = 1;
485 if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
486 /* update sock_erro to errno */
487 tsd->sock_error = SOCKERRNO;
488 }
489 }
490#endif
491 tsd->done = 1;
492 Curl_mutex_release(tsd->mtx);
493 }
494
495 return 0;
496}
497
498#else /* HAVE_GETADDRINFO */
499
500/*
501 * gethostbyname_thread() resolves a name and then exits.
502 */
503static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
504{
505 struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
506 struct thread_data *td = tsd->td;
507
508 tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
509
510 if(!tsd->res) {
511 tsd->sock_error = SOCKERRNO;
512 if(tsd->sock_error == 0)
513 tsd->sock_error = RESOLVER_ENOMEM;
514 }
515
516 Curl_mutex_acquire(tsd->mtx);
517 if(tsd->done) {
518 /* too late, gotta clean up the mess */
519 Curl_mutex_release(tsd->mtx);
520 destroy_thread_sync_data(tsd);
521 free(td);
522 }
523 else {
524 tsd->done = 1;
525 Curl_mutex_release(tsd->mtx);
526 }
527
528 return 0;
529}
530
531#endif /* HAVE_GETADDRINFO */
532
533/*
534 * destroy_async_data() cleans up async resolver data and thread handle.
535 */
536static void destroy_async_data(struct Curl_async *async)
537{
538 if(async->tdata) {
539 struct thread_data *td = async->tdata;
540 int done;
541#ifndef CURL_DISABLE_SOCKETPAIR
542 curl_socket_t sock_rd = td->tsd.sock_pair[0];
543 struct Curl_easy *data = td->tsd.data;
544#endif
545
546 /*
547 * if the thread is still blocking in the resolve syscall, detach it and
548 * let the thread do the cleanup...
549 */
550 Curl_mutex_acquire(td->tsd.mtx);
551 done = td->tsd.done;
552 td->tsd.done = 1;
553 Curl_mutex_release(td->tsd.mtx);
554
555 if(!done) {
556#ifdef _WIN32
557 if(td->complete_ev)
558 CloseHandle(td->complete_ev);
559 else
560#endif
561 Curl_thread_destroy(td->thread_hnd);
562 }
563 else {
564#ifdef _WIN32
565 if(td->complete_ev) {
566 Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
567 WaitForSingleObject(td->complete_ev, INFINITE);
568 CloseHandle(td->complete_ev);
569 }
570#endif
571 if(td->thread_hnd != curl_thread_t_null)
572 Curl_thread_join(&td->thread_hnd);
573
574 destroy_thread_sync_data(&td->tsd);
575
576 free(async->tdata);
577 }
578#ifndef CURL_DISABLE_SOCKETPAIR
579 /*
580 * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
581 * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
582 */
583 Curl_multi_closed(data, sock_rd);
584 wakeup_close(sock_rd);
585#endif
586 }
587 async->tdata = NULL;
588
589 free(async->hostname);
590 async->hostname = NULL;
591}
592
593/*
594 * init_resolve_thread() starts a new thread that performs the actual
595 * resolve. This function returns before the resolve is done.
596 *
597 * Returns FALSE in case of failure, otherwise TRUE.
598 */
599static bool init_resolve_thread(struct Curl_easy *data,
600 const char *hostname, int port,
601 const struct addrinfo *hints)
602{
603 struct thread_data *td = calloc(1, sizeof(struct thread_data));
604 int err = ENOMEM;
605 struct Curl_async *asp = &data->state.async;
606
607 data->state.async.tdata = td;
608 if(!td)
609 goto errno_exit;
610
611 asp->port = port;
612 asp->done = FALSE;
613 asp->status = 0;
614 asp->dns = NULL;
615 td->thread_hnd = curl_thread_t_null;
616#ifdef _WIN32
617 td->complete_ev = NULL;
618#endif
619
620 if(!init_thread_sync_data(td, hostname, port, hints)) {
621 asp->tdata = NULL;
622 free(td);
623 goto errno_exit;
624 }
625
626 free(asp->hostname);
627 asp->hostname = strdup(hostname);
628 if(!asp->hostname)
629 goto err_exit;
630
631 /* The thread will set this to 1 when complete. */
632 td->tsd.done = 0;
633
634#ifdef _WIN32
635 if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
636 Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {
637#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
638#define MAX_PORT_LEN 8
639 WCHAR namebuf[MAX_NAME_LEN];
640 WCHAR portbuf[MAX_PORT_LEN];
641 /* calculate required length */
642 int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
643 -1, NULL, 0);
644 if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
645 /* do utf8 conversion */
646 w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
647 if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
648 swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
649 td->tsd.w8.hints.ai_family = hints->ai_family;
650 td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
651 td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
652 if(!td->complete_ev) {
653 /* failed to start, mark it as done here for proper cleanup. */
654 td->tsd.done = 1;
655 goto err_exit;
656 }
657 err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
658 NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
659 NULL, &td->tsd.w8.overlapped,
660 &query_complete, &td->tsd.w8.cancel_ev);
661 if(err != WSA_IO_PENDING)
662 query_complete(err, 0, &td->tsd.w8.overlapped);
663 return TRUE;
664 }
665 }
666 }
667#endif
668
669#ifdef HAVE_GETADDRINFO
670 td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
671#else
672 td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
673#endif
674
675 if(!td->thread_hnd) {
676 /* The thread never started, so mark it as done here for proper cleanup. */
677 td->tsd.done = 1;
678 err = errno;
679 goto err_exit;
680 }
681
682 return TRUE;
683
684err_exit:
685 destroy_async_data(asp);
686
687errno_exit:
688 errno = err;
689 return FALSE;
690}
691
692/*
693 * 'entry' may be NULL and then no data is returned
694 */
695static CURLcode thread_wait_resolv(struct Curl_easy *data,
696 struct Curl_dns_entry **entry,
697 bool report)
698{
699 struct thread_data *td;
700 CURLcode result = CURLE_OK;
701
702 DEBUGASSERT(data);
703 td = data->state.async.tdata;
704 DEBUGASSERT(td);
705#ifdef _WIN32
706 DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
707#else
708 DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
709#endif
710
711 /* wait for the thread to resolve the name */
712#ifdef _WIN32
713 if(td->complete_ev) {
714 WaitForSingleObject(td->complete_ev, INFINITE);
715 CloseHandle(td->complete_ev);
716 if(entry)
717 result = getaddrinfo_complete(data);
718 }
719 else
720#endif
721 if(Curl_thread_join(&td->thread_hnd)) {
722 if(entry)
723 result = getaddrinfo_complete(data);
724 }
725 else
726 DEBUGASSERT(0);
727
728 data->state.async.done = TRUE;
729
730 if(entry)
731 *entry = data->state.async.dns;
732
733 if(!data->state.async.dns && report)
734 /* a name was not resolved, report error */
735 result = Curl_resolver_error(data);
736
737 destroy_async_data(&data->state.async);
738
739 if(!data->state.async.dns && report)
740 connclose(data->conn, "asynch resolve failed");
741
742 return result;
743}
744
745
746/*
747 * Until we gain a way to signal the resolver threads to stop early, we must
748 * simply wait for them and ignore their results.
749 */
750void Curl_resolver_kill(struct Curl_easy *data)
751{
752 struct thread_data *td = data->state.async.tdata;
753
754 /* If we're still resolving, we must wait for the threads to fully clean up,
755 unfortunately. Otherwise, we can simply cancel to clean up any resolver
756 data. */
757 if(td && td->thread_hnd != curl_thread_t_null
758 && (data->set.quick_exit != 1L))
759 (void)thread_wait_resolv(data, NULL, FALSE);
760 else
761 Curl_resolver_cancel(data);
762}
763
764/*
765 * Curl_resolver_wait_resolv()
766 *
767 * Waits for a resolve to finish. This function should be avoided since using
768 * this risk getting the multi interface to "hang".
769 *
770 * If 'entry' is non-NULL, make it point to the resolved dns entry
771 *
772 * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
773 * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
774 *
775 * This is the version for resolves-in-a-thread.
776 */
777CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
778 struct Curl_dns_entry **entry)
779{
780 return thread_wait_resolv(data, entry, TRUE);
781}
782
783/*
784 * Curl_resolver_is_resolved() is called repeatedly to check if a previous
785 * name resolve request has completed. It should also make sure to time-out if
786 * the operation seems to take too long.
787 */
788CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
789 struct Curl_dns_entry **entry)
790{
791 struct thread_data *td = data->state.async.tdata;
792 int done = 0;
793
794 DEBUGASSERT(entry);
795 *entry = NULL;
796
797 if(!td) {
798 DEBUGASSERT(td);
799 return CURLE_COULDNT_RESOLVE_HOST;
800 }
801
802 Curl_mutex_acquire(td->tsd.mtx);
803 done = td->tsd.done;
804 Curl_mutex_release(td->tsd.mtx);
805
806 if(done) {
807 getaddrinfo_complete(data);
808
809 if(!data->state.async.dns) {
810 CURLcode result = Curl_resolver_error(data);
811 destroy_async_data(&data->state.async);
812 return result;
813 }
814 destroy_async_data(&data->state.async);
815 *entry = data->state.async.dns;
816 }
817 else {
818 /* poll for name lookup done with exponential backoff up to 250ms */
819 /* should be fine even if this converts to 32 bit */
820 timediff_t elapsed = Curl_timediff(Curl_now(),
821 data->progress.t_startsingle);
822 if(elapsed < 0)
823 elapsed = 0;
824
825 if(td->poll_interval == 0)
826 /* Start at 1ms poll interval */
827 td->poll_interval = 1;
828 else if(elapsed >= td->interval_end)
829 /* Back-off exponentially if last interval expired */
830 td->poll_interval *= 2;
831
832 if(td->poll_interval > 250)
833 td->poll_interval = 250;
834
835 td->interval_end = elapsed + td->poll_interval;
836 Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
837 }
838
839 return CURLE_OK;
840}
841
842int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
843{
844 int ret_val = 0;
845 timediff_t milli;
846 timediff_t ms;
847 struct resdata *reslv = (struct resdata *)data->state.async.resolver;
848#ifndef CURL_DISABLE_SOCKETPAIR
849 struct thread_data *td = data->state.async.tdata;
850#else
851 (void)socks;
852#endif
853
854#ifndef CURL_DISABLE_SOCKETPAIR
855 if(td) {
856 /* return read fd to client for polling the DNS resolution status */
857 socks[0] = td->tsd.sock_pair[0];
858 td->tsd.data = data;
859 ret_val = GETSOCK_READSOCK(0);
860 }
861 else {
862#endif
863 ms = Curl_timediff(Curl_now(), reslv->start);
864 if(ms < 3)
865 milli = 0;
866 else if(ms <= 50)
867 milli = ms/3;
868 else if(ms <= 250)
869 milli = 50;
870 else
871 milli = 200;
872 Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
873#ifndef CURL_DISABLE_SOCKETPAIR
874 }
875#endif
876
877
878 return ret_val;
879}
880
881#ifndef HAVE_GETADDRINFO
882/*
883 * Curl_getaddrinfo() - for platforms without getaddrinfo
884 */
885struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
886 const char *hostname,
887 int port,
888 int *waitp)
889{
890 struct resdata *reslv = (struct resdata *)data->state.async.resolver;
891
892 *waitp = 0; /* default to synchronous response */
893
894 reslv->start = Curl_now();
895
896 /* fire up a new resolver thread! */
897 if(init_resolve_thread(data, hostname, port, NULL)) {
898 *waitp = 1; /* expect asynchronous response */
899 return NULL;
900 }
901
902 failf(data, "getaddrinfo() thread failed");
903
904 return NULL;
905}
906
907#else /* !HAVE_GETADDRINFO */
908
909/*
910 * Curl_resolver_getaddrinfo() - for getaddrinfo
911 */
912struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
913 const char *hostname,
914 int port,
915 int *waitp)
916{
917 struct addrinfo hints;
918 int pf = PF_INET;
919 struct resdata *reslv = (struct resdata *)data->state.async.resolver;
920
921 *waitp = 0; /* default to synchronous response */
922
923#ifdef CURLRES_IPV6
924 if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
925 /* The stack seems to be IPv6-enabled */
926 if(data->conn->ip_version == CURL_IPRESOLVE_V6)
927 pf = PF_INET6;
928 else
929 pf = PF_UNSPEC;
930 }
931#endif /* CURLRES_IPV6 */
932
933 memset(&hints, 0, sizeof(hints));
934 hints.ai_family = pf;
935 hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
936 SOCK_STREAM : SOCK_DGRAM;
937
938 reslv->start = Curl_now();
939 /* fire up a new resolver thread! */
940 if(init_resolve_thread(data, hostname, port, &hints)) {
941 *waitp = 1; /* expect asynchronous response */
942 return NULL;
943 }
944
945 failf(data, "getaddrinfo() thread failed to start");
946 return NULL;
947
948}
949
950#endif /* !HAVE_GETADDRINFO */
951
952CURLcode Curl_set_dns_servers(struct Curl_easy *data,
953 char *servers)
954{
955 (void)data;
956 (void)servers;
957 return CURLE_NOT_BUILT_IN;
958
959}
960
961CURLcode Curl_set_dns_interface(struct Curl_easy *data,
962 const char *interf)
963{
964 (void)data;
965 (void)interf;
966 return CURLE_NOT_BUILT_IN;
967}
968
969CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
970 const char *local_ip4)
971{
972 (void)data;
973 (void)local_ip4;
974 return CURLE_NOT_BUILT_IN;
975}
976
977CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
978 const char *local_ip6)
979{
980 (void)data;
981 (void)local_ip6;
982 return CURLE_NOT_BUILT_IN;
983}
984
985#endif /* CURLRES_THREADED */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette