113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci#include "socketpair.h"
2713498266Sopenharmony_ci
2813498266Sopenharmony_ci/***********************************************************************
2913498266Sopenharmony_ci * Only for threaded name resolves builds
3013498266Sopenharmony_ci **********************************************************************/
3113498266Sopenharmony_ci#ifdef CURLRES_THREADED
3213498266Sopenharmony_ci
3313498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
3413498266Sopenharmony_ci#include <netinet/in.h>
3513498266Sopenharmony_ci#endif
3613498266Sopenharmony_ci#ifdef HAVE_NETDB_H
3713498266Sopenharmony_ci#include <netdb.h>
3813498266Sopenharmony_ci#endif
3913498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
4013498266Sopenharmony_ci#include <arpa/inet.h>
4113498266Sopenharmony_ci#endif
4213498266Sopenharmony_ci#ifdef __VMS
4313498266Sopenharmony_ci#include <in.h>
4413498266Sopenharmony_ci#include <inet.h>
4513498266Sopenharmony_ci#endif
4613498266Sopenharmony_ci
4713498266Sopenharmony_ci#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
4813498266Sopenharmony_ci#  include <pthread.h>
4913498266Sopenharmony_ci#endif
5013498266Sopenharmony_ci
5113498266Sopenharmony_ci#ifdef HAVE_GETADDRINFO
5213498266Sopenharmony_ci#  define RESOLVER_ENOMEM  EAI_MEMORY
5313498266Sopenharmony_ci#else
5413498266Sopenharmony_ci#  define RESOLVER_ENOMEM  ENOMEM
5513498266Sopenharmony_ci#endif
5613498266Sopenharmony_ci
5713498266Sopenharmony_ci#include "system_win32.h"
5813498266Sopenharmony_ci#include "urldata.h"
5913498266Sopenharmony_ci#include "sendf.h"
6013498266Sopenharmony_ci#include "hostip.h"
6113498266Sopenharmony_ci#include "hash.h"
6213498266Sopenharmony_ci#include "share.h"
6313498266Sopenharmony_ci#include "url.h"
6413498266Sopenharmony_ci#include "multiif.h"
6513498266Sopenharmony_ci#include "inet_ntop.h"
6613498266Sopenharmony_ci#include "curl_threads.h"
6713498266Sopenharmony_ci#include "connect.h"
6813498266Sopenharmony_ci/* The last 3 #include files should be in this order */
6913498266Sopenharmony_ci#include "curl_printf.h"
7013498266Sopenharmony_ci#include "curl_memory.h"
7113498266Sopenharmony_ci#include "memdebug.h"
7213498266Sopenharmony_ci
7313498266Sopenharmony_cistruct resdata {
7413498266Sopenharmony_ci  struct curltime start;
7513498266Sopenharmony_ci};
7613498266Sopenharmony_ci
7713498266Sopenharmony_ci/*
7813498266Sopenharmony_ci * Curl_resolver_global_init()
7913498266Sopenharmony_ci * Called from curl_global_init() to initialize global resolver environment.
8013498266Sopenharmony_ci * Does nothing here.
8113498266Sopenharmony_ci */
8213498266Sopenharmony_ciint Curl_resolver_global_init(void)
8313498266Sopenharmony_ci{
8413498266Sopenharmony_ci  return CURLE_OK;
8513498266Sopenharmony_ci}
8613498266Sopenharmony_ci
8713498266Sopenharmony_ci/*
8813498266Sopenharmony_ci * Curl_resolver_global_cleanup()
8913498266Sopenharmony_ci * Called from curl_global_cleanup() to destroy global resolver environment.
9013498266Sopenharmony_ci * Does nothing here.
9113498266Sopenharmony_ci */
9213498266Sopenharmony_civoid Curl_resolver_global_cleanup(void)
9313498266Sopenharmony_ci{
9413498266Sopenharmony_ci}
9513498266Sopenharmony_ci
9613498266Sopenharmony_ci/*
9713498266Sopenharmony_ci * Curl_resolver_init()
9813498266Sopenharmony_ci * Called from curl_easy_init() -> Curl_open() to initialize resolver
9913498266Sopenharmony_ci * URL-state specific environment ('resolver' member of the UrlState
10013498266Sopenharmony_ci * structure).
10113498266Sopenharmony_ci */
10213498266Sopenharmony_ciCURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
10313498266Sopenharmony_ci{
10413498266Sopenharmony_ci  (void)easy;
10513498266Sopenharmony_ci  *resolver = calloc(1, sizeof(struct resdata));
10613498266Sopenharmony_ci  if(!*resolver)
10713498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
10813498266Sopenharmony_ci  return CURLE_OK;
10913498266Sopenharmony_ci}
11013498266Sopenharmony_ci
11113498266Sopenharmony_ci/*
11213498266Sopenharmony_ci * Curl_resolver_cleanup()
11313498266Sopenharmony_ci * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
11413498266Sopenharmony_ci * URL-state specific environment ('resolver' member of the UrlState
11513498266Sopenharmony_ci * structure).
11613498266Sopenharmony_ci */
11713498266Sopenharmony_civoid Curl_resolver_cleanup(void *resolver)
11813498266Sopenharmony_ci{
11913498266Sopenharmony_ci  free(resolver);
12013498266Sopenharmony_ci}
12113498266Sopenharmony_ci
12213498266Sopenharmony_ci/*
12313498266Sopenharmony_ci * Curl_resolver_duphandle()
12413498266Sopenharmony_ci * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
12513498266Sopenharmony_ci * environment ('resolver' member of the UrlState structure).
12613498266Sopenharmony_ci */
12713498266Sopenharmony_ciCURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
12813498266Sopenharmony_ci{
12913498266Sopenharmony_ci  (void)from;
13013498266Sopenharmony_ci  return Curl_resolver_init(easy, to);
13113498266Sopenharmony_ci}
13213498266Sopenharmony_ci
13313498266Sopenharmony_cistatic void destroy_async_data(struct Curl_async *);
13413498266Sopenharmony_ci
13513498266Sopenharmony_ci/*
13613498266Sopenharmony_ci * Cancel all possibly still on-going resolves for this connection.
13713498266Sopenharmony_ci */
13813498266Sopenharmony_civoid Curl_resolver_cancel(struct Curl_easy *data)
13913498266Sopenharmony_ci{
14013498266Sopenharmony_ci  destroy_async_data(&data->state.async);
14113498266Sopenharmony_ci}
14213498266Sopenharmony_ci
14313498266Sopenharmony_ci/* This function is used to init a threaded resolve */
14413498266Sopenharmony_cistatic bool init_resolve_thread(struct Curl_easy *data,
14513498266Sopenharmony_ci                                const char *hostname, int port,
14613498266Sopenharmony_ci                                const struct addrinfo *hints);
14713498266Sopenharmony_ci
14813498266Sopenharmony_ci#ifdef _WIN32
14913498266Sopenharmony_ci/* Thread sync data used by GetAddrInfoExW for win8+ */
15013498266Sopenharmony_cistruct thread_sync_data_w8
15113498266Sopenharmony_ci{
15213498266Sopenharmony_ci  OVERLAPPED overlapped;
15313498266Sopenharmony_ci  ADDRINFOEXW_ *res;
15413498266Sopenharmony_ci  HANDLE cancel_ev;
15513498266Sopenharmony_ci  ADDRINFOEXW_ hints;
15613498266Sopenharmony_ci};
15713498266Sopenharmony_ci#endif
15813498266Sopenharmony_ci
15913498266Sopenharmony_ci/* Data for synchronization between resolver thread and its parent */
16013498266Sopenharmony_cistruct thread_sync_data {
16113498266Sopenharmony_ci#ifdef _WIN32
16213498266Sopenharmony_ci  struct thread_sync_data_w8 w8;
16313498266Sopenharmony_ci#endif
16413498266Sopenharmony_ci  curl_mutex_t *mtx;
16513498266Sopenharmony_ci  int done;
16613498266Sopenharmony_ci  int port;
16713498266Sopenharmony_ci  char *hostname;        /* hostname to resolve, Curl_async.hostname
16813498266Sopenharmony_ci                            duplicate */
16913498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
17013498266Sopenharmony_ci  struct Curl_easy *data;
17113498266Sopenharmony_ci  curl_socket_t sock_pair[2]; /* socket pair */
17213498266Sopenharmony_ci#endif
17313498266Sopenharmony_ci  int sock_error;
17413498266Sopenharmony_ci  struct Curl_addrinfo *res;
17513498266Sopenharmony_ci#ifdef HAVE_GETADDRINFO
17613498266Sopenharmony_ci  struct addrinfo hints;
17713498266Sopenharmony_ci#endif
17813498266Sopenharmony_ci  struct thread_data *td; /* for thread-self cleanup */
17913498266Sopenharmony_ci};
18013498266Sopenharmony_ci
18113498266Sopenharmony_cistruct thread_data {
18213498266Sopenharmony_ci#ifdef _WIN32
18313498266Sopenharmony_ci  HANDLE complete_ev;
18413498266Sopenharmony_ci#endif
18513498266Sopenharmony_ci  curl_thread_t thread_hnd;
18613498266Sopenharmony_ci  unsigned int poll_interval;
18713498266Sopenharmony_ci  timediff_t interval_end;
18813498266Sopenharmony_ci  struct thread_sync_data tsd;
18913498266Sopenharmony_ci};
19013498266Sopenharmony_ci
19113498266Sopenharmony_cistatic struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
19213498266Sopenharmony_ci{
19313498266Sopenharmony_ci  return &(data->state.async.tdata->tsd);
19413498266Sopenharmony_ci}
19513498266Sopenharmony_ci
19613498266Sopenharmony_ci/* Destroy resolver thread synchronization data */
19713498266Sopenharmony_cistatic
19813498266Sopenharmony_civoid destroy_thread_sync_data(struct thread_sync_data *tsd)
19913498266Sopenharmony_ci{
20013498266Sopenharmony_ci  if(tsd->mtx) {
20113498266Sopenharmony_ci    Curl_mutex_destroy(tsd->mtx);
20213498266Sopenharmony_ci    free(tsd->mtx);
20313498266Sopenharmony_ci  }
20413498266Sopenharmony_ci
20513498266Sopenharmony_ci  free(tsd->hostname);
20613498266Sopenharmony_ci
20713498266Sopenharmony_ci  if(tsd->res)
20813498266Sopenharmony_ci    Curl_freeaddrinfo(tsd->res);
20913498266Sopenharmony_ci
21013498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
21113498266Sopenharmony_ci  /*
21213498266Sopenharmony_ci   * close one end of the socket pair (may be done in resolver thread);
21313498266Sopenharmony_ci   * the other end (for reading) is always closed in the parent thread.
21413498266Sopenharmony_ci   */
21513498266Sopenharmony_ci  if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
21613498266Sopenharmony_ci    wakeup_close(tsd->sock_pair[1]);
21713498266Sopenharmony_ci  }
21813498266Sopenharmony_ci#endif
21913498266Sopenharmony_ci  memset(tsd, 0, sizeof(*tsd));
22013498266Sopenharmony_ci}
22113498266Sopenharmony_ci
22213498266Sopenharmony_ci/* Initialize resolver thread synchronization data */
22313498266Sopenharmony_cistatic
22413498266Sopenharmony_ciint init_thread_sync_data(struct thread_data *td,
22513498266Sopenharmony_ci                           const char *hostname,
22613498266Sopenharmony_ci                           int port,
22713498266Sopenharmony_ci                           const struct addrinfo *hints)
22813498266Sopenharmony_ci{
22913498266Sopenharmony_ci  struct thread_sync_data *tsd = &td->tsd;
23013498266Sopenharmony_ci
23113498266Sopenharmony_ci  memset(tsd, 0, sizeof(*tsd));
23213498266Sopenharmony_ci
23313498266Sopenharmony_ci  tsd->td = td;
23413498266Sopenharmony_ci  tsd->port = port;
23513498266Sopenharmony_ci  /* Treat the request as done until the thread actually starts so any early
23613498266Sopenharmony_ci   * cleanup gets done properly.
23713498266Sopenharmony_ci   */
23813498266Sopenharmony_ci  tsd->done = 1;
23913498266Sopenharmony_ci#ifdef HAVE_GETADDRINFO
24013498266Sopenharmony_ci  DEBUGASSERT(hints);
24113498266Sopenharmony_ci  tsd->hints = *hints;
24213498266Sopenharmony_ci#else
24313498266Sopenharmony_ci  (void) hints;
24413498266Sopenharmony_ci#endif
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci  tsd->mtx = malloc(sizeof(curl_mutex_t));
24713498266Sopenharmony_ci  if(!tsd->mtx)
24813498266Sopenharmony_ci    goto err_exit;
24913498266Sopenharmony_ci
25013498266Sopenharmony_ci  Curl_mutex_init(tsd->mtx);
25113498266Sopenharmony_ci
25213498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
25313498266Sopenharmony_ci  /* create socket pair or pipe */
25413498266Sopenharmony_ci  if(wakeup_create(&tsd->sock_pair[0]) < 0) {
25513498266Sopenharmony_ci    tsd->sock_pair[0] = CURL_SOCKET_BAD;
25613498266Sopenharmony_ci    tsd->sock_pair[1] = CURL_SOCKET_BAD;
25713498266Sopenharmony_ci    goto err_exit;
25813498266Sopenharmony_ci  }
25913498266Sopenharmony_ci#endif
26013498266Sopenharmony_ci  tsd->sock_error = CURL_ASYNC_SUCCESS;
26113498266Sopenharmony_ci
26213498266Sopenharmony_ci  /* Copying hostname string because original can be destroyed by parent
26313498266Sopenharmony_ci   * thread during gethostbyname execution.
26413498266Sopenharmony_ci   */
26513498266Sopenharmony_ci  tsd->hostname = strdup(hostname);
26613498266Sopenharmony_ci  if(!tsd->hostname)
26713498266Sopenharmony_ci    goto err_exit;
26813498266Sopenharmony_ci
26913498266Sopenharmony_ci  return 1;
27013498266Sopenharmony_ci
27113498266Sopenharmony_cierr_exit:
27213498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
27313498266Sopenharmony_ci  if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
27413498266Sopenharmony_ci    wakeup_close(tsd->sock_pair[0]);
27513498266Sopenharmony_ci    tsd->sock_pair[0] = CURL_SOCKET_BAD;
27613498266Sopenharmony_ci  }
27713498266Sopenharmony_ci#endif
27813498266Sopenharmony_ci  destroy_thread_sync_data(tsd);
27913498266Sopenharmony_ci  return 0;
28013498266Sopenharmony_ci}
28113498266Sopenharmony_ci
28213498266Sopenharmony_cistatic CURLcode getaddrinfo_complete(struct Curl_easy *data)
28313498266Sopenharmony_ci{
28413498266Sopenharmony_ci  struct thread_sync_data *tsd = conn_thread_sync_data(data);
28513498266Sopenharmony_ci  CURLcode result;
28613498266Sopenharmony_ci
28713498266Sopenharmony_ci  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
28813498266Sopenharmony_ci  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
28913498266Sopenharmony_ci     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
29013498266Sopenharmony_ci  */
29113498266Sopenharmony_ci  tsd->res = NULL;
29213498266Sopenharmony_ci
29313498266Sopenharmony_ci  return result;
29413498266Sopenharmony_ci}
29513498266Sopenharmony_ci
29613498266Sopenharmony_ci#ifdef _WIN32
29713498266Sopenharmony_cistatic VOID WINAPI
29813498266Sopenharmony_ciquery_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
29913498266Sopenharmony_ci{
30013498266Sopenharmony_ci  size_t ss_size;
30113498266Sopenharmony_ci  const ADDRINFOEXW_ *ai;
30213498266Sopenharmony_ci  struct Curl_addrinfo *ca;
30313498266Sopenharmony_ci  struct Curl_addrinfo *cafirst = NULL;
30413498266Sopenharmony_ci  struct Curl_addrinfo *calast = NULL;
30513498266Sopenharmony_ci#ifdef __clang__
30613498266Sopenharmony_ci#pragma clang diagnostic push
30713498266Sopenharmony_ci#pragma clang diagnostic ignored "-Wcast-align"
30813498266Sopenharmony_ci#endif
30913498266Sopenharmony_ci  struct thread_sync_data *tsd =
31013498266Sopenharmony_ci    CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
31113498266Sopenharmony_ci#ifdef __clang__
31213498266Sopenharmony_ci#pragma clang diagnostic pop
31313498266Sopenharmony_ci#endif
31413498266Sopenharmony_ci  struct thread_data *td = tsd->td;
31513498266Sopenharmony_ci  const ADDRINFOEXW_ *res = tsd->w8.res;
31613498266Sopenharmony_ci  int error = (int)err;
31713498266Sopenharmony_ci  (void)bytes;
31813498266Sopenharmony_ci
31913498266Sopenharmony_ci  if(error == ERROR_SUCCESS) {
32013498266Sopenharmony_ci    /* traverse the addrinfo list */
32113498266Sopenharmony_ci
32213498266Sopenharmony_ci    for(ai = res; ai != NULL; ai = ai->ai_next) {
32313498266Sopenharmony_ci      size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
32413498266Sopenharmony_ci      /* ignore elements with unsupported address family, */
32513498266Sopenharmony_ci      /* settle family-specific sockaddr structure size.  */
32613498266Sopenharmony_ci      if(ai->ai_family == AF_INET)
32713498266Sopenharmony_ci        ss_size = sizeof(struct sockaddr_in);
32813498266Sopenharmony_ci#ifdef ENABLE_IPV6
32913498266Sopenharmony_ci      else if(ai->ai_family == AF_INET6)
33013498266Sopenharmony_ci        ss_size = sizeof(struct sockaddr_in6);
33113498266Sopenharmony_ci#endif
33213498266Sopenharmony_ci      else
33313498266Sopenharmony_ci        continue;
33413498266Sopenharmony_ci
33513498266Sopenharmony_ci      /* ignore elements without required address info */
33613498266Sopenharmony_ci      if(!ai->ai_addr || !(ai->ai_addrlen > 0))
33713498266Sopenharmony_ci        continue;
33813498266Sopenharmony_ci
33913498266Sopenharmony_ci      /* ignore elements with bogus address size */
34013498266Sopenharmony_ci      if((size_t)ai->ai_addrlen < ss_size)
34113498266Sopenharmony_ci        continue;
34213498266Sopenharmony_ci
34313498266Sopenharmony_ci      ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
34413498266Sopenharmony_ci      if(!ca) {
34513498266Sopenharmony_ci        error = EAI_MEMORY;
34613498266Sopenharmony_ci        break;
34713498266Sopenharmony_ci      }
34813498266Sopenharmony_ci
34913498266Sopenharmony_ci      /* copy each structure member individually, member ordering, */
35013498266Sopenharmony_ci      /* size, or padding might be different for each platform.    */
35113498266Sopenharmony_ci      ca->ai_flags     = ai->ai_flags;
35213498266Sopenharmony_ci      ca->ai_family    = ai->ai_family;
35313498266Sopenharmony_ci      ca->ai_socktype  = ai->ai_socktype;
35413498266Sopenharmony_ci      ca->ai_protocol  = ai->ai_protocol;
35513498266Sopenharmony_ci      ca->ai_addrlen   = (curl_socklen_t)ss_size;
35613498266Sopenharmony_ci      ca->ai_addr      = NULL;
35713498266Sopenharmony_ci      ca->ai_canonname = NULL;
35813498266Sopenharmony_ci      ca->ai_next      = NULL;
35913498266Sopenharmony_ci
36013498266Sopenharmony_ci      ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
36113498266Sopenharmony_ci      memcpy(ca->ai_addr, ai->ai_addr, ss_size);
36213498266Sopenharmony_ci
36313498266Sopenharmony_ci      if(namelen) {
36413498266Sopenharmony_ci        size_t i;
36513498266Sopenharmony_ci        ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
36613498266Sopenharmony_ci        for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
36713498266Sopenharmony_ci          ca->ai_canonname[i] = (char)ai->ai_canonname[i];
36813498266Sopenharmony_ci        ca->ai_canonname[namelen] = '\0';
36913498266Sopenharmony_ci      }
37013498266Sopenharmony_ci
37113498266Sopenharmony_ci      /* if the return list is empty, this becomes the first element */
37213498266Sopenharmony_ci      if(!cafirst)
37313498266Sopenharmony_ci        cafirst = ca;
37413498266Sopenharmony_ci
37513498266Sopenharmony_ci      /* add this element last in the return list */
37613498266Sopenharmony_ci      if(calast)
37713498266Sopenharmony_ci        calast->ai_next = ca;
37813498266Sopenharmony_ci      calast = ca;
37913498266Sopenharmony_ci    }
38013498266Sopenharmony_ci
38113498266Sopenharmony_ci    /* if we failed, also destroy the Curl_addrinfo list */
38213498266Sopenharmony_ci    if(error) {
38313498266Sopenharmony_ci      Curl_freeaddrinfo(cafirst);
38413498266Sopenharmony_ci      cafirst = NULL;
38513498266Sopenharmony_ci    }
38613498266Sopenharmony_ci    else if(!cafirst) {
38713498266Sopenharmony_ci#ifdef EAI_NONAME
38813498266Sopenharmony_ci      /* rfc3493 conformant */
38913498266Sopenharmony_ci      error = EAI_NONAME;
39013498266Sopenharmony_ci#else
39113498266Sopenharmony_ci      /* rfc3493 obsoleted */
39213498266Sopenharmony_ci      error = EAI_NODATA;
39313498266Sopenharmony_ci#endif
39413498266Sopenharmony_ci#ifdef USE_WINSOCK
39513498266Sopenharmony_ci      SET_SOCKERRNO(error);
39613498266Sopenharmony_ci#endif
39713498266Sopenharmony_ci    }
39813498266Sopenharmony_ci    tsd->res = cafirst;
39913498266Sopenharmony_ci  }
40013498266Sopenharmony_ci
40113498266Sopenharmony_ci  if(tsd->w8.res) {
40213498266Sopenharmony_ci    Curl_FreeAddrInfoExW(tsd->w8.res);
40313498266Sopenharmony_ci    tsd->w8.res = NULL;
40413498266Sopenharmony_ci  }
40513498266Sopenharmony_ci
40613498266Sopenharmony_ci  if(error) {
40713498266Sopenharmony_ci    tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
40813498266Sopenharmony_ci    if(tsd->sock_error == 0)
40913498266Sopenharmony_ci      tsd->sock_error = RESOLVER_ENOMEM;
41013498266Sopenharmony_ci  }
41113498266Sopenharmony_ci  else {
41213498266Sopenharmony_ci    Curl_addrinfo_set_port(tsd->res, tsd->port);
41313498266Sopenharmony_ci  }
41413498266Sopenharmony_ci
41513498266Sopenharmony_ci  Curl_mutex_acquire(tsd->mtx);
41613498266Sopenharmony_ci  if(tsd->done) {
41713498266Sopenharmony_ci    /* too late, gotta clean up the mess */
41813498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
41913498266Sopenharmony_ci    destroy_thread_sync_data(tsd);
42013498266Sopenharmony_ci    free(td);
42113498266Sopenharmony_ci  }
42213498266Sopenharmony_ci  else {
42313498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
42413498266Sopenharmony_ci    char buf[1];
42513498266Sopenharmony_ci    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
42613498266Sopenharmony_ci      /* DNS has been resolved, signal client task */
42713498266Sopenharmony_ci      buf[0] = 1;
42813498266Sopenharmony_ci      if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
42913498266Sopenharmony_ci        /* update sock_erro to errno */
43013498266Sopenharmony_ci        tsd->sock_error = SOCKERRNO;
43113498266Sopenharmony_ci      }
43213498266Sopenharmony_ci    }
43313498266Sopenharmony_ci#endif
43413498266Sopenharmony_ci    tsd->done = 1;
43513498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
43613498266Sopenharmony_ci    if(td->complete_ev)
43713498266Sopenharmony_ci      SetEvent(td->complete_ev); /* Notify caller that the query completed */
43813498266Sopenharmony_ci  }
43913498266Sopenharmony_ci}
44013498266Sopenharmony_ci#endif
44113498266Sopenharmony_ci
44213498266Sopenharmony_ci#ifdef HAVE_GETADDRINFO
44313498266Sopenharmony_ci
44413498266Sopenharmony_ci/*
44513498266Sopenharmony_ci * getaddrinfo_thread() resolves a name and then exits.
44613498266Sopenharmony_ci *
44713498266Sopenharmony_ci * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
44813498266Sopenharmony_ci * and wait on it.
44913498266Sopenharmony_ci */
45013498266Sopenharmony_cistatic unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
45113498266Sopenharmony_ci{
45213498266Sopenharmony_ci  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
45313498266Sopenharmony_ci  struct thread_data *td = tsd->td;
45413498266Sopenharmony_ci  char service[12];
45513498266Sopenharmony_ci  int rc;
45613498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
45713498266Sopenharmony_ci  char buf[1];
45813498266Sopenharmony_ci#endif
45913498266Sopenharmony_ci
46013498266Sopenharmony_ci  msnprintf(service, sizeof(service), "%d", tsd->port);
46113498266Sopenharmony_ci
46213498266Sopenharmony_ci  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
46313498266Sopenharmony_ci
46413498266Sopenharmony_ci  if(rc) {
46513498266Sopenharmony_ci    tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
46613498266Sopenharmony_ci    if(tsd->sock_error == 0)
46713498266Sopenharmony_ci      tsd->sock_error = RESOLVER_ENOMEM;
46813498266Sopenharmony_ci  }
46913498266Sopenharmony_ci  else {
47013498266Sopenharmony_ci    Curl_addrinfo_set_port(tsd->res, tsd->port);
47113498266Sopenharmony_ci  }
47213498266Sopenharmony_ci
47313498266Sopenharmony_ci  Curl_mutex_acquire(tsd->mtx);
47413498266Sopenharmony_ci  if(tsd->done) {
47513498266Sopenharmony_ci    /* too late, gotta clean up the mess */
47613498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
47713498266Sopenharmony_ci    destroy_thread_sync_data(tsd);
47813498266Sopenharmony_ci    free(td);
47913498266Sopenharmony_ci  }
48013498266Sopenharmony_ci  else {
48113498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
48213498266Sopenharmony_ci    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
48313498266Sopenharmony_ci      /* DNS has been resolved, signal client task */
48413498266Sopenharmony_ci      buf[0] = 1;
48513498266Sopenharmony_ci      if(wakeup_write(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
48613498266Sopenharmony_ci        /* update sock_erro to errno */
48713498266Sopenharmony_ci        tsd->sock_error = SOCKERRNO;
48813498266Sopenharmony_ci      }
48913498266Sopenharmony_ci    }
49013498266Sopenharmony_ci#endif
49113498266Sopenharmony_ci    tsd->done = 1;
49213498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
49313498266Sopenharmony_ci  }
49413498266Sopenharmony_ci
49513498266Sopenharmony_ci  return 0;
49613498266Sopenharmony_ci}
49713498266Sopenharmony_ci
49813498266Sopenharmony_ci#else /* HAVE_GETADDRINFO */
49913498266Sopenharmony_ci
50013498266Sopenharmony_ci/*
50113498266Sopenharmony_ci * gethostbyname_thread() resolves a name and then exits.
50213498266Sopenharmony_ci */
50313498266Sopenharmony_cistatic unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
50413498266Sopenharmony_ci{
50513498266Sopenharmony_ci  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
50613498266Sopenharmony_ci  struct thread_data *td = tsd->td;
50713498266Sopenharmony_ci
50813498266Sopenharmony_ci  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
50913498266Sopenharmony_ci
51013498266Sopenharmony_ci  if(!tsd->res) {
51113498266Sopenharmony_ci    tsd->sock_error = SOCKERRNO;
51213498266Sopenharmony_ci    if(tsd->sock_error == 0)
51313498266Sopenharmony_ci      tsd->sock_error = RESOLVER_ENOMEM;
51413498266Sopenharmony_ci  }
51513498266Sopenharmony_ci
51613498266Sopenharmony_ci  Curl_mutex_acquire(tsd->mtx);
51713498266Sopenharmony_ci  if(tsd->done) {
51813498266Sopenharmony_ci    /* too late, gotta clean up the mess */
51913498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
52013498266Sopenharmony_ci    destroy_thread_sync_data(tsd);
52113498266Sopenharmony_ci    free(td);
52213498266Sopenharmony_ci  }
52313498266Sopenharmony_ci  else {
52413498266Sopenharmony_ci    tsd->done = 1;
52513498266Sopenharmony_ci    Curl_mutex_release(tsd->mtx);
52613498266Sopenharmony_ci  }
52713498266Sopenharmony_ci
52813498266Sopenharmony_ci  return 0;
52913498266Sopenharmony_ci}
53013498266Sopenharmony_ci
53113498266Sopenharmony_ci#endif /* HAVE_GETADDRINFO */
53213498266Sopenharmony_ci
53313498266Sopenharmony_ci/*
53413498266Sopenharmony_ci * destroy_async_data() cleans up async resolver data and thread handle.
53513498266Sopenharmony_ci */
53613498266Sopenharmony_cistatic void destroy_async_data(struct Curl_async *async)
53713498266Sopenharmony_ci{
53813498266Sopenharmony_ci  if(async->tdata) {
53913498266Sopenharmony_ci    struct thread_data *td = async->tdata;
54013498266Sopenharmony_ci    int done;
54113498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
54213498266Sopenharmony_ci    curl_socket_t sock_rd = td->tsd.sock_pair[0];
54313498266Sopenharmony_ci    struct Curl_easy *data = td->tsd.data;
54413498266Sopenharmony_ci#endif
54513498266Sopenharmony_ci
54613498266Sopenharmony_ci    /*
54713498266Sopenharmony_ci     * if the thread is still blocking in the resolve syscall, detach it and
54813498266Sopenharmony_ci     * let the thread do the cleanup...
54913498266Sopenharmony_ci     */
55013498266Sopenharmony_ci    Curl_mutex_acquire(td->tsd.mtx);
55113498266Sopenharmony_ci    done = td->tsd.done;
55213498266Sopenharmony_ci    td->tsd.done = 1;
55313498266Sopenharmony_ci    Curl_mutex_release(td->tsd.mtx);
55413498266Sopenharmony_ci
55513498266Sopenharmony_ci    if(!done) {
55613498266Sopenharmony_ci#ifdef _WIN32
55713498266Sopenharmony_ci      if(td->complete_ev)
55813498266Sopenharmony_ci        CloseHandle(td->complete_ev);
55913498266Sopenharmony_ci      else
56013498266Sopenharmony_ci#endif
56113498266Sopenharmony_ci      Curl_thread_destroy(td->thread_hnd);
56213498266Sopenharmony_ci    }
56313498266Sopenharmony_ci    else {
56413498266Sopenharmony_ci#ifdef _WIN32
56513498266Sopenharmony_ci      if(td->complete_ev) {
56613498266Sopenharmony_ci        Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
56713498266Sopenharmony_ci        WaitForSingleObject(td->complete_ev, INFINITE);
56813498266Sopenharmony_ci        CloseHandle(td->complete_ev);
56913498266Sopenharmony_ci      }
57013498266Sopenharmony_ci#endif
57113498266Sopenharmony_ci      if(td->thread_hnd != curl_thread_t_null)
57213498266Sopenharmony_ci        Curl_thread_join(&td->thread_hnd);
57313498266Sopenharmony_ci
57413498266Sopenharmony_ci      destroy_thread_sync_data(&td->tsd);
57513498266Sopenharmony_ci
57613498266Sopenharmony_ci      free(async->tdata);
57713498266Sopenharmony_ci    }
57813498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
57913498266Sopenharmony_ci    /*
58013498266Sopenharmony_ci     * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
58113498266Sopenharmony_ci     * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
58213498266Sopenharmony_ci     */
58313498266Sopenharmony_ci    Curl_multi_closed(data, sock_rd);
58413498266Sopenharmony_ci    sclose(sock_rd);
58513498266Sopenharmony_ci#endif
58613498266Sopenharmony_ci  }
58713498266Sopenharmony_ci  async->tdata = NULL;
58813498266Sopenharmony_ci
58913498266Sopenharmony_ci  free(async->hostname);
59013498266Sopenharmony_ci  async->hostname = NULL;
59113498266Sopenharmony_ci}
59213498266Sopenharmony_ci
59313498266Sopenharmony_ci/*
59413498266Sopenharmony_ci * init_resolve_thread() starts a new thread that performs the actual
59513498266Sopenharmony_ci * resolve. This function returns before the resolve is done.
59613498266Sopenharmony_ci *
59713498266Sopenharmony_ci * Returns FALSE in case of failure, otherwise TRUE.
59813498266Sopenharmony_ci */
59913498266Sopenharmony_cistatic bool init_resolve_thread(struct Curl_easy *data,
60013498266Sopenharmony_ci                                const char *hostname, int port,
60113498266Sopenharmony_ci                                const struct addrinfo *hints)
60213498266Sopenharmony_ci{
60313498266Sopenharmony_ci  struct thread_data *td = calloc(1, sizeof(struct thread_data));
60413498266Sopenharmony_ci  int err = ENOMEM;
60513498266Sopenharmony_ci  struct Curl_async *asp = &data->state.async;
60613498266Sopenharmony_ci
60713498266Sopenharmony_ci  data->state.async.tdata = td;
60813498266Sopenharmony_ci  if(!td)
60913498266Sopenharmony_ci    goto errno_exit;
61013498266Sopenharmony_ci
61113498266Sopenharmony_ci  asp->port = port;
61213498266Sopenharmony_ci  asp->done = FALSE;
61313498266Sopenharmony_ci  asp->status = 0;
61413498266Sopenharmony_ci  asp->dns = NULL;
61513498266Sopenharmony_ci  td->thread_hnd = curl_thread_t_null;
61613498266Sopenharmony_ci#ifdef _WIN32
61713498266Sopenharmony_ci  td->complete_ev = NULL;
61813498266Sopenharmony_ci#endif
61913498266Sopenharmony_ci
62013498266Sopenharmony_ci  if(!init_thread_sync_data(td, hostname, port, hints)) {
62113498266Sopenharmony_ci    asp->tdata = NULL;
62213498266Sopenharmony_ci    free(td);
62313498266Sopenharmony_ci    goto errno_exit;
62413498266Sopenharmony_ci  }
62513498266Sopenharmony_ci
62613498266Sopenharmony_ci  free(asp->hostname);
62713498266Sopenharmony_ci  asp->hostname = strdup(hostname);
62813498266Sopenharmony_ci  if(!asp->hostname)
62913498266Sopenharmony_ci    goto err_exit;
63013498266Sopenharmony_ci
63113498266Sopenharmony_ci  /* The thread will set this to 1 when complete. */
63213498266Sopenharmony_ci  td->tsd.done = 0;
63313498266Sopenharmony_ci
63413498266Sopenharmony_ci#ifdef _WIN32
63513498266Sopenharmony_ci  if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
63613498266Sopenharmony_ci     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {
63713498266Sopenharmony_ci#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
63813498266Sopenharmony_ci#define MAX_PORT_LEN 8
63913498266Sopenharmony_ci    WCHAR namebuf[MAX_NAME_LEN];
64013498266Sopenharmony_ci    WCHAR portbuf[MAX_PORT_LEN];
64113498266Sopenharmony_ci    /* calculate required length */
64213498266Sopenharmony_ci    int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
64313498266Sopenharmony_ci                                    -1, NULL, 0);
64413498266Sopenharmony_ci    if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
64513498266Sopenharmony_ci      /* do utf8 conversion */
64613498266Sopenharmony_ci      w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
64713498266Sopenharmony_ci      if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
64813498266Sopenharmony_ci        swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
64913498266Sopenharmony_ci        td->tsd.w8.hints.ai_family = hints->ai_family;
65013498266Sopenharmony_ci        td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
65113498266Sopenharmony_ci        td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
65213498266Sopenharmony_ci        if(!td->complete_ev) {
65313498266Sopenharmony_ci          /* failed to start, mark it as done here for proper cleanup. */
65413498266Sopenharmony_ci          td->tsd.done = 1;
65513498266Sopenharmony_ci          goto err_exit;
65613498266Sopenharmony_ci        }
65713498266Sopenharmony_ci        err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
65813498266Sopenharmony_ci                                  NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
65913498266Sopenharmony_ci                                  NULL, &td->tsd.w8.overlapped,
66013498266Sopenharmony_ci                                  &query_complete, &td->tsd.w8.cancel_ev);
66113498266Sopenharmony_ci        if(err != WSA_IO_PENDING)
66213498266Sopenharmony_ci          query_complete(err, 0, &td->tsd.w8.overlapped);
66313498266Sopenharmony_ci        return TRUE;
66413498266Sopenharmony_ci      }
66513498266Sopenharmony_ci    }
66613498266Sopenharmony_ci  }
66713498266Sopenharmony_ci#endif
66813498266Sopenharmony_ci
66913498266Sopenharmony_ci#ifdef HAVE_GETADDRINFO
67013498266Sopenharmony_ci  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
67113498266Sopenharmony_ci#else
67213498266Sopenharmony_ci  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
67313498266Sopenharmony_ci#endif
67413498266Sopenharmony_ci
67513498266Sopenharmony_ci  if(!td->thread_hnd) {
67613498266Sopenharmony_ci    /* The thread never started, so mark it as done here for proper cleanup. */
67713498266Sopenharmony_ci    td->tsd.done = 1;
67813498266Sopenharmony_ci    err = errno;
67913498266Sopenharmony_ci    goto err_exit;
68013498266Sopenharmony_ci  }
68113498266Sopenharmony_ci
68213498266Sopenharmony_ci  return TRUE;
68313498266Sopenharmony_ci
68413498266Sopenharmony_cierr_exit:
68513498266Sopenharmony_ci  destroy_async_data(asp);
68613498266Sopenharmony_ci
68713498266Sopenharmony_cierrno_exit:
68813498266Sopenharmony_ci  errno = err;
68913498266Sopenharmony_ci  return FALSE;
69013498266Sopenharmony_ci}
69113498266Sopenharmony_ci
69213498266Sopenharmony_ci/*
69313498266Sopenharmony_ci * 'entry' may be NULL and then no data is returned
69413498266Sopenharmony_ci */
69513498266Sopenharmony_cistatic CURLcode thread_wait_resolv(struct Curl_easy *data,
69613498266Sopenharmony_ci                                   struct Curl_dns_entry **entry,
69713498266Sopenharmony_ci                                   bool report)
69813498266Sopenharmony_ci{
69913498266Sopenharmony_ci  struct thread_data *td;
70013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
70113498266Sopenharmony_ci
70213498266Sopenharmony_ci  DEBUGASSERT(data);
70313498266Sopenharmony_ci  td = data->state.async.tdata;
70413498266Sopenharmony_ci  DEBUGASSERT(td);
70513498266Sopenharmony_ci#ifdef _WIN32
70613498266Sopenharmony_ci  DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
70713498266Sopenharmony_ci#else
70813498266Sopenharmony_ci  DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
70913498266Sopenharmony_ci#endif
71013498266Sopenharmony_ci
71113498266Sopenharmony_ci  /* wait for the thread to resolve the name */
71213498266Sopenharmony_ci#ifdef _WIN32
71313498266Sopenharmony_ci  if(td->complete_ev) {
71413498266Sopenharmony_ci    WaitForSingleObject(td->complete_ev, INFINITE);
71513498266Sopenharmony_ci    CloseHandle(td->complete_ev);
71613498266Sopenharmony_ci    if(entry)
71713498266Sopenharmony_ci      result = getaddrinfo_complete(data);
71813498266Sopenharmony_ci  }
71913498266Sopenharmony_ci  else
72013498266Sopenharmony_ci#endif
72113498266Sopenharmony_ci  if(Curl_thread_join(&td->thread_hnd)) {
72213498266Sopenharmony_ci    if(entry)
72313498266Sopenharmony_ci      result = getaddrinfo_complete(data);
72413498266Sopenharmony_ci  }
72513498266Sopenharmony_ci  else
72613498266Sopenharmony_ci    DEBUGASSERT(0);
72713498266Sopenharmony_ci
72813498266Sopenharmony_ci  data->state.async.done = TRUE;
72913498266Sopenharmony_ci
73013498266Sopenharmony_ci  if(entry)
73113498266Sopenharmony_ci    *entry = data->state.async.dns;
73213498266Sopenharmony_ci
73313498266Sopenharmony_ci  if(!data->state.async.dns && report)
73413498266Sopenharmony_ci    /* a name was not resolved, report error */
73513498266Sopenharmony_ci    result = Curl_resolver_error(data);
73613498266Sopenharmony_ci
73713498266Sopenharmony_ci  destroy_async_data(&data->state.async);
73813498266Sopenharmony_ci
73913498266Sopenharmony_ci  if(!data->state.async.dns && report)
74013498266Sopenharmony_ci    connclose(data->conn, "asynch resolve failed");
74113498266Sopenharmony_ci
74213498266Sopenharmony_ci  return result;
74313498266Sopenharmony_ci}
74413498266Sopenharmony_ci
74513498266Sopenharmony_ci
74613498266Sopenharmony_ci/*
74713498266Sopenharmony_ci * Until we gain a way to signal the resolver threads to stop early, we must
74813498266Sopenharmony_ci * simply wait for them and ignore their results.
74913498266Sopenharmony_ci */
75013498266Sopenharmony_civoid Curl_resolver_kill(struct Curl_easy *data)
75113498266Sopenharmony_ci{
75213498266Sopenharmony_ci  struct thread_data *td = data->state.async.tdata;
75313498266Sopenharmony_ci
75413498266Sopenharmony_ci  /* If we're still resolving, we must wait for the threads to fully clean up,
75513498266Sopenharmony_ci     unfortunately.  Otherwise, we can simply cancel to clean up any resolver
75613498266Sopenharmony_ci     data. */
75713498266Sopenharmony_ci  if(td && td->thread_hnd != curl_thread_t_null
75813498266Sopenharmony_ci     && (data->set.quick_exit != 1L))
75913498266Sopenharmony_ci    (void)thread_wait_resolv(data, NULL, FALSE);
76013498266Sopenharmony_ci  else
76113498266Sopenharmony_ci    Curl_resolver_cancel(data);
76213498266Sopenharmony_ci}
76313498266Sopenharmony_ci
76413498266Sopenharmony_ci/*
76513498266Sopenharmony_ci * Curl_resolver_wait_resolv()
76613498266Sopenharmony_ci *
76713498266Sopenharmony_ci * Waits for a resolve to finish. This function should be avoided since using
76813498266Sopenharmony_ci * this risk getting the multi interface to "hang".
76913498266Sopenharmony_ci *
77013498266Sopenharmony_ci * If 'entry' is non-NULL, make it point to the resolved dns entry
77113498266Sopenharmony_ci *
77213498266Sopenharmony_ci * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
77313498266Sopenharmony_ci * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
77413498266Sopenharmony_ci *
77513498266Sopenharmony_ci * This is the version for resolves-in-a-thread.
77613498266Sopenharmony_ci */
77713498266Sopenharmony_ciCURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
77813498266Sopenharmony_ci                                   struct Curl_dns_entry **entry)
77913498266Sopenharmony_ci{
78013498266Sopenharmony_ci  return thread_wait_resolv(data, entry, TRUE);
78113498266Sopenharmony_ci}
78213498266Sopenharmony_ci
78313498266Sopenharmony_ci/*
78413498266Sopenharmony_ci * Curl_resolver_is_resolved() is called repeatedly to check if a previous
78513498266Sopenharmony_ci * name resolve request has completed. It should also make sure to time-out if
78613498266Sopenharmony_ci * the operation seems to take too long.
78713498266Sopenharmony_ci */
78813498266Sopenharmony_ciCURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
78913498266Sopenharmony_ci                                   struct Curl_dns_entry **entry)
79013498266Sopenharmony_ci{
79113498266Sopenharmony_ci  struct thread_data *td = data->state.async.tdata;
79213498266Sopenharmony_ci  int done = 0;
79313498266Sopenharmony_ci
79413498266Sopenharmony_ci  DEBUGASSERT(entry);
79513498266Sopenharmony_ci  *entry = NULL;
79613498266Sopenharmony_ci
79713498266Sopenharmony_ci  if(!td) {
79813498266Sopenharmony_ci    DEBUGASSERT(td);
79913498266Sopenharmony_ci    return CURLE_COULDNT_RESOLVE_HOST;
80013498266Sopenharmony_ci  }
80113498266Sopenharmony_ci
80213498266Sopenharmony_ci  Curl_mutex_acquire(td->tsd.mtx);
80313498266Sopenharmony_ci  done = td->tsd.done;
80413498266Sopenharmony_ci  Curl_mutex_release(td->tsd.mtx);
80513498266Sopenharmony_ci
80613498266Sopenharmony_ci  if(done) {
80713498266Sopenharmony_ci    getaddrinfo_complete(data);
80813498266Sopenharmony_ci
80913498266Sopenharmony_ci    if(!data->state.async.dns) {
81013498266Sopenharmony_ci      CURLcode result = Curl_resolver_error(data);
81113498266Sopenharmony_ci      destroy_async_data(&data->state.async);
81213498266Sopenharmony_ci      return result;
81313498266Sopenharmony_ci    }
81413498266Sopenharmony_ci    destroy_async_data(&data->state.async);
81513498266Sopenharmony_ci    *entry = data->state.async.dns;
81613498266Sopenharmony_ci  }
81713498266Sopenharmony_ci  else {
81813498266Sopenharmony_ci    /* poll for name lookup done with exponential backoff up to 250ms */
81913498266Sopenharmony_ci    /* should be fine even if this converts to 32 bit */
82013498266Sopenharmony_ci    timediff_t elapsed = Curl_timediff(Curl_now(),
82113498266Sopenharmony_ci                                       data->progress.t_startsingle);
82213498266Sopenharmony_ci    if(elapsed < 0)
82313498266Sopenharmony_ci      elapsed = 0;
82413498266Sopenharmony_ci
82513498266Sopenharmony_ci    if(td->poll_interval == 0)
82613498266Sopenharmony_ci      /* Start at 1ms poll interval */
82713498266Sopenharmony_ci      td->poll_interval = 1;
82813498266Sopenharmony_ci    else if(elapsed >= td->interval_end)
82913498266Sopenharmony_ci      /* Back-off exponentially if last interval expired  */
83013498266Sopenharmony_ci      td->poll_interval *= 2;
83113498266Sopenharmony_ci
83213498266Sopenharmony_ci    if(td->poll_interval > 250)
83313498266Sopenharmony_ci      td->poll_interval = 250;
83413498266Sopenharmony_ci
83513498266Sopenharmony_ci    td->interval_end = elapsed + td->poll_interval;
83613498266Sopenharmony_ci    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
83713498266Sopenharmony_ci  }
83813498266Sopenharmony_ci
83913498266Sopenharmony_ci  return CURLE_OK;
84013498266Sopenharmony_ci}
84113498266Sopenharmony_ci
84213498266Sopenharmony_ciint Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
84313498266Sopenharmony_ci{
84413498266Sopenharmony_ci  int ret_val = 0;
84513498266Sopenharmony_ci  timediff_t milli;
84613498266Sopenharmony_ci  timediff_t ms;
84713498266Sopenharmony_ci  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
84813498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
84913498266Sopenharmony_ci  struct thread_data *td = data->state.async.tdata;
85013498266Sopenharmony_ci#else
85113498266Sopenharmony_ci  (void)socks;
85213498266Sopenharmony_ci#endif
85313498266Sopenharmony_ci
85413498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
85513498266Sopenharmony_ci  if(td) {
85613498266Sopenharmony_ci    /* return read fd to client for polling the DNS resolution status */
85713498266Sopenharmony_ci    socks[0] = td->tsd.sock_pair[0];
85813498266Sopenharmony_ci    td->tsd.data = data;
85913498266Sopenharmony_ci    ret_val = GETSOCK_READSOCK(0);
86013498266Sopenharmony_ci  }
86113498266Sopenharmony_ci  else {
86213498266Sopenharmony_ci#endif
86313498266Sopenharmony_ci    ms = Curl_timediff(Curl_now(), reslv->start);
86413498266Sopenharmony_ci    if(ms < 3)
86513498266Sopenharmony_ci      milli = 0;
86613498266Sopenharmony_ci    else if(ms <= 50)
86713498266Sopenharmony_ci      milli = ms/3;
86813498266Sopenharmony_ci    else if(ms <= 250)
86913498266Sopenharmony_ci      milli = 50;
87013498266Sopenharmony_ci    else
87113498266Sopenharmony_ci      milli = 200;
87213498266Sopenharmony_ci    Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
87313498266Sopenharmony_ci#ifndef CURL_DISABLE_SOCKETPAIR
87413498266Sopenharmony_ci  }
87513498266Sopenharmony_ci#endif
87613498266Sopenharmony_ci
87713498266Sopenharmony_ci
87813498266Sopenharmony_ci  return ret_val;
87913498266Sopenharmony_ci}
88013498266Sopenharmony_ci
88113498266Sopenharmony_ci#ifndef HAVE_GETADDRINFO
88213498266Sopenharmony_ci/*
88313498266Sopenharmony_ci * Curl_getaddrinfo() - for platforms without getaddrinfo
88413498266Sopenharmony_ci */
88513498266Sopenharmony_cistruct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
88613498266Sopenharmony_ci                                                const char *hostname,
88713498266Sopenharmony_ci                                                int port,
88813498266Sopenharmony_ci                                                int *waitp)
88913498266Sopenharmony_ci{
89013498266Sopenharmony_ci  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
89113498266Sopenharmony_ci
89213498266Sopenharmony_ci  *waitp = 0; /* default to synchronous response */
89313498266Sopenharmony_ci
89413498266Sopenharmony_ci  reslv->start = Curl_now();
89513498266Sopenharmony_ci
89613498266Sopenharmony_ci  /* fire up a new resolver thread! */
89713498266Sopenharmony_ci  if(init_resolve_thread(data, hostname, port, NULL)) {
89813498266Sopenharmony_ci    *waitp = 1; /* expect asynchronous response */
89913498266Sopenharmony_ci    return NULL;
90013498266Sopenharmony_ci  }
90113498266Sopenharmony_ci
90213498266Sopenharmony_ci  failf(data, "getaddrinfo() thread failed");
90313498266Sopenharmony_ci
90413498266Sopenharmony_ci  return NULL;
90513498266Sopenharmony_ci}
90613498266Sopenharmony_ci
90713498266Sopenharmony_ci#else /* !HAVE_GETADDRINFO */
90813498266Sopenharmony_ci
90913498266Sopenharmony_ci/*
91013498266Sopenharmony_ci * Curl_resolver_getaddrinfo() - for getaddrinfo
91113498266Sopenharmony_ci */
91213498266Sopenharmony_cistruct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
91313498266Sopenharmony_ci                                                const char *hostname,
91413498266Sopenharmony_ci                                                int port,
91513498266Sopenharmony_ci                                                int *waitp)
91613498266Sopenharmony_ci{
91713498266Sopenharmony_ci  struct addrinfo hints;
91813498266Sopenharmony_ci  int pf = PF_INET;
91913498266Sopenharmony_ci  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
92013498266Sopenharmony_ci
92113498266Sopenharmony_ci  *waitp = 0; /* default to synchronous response */
92213498266Sopenharmony_ci
92313498266Sopenharmony_ci#ifdef CURLRES_IPV6
92413498266Sopenharmony_ci  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
92513498266Sopenharmony_ci    /* The stack seems to be IPv6-enabled */
92613498266Sopenharmony_ci    if(data->conn->ip_version == CURL_IPRESOLVE_V6)
92713498266Sopenharmony_ci      pf = PF_INET6;
92813498266Sopenharmony_ci    else
92913498266Sopenharmony_ci      pf = PF_UNSPEC;
93013498266Sopenharmony_ci  }
93113498266Sopenharmony_ci#endif /* CURLRES_IPV6 */
93213498266Sopenharmony_ci
93313498266Sopenharmony_ci  memset(&hints, 0, sizeof(hints));
93413498266Sopenharmony_ci  hints.ai_family = pf;
93513498266Sopenharmony_ci  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
93613498266Sopenharmony_ci    SOCK_STREAM : SOCK_DGRAM;
93713498266Sopenharmony_ci
93813498266Sopenharmony_ci  reslv->start = Curl_now();
93913498266Sopenharmony_ci  /* fire up a new resolver thread! */
94013498266Sopenharmony_ci  if(init_resolve_thread(data, hostname, port, &hints)) {
94113498266Sopenharmony_ci    *waitp = 1; /* expect asynchronous response */
94213498266Sopenharmony_ci    return NULL;
94313498266Sopenharmony_ci  }
94413498266Sopenharmony_ci
94513498266Sopenharmony_ci  failf(data, "getaddrinfo() thread failed to start");
94613498266Sopenharmony_ci  return NULL;
94713498266Sopenharmony_ci
94813498266Sopenharmony_ci}
94913498266Sopenharmony_ci
95013498266Sopenharmony_ci#endif /* !HAVE_GETADDRINFO */
95113498266Sopenharmony_ci
95213498266Sopenharmony_ciCURLcode Curl_set_dns_servers(struct Curl_easy *data,
95313498266Sopenharmony_ci                              char *servers)
95413498266Sopenharmony_ci{
95513498266Sopenharmony_ci  (void)data;
95613498266Sopenharmony_ci  (void)servers;
95713498266Sopenharmony_ci  return CURLE_NOT_BUILT_IN;
95813498266Sopenharmony_ci
95913498266Sopenharmony_ci}
96013498266Sopenharmony_ci
96113498266Sopenharmony_ciCURLcode Curl_set_dns_interface(struct Curl_easy *data,
96213498266Sopenharmony_ci                                const char *interf)
96313498266Sopenharmony_ci{
96413498266Sopenharmony_ci  (void)data;
96513498266Sopenharmony_ci  (void)interf;
96613498266Sopenharmony_ci  return CURLE_NOT_BUILT_IN;
96713498266Sopenharmony_ci}
96813498266Sopenharmony_ci
96913498266Sopenharmony_ciCURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
97013498266Sopenharmony_ci                                const char *local_ip4)
97113498266Sopenharmony_ci{
97213498266Sopenharmony_ci  (void)data;
97313498266Sopenharmony_ci  (void)local_ip4;
97413498266Sopenharmony_ci  return CURLE_NOT_BUILT_IN;
97513498266Sopenharmony_ci}
97613498266Sopenharmony_ci
97713498266Sopenharmony_ciCURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
97813498266Sopenharmony_ci                                const char *local_ip6)
97913498266Sopenharmony_ci{
98013498266Sopenharmony_ci  (void)data;
98113498266Sopenharmony_ci  (void)local_ip6;
98213498266Sopenharmony_ci  return CURLE_NOT_BUILT_IN;
98313498266Sopenharmony_ci}
98413498266Sopenharmony_ci
98513498266Sopenharmony_ci#endif /* CURLRES_THREADED */
986