asyn-thread.c 20 KB

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