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