asyn-thread.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #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 "system_win32.h"
  52. #include "urldata.h"
  53. #include "sendf.h"
  54. #include "hostip.h"
  55. #include "hash.h"
  56. #include "share.h"
  57. #include "url.h"
  58. #include "multiif.h"
  59. #include "inet_ntop.h"
  60. #include "curl_threads.h"
  61. #include "connect.h"
  62. /* The last 3 #include files should be in this order */
  63. #include "curl_printf.h"
  64. #include "curl_memory.h"
  65. #include "memdebug.h"
  66. struct resdata {
  67. struct curltime start;
  68. };
  69. /*
  70. * Curl_resolver_global_init()
  71. * Called from curl_global_init() to initialize global resolver environment.
  72. * Does nothing here.
  73. */
  74. int Curl_resolver_global_init(void)
  75. {
  76. return CURLE_OK;
  77. }
  78. /*
  79. * Curl_resolver_global_cleanup()
  80. * Called from curl_global_cleanup() to destroy global resolver environment.
  81. * Does nothing here.
  82. */
  83. void Curl_resolver_global_cleanup(void)
  84. {
  85. }
  86. /*
  87. * Curl_resolver_init()
  88. * Called from curl_easy_init() -> Curl_open() to initialize resolver
  89. * URL-state specific environment ('resolver' member of the UrlState
  90. * structure).
  91. */
  92. CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
  93. {
  94. (void)easy;
  95. *resolver = calloc(1, sizeof(struct resdata));
  96. if(!*resolver)
  97. return CURLE_OUT_OF_MEMORY;
  98. return CURLE_OK;
  99. }
  100. /*
  101. * Curl_resolver_cleanup()
  102. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
  103. * URL-state specific environment ('resolver' member of the UrlState
  104. * structure).
  105. */
  106. void Curl_resolver_cleanup(void *resolver)
  107. {
  108. free(resolver);
  109. }
  110. /*
  111. * Curl_resolver_duphandle()
  112. * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
  113. * environment ('resolver' member of the UrlState structure).
  114. */
  115. CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
  116. {
  117. (void)from;
  118. return Curl_resolver_init(easy, to);
  119. }
  120. static void destroy_async_data(struct Curl_async *);
  121. /*
  122. * Cancel all possibly still on-going resolves for this connection.
  123. */
  124. void Curl_resolver_cancel(struct Curl_easy *data)
  125. {
  126. destroy_async_data(&data->state.async);
  127. }
  128. /* This function is used to init a threaded resolve */
  129. static bool init_resolve_thread(struct Curl_easy *data,
  130. const char *hostname, int port,
  131. const struct addrinfo *hints);
  132. #ifdef _WIN32
  133. /* Thread sync data used by GetAddrInfoExW for win8+ */
  134. struct thread_sync_data_w8
  135. {
  136. OVERLAPPED overlapped;
  137. ADDRINFOEXW_ *res;
  138. HANDLE cancel_ev;
  139. ADDRINFOEXW_ hints;
  140. };
  141. #endif
  142. /* Data for synchronization between resolver thread and its parent */
  143. struct thread_sync_data {
  144. #ifdef _WIN32
  145. struct thread_sync_data_w8 w8;
  146. #endif
  147. curl_mutex_t *mtx;
  148. int done;
  149. int port;
  150. char *hostname; /* hostname to resolve, Curl_async.hostname
  151. duplicate */
  152. #ifndef CURL_DISABLE_SOCKETPAIR
  153. struct Curl_easy *data;
  154. curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
  155. #endif
  156. int sock_error;
  157. struct Curl_addrinfo *res;
  158. #ifdef HAVE_GETADDRINFO
  159. struct addrinfo hints;
  160. #endif
  161. struct thread_data *td; /* for thread-self cleanup */
  162. };
  163. struct thread_data {
  164. #ifdef _WIN32
  165. HANDLE complete_ev;
  166. #endif
  167. curl_thread_t thread_hnd;
  168. unsigned int poll_interval;
  169. timediff_t interval_end;
  170. struct thread_sync_data tsd;
  171. };
  172. static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
  173. {
  174. return &(data->state.async.tdata->tsd);
  175. }
  176. /* Destroy resolver thread synchronization data */
  177. static
  178. void destroy_thread_sync_data(struct thread_sync_data *tsd)
  179. {
  180. if(tsd->mtx) {
  181. Curl_mutex_destroy(tsd->mtx);
  182. free(tsd->mtx);
  183. }
  184. free(tsd->hostname);
  185. if(tsd->res)
  186. Curl_freeaddrinfo(tsd->res);
  187. #ifndef CURL_DISABLE_SOCKETPAIR
  188. /*
  189. * close one end of the socket pair (may be done in resolver thread);
  190. * the other end (for reading) is always closed in the parent thread.
  191. */
  192. if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
  193. wakeup_close(tsd->sock_pair[1]);
  194. }
  195. #endif
  196. memset(tsd, 0, sizeof(*tsd));
  197. }
  198. /* Initialize resolver thread synchronization data */
  199. static
  200. int init_thread_sync_data(struct thread_data *td,
  201. const char *hostname,
  202. int port,
  203. const struct addrinfo *hints)
  204. {
  205. struct thread_sync_data *tsd = &td->tsd;
  206. memset(tsd, 0, sizeof(*tsd));
  207. tsd->td = td;
  208. tsd->port = port;
  209. /* Treat the request as done until the thread actually starts so any early
  210. * cleanup gets done properly.
  211. */
  212. tsd->done = 1;
  213. #ifdef HAVE_GETADDRINFO
  214. DEBUGASSERT(hints);
  215. tsd->hints = *hints;
  216. #else
  217. (void) hints;
  218. #endif
  219. tsd->mtx = malloc(sizeof(curl_mutex_t));
  220. if(!tsd->mtx)
  221. goto err_exit;
  222. Curl_mutex_init(tsd->mtx);
  223. #ifndef CURL_DISABLE_SOCKETPAIR
  224. /* create socket pair or pipe */
  225. if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
  226. tsd->sock_pair[0] = CURL_SOCKET_BAD;
  227. tsd->sock_pair[1] = CURL_SOCKET_BAD;
  228. goto err_exit;
  229. }
  230. #endif
  231. tsd->sock_error = CURL_ASYNC_SUCCESS;
  232. /* Copying hostname string because original can be destroyed by parent
  233. * thread during gethostbyname execution.
  234. */
  235. tsd->hostname = strdup(hostname);
  236. if(!tsd->hostname)
  237. goto err_exit;
  238. return 1;
  239. err_exit:
  240. #ifndef CURL_DISABLE_SOCKETPAIR
  241. if(tsd->sock_pair[0] != CURL_SOCKET_BAD) {
  242. wakeup_close(tsd->sock_pair[0]);
  243. tsd->sock_pair[0] = CURL_SOCKET_BAD;
  244. }
  245. #endif
  246. destroy_thread_sync_data(tsd);
  247. return 0;
  248. }
  249. static CURLcode getaddrinfo_complete(struct Curl_easy *data)
  250. {
  251. struct thread_sync_data *tsd = conn_thread_sync_data(data);
  252. CURLcode result;
  253. result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
  254. /* The tsd->res structure has been copied to async.dns and perhaps the DNS
  255. cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
  256. */
  257. tsd->res = NULL;
  258. return result;
  259. }
  260. #ifdef _WIN32
  261. static VOID WINAPI
  262. query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
  263. {
  264. size_t ss_size;
  265. const ADDRINFOEXW_ *ai;
  266. struct Curl_addrinfo *ca;
  267. struct Curl_addrinfo *cafirst = NULL;
  268. struct Curl_addrinfo *calast = NULL;
  269. #ifndef CURL_DISABLE_SOCKETPAIR
  270. #ifdef USE_EVENTFD
  271. const void *buf;
  272. const uint64_t val = 1;
  273. #else
  274. char buf[1];
  275. #endif
  276. #endif
  277. #ifdef __clang__
  278. #pragma clang diagnostic push
  279. #pragma clang diagnostic ignored "-Wcast-align"
  280. #endif
  281. struct thread_sync_data *tsd =
  282. CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
  283. #ifdef __clang__
  284. #pragma clang diagnostic pop
  285. #endif
  286. struct thread_data *td = tsd->td;
  287. const ADDRINFOEXW_ *res = tsd->w8.res;
  288. int error = (int)err;
  289. (void)bytes;
  290. if(error == ERROR_SUCCESS) {
  291. /* traverse the addrinfo list */
  292. for(ai = res; ai != NULL; ai = ai->ai_next) {
  293. size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
  294. /* ignore elements with unsupported address family, */
  295. /* settle family-specific sockaddr structure size. */
  296. if(ai->ai_family == AF_INET)
  297. ss_size = sizeof(struct sockaddr_in);
  298. #ifdef USE_IPV6
  299. else if(ai->ai_family == AF_INET6)
  300. ss_size = sizeof(struct sockaddr_in6);
  301. #endif
  302. else
  303. continue;
  304. /* ignore elements without required address info */
  305. if(!ai->ai_addr || !(ai->ai_addrlen > 0))
  306. continue;
  307. /* ignore elements with bogus address size */
  308. if((size_t)ai->ai_addrlen < ss_size)
  309. continue;
  310. ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
  311. if(!ca) {
  312. error = EAI_MEMORY;
  313. break;
  314. }
  315. /* copy each structure member individually, member ordering, */
  316. /* size, or padding might be different for each platform. */
  317. ca->ai_flags = ai->ai_flags;
  318. ca->ai_family = ai->ai_family;
  319. ca->ai_socktype = ai->ai_socktype;
  320. ca->ai_protocol = ai->ai_protocol;
  321. ca->ai_addrlen = (curl_socklen_t)ss_size;
  322. ca->ai_addr = NULL;
  323. ca->ai_canonname = NULL;
  324. ca->ai_next = NULL;
  325. ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
  326. memcpy(ca->ai_addr, ai->ai_addr, ss_size);
  327. if(namelen) {
  328. size_t i;
  329. ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
  330. for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
  331. ca->ai_canonname[i] = (char)ai->ai_canonname[i];
  332. ca->ai_canonname[namelen] = '\0';
  333. }
  334. /* if the return list is empty, this becomes the first element */
  335. if(!cafirst)
  336. cafirst = ca;
  337. /* add this element last in the return list */
  338. if(calast)
  339. calast->ai_next = ca;
  340. calast = ca;
  341. }
  342. /* if we failed, also destroy the Curl_addrinfo list */
  343. if(error) {
  344. Curl_freeaddrinfo(cafirst);
  345. cafirst = NULL;
  346. }
  347. else if(!cafirst) {
  348. #ifdef EAI_NONAME
  349. /* rfc3493 conformant */
  350. error = EAI_NONAME;
  351. #else
  352. /* rfc3493 obsoleted */
  353. error = EAI_NODATA;
  354. #endif
  355. #ifdef USE_WINSOCK
  356. SET_SOCKERRNO(error);
  357. #endif
  358. }
  359. tsd->res = cafirst;
  360. }
  361. if(tsd->w8.res) {
  362. Curl_FreeAddrInfoExW(tsd->w8.res);
  363. tsd->w8.res = NULL;
  364. }
  365. if(error) {
  366. tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
  367. if(tsd->sock_error == 0)
  368. tsd->sock_error = RESOLVER_ENOMEM;
  369. }
  370. else {
  371. Curl_addrinfo_set_port(tsd->res, tsd->port);
  372. }
  373. Curl_mutex_acquire(tsd->mtx);
  374. if(tsd->done) {
  375. /* too late, gotta clean up the mess */
  376. Curl_mutex_release(tsd->mtx);
  377. destroy_thread_sync_data(tsd);
  378. free(td);
  379. }
  380. else {
  381. #ifndef CURL_DISABLE_SOCKETPAIR
  382. if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
  383. #ifdef USE_EVENTFD
  384. buf = &val;
  385. #else
  386. buf[0] = 1;
  387. #endif
  388. /* DNS has been resolved, signal client task */
  389. if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
  390. /* update sock_erro to errno */
  391. tsd->sock_error = SOCKERRNO;
  392. }
  393. }
  394. #endif
  395. tsd->done = 1;
  396. Curl_mutex_release(tsd->mtx);
  397. if(td->complete_ev)
  398. SetEvent(td->complete_ev); /* Notify caller that the query completed */
  399. }
  400. }
  401. #endif
  402. #ifdef HAVE_GETADDRINFO
  403. /*
  404. * getaddrinfo_thread() resolves a name and then exits.
  405. *
  406. * For builds without ARES, but with USE_IPV6, create a resolver thread
  407. * and wait on it.
  408. */
  409. static
  410. #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
  411. DWORD
  412. #else
  413. unsigned int
  414. #endif
  415. CURL_STDCALL getaddrinfo_thread(void *arg)
  416. {
  417. struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  418. struct thread_data *td = tsd->td;
  419. char service[12];
  420. int rc;
  421. #ifndef CURL_DISABLE_SOCKETPAIR
  422. #ifdef USE_EVENTFD
  423. const void *buf;
  424. const uint64_t val = 1;
  425. #else
  426. char buf[1];
  427. #endif
  428. #endif
  429. msnprintf(service, sizeof(service), "%d", tsd->port);
  430. rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
  431. if(rc) {
  432. tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
  433. if(tsd->sock_error == 0)
  434. tsd->sock_error = RESOLVER_ENOMEM;
  435. }
  436. else {
  437. Curl_addrinfo_set_port(tsd->res, tsd->port);
  438. }
  439. Curl_mutex_acquire(tsd->mtx);
  440. if(tsd->done) {
  441. /* too late, gotta clean up the mess */
  442. Curl_mutex_release(tsd->mtx);
  443. destroy_thread_sync_data(tsd);
  444. free(td);
  445. }
  446. else {
  447. #ifndef CURL_DISABLE_SOCKETPAIR
  448. if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
  449. #ifdef USE_EVENTFD
  450. buf = &val;
  451. #else
  452. buf[0] = 1;
  453. #endif
  454. /* DNS has been resolved, signal client task */
  455. if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
  456. /* update sock_erro to errno */
  457. tsd->sock_error = SOCKERRNO;
  458. }
  459. }
  460. #endif
  461. tsd->done = 1;
  462. Curl_mutex_release(tsd->mtx);
  463. }
  464. return 0;
  465. }
  466. #else /* HAVE_GETADDRINFO */
  467. /*
  468. * gethostbyname_thread() resolves a name and then exits.
  469. */
  470. static
  471. #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
  472. DWORD
  473. #else
  474. unsigned int
  475. #endif
  476. CURL_STDCALL gethostbyname_thread(void *arg)
  477. {
  478. struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  479. struct thread_data *td = tsd->td;
  480. tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
  481. if(!tsd->res) {
  482. tsd->sock_error = SOCKERRNO;
  483. if(tsd->sock_error == 0)
  484. tsd->sock_error = RESOLVER_ENOMEM;
  485. }
  486. Curl_mutex_acquire(tsd->mtx);
  487. if(tsd->done) {
  488. /* too late, gotta clean up the mess */
  489. Curl_mutex_release(tsd->mtx);
  490. destroy_thread_sync_data(tsd);
  491. free(td);
  492. }
  493. else {
  494. tsd->done = 1;
  495. Curl_mutex_release(tsd->mtx);
  496. }
  497. return 0;
  498. }
  499. #endif /* HAVE_GETADDRINFO */
  500. /*
  501. * destroy_async_data() cleans up async resolver data and thread handle.
  502. */
  503. static void destroy_async_data(struct Curl_async *async)
  504. {
  505. if(async->tdata) {
  506. struct thread_data *td = async->tdata;
  507. int done;
  508. #ifndef CURL_DISABLE_SOCKETPAIR
  509. curl_socket_t sock_rd = td->tsd.sock_pair[0];
  510. struct Curl_easy *data = td->tsd.data;
  511. #endif
  512. /*
  513. * if the thread is still blocking in the resolve syscall, detach it and
  514. * let the thread do the cleanup...
  515. */
  516. Curl_mutex_acquire(td->tsd.mtx);
  517. done = td->tsd.done;
  518. td->tsd.done = 1;
  519. Curl_mutex_release(td->tsd.mtx);
  520. if(!done) {
  521. #ifdef _WIN32
  522. if(td->complete_ev) {
  523. CloseHandle(td->complete_ev);
  524. td->complete_ev = NULL;
  525. }
  526. #endif
  527. if(td->thread_hnd != curl_thread_t_null) {
  528. Curl_thread_destroy(td->thread_hnd);
  529. td->thread_hnd = curl_thread_t_null;
  530. }
  531. }
  532. else {
  533. #ifdef _WIN32
  534. if(td->complete_ev) {
  535. Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
  536. WaitForSingleObject(td->complete_ev, INFINITE);
  537. CloseHandle(td->complete_ev);
  538. td->complete_ev = NULL;
  539. }
  540. #endif
  541. if(td->thread_hnd != curl_thread_t_null)
  542. Curl_thread_join(&td->thread_hnd);
  543. destroy_thread_sync_data(&td->tsd);
  544. free(async->tdata);
  545. }
  546. #ifndef CURL_DISABLE_SOCKETPAIR
  547. /*
  548. * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
  549. * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
  550. */
  551. Curl_multi_closed(data, sock_rd);
  552. wakeup_close(sock_rd);
  553. #endif
  554. }
  555. async->tdata = NULL;
  556. free(async->hostname);
  557. async->hostname = NULL;
  558. }
  559. /*
  560. * init_resolve_thread() starts a new thread that performs the actual
  561. * resolve. This function returns before the resolve is done.
  562. *
  563. * Returns FALSE in case of failure, otherwise TRUE.
  564. */
  565. static bool init_resolve_thread(struct Curl_easy *data,
  566. const char *hostname, int port,
  567. const struct addrinfo *hints)
  568. {
  569. struct thread_data *td = calloc(1, sizeof(struct thread_data));
  570. int err = ENOMEM;
  571. struct Curl_async *asp = &data->state.async;
  572. data->state.async.tdata = td;
  573. if(!td)
  574. goto errno_exit;
  575. asp->port = port;
  576. asp->done = FALSE;
  577. asp->status = 0;
  578. asp->dns = NULL;
  579. td->thread_hnd = curl_thread_t_null;
  580. #ifdef _WIN32
  581. td->complete_ev = NULL;
  582. #endif
  583. if(!init_thread_sync_data(td, hostname, port, hints)) {
  584. asp->tdata = NULL;
  585. free(td);
  586. goto errno_exit;
  587. }
  588. free(asp->hostname);
  589. asp->hostname = strdup(hostname);
  590. if(!asp->hostname)
  591. goto err_exit;
  592. /* The thread will set this to 1 when complete. */
  593. td->tsd.done = 0;
  594. #ifdef _WIN32
  595. if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
  596. Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW &&
  597. !Curl_win32_impersonating()) {
  598. #define MAX_NAME_LEN 256 /* max domain name is 253 chars */
  599. #define MAX_PORT_LEN 8
  600. WCHAR namebuf[MAX_NAME_LEN];
  601. WCHAR portbuf[MAX_PORT_LEN];
  602. /* calculate required length */
  603. int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
  604. -1, NULL, 0);
  605. if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
  606. /* do utf8 conversion */
  607. w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
  608. if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
  609. swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
  610. td->tsd.w8.hints.ai_family = hints->ai_family;
  611. td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
  612. td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
  613. if(!td->complete_ev) {
  614. /* failed to start, mark it as done here for proper cleanup. */
  615. td->tsd.done = 1;
  616. goto err_exit;
  617. }
  618. err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
  619. NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
  620. NULL, &td->tsd.w8.overlapped,
  621. &query_complete, &td->tsd.w8.cancel_ev);
  622. if(err != WSA_IO_PENDING)
  623. query_complete((DWORD)err, 0, &td->tsd.w8.overlapped);
  624. return TRUE;
  625. }
  626. }
  627. }
  628. #endif
  629. #ifdef HAVE_GETADDRINFO
  630. td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
  631. #else
  632. td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
  633. #endif
  634. if(td->thread_hnd == curl_thread_t_null) {
  635. /* The thread never started, so mark it as done here for proper cleanup. */
  636. td->tsd.done = 1;
  637. err = errno;
  638. goto err_exit;
  639. }
  640. return TRUE;
  641. err_exit:
  642. destroy_async_data(asp);
  643. errno_exit:
  644. errno = err;
  645. return FALSE;
  646. }
  647. /*
  648. * 'entry' may be NULL and then no data is returned
  649. */
  650. static CURLcode thread_wait_resolv(struct Curl_easy *data,
  651. struct Curl_dns_entry **entry,
  652. bool report)
  653. {
  654. struct thread_data *td;
  655. CURLcode result = CURLE_OK;
  656. DEBUGASSERT(data);
  657. td = data->state.async.tdata;
  658. DEBUGASSERT(td);
  659. #ifdef _WIN32
  660. DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
  661. #else
  662. DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
  663. #endif
  664. /* wait for the thread to resolve the name */
  665. #ifdef _WIN32
  666. if(td->complete_ev) {
  667. WaitForSingleObject(td->complete_ev, INFINITE);
  668. CloseHandle(td->complete_ev);
  669. td->complete_ev = NULL;
  670. if(entry)
  671. result = getaddrinfo_complete(data);
  672. }
  673. else
  674. #endif
  675. if(Curl_thread_join(&td->thread_hnd)) {
  676. if(entry)
  677. result = getaddrinfo_complete(data);
  678. }
  679. else
  680. DEBUGASSERT(0);
  681. data->state.async.done = TRUE;
  682. if(entry)
  683. *entry = data->state.async.dns;
  684. if(!data->state.async.dns && report)
  685. /* a name was not resolved, report error */
  686. result = Curl_resolver_error(data);
  687. destroy_async_data(&data->state.async);
  688. if(!data->state.async.dns && report)
  689. connclose(data->conn, "asynch resolve failed");
  690. return result;
  691. }
  692. /*
  693. * Until we gain a way to signal the resolver threads to stop early, we must
  694. * simply wait for them and ignore their results.
  695. */
  696. void Curl_resolver_kill(struct Curl_easy *data)
  697. {
  698. struct thread_data *td = data->state.async.tdata;
  699. /* If we're still resolving, we must wait for the threads to fully clean up,
  700. unfortunately. Otherwise, we can simply cancel to clean up any resolver
  701. data. */
  702. #ifdef _WIN32
  703. if(td && td->complete_ev) {
  704. Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
  705. (void)thread_wait_resolv(data, NULL, FALSE);
  706. }
  707. else
  708. #endif
  709. if(td && td->thread_hnd != curl_thread_t_null
  710. && (data->set.quick_exit != 1L))
  711. (void)thread_wait_resolv(data, NULL, FALSE);
  712. else
  713. Curl_resolver_cancel(data);
  714. }
  715. /*
  716. * Curl_resolver_wait_resolv()
  717. *
  718. * Waits for a resolve to finish. This function should be avoided since using
  719. * this risk getting the multi interface to "hang".
  720. *
  721. * If 'entry' is non-NULL, make it point to the resolved dns entry
  722. *
  723. * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  724. * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  725. *
  726. * This is the version for resolves-in-a-thread.
  727. */
  728. CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
  729. struct Curl_dns_entry **entry)
  730. {
  731. return thread_wait_resolv(data, entry, TRUE);
  732. }
  733. /*
  734. * Curl_resolver_is_resolved() is called repeatedly to check if a previous
  735. * name resolve request has completed. It should also make sure to time-out if
  736. * the operation seems to take too long.
  737. */
  738. CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
  739. struct Curl_dns_entry **entry)
  740. {
  741. struct thread_data *td = data->state.async.tdata;
  742. int done = 0;
  743. DEBUGASSERT(entry);
  744. *entry = NULL;
  745. if(!td) {
  746. DEBUGASSERT(td);
  747. return CURLE_COULDNT_RESOLVE_HOST;
  748. }
  749. Curl_mutex_acquire(td->tsd.mtx);
  750. done = td->tsd.done;
  751. Curl_mutex_release(td->tsd.mtx);
  752. if(done) {
  753. getaddrinfo_complete(data);
  754. if(!data->state.async.dns) {
  755. CURLcode result = Curl_resolver_error(data);
  756. destroy_async_data(&data->state.async);
  757. return result;
  758. }
  759. destroy_async_data(&data->state.async);
  760. *entry = data->state.async.dns;
  761. }
  762. else {
  763. /* poll for name lookup done with exponential backoff up to 250ms */
  764. /* should be fine even if this converts to 32 bit */
  765. timediff_t elapsed = Curl_timediff(Curl_now(),
  766. data->progress.t_startsingle);
  767. if(elapsed < 0)
  768. elapsed = 0;
  769. if(td->poll_interval == 0)
  770. /* Start at 1ms poll interval */
  771. td->poll_interval = 1;
  772. else if(elapsed >= td->interval_end)
  773. /* Back-off exponentially if last interval expired */
  774. td->poll_interval *= 2;
  775. if(td->poll_interval > 250)
  776. td->poll_interval = 250;
  777. td->interval_end = elapsed + td->poll_interval;
  778. Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
  779. }
  780. return CURLE_OK;
  781. }
  782. int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
  783. {
  784. int ret_val = 0;
  785. timediff_t milli;
  786. timediff_t ms;
  787. struct resdata *reslv = (struct resdata *)data->state.async.resolver;
  788. #ifndef CURL_DISABLE_SOCKETPAIR
  789. struct thread_data *td = data->state.async.tdata;
  790. #else
  791. (void)socks;
  792. #endif
  793. #ifndef CURL_DISABLE_SOCKETPAIR
  794. if(td) {
  795. /* return read fd to client for polling the DNS resolution status */
  796. socks[0] = td->tsd.sock_pair[0];
  797. td->tsd.data = data;
  798. ret_val = GETSOCK_READSOCK(0);
  799. }
  800. else {
  801. #endif
  802. ms = Curl_timediff(Curl_now(), reslv->start);
  803. if(ms < 3)
  804. milli = 0;
  805. else if(ms <= 50)
  806. milli = ms/3;
  807. else if(ms <= 250)
  808. milli = 50;
  809. else
  810. milli = 200;
  811. Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
  812. #ifndef CURL_DISABLE_SOCKETPAIR
  813. }
  814. #endif
  815. return ret_val;
  816. }
  817. #ifndef HAVE_GETADDRINFO
  818. /*
  819. * Curl_getaddrinfo() - for platforms without getaddrinfo
  820. */
  821. struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
  822. const char *hostname,
  823. int port,
  824. int *waitp)
  825. {
  826. struct resdata *reslv = (struct resdata *)data->state.async.resolver;
  827. *waitp = 0; /* default to synchronous response */
  828. reslv->start = Curl_now();
  829. /* fire up a new resolver thread! */
  830. if(init_resolve_thread(data, hostname, port, NULL)) {
  831. *waitp = 1; /* expect asynchronous response */
  832. return NULL;
  833. }
  834. failf(data, "getaddrinfo() thread failed");
  835. return NULL;
  836. }
  837. #else /* !HAVE_GETADDRINFO */
  838. /*
  839. * Curl_resolver_getaddrinfo() - for getaddrinfo
  840. */
  841. struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
  842. const char *hostname,
  843. int port,
  844. int *waitp)
  845. {
  846. struct addrinfo hints;
  847. int pf = PF_INET;
  848. struct resdata *reslv = (struct resdata *)data->state.async.resolver;
  849. *waitp = 0; /* default to synchronous response */
  850. #ifdef CURLRES_IPV6
  851. if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
  852. /* The stack seems to be IPv6-enabled */
  853. if(data->conn->ip_version == CURL_IPRESOLVE_V6)
  854. pf = PF_INET6;
  855. else
  856. pf = PF_UNSPEC;
  857. }
  858. #endif /* CURLRES_IPV6 */
  859. memset(&hints, 0, sizeof(hints));
  860. hints.ai_family = pf;
  861. hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
  862. SOCK_STREAM : SOCK_DGRAM;
  863. reslv->start = Curl_now();
  864. /* fire up a new resolver thread! */
  865. if(init_resolve_thread(data, hostname, port, &hints)) {
  866. *waitp = 1; /* expect asynchronous response */
  867. return NULL;
  868. }
  869. failf(data, "getaddrinfo() thread failed to start");
  870. return NULL;
  871. }
  872. #endif /* !HAVE_GETADDRINFO */
  873. CURLcode Curl_set_dns_servers(struct Curl_easy *data,
  874. char *servers)
  875. {
  876. (void)data;
  877. (void)servers;
  878. return CURLE_NOT_BUILT_IN;
  879. }
  880. CURLcode Curl_set_dns_interface(struct Curl_easy *data,
  881. const char *interf)
  882. {
  883. (void)data;
  884. (void)interf;
  885. return CURLE_NOT_BUILT_IN;
  886. }
  887. CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
  888. const char *local_ip4)
  889. {
  890. (void)data;
  891. (void)local_ip4;
  892. return CURLE_NOT_BUILT_IN;
  893. }
  894. CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
  895. const char *local_ip6)
  896. {
  897. (void)data;
  898. (void)local_ip6;
  899. return CURLE_NOT_BUILT_IN;
  900. }
  901. #endif /* CURLRES_THREADED */