Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/lib/asyn-thrdd.c
2065 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 "sendf.h"
59
#include "hostip.h"
60
#include "hash.h"
61
#include "share.h"
62
#include "url.h"
63
#include "multiif.h"
64
#include "inet_ntop.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
data->state.async.hostname = strdup(hostname);
427
if(!data->state.async.hostname)
428
goto err_exit;
429
430
addr_ctx = addr_ctx_create(hostname, port, hints);
431
if(!addr_ctx)
432
goto err_exit;
433
thrdd->addr = addr_ctx;
434
435
Curl_mutex_acquire(&addr_ctx->mutx);
436
DEBUGASSERT(addr_ctx->ref_count == 1);
437
/* passing addr_ctx to the thread adds a reference */
438
addr_ctx->start = curlx_now();
439
++addr_ctx->ref_count;
440
#ifdef HAVE_GETADDRINFO
441
addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx);
442
#else
443
addr_ctx->thread_hnd = Curl_thread_create(gethostbyname_thread, addr_ctx);
444
#endif
445
if(addr_ctx->thread_hnd == curl_thread_t_null) {
446
/* The thread never started, remove its reference that never happened. */
447
--addr_ctx->ref_count;
448
err = errno;
449
Curl_mutex_release(&addr_ctx->mutx);
450
goto err_exit;
451
}
452
Curl_mutex_release(&addr_ctx->mutx);
453
454
#ifdef USE_HTTPSRR_ARES
455
if(async_rr_start(data))
456
infof(data, "Failed HTTPS RR operation");
457
#endif
458
CURL_TRC_DNS(data, "resolve thread started for of %s:%d", hostname, port);
459
return TRUE;
460
461
err_exit:
462
CURL_TRC_DNS(data, "resolve thread failed init: %d", err);
463
async_thrdd_destroy(data);
464
CURL_SETERRNO(err);
465
return FALSE;
466
}
467
468
/*
469
* 'entry' may be NULL and then no data is returned
470
*/
471
static CURLcode asyn_thrdd_await(struct Curl_easy *data,
472
struct async_thrdd_addr_ctx *addr_ctx,
473
struct Curl_dns_entry **entry)
474
{
475
CURLcode result = CURLE_OK;
476
477
DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null);
478
479
CURL_TRC_DNS(data, "resolve, wait for thread to finish");
480
/* wait for the thread to resolve the name */
481
if(Curl_thread_join(&addr_ctx->thread_hnd)) {
482
if(entry)
483
result = Curl_async_is_resolved(data, entry);
484
}
485
else
486
DEBUGASSERT(0);
487
488
data->state.async.done = TRUE;
489
if(entry)
490
*entry = data->state.async.dns;
491
492
async_thrdd_destroy(data);
493
return result;
494
}
495
496
497
/*
498
* Until we gain a way to signal the resolver threads to stop early, we must
499
* simply wait for them and ignore their results.
500
*/
501
void Curl_async_thrdd_shutdown(struct Curl_easy *data)
502
{
503
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
504
505
/* If we are still resolving, we must wait for the threads to fully clean up,
506
unfortunately. Otherwise, we can simply cancel to clean up any resolver
507
data. */
508
if(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null) &&
509
!data->set.quick_exit)
510
(void)asyn_thrdd_await(data, thrdd->addr, NULL);
511
else
512
async_thrdd_destroy(data);
513
}
514
515
void Curl_async_thrdd_destroy(struct Curl_easy *data)
516
{
517
Curl_async_thrdd_shutdown(data);
518
}
519
520
/*
521
* Curl_async_await()
522
*
523
* Waits for a resolve to finish. This function should be avoided since using
524
* this risk getting the multi interface to "hang".
525
*
526
* If 'entry' is non-NULL, make it point to the resolved dns entry
527
*
528
* Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
529
* CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
530
*
531
* This is the version for resolves-in-a-thread.
532
*/
533
CURLcode Curl_async_await(struct Curl_easy *data,
534
struct Curl_dns_entry **entry)
535
{
536
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
537
if(thrdd->addr)
538
return asyn_thrdd_await(data, thrdd->addr, entry);
539
return CURLE_FAILED_INIT;
540
}
541
542
/*
543
* Curl_async_is_resolved() is called repeatedly to check if a previous
544
* name resolve request has completed. It should also make sure to time-out if
545
* the operation seems to take too long.
546
*/
547
CURLcode Curl_async_is_resolved(struct Curl_easy *data,
548
struct Curl_dns_entry **dns)
549
{
550
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
551
bool done = FALSE;
552
553
DEBUGASSERT(dns);
554
*dns = NULL;
555
556
if(data->state.async.done) {
557
*dns = data->state.async.dns;
558
CURL_TRC_DNS(data, "threaded: is_resolved(), already done, dns=%sfound",
559
*dns ? "" : "not ");
560
return CURLE_OK;
561
}
562
563
#ifdef USE_HTTPSRR_ARES
564
/* best effort, ignore errors */
565
if(thrdd->rr.channel)
566
(void)Curl_ares_perform(thrdd->rr.channel, 0);
567
#endif
568
569
DEBUGASSERT(thrdd->addr);
570
if(!thrdd->addr)
571
return CURLE_FAILED_INIT;
572
573
Curl_mutex_acquire(&thrdd->addr->mutx);
574
done = (thrdd->addr->ref_count == 1);
575
Curl_mutex_release(&thrdd->addr->mutx);
576
577
if(done) {
578
CURLcode result = CURLE_OK;
579
580
data->state.async.done = TRUE;
581
Curl_resolv_unlink(data, &data->state.async.dns);
582
583
if(thrdd->addr->res) {
584
data->state.async.dns =
585
Curl_dnscache_mk_entry(data, thrdd->addr->res,
586
data->state.async.hostname, 0,
587
data->state.async.port, FALSE);
588
thrdd->addr->res = NULL;
589
if(!data->state.async.dns)
590
result = CURLE_OUT_OF_MEMORY;
591
592
#ifdef USE_HTTPSRR_ARES
593
if(thrdd->rr.channel) {
594
result = thrdd->rr.result;
595
if(!result) {
596
struct Curl_https_rrinfo *lhrr;
597
lhrr = Curl_httpsrr_dup_move(&thrdd->rr.hinfo);
598
if(!lhrr)
599
result = CURLE_OUT_OF_MEMORY;
600
else
601
data->state.async.dns->hinfo = lhrr;
602
}
603
}
604
#endif
605
if(!result && data->state.async.dns)
606
result = Curl_dnscache_add(data, data->state.async.dns);
607
}
608
609
if(!result && !data->state.async.dns)
610
result = Curl_resolver_error(data);
611
if(result)
612
Curl_resolv_unlink(data, &data->state.async.dns);
613
*dns = data->state.async.dns;
614
CURL_TRC_DNS(data, "is_resolved() result=%d, dns=%sfound",
615
result, *dns ? "" : "not ");
616
async_thrdd_destroy(data);
617
return result;
618
}
619
else {
620
/* poll for name lookup done with exponential backoff up to 250ms */
621
/* should be fine even if this converts to 32-bit */
622
timediff_t elapsed = curlx_timediff(curlx_now(),
623
data->progress.t_startsingle);
624
if(elapsed < 0)
625
elapsed = 0;
626
627
if(thrdd->addr->poll_interval == 0)
628
/* Start at 1ms poll interval */
629
thrdd->addr->poll_interval = 1;
630
else if(elapsed >= thrdd->addr->interval_end)
631
/* Back-off exponentially if last interval expired */
632
thrdd->addr->poll_interval *= 2;
633
634
if(thrdd->addr->poll_interval > 250)
635
thrdd->addr->poll_interval = 250;
636
637
thrdd->addr->interval_end = elapsed + thrdd->addr->poll_interval;
638
Curl_expire(data, thrdd->addr->poll_interval, EXPIRE_ASYNC_NAME);
639
return CURLE_OK;
640
}
641
}
642
643
int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
644
{
645
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
646
int ret_val = 0;
647
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
648
int socketi = 0;
649
#else
650
(void)socks;
651
#endif
652
653
#ifdef USE_HTTPSRR_ARES
654
if(thrdd->rr.channel) {
655
ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks);
656
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
657
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
658
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
659
break;
660
}
661
#endif
662
if(!thrdd->addr)
663
return ret_val;
664
665
#ifndef CURL_DISABLE_SOCKETPAIR
666
if(thrdd->addr) {
667
/* return read fd to client for polling the DNS resolution status */
668
socks[socketi] = thrdd->addr->sock_pair[0];
669
ret_val |= GETSOCK_READSOCK(socketi);
670
}
671
else
672
#endif
673
{
674
timediff_t milli;
675
timediff_t ms = curlx_timediff(curlx_now(), thrdd->addr->start);
676
if(ms < 3)
677
milli = 0;
678
else if(ms <= 50)
679
milli = ms/3;
680
else if(ms <= 250)
681
milli = 50;
682
else
683
milli = 200;
684
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
685
}
686
687
return ret_val;
688
}
689
690
#ifndef HAVE_GETADDRINFO
691
/*
692
* Curl_async_getaddrinfo() - for platforms without getaddrinfo
693
*/
694
struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
695
const char *hostname,
696
int port,
697
int ip_version,
698
int *waitp)
699
{
700
(void)ip_version;
701
*waitp = 0; /* default to synchronous response */
702
703
/* fire up a new resolver thread! */
704
if(async_thrdd_init(data, hostname, port, ip_version, NULL)) {
705
*waitp = 1; /* expect asynchronous response */
706
return NULL;
707
}
708
709
failf(data, "getaddrinfo() thread failed");
710
711
return NULL;
712
}
713
714
#else /* !HAVE_GETADDRINFO */
715
716
/*
717
* Curl_async_getaddrinfo() - for getaddrinfo
718
*/
719
struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
720
const char *hostname,
721
int port,
722
int ip_version,
723
int *waitp)
724
{
725
struct addrinfo hints;
726
int pf = PF_INET;
727
*waitp = 0; /* default to synchronous response */
728
729
CURL_TRC_DNS(data, "init threaded resolve of %s:%d", hostname, port);
730
#ifdef CURLRES_IPV6
731
if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
732
/* The stack seems to be IPv6-enabled */
733
if(ip_version == CURL_IPRESOLVE_V6)
734
pf = PF_INET6;
735
else
736
pf = PF_UNSPEC;
737
}
738
#else
739
(void)ip_version;
740
#endif /* CURLRES_IPV6 */
741
742
memset(&hints, 0, sizeof(hints));
743
hints.ai_family = pf;
744
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
745
SOCK_STREAM : SOCK_DGRAM;
746
747
/* fire up a new resolver thread! */
748
if(async_thrdd_init(data, hostname, port, ip_version, &hints)) {
749
*waitp = 1; /* expect asynchronous response */
750
return NULL;
751
}
752
753
failf(data, "getaddrinfo() thread failed to start");
754
return NULL;
755
756
}
757
758
#endif /* !HAVE_GETADDRINFO */
759
760
#endif /* CURLRES_THREADED */
761
762