Coverage Report

Created: 2023-06-07 07:02

/src/curl/lib/asyn-thread.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at 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
0
#  define RESOLVER_ENOMEM  EAI_MEMORY
53
#else
54
#  define RESOLVER_ENOMEM  ENOMEM
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 "connect.h"
67
/* The last 3 #include files should be in this order */
68
#include "curl_printf.h"
69
#include "curl_memory.h"
70
#include "memdebug.h"
71
72
struct resdata {
73
  struct curltime start;
74
};
75
76
/*
77
 * Curl_resolver_global_init()
78
 * Called from curl_global_init() to initialize global resolver environment.
79
 * Does nothing here.
80
 */
81
int Curl_resolver_global_init(void)
82
1
{
83
1
  return CURLE_OK;
84
1
}
85
86
/*
87
 * Curl_resolver_global_cleanup()
88
 * Called from curl_global_cleanup() to destroy global resolver environment.
89
 * Does nothing here.
90
 */
91
void Curl_resolver_global_cleanup(void)
92
0
{
93
0
}
94
95
/*
96
 * Curl_resolver_init()
97
 * Called from curl_easy_init() -> Curl_open() to initialize resolver
98
 * URL-state specific environment ('resolver' member of the UrlState
99
 * structure).
100
 */
101
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
102
1.20k
{
103
1.20k
  (void)easy;
104
1.20k
  *resolver = calloc(1, sizeof(struct resdata));
105
1.20k
  if(!*resolver)
106
0
    return CURLE_OUT_OF_MEMORY;
107
1.20k
  return CURLE_OK;
108
1.20k
}
109
110
/*
111
 * Curl_resolver_cleanup()
112
 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
113
 * URL-state specific environment ('resolver' member of the UrlState
114
 * structure).
115
 */
116
void Curl_resolver_cleanup(void *resolver)
117
1.20k
{
118
1.20k
  free(resolver);
119
1.20k
}
120
121
/*
122
 * Curl_resolver_duphandle()
123
 * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
124
 * environment ('resolver' member of the UrlState structure).
125
 */
126
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
127
0
{
128
0
  (void)from;
129
0
  return Curl_resolver_init(easy, to);
130
0
}
131
132
static void destroy_async_data(struct Curl_async *);
133
134
/*
135
 * Cancel all possibly still on-going resolves for this connection.
136
 */
137
void Curl_resolver_cancel(struct Curl_easy *data)
138
1.20k
{
139
1.20k
  destroy_async_data(&data->state.async);
140
1.20k
}
141
142
/* This function is used to init a threaded resolve */
143
static bool init_resolve_thread(struct Curl_easy *data,
144
                                const char *hostname, int port,
145
                                const struct addrinfo *hints);
146
147
148
/* Data for synchronization between resolver thread and its parent */
149
struct thread_sync_data {
150
  curl_mutex_t *mtx;
151
  int done;
152
  int port;
153
  char *hostname;        /* hostname to resolve, Curl_async.hostname
154
                            duplicate */
155
#ifndef CURL_DISABLE_SOCKETPAIR
156
  struct Curl_easy *data;
157
  curl_socket_t sock_pair[2]; /* socket pair */
158
#endif
159
  int sock_error;
160
  struct Curl_addrinfo *res;
161
#ifdef HAVE_GETADDRINFO
162
  struct addrinfo hints;
163
#endif
164
  struct thread_data *td; /* for thread-self cleanup */
165
};
166
167
struct thread_data {
168
  curl_thread_t thread_hnd;
169
  unsigned int poll_interval;
170
  timediff_t interval_end;
171
  struct thread_sync_data tsd;
172
};
173
174
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
175
0
{
176
0
  return &(data->state.async.tdata->tsd);
177
0
}
178
179
/* Destroy resolver thread synchronization data */
180
static
181
void destroy_thread_sync_data(struct thread_sync_data *tsd)
182
0
{
183
0
  if(tsd->mtx) {
184
0
    Curl_mutex_destroy(tsd->mtx);
185
0
    free(tsd->mtx);
186
0
  }
187
188
0
  free(tsd->hostname);
189
190
0
  if(tsd->res)
191
0
    Curl_freeaddrinfo(tsd->res);
192
193
0
#ifndef CURL_DISABLE_SOCKETPAIR
194
  /*
195
   * close one end of the socket pair (may be done in resolver thread);
196
   * the other end (for reading) is always closed in the parent thread.
197
   */
198
0
  if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
199
0
    sclose(tsd->sock_pair[1]);
200
0
  }
201
0
#endif
202
0
  memset(tsd, 0, sizeof(*tsd));
203
0
}
204
205
/* Initialize resolver thread synchronization data */
206
static
207
int init_thread_sync_data(struct thread_data *td,
208
                           const char *hostname,
209
                           int port,
210
                           const struct addrinfo *hints)
211
0
{
212
0
  struct thread_sync_data *tsd = &td->tsd;
213
214
0
  memset(tsd, 0, sizeof(*tsd));
215
216
0
  tsd->td = td;
217
0
  tsd->port = port;
218
  /* Treat the request as done until the thread actually starts so any early
219
   * cleanup gets done properly.
220
   */
221
0
  tsd->done = 1;
222
0
#ifdef HAVE_GETADDRINFO
223
0
  DEBUGASSERT(hints);
224
0
  tsd->hints = *hints;
225
#else
226
  (void) hints;
227
#endif
228
229
0
  tsd->mtx = malloc(sizeof(curl_mutex_t));
230
0
  if(!tsd->mtx)
231
0
    goto err_exit;
232
233
0
  Curl_mutex_init(tsd->mtx);
234
235
0
#ifndef CURL_DISABLE_SOCKETPAIR
236
  /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
237
0
  if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
238
0
    tsd->sock_pair[0] = CURL_SOCKET_BAD;
239
0
    tsd->sock_pair[1] = CURL_SOCKET_BAD;
240
0
    goto err_exit;
241
0
  }
242
0
#endif
243
0
  tsd->sock_error = CURL_ASYNC_SUCCESS;
244
245
  /* Copying hostname string because original can be destroyed by parent
246
   * thread during gethostbyname execution.
247
   */
248
0
  tsd->hostname = strdup(hostname);
249
0
  if(!tsd->hostname)
250
0
    goto err_exit;
251
252
0
  return 1;
253
254
0
err_exit:
255
0
#ifndef CURL_DISABLE_SOCKETPAIR
256
0
  if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
257
0
    sclose(tsd->sock_pair[0]);
258
0
    tsd->sock_pair[0] = CURL_SOCKET_BAD;
259
0
  }
260
0
#endif
261
0
  destroy_thread_sync_data(tsd);
262
0
  return 0;
263
0
}
264
265
static CURLcode getaddrinfo_complete(struct Curl_easy *data)
266
0
{
267
0
  struct thread_sync_data *tsd = conn_thread_sync_data(data);
268
0
  CURLcode result;
269
270
0
  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
271
  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
272
     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
273
  */
274
0
  tsd->res = NULL;
275
276
0
  return result;
277
0
}
278
279
280
#ifdef HAVE_GETADDRINFO
281
282
/*
283
 * getaddrinfo_thread() resolves a name and then exits.
284
 *
285
 * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
286
 * and wait on it.
287
 */
288
static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
289
0
{
290
0
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
291
0
  struct thread_data *td = tsd->td;
292
0
  char service[12];
293
0
  int rc;
294
0
#ifndef CURL_DISABLE_SOCKETPAIR
295
0
  char buf[1];
296
0
#endif
297
298
0
  msnprintf(service, sizeof(service), "%d", tsd->port);
299
300
0
  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
301
302
0
  if(rc) {
303
0
    tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
304
0
    if(tsd->sock_error == 0)
305
0
      tsd->sock_error = RESOLVER_ENOMEM;
306
0
  }
307
0
  else {
308
0
    Curl_addrinfo_set_port(tsd->res, tsd->port);
309
0
  }
310
311
0
  Curl_mutex_acquire(tsd->mtx);
312
0
  if(tsd->done) {
313
    /* too late, gotta clean up the mess */
314
0
    Curl_mutex_release(tsd->mtx);
315
0
    destroy_thread_sync_data(tsd);
316
0
    free(td);
317
0
  }
318
0
  else {
319
0
#ifndef CURL_DISABLE_SOCKETPAIR
320
0
    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
321
      /* DNS has been resolved, signal client task */
322
0
      buf[0] = 1;
323
0
      if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
324
        /* update sock_erro to errno */
325
0
        tsd->sock_error = SOCKERRNO;
326
0
      }
327
0
    }
328
0
#endif
329
0
    tsd->done = 1;
330
0
    Curl_mutex_release(tsd->mtx);
331
0
  }
332
333
0
  return 0;
334
0
}
335
336
#else /* HAVE_GETADDRINFO */
337
338
/*
339
 * gethostbyname_thread() resolves a name and then exits.
340
 */
341
static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
342
{
343
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
344
  struct thread_data *td = tsd->td;
345
346
  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
347
348
  if(!tsd->res) {
349
    tsd->sock_error = SOCKERRNO;
350
    if(tsd->sock_error == 0)
351
      tsd->sock_error = RESOLVER_ENOMEM;
352
  }
353
354
  Curl_mutex_acquire(tsd->mtx);
355
  if(tsd->done) {
356
    /* too late, gotta clean up the mess */
357
    Curl_mutex_release(tsd->mtx);
358
    destroy_thread_sync_data(tsd);
359
    free(td);
360
  }
361
  else {
362
    tsd->done = 1;
363
    Curl_mutex_release(tsd->mtx);
364
  }
365
366
  return 0;
367
}
368
369
#endif /* HAVE_GETADDRINFO */
370
371
/*
372
 * destroy_async_data() cleans up async resolver data and thread handle.
373
 */
374
static void destroy_async_data(struct Curl_async *async)
375
1.20k
{
376
1.20k
  if(async->tdata) {
377
0
    struct thread_data *td = async->tdata;
378
0
    int done;
379
0
#ifndef CURL_DISABLE_SOCKETPAIR
380
0
    curl_socket_t sock_rd = td->tsd.sock_pair[0];
381
0
    struct Curl_easy *data = td->tsd.data;
382
0
#endif
383
384
    /*
385
     * if the thread is still blocking in the resolve syscall, detach it and
386
     * let the thread do the cleanup...
387
     */
388
0
    Curl_mutex_acquire(td->tsd.mtx);
389
0
    done = td->tsd.done;
390
0
    td->tsd.done = 1;
391
0
    Curl_mutex_release(td->tsd.mtx);
392
393
0
    if(!done) {
394
0
      Curl_thread_destroy(td->thread_hnd);
395
0
    }
396
0
    else {
397
0
      if(td->thread_hnd != curl_thread_t_null)
398
0
        Curl_thread_join(&td->thread_hnd);
399
400
0
      destroy_thread_sync_data(&td->tsd);
401
402
0
      free(async->tdata);
403
0
    }
404
0
#ifndef CURL_DISABLE_SOCKETPAIR
405
    /*
406
     * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
407
     * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
408
     */
409
0
    Curl_multi_closed(data, sock_rd);
410
0
    sclose(sock_rd);
411
0
#endif
412
0
  }
413
1.20k
  async->tdata = NULL;
414
415
1.20k
  free(async->hostname);
416
1.20k
  async->hostname = NULL;
417
1.20k
}
418
419
/*
420
 * init_resolve_thread() starts a new thread that performs the actual
421
 * resolve. This function returns before the resolve is done.
422
 *
423
 * Returns FALSE in case of failure, otherwise TRUE.
424
 */
425
static bool init_resolve_thread(struct Curl_easy *data,
426
                                const char *hostname, int port,
427
                                const struct addrinfo *hints)
428
0
{
429
0
  struct thread_data *td = calloc(1, sizeof(struct thread_data));
430
0
  int err = ENOMEM;
431
0
  struct Curl_async *asp = &data->state.async;
432
433
0
  data->state.async.tdata = td;
434
0
  if(!td)
435
0
    goto errno_exit;
436
437
0
  asp->port = port;
438
0
  asp->done = FALSE;
439
0
  asp->status = 0;
440
0
  asp->dns = NULL;
441
0
  td->thread_hnd = curl_thread_t_null;
442
443
0
  if(!init_thread_sync_data(td, hostname, port, hints)) {
444
0
    asp->tdata = NULL;
445
0
    free(td);
446
0
    goto errno_exit;
447
0
  }
448
449
0
  free(asp->hostname);
450
0
  asp->hostname = strdup(hostname);
451
0
  if(!asp->hostname)
452
0
    goto err_exit;
453
454
  /* The thread will set this to 1 when complete. */
455
0
  td->tsd.done = 0;
456
457
0
#ifdef HAVE_GETADDRINFO
458
0
  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
459
#else
460
  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
461
#endif
462
463
0
  if(!td->thread_hnd) {
464
    /* The thread never started, so mark it as done here for proper cleanup. */
465
0
    td->tsd.done = 1;
466
0
    err = errno;
467
0
    goto err_exit;
468
0
  }
469
470
0
  return TRUE;
471
472
0
err_exit:
473
0
  destroy_async_data(asp);
474
475
0
errno_exit:
476
0
  errno = err;
477
0
  return FALSE;
478
0
}
479
480
/*
481
 * 'entry' may be NULL and then no data is returned
482
 */
483
static CURLcode thread_wait_resolv(struct Curl_easy *data,
484
                                   struct Curl_dns_entry **entry,
485
                                   bool report)
486
0
{
487
0
  struct thread_data *td;
488
0
  CURLcode result = CURLE_OK;
489
490
0
  DEBUGASSERT(data);
491
0
  td = data->state.async.tdata;
492
0
  DEBUGASSERT(td);
493
0
  DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
494
495
  /* wait for the thread to resolve the name */
496
0
  if(Curl_thread_join(&td->thread_hnd)) {
497
0
    if(entry)
498
0
      result = getaddrinfo_complete(data);
499
0
  }
500
0
  else
501
0
    DEBUGASSERT(0);
502
503
0
  data->state.async.done = TRUE;
504
505
0
  if(entry)
506
0
    *entry = data->state.async.dns;
507
508
0
  if(!data->state.async.dns && report)
509
    /* a name was not resolved, report error */
510
0
    result = Curl_resolver_error(data);
511
512
0
  destroy_async_data(&data->state.async);
513
514
0
  if(!data->state.async.dns && report)
515
0
    connclose(data->conn, "asynch resolve failed");
516
517
0
  return result;
518
0
}
519
520
521
/*
522
 * Until we gain a way to signal the resolver threads to stop early, we must
523
 * simply wait for them and ignore their results.
524
 */
525
void Curl_resolver_kill(struct Curl_easy *data)
526
0
{
527
0
  struct thread_data *td = data->state.async.tdata;
528
529
  /* If we're still resolving, we must wait for the threads to fully clean up,
530
     unfortunately.  Otherwise, we can simply cancel to clean up any resolver
531
     data. */
532
0
  if(td && td->thread_hnd != curl_thread_t_null
533
0
     && (data->set.quick_exit != 1L))
534
0
    (void)thread_wait_resolv(data, NULL, FALSE);
535
0
  else
536
0
    Curl_resolver_cancel(data);
537
0
}
538
539
/*
540
 * Curl_resolver_wait_resolv()
541
 *
542
 * Waits for a resolve to finish. This function should be avoided since using
543
 * this risk getting the multi interface to "hang".
544
 *
545
 * If 'entry' is non-NULL, make it point to the resolved dns entry
546
 *
547
 * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
548
 * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
549
 *
550
 * This is the version for resolves-in-a-thread.
551
 */
552
CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
553
                                   struct Curl_dns_entry **entry)
554
0
{
555
0
  return thread_wait_resolv(data, entry, TRUE);
556
0
}
557
558
/*
559
 * Curl_resolver_is_resolved() is called repeatedly to check if a previous
560
 * name resolve request has completed. It should also make sure to time-out if
561
 * the operation seems to take too long.
562
 */
563
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
564
                                   struct Curl_dns_entry **entry)
565
0
{
566
0
  struct thread_data *td = data->state.async.tdata;
567
0
  int done = 0;
568
569
0
  DEBUGASSERT(entry);
570
0
  *entry = NULL;
571
572
0
  if(!td) {
573
0
    DEBUGASSERT(td);
574
0
    return CURLE_COULDNT_RESOLVE_HOST;
575
0
  }
576
577
0
  Curl_mutex_acquire(td->tsd.mtx);
578
0
  done = td->tsd.done;
579
0
  Curl_mutex_release(td->tsd.mtx);
580
581
0
  if(done) {
582
0
    getaddrinfo_complete(data);
583
584
0
    if(!data->state.async.dns) {
585
0
      CURLcode result = Curl_resolver_error(data);
586
0
      destroy_async_data(&data->state.async);
587
0
      return result;
588
0
    }
589
0
    destroy_async_data(&data->state.async);
590
0
    *entry = data->state.async.dns;
591
0
  }
592
0
  else {
593
    /* poll for name lookup done with exponential backoff up to 250ms */
594
    /* should be fine even if this converts to 32 bit */
595
0
    timediff_t elapsed = Curl_timediff(Curl_now(),
596
0
                                       data->progress.t_startsingle);
597
0
    if(elapsed < 0)
598
0
      elapsed = 0;
599
600
0
    if(td->poll_interval == 0)
601
      /* Start at 1ms poll interval */
602
0
      td->poll_interval = 1;
603
0
    else if(elapsed >= td->interval_end)
604
      /* Back-off exponentially if last interval expired  */
605
0
      td->poll_interval *= 2;
606
607
0
    if(td->poll_interval > 250)
608
0
      td->poll_interval = 250;
609
610
0
    td->interval_end = elapsed + td->poll_interval;
611
0
    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
612
0
  }
613
614
0
  return CURLE_OK;
615
0
}
616
617
int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
618
0
{
619
0
  int ret_val = 0;
620
0
  timediff_t milli;
621
0
  timediff_t ms;
622
0
  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
623
0
#ifndef CURL_DISABLE_SOCKETPAIR
624
0
  struct thread_data *td = data->state.async.tdata;
625
#else
626
  (void)socks;
627
#endif
628
629
0
#ifndef CURL_DISABLE_SOCKETPAIR
630
0
  if(td) {
631
    /* return read fd to client for polling the DNS resolution status */
632
0
    socks[0] = td->tsd.sock_pair[0];
633
0
    td->tsd.data = data;
634
0
    ret_val = GETSOCK_READSOCK(0);
635
0
  }
636
0
  else {
637
0
#endif
638
0
    ms = Curl_timediff(Curl_now(), reslv->start);
639
0
    if(ms < 3)
640
0
      milli = 0;
641
0
    else if(ms <= 50)
642
0
      milli = ms/3;
643
0
    else if(ms <= 250)
644
0
      milli = 50;
645
0
    else
646
0
      milli = 200;
647
0
    Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
648
0
#ifndef CURL_DISABLE_SOCKETPAIR
649
0
  }
650
0
#endif
651
652
653
0
  return ret_val;
654
0
}
655
656
#ifndef HAVE_GETADDRINFO
657
/*
658
 * Curl_getaddrinfo() - for platforms without getaddrinfo
659
 */
660
struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
661
                                                const char *hostname,
662
                                                int port,
663
                                                int *waitp)
664
{
665
  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
666
667
  *waitp = 0; /* default to synchronous response */
668
669
  reslv->start = Curl_now();
670
671
  /* fire up a new resolver thread! */
672
  if(init_resolve_thread(data, hostname, port, NULL)) {
673
    *waitp = 1; /* expect asynchronous response */
674
    return NULL;
675
  }
676
677
  failf(data, "getaddrinfo() thread failed");
678
679
  return NULL;
680
}
681
682
#else /* !HAVE_GETADDRINFO */
683
684
/*
685
 * Curl_resolver_getaddrinfo() - for getaddrinfo
686
 */
687
struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
688
                                                const char *hostname,
689
                                                int port,
690
                                                int *waitp)
691
0
{
692
0
  struct addrinfo hints;
693
0
  int pf = PF_INET;
694
0
  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
695
696
0
  *waitp = 0; /* default to synchronous response */
697
698
0
#ifdef CURLRES_IPV6
699
0
  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data))
700
    /* The stack seems to be IPv6-enabled */
701
0
    pf = PF_UNSPEC;
702
0
#endif /* CURLRES_IPV6 */
703
704
0
  memset(&hints, 0, sizeof(hints));
705
0
  hints.ai_family = pf;
706
0
  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
707
0
    SOCK_STREAM : SOCK_DGRAM;
708
709
0
  reslv->start = Curl_now();
710
  /* fire up a new resolver thread! */
711
0
  if(init_resolve_thread(data, hostname, port, &hints)) {
712
0
    *waitp = 1; /* expect asynchronous response */
713
0
    return NULL;
714
0
  }
715
716
0
  failf(data, "getaddrinfo() thread failed to start");
717
0
  return NULL;
718
719
0
}
720
721
#endif /* !HAVE_GETADDRINFO */
722
723
CURLcode Curl_set_dns_servers(struct Curl_easy *data,
724
                              char *servers)
725
0
{
726
0
  (void)data;
727
0
  (void)servers;
728
0
  return CURLE_NOT_BUILT_IN;
729
730
0
}
731
732
CURLcode Curl_set_dns_interface(struct Curl_easy *data,
733
                                const char *interf)
734
0
{
735
0
  (void)data;
736
0
  (void)interf;
737
0
  return CURLE_NOT_BUILT_IN;
738
0
}
739
740
CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
741
                                const char *local_ip4)
742
0
{
743
0
  (void)data;
744
0
  (void)local_ip4;
745
0
  return CURLE_NOT_BUILT_IN;
746
0
}
747
748
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
749
                                const char *local_ip6)
750
0
{
751
0
  (void)data;
752
0
  (void)local_ip6;
753
0
  return CURLE_NOT_BUILT_IN;
754
0
}
755
756
#endif /* CURLRES_THREADED */