Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmcurl/lib/asyn-thrdd.c
3153 views
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 /* = WSA_NOT_ENOUGH_MEMORY on Windows */
53
#else
54
# define RESOLVER_ENOMEM SOCKENOMEM
55
#endif
56
57
#include "urldata.h"
58
#include "cfilters.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 "curl_threads.h"
66
#include "strdup.h"
67
68
#ifdef USE_ARES
69
#include <ares.h>
70
#ifdef USE_HTTPSRR
71
#define USE_HTTPSRR_ARES /* the combo */
72
#endif
73
#endif
74
75
/* The last 3 #include files should be in this order */
76
#include "curl_printf.h"
77
#include "curl_memory.h"
78
#include "memdebug.h"
79
80
81
/*
82
* Curl_async_global_init()
83
* Called from curl_global_init() to initialize global resolver environment.
84
* Does nothing here.
85
*/
86
int Curl_async_global_init(void)
87
{
88
#if defined(USE_ARES) && defined(CARES_HAVE_ARES_LIBRARY_INIT)
89
if(ares_library_init(ARES_LIB_INIT_ALL)) {
90
return CURLE_FAILED_INIT;
91
}
92
#endif
93
return CURLE_OK;
94
}
95
96
/*
97
* Curl_async_global_cleanup()
98
* Called from curl_global_cleanup() to destroy global resolver environment.
99
* Does nothing here.
100
*/
101
void Curl_async_global_cleanup(void)
102
{
103
#if defined(USE_ARES) && defined(CARES_HAVE_ARES_LIBRARY_INIT)
104
ares_library_cleanup();
105
#endif
106
}
107
108
static void async_thrdd_destroy(struct Curl_easy *);
109
110
CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl)
111
{
112
(void)data;
113
*impl = NULL;
114
return CURLE_OK;
115
}
116
117
/* Destroy context of threaded resolver */
118
static void addr_ctx_destroy(struct async_thrdd_addr_ctx *addr_ctx)
119
{
120
if(addr_ctx) {
121
DEBUGASSERT(!addr_ctx->ref_count);
122
Curl_mutex_destroy(&addr_ctx->mutx);
123
free(addr_ctx->hostname);
124
if(addr_ctx->res)
125
Curl_freeaddrinfo(addr_ctx->res);
126
#ifndef CURL_DISABLE_SOCKETPAIR
127
/*
128
* close one end of the socket pair (may be done in resolver thread);
129
* the other end (for reading) is always closed in the parent thread.
130
*/
131
#ifndef USE_EVENTFD
132
if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
133
wakeup_close(addr_ctx->sock_pair[1]);
134
}
135
#endif
136
#endif
137
free(addr_ctx);
138
}
139
}
140
141
/* Initialize context for threaded resolver */
142
static struct async_thrdd_addr_ctx *
143
addr_ctx_create(const char *hostname, int port,
144
const struct addrinfo *hints)
145
{
146
struct async_thrdd_addr_ctx *addr_ctx = calloc(1, sizeof(*addr_ctx));
147
if(!addr_ctx)
148
return NULL;
149
150
addr_ctx->thread_hnd = curl_thread_t_null;
151
addr_ctx->port = port;
152
#ifndef CURL_DISABLE_SOCKETPAIR
153
addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
154
addr_ctx->sock_pair[1] = CURL_SOCKET_BAD;
155
#endif
156
addr_ctx->ref_count = 0;
157
158
#ifdef HAVE_GETADDRINFO
159
DEBUGASSERT(hints);
160
addr_ctx->hints = *hints;
161
#else
162
(void) hints;
163
#endif
164
165
Curl_mutex_init(&addr_ctx->mutx);
166
167
#ifndef CURL_DISABLE_SOCKETPAIR
168
/* create socket pair or pipe */
169
if(wakeup_create(addr_ctx->sock_pair, FALSE) < 0) {
170
addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
171
addr_ctx->sock_pair[1] = CURL_SOCKET_BAD;
172
goto err_exit;
173
}
174
#endif
175
addr_ctx->sock_error = CURL_ASYNC_SUCCESS;
176
177
/* Copying hostname string because original can be destroyed by parent
178
* thread during gethostbyname execution.
179
*/
180
addr_ctx->hostname = strdup(hostname);
181
if(!addr_ctx->hostname)
182
goto err_exit;
183
184
addr_ctx->ref_count = 1;
185
return addr_ctx;
186
187
err_exit:
188
#ifndef CURL_DISABLE_SOCKETPAIR
189
if(addr_ctx->sock_pair[0] != CURL_SOCKET_BAD) {
190
wakeup_close(addr_ctx->sock_pair[0]);
191
addr_ctx->sock_pair[0] = CURL_SOCKET_BAD;
192
}
193
#endif
194
addr_ctx_destroy(addr_ctx);
195
return NULL;
196
}
197
198
#ifdef HAVE_GETADDRINFO
199
200
/*
201
* getaddrinfo_thread() resolves a name and then exits.
202
*
203
* For builds without ARES, but with USE_IPV6, create a resolver thread
204
* and wait on it.
205
*/
206
static
207
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
208
DWORD
209
#else
210
unsigned int
211
#endif
212
CURL_STDCALL getaddrinfo_thread(void *arg)
213
{
214
struct async_thrdd_addr_ctx *addr_ctx = arg;
215
char service[12];
216
int rc;
217
bool all_gone;
218
219
msnprintf(service, sizeof(service), "%d", addr_ctx->port);
220
221
rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service,
222
&addr_ctx->hints, &addr_ctx->res);
223
224
if(rc) {
225
addr_ctx->sock_error = SOCKERRNO ? SOCKERRNO : rc;
226
if(addr_ctx->sock_error == 0)
227
addr_ctx->sock_error = RESOLVER_ENOMEM;
228
}
229
else {
230
Curl_addrinfo_set_port(addr_ctx->res, addr_ctx->port);
231
}
232
233
Curl_mutex_acquire(&addr_ctx->mutx);
234
if(addr_ctx->ref_count > 1) {
235
/* Someone still waiting on our results. */
236
#ifndef CURL_DISABLE_SOCKETPAIR
237
if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) {
238
#ifdef USE_EVENTFD
239
const uint64_t buf[1] = { 1 };
240
#else
241
const char buf[1] = { 1 };
242
#endif
243
/* DNS has been resolved, signal client task */
244
if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) {
245
/* update sock_erro to errno */
246
addr_ctx->sock_error = SOCKERRNO;
247
}
248
}
249
#endif
250
}
251
/* thread gives up its reference to the shared data now. */
252
--addr_ctx->ref_count;
253
all_gone = !addr_ctx->ref_count;
254
Curl_mutex_release(&addr_ctx->mutx);
255
if(all_gone)
256
addr_ctx_destroy(addr_ctx);
257
258
return 0;
259
}
260
261
#else /* HAVE_GETADDRINFO */
262
263
/*
264
* gethostbyname_thread() resolves a name and then exits.
265
*/
266
static
267
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
268
DWORD
269
#else
270
unsigned int
271
#endif
272
CURL_STDCALL gethostbyname_thread(void *arg)
273
{
274
struct async_thrdd_addr_ctx *addr_ctx = arg;
275
bool all_gone;
276
277
addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port);
278
279
if(!addr_ctx->res) {
280
addr_ctx->sock_error = SOCKERRNO;
281
if(addr_ctx->sock_error == 0)
282
addr_ctx->sock_error = RESOLVER_ENOMEM;
283
}
284
285
Curl_mutex_acquire(&addr_ctx->mutx);
286
/* thread gives up its reference to the shared data now. */
287
--addr_ctx->ref_count;
288
all_gone = !addr_ctx->ref_count;;
289
Curl_mutex_release(&addr_ctx->mutx);
290
if(all_gone)
291
addr_ctx_destroy(addr_ctx);
292
293
return 0;
294
}
295
296
#endif /* HAVE_GETADDRINFO */
297
298
/*
299
* async_thrdd_destroy() cleans up async resolver data and thread handle.
300
*/
301
static void async_thrdd_destroy(struct Curl_easy *data)
302
{
303
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
304
struct async_thrdd_addr_ctx *addr = thrdd->addr;
305
#ifdef USE_HTTPSRR_ARES
306
if(thrdd->rr.channel) {
307
ares_destroy(thrdd->rr.channel);
308
thrdd->rr.channel = NULL;
309
}
310
Curl_httpsrr_cleanup(&thrdd->rr.hinfo);
311
#endif
312
313
if(addr) {
314
#ifndef CURL_DISABLE_SOCKETPAIR
315
curl_socket_t sock_rd = addr->sock_pair[0];
316
#endif
317
bool done;
318
319
/* Release our reference to the data shared with the thread. */
320
Curl_mutex_acquire(&addr->mutx);
321
--addr->ref_count;
322
CURL_TRC_DNS(data, "resolve, destroy async data, shared ref=%d",
323
addr->ref_count);
324
done = !addr->ref_count;
325
/* we give up our reference to `addr`, so NULL our pointer.
326
* coverity analyses this as being a potential unsynched write,
327
* assuming two calls to this function could be invoked concurrently.
328
* Which they never are, as the transfer's side runs single-threaded. */
329
thrdd->addr = NULL;
330
if(!done) {
331
/* thread is still running. Detach the thread while mutexed, it will
332
* trigger the cleanup when it releases its reference. */
333
Curl_thread_destroy(&addr->thread_hnd);
334
}
335
Curl_mutex_release(&addr->mutx);
336
337
if(done) {
338
/* thread has released its reference, join it and
339
* release the memory we shared with it. */
340
if(addr->thread_hnd != curl_thread_t_null)
341
Curl_thread_join(&addr->thread_hnd);
342
addr_ctx_destroy(addr);
343
}
344
#ifndef CURL_DISABLE_SOCKETPAIR
345
/*
346
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
347
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
348
*/
349
Curl_multi_will_close(data, sock_rd);
350
wakeup_close(sock_rd);
351
#endif
352
}
353
}
354
355
#ifdef USE_HTTPSRR_ARES
356
357
static void async_thrdd_rr_done(void *user_data, ares_status_t status,
358
size_t timeouts,
359
const ares_dns_record_t *dnsrec)
360
{
361
struct Curl_easy *data = user_data;
362
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
363
364
(void)timeouts;
365
thrdd->rr.done = TRUE;
366
if((ARES_SUCCESS != status) || !dnsrec)
367
return;
368
thrdd->rr.result = Curl_httpsrr_from_ares(data, dnsrec, &thrdd->rr.hinfo);
369
}
370
371
static CURLcode async_rr_start(struct Curl_easy *data)
372
{
373
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
374
int status;
375
376
DEBUGASSERT(!thrdd->rr.channel);
377
status = ares_init_options(&thrdd->rr.channel, NULL, 0);
378
if(status != ARES_SUCCESS) {
379
thrdd->rr.channel = NULL;
380
return CURLE_FAILED_INIT;
381
}
382
383
memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo));
384
thrdd->rr.hinfo.port = -1;
385
ares_query_dnsrec(thrdd->rr.channel,
386
data->conn->host.name, ARES_CLASS_IN,
387
ARES_REC_TYPE_HTTPS,
388
async_thrdd_rr_done, data, NULL);
389
return CURLE_OK;
390
}
391
#endif
392
393
/*
394
* async_thrdd_init() starts a new thread that performs the actual
395
* resolve. This function returns before the resolve is done.
396
*
397
* Returns FALSE in case of failure, otherwise TRUE.
398
*/
399
static bool async_thrdd_init(struct Curl_easy *data,
400
const char *hostname, int port, int ip_version,
401
const struct addrinfo *hints)
402
{
403
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
404
struct async_thrdd_addr_ctx *addr_ctx;
405
406
/* !checksrc! disable ERRNOVAR 1 */
407
int err = ENOMEM;
408
409
if(thrdd->addr
410
#ifdef USE_HTTPSRR_ARES
411
|| thrdd->rr.channel
412
#endif
413
) {
414
CURL_TRC_DNS(data, "starting new resolve, with previous not cleaned up");
415
async_thrdd_destroy(data);
416
DEBUGASSERT(!thrdd->addr);
417
#ifdef USE_HTTPSRR_ARES
418
DEBUGASSERT(!thrdd->rr.channel);
419
#endif
420
}
421
422
data->state.async.dns = NULL;
423
data->state.async.done = FALSE;
424
data->state.async.port = port;
425
data->state.async.ip_version = ip_version;
426
free(data->state.async.hostname);
427
data->state.async.hostname = strdup(hostname);
428
if(!data->state.async.hostname)
429
goto err_exit;
430
431
addr_ctx = addr_ctx_create(hostname, port, hints);
432
if(!addr_ctx)
433
goto err_exit;
434
thrdd->addr = addr_ctx;
435
436
Curl_mutex_acquire(&addr_ctx->mutx);
437
DEBUGASSERT(addr_ctx->ref_count == 1);
438
/* passing addr_ctx to the thread adds a reference */
439
addr_ctx->start = curlx_now();
440
++addr_ctx->ref_count;
441
#ifdef HAVE_GETADDRINFO
442
addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx);
443
#else
444
addr_ctx->thread_hnd = Curl_thread_create(gethostbyname_thread, addr_ctx);
445
#endif
446
if(addr_ctx->thread_hnd == curl_thread_t_null) {
447
/* The thread never started, remove its reference that never happened. */
448
--addr_ctx->ref_count;
449
err = errno;
450
Curl_mutex_release(&addr_ctx->mutx);
451
goto err_exit;
452
}
453
Curl_mutex_release(&addr_ctx->mutx);
454
455
#ifdef USE_HTTPSRR_ARES
456
if(async_rr_start(data))
457
infof(data, "Failed HTTPS RR operation");
458
#endif
459
CURL_TRC_DNS(data, "resolve thread started for of %s:%d", hostname, port);
460
return TRUE;
461
462
err_exit:
463
CURL_TRC_DNS(data, "resolve thread failed init: %d", err);
464
async_thrdd_destroy(data);
465
CURL_SETERRNO(err);
466
return FALSE;
467
}
468
469
/*
470
* 'entry' may be NULL and then no data is returned
471
*/
472
static CURLcode asyn_thrdd_await(struct Curl_easy *data,
473
struct async_thrdd_addr_ctx *addr_ctx,
474
struct Curl_dns_entry **entry)
475
{
476
CURLcode result = CURLE_OK;
477
478
DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null);
479
480
CURL_TRC_DNS(data, "resolve, wait for thread to finish");
481
/* wait for the thread to resolve the name */
482
if(Curl_thread_join(&addr_ctx->thread_hnd)) {
483
if(entry)
484
result = Curl_async_is_resolved(data, entry);
485
}
486
else
487
DEBUGASSERT(0);
488
489
data->state.async.done = TRUE;
490
if(entry)
491
*entry = data->state.async.dns;
492
493
async_thrdd_destroy(data);
494
return result;
495
}
496
497
498
/*
499
* Until we gain a way to signal the resolver threads to stop early, we must
500
* simply wait for them and ignore their results.
501
*/
502
void Curl_async_thrdd_shutdown(struct Curl_easy *data)
503
{
504
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
505
506
/* If we are still resolving, we must wait for the threads to fully clean up,
507
unfortunately. Otherwise, we can simply cancel to clean up any resolver
508
data. */
509
if(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null) &&
510
!data->set.quick_exit)
511
(void)asyn_thrdd_await(data, thrdd->addr, NULL);
512
else
513
async_thrdd_destroy(data);
514
}
515
516
void Curl_async_thrdd_destroy(struct Curl_easy *data)
517
{
518
Curl_async_thrdd_shutdown(data);
519
}
520
521
/*
522
* Curl_async_await()
523
*
524
* Waits for a resolve to finish. This function should be avoided since using
525
* this risk getting the multi interface to "hang".
526
*
527
* If 'entry' is non-NULL, make it point to the resolved dns entry
528
*
529
* Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
530
* CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
531
*
532
* This is the version for resolves-in-a-thread.
533
*/
534
CURLcode Curl_async_await(struct Curl_easy *data,
535
struct Curl_dns_entry **entry)
536
{
537
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
538
if(thrdd->addr)
539
return asyn_thrdd_await(data, thrdd->addr, entry);
540
return CURLE_FAILED_INIT;
541
}
542
543
/*
544
* Curl_async_is_resolved() is called repeatedly to check if a previous
545
* name resolve request has completed. It should also make sure to time-out if
546
* the operation seems to take too long.
547
*/
548
CURLcode Curl_async_is_resolved(struct Curl_easy *data,
549
struct Curl_dns_entry **dns)
550
{
551
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
552
bool done = FALSE;
553
554
DEBUGASSERT(dns);
555
*dns = NULL;
556
557
if(data->state.async.done) {
558
*dns = data->state.async.dns;
559
CURL_TRC_DNS(data, "threaded: is_resolved(), already done, dns=%sfound",
560
*dns ? "" : "not ");
561
return CURLE_OK;
562
}
563
564
#ifdef USE_HTTPSRR_ARES
565
/* best effort, ignore errors */
566
if(thrdd->rr.channel)
567
(void)Curl_ares_perform(thrdd->rr.channel, 0);
568
#endif
569
570
DEBUGASSERT(thrdd->addr);
571
if(!thrdd->addr)
572
return CURLE_FAILED_INIT;
573
574
Curl_mutex_acquire(&thrdd->addr->mutx);
575
done = (thrdd->addr->ref_count == 1);
576
Curl_mutex_release(&thrdd->addr->mutx);
577
578
if(done) {
579
CURLcode result = CURLE_OK;
580
581
data->state.async.done = TRUE;
582
Curl_resolv_unlink(data, &data->state.async.dns);
583
584
if(thrdd->addr->res) {
585
data->state.async.dns =
586
Curl_dnscache_mk_entry(data, thrdd->addr->res,
587
data->state.async.hostname, 0,
588
data->state.async.port, FALSE);
589
thrdd->addr->res = NULL;
590
if(!data->state.async.dns)
591
result = CURLE_OUT_OF_MEMORY;
592
593
#ifdef USE_HTTPSRR_ARES
594
if(thrdd->rr.channel) {
595
result = thrdd->rr.result;
596
if(!result) {
597
struct Curl_https_rrinfo *lhrr;
598
lhrr = Curl_httpsrr_dup_move(&thrdd->rr.hinfo);
599
if(!lhrr)
600
result = CURLE_OUT_OF_MEMORY;
601
else
602
data->state.async.dns->hinfo = lhrr;
603
}
604
}
605
#endif
606
if(!result && data->state.async.dns)
607
result = Curl_dnscache_add(data, data->state.async.dns);
608
}
609
610
if(!result && !data->state.async.dns)
611
result = Curl_resolver_error(data);
612
if(result)
613
Curl_resolv_unlink(data, &data->state.async.dns);
614
*dns = data->state.async.dns;
615
CURL_TRC_DNS(data, "is_resolved() result=%d, dns=%sfound",
616
result, *dns ? "" : "not ");
617
async_thrdd_destroy(data);
618
return result;
619
}
620
else {
621
/* poll for name lookup done with exponential backoff up to 250ms */
622
/* should be fine even if this converts to 32-bit */
623
timediff_t elapsed = curlx_timediff(curlx_now(),
624
data->progress.t_startsingle);
625
if(elapsed < 0)
626
elapsed = 0;
627
628
if(thrdd->addr->poll_interval == 0)
629
/* Start at 1ms poll interval */
630
thrdd->addr->poll_interval = 1;
631
else if(elapsed >= thrdd->addr->interval_end)
632
/* Back-off exponentially if last interval expired */
633
thrdd->addr->poll_interval *= 2;
634
635
if(thrdd->addr->poll_interval > 250)
636
thrdd->addr->poll_interval = 250;
637
638
thrdd->addr->interval_end = elapsed + thrdd->addr->poll_interval;
639
Curl_expire(data, thrdd->addr->poll_interval, EXPIRE_ASYNC_NAME);
640
return CURLE_OK;
641
}
642
}
643
644
int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
645
{
646
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
647
int ret_val = 0;
648
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
649
int socketi = 0;
650
#else
651
(void)socks;
652
#endif
653
654
#ifdef USE_HTTPSRR_ARES
655
if(thrdd->rr.channel) {
656
ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks);
657
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
658
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
659
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
660
break;
661
}
662
#endif
663
if(!thrdd->addr)
664
return ret_val;
665
666
#ifndef CURL_DISABLE_SOCKETPAIR
667
if(thrdd->addr) {
668
/* return read fd to client for polling the DNS resolution status */
669
socks[socketi] = thrdd->addr->sock_pair[0];
670
ret_val |= GETSOCK_READSOCK(socketi);
671
}
672
else
673
#endif
674
{
675
timediff_t milli;
676
timediff_t ms = curlx_timediff(curlx_now(), thrdd->addr->start);
677
if(ms < 3)
678
milli = 0;
679
else if(ms <= 50)
680
milli = ms/3;
681
else if(ms <= 250)
682
milli = 50;
683
else
684
milli = 200;
685
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
686
}
687
688
return ret_val;
689
}
690
691
#ifndef HAVE_GETADDRINFO
692
/*
693
* Curl_async_getaddrinfo() - for platforms without getaddrinfo
694
*/
695
struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
696
const char *hostname,
697
int port,
698
int ip_version,
699
int *waitp)
700
{
701
(void)ip_version;
702
*waitp = 0; /* default to synchronous response */
703
704
/* fire up a new resolver thread! */
705
if(async_thrdd_init(data, hostname, port, ip_version, NULL)) {
706
*waitp = 1; /* expect asynchronous response */
707
return NULL;
708
}
709
710
failf(data, "getaddrinfo() thread failed");
711
712
return NULL;
713
}
714
715
#else /* !HAVE_GETADDRINFO */
716
717
/*
718
* Curl_async_getaddrinfo() - for getaddrinfo
719
*/
720
struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
721
const char *hostname,
722
int port,
723
int ip_version,
724
int *waitp)
725
{
726
struct addrinfo hints;
727
int pf = PF_INET;
728
*waitp = 0; /* default to synchronous response */
729
730
CURL_TRC_DNS(data, "init threaded resolve of %s:%d", hostname, port);
731
#ifdef CURLRES_IPV6
732
if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
733
/* The stack seems to be IPv6-enabled */
734
if(ip_version == CURL_IPRESOLVE_V6)
735
pf = PF_INET6;
736
else
737
pf = PF_UNSPEC;
738
}
739
#else
740
(void)ip_version;
741
#endif /* CURLRES_IPV6 */
742
743
memset(&hints, 0, sizeof(hints));
744
hints.ai_family = pf;
745
hints.ai_socktype =
746
(Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
747
SOCK_STREAM : SOCK_DGRAM;
748
749
/* fire up a new resolver thread! */
750
if(async_thrdd_init(data, hostname, port, ip_version, &hints)) {
751
*waitp = 1; /* expect asynchronous response */
752
return NULL;
753
}
754
755
failf(data, "getaddrinfo() thread failed to start");
756
return NULL;
757
758
}
759
760
#endif /* !HAVE_GETADDRINFO */
761
762
#endif /* CURLRES_THREADED */
763
764