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