asyn-thread.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2020, 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. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #include "socketpair.h"
  24. /***********************************************************************
  25. * Only for threaded name resolves builds
  26. **********************************************************************/
  27. #ifdef CURLRES_THREADED
  28. #ifdef HAVE_NETINET_IN_H
  29. #include <netinet/in.h>
  30. #endif
  31. #ifdef HAVE_NETDB_H
  32. #include <netdb.h>
  33. #endif
  34. #ifdef HAVE_ARPA_INET_H
  35. #include <arpa/inet.h>
  36. #endif
  37. #ifdef __VMS
  38. #include <in.h>
  39. #include <inet.h>
  40. #endif
  41. #if defined(USE_THREADS_POSIX)
  42. # ifdef HAVE_PTHREAD_H
  43. # include <pthread.h>
  44. # endif
  45. #elif defined(USE_THREADS_WIN32)
  46. # ifdef HAVE_PROCESS_H
  47. # include <process.h>
  48. # endif
  49. #endif
  50. #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
  51. #undef in_addr_t
  52. #define in_addr_t unsigned long
  53. #endif
  54. #ifdef HAVE_GETADDRINFO
  55. # define RESOLVER_ENOMEM EAI_MEMORY
  56. #else
  57. # define RESOLVER_ENOMEM ENOMEM
  58. #endif
  59. #include "urldata.h"
  60. #include "sendf.h"
  61. #include "hostip.h"
  62. #include "hash.h"
  63. #include "share.h"
  64. #include "strerror.h"
  65. #include "url.h"
  66. #include "multiif.h"
  67. #include "inet_ntop.h"
  68. #include "curl_threads.h"
  69. #include "connect.h"
  70. #include "socketpair.h"
  71. /* The last 3 #include files should be in this order */
  72. #include "curl_printf.h"
  73. #include "curl_memory.h"
  74. #include "memdebug.h"
  75. struct resdata {
  76. struct curltime start;
  77. };
  78. /* Doubly linked list of orphaned thread handles. */
  79. struct thread_list {
  80. curl_thread_t handle;
  81. /* 'exiting' is set true right before an orphaned thread exits.
  82. it should only be set by the orphaned thread from
  83. signal_orphan_is_exiting(). */
  84. bool exiting;
  85. struct thread_list *prev, *next;
  86. };
  87. /* Orphaned threads: A global list of resolver threads that could not be
  88. * completed in time and so they were abandoned by their parent. The list is
  89. * culled periodically by soon-to-be exiting orphans to wait on and destroy
  90. * those that are in the process of or have since exited, which is fast. On
  91. * global cleanup we wait on and destroy any remaining threads, which may be
  92. * slow but at that point we cannot defer it any longer.
  93. */
  94. struct orphaned_threads {
  95. /* Mutex to lock this. To avoid deadlock the thread-specific thread_sync_data
  96. mutex cannot be used as an inner lock when orphaned_threads is locked. */
  97. curl_mutex_t mutex;
  98. /* List of orphaned threads. */
  99. struct thread_list *first, *last;
  100. /* Count of threads in the list that are in the process of or have exited.
  101. (ie .exiting member of the thread_list item is set true) */
  102. size_t exiting_count;
  103. };
  104. static struct orphaned_threads orphaned_threads;
  105. /* Flags for wait_and_destroy_orphaned_threads().
  106. They're documented above the function definition. */
  107. #define WAIT_DESTROY_ALL (1<<0)
  108. #define WAIT_DESTROY_EXITING_THREADS_ONLY (1<<1)
  109. static void wait_and_destroy_orphaned_threads(int flags);
  110. static void signal_orphan_is_exiting(struct thread_list *orphan);
  111. /*
  112. * Curl_resolver_global_init()
  113. * Called from curl_global_init() to initialize global resolver environment.
  114. */
  115. int Curl_resolver_global_init(void)
  116. {
  117. memset(&orphaned_threads, 0, sizeof(orphaned_threads));
  118. if(Curl_mutex_init(&orphaned_threads.mutex))
  119. return CURLE_FAILED_INIT;
  120. return CURLE_OK;
  121. }
  122. /*
  123. * Curl_resolver_global_cleanup()
  124. * Called from curl_global_cleanup() to destroy global resolver environment.
  125. */
  126. void Curl_resolver_global_cleanup(void)
  127. {
  128. /* Take ownership of all orphaned resolver threads and wait for them to exit.
  129. This is necessary because the user may choose to unload the shared library
  130. that is/contains libcurl. */
  131. wait_and_destroy_orphaned_threads(WAIT_DESTROY_ALL);
  132. Curl_mutex_destroy(&orphaned_threads.mutex);
  133. }
  134. /*
  135. * Curl_resolver_init()
  136. * Called from curl_easy_init() -> Curl_open() to initialize resolver
  137. * URL-state specific environment ('resolver' member of the UrlState
  138. * structure).
  139. */
  140. CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
  141. {
  142. (void)easy;
  143. *resolver = calloc(1, sizeof(struct resdata));
  144. if(!*resolver)
  145. return CURLE_OUT_OF_MEMORY;
  146. return CURLE_OK;
  147. }
  148. /*
  149. * Curl_resolver_cleanup()
  150. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
  151. * URL-state specific environment ('resolver' member of the UrlState
  152. * structure).
  153. */
  154. void Curl_resolver_cleanup(void *resolver)
  155. {
  156. free(resolver);
  157. }
  158. /*
  159. * Curl_resolver_duphandle()
  160. * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
  161. * environment ('resolver' member of the UrlState structure).
  162. */
  163. CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
  164. {
  165. (void)from;
  166. return Curl_resolver_init(easy, to);
  167. }
  168. static void destroy_async_data(struct Curl_async *);
  169. /*
  170. * Cancel all possibly still on-going resolves for this connection.
  171. */
  172. void Curl_resolver_cancel(struct connectdata *conn)
  173. {
  174. destroy_async_data(&conn->async);
  175. }
  176. /* This function is used to init a threaded resolve */
  177. static bool init_resolve_thread(struct connectdata *conn,
  178. const char *hostname, int port,
  179. const struct addrinfo *hints);
  180. /* Data for synchronization between resolver thread and its parent */
  181. struct thread_sync_data {
  182. curl_mutex_t *mtx;
  183. int done;
  184. char *hostname; /* hostname to resolve, Curl_async.hostname
  185. duplicate */
  186. int port;
  187. #ifdef USE_SOCKETPAIR
  188. struct connectdata *conn;
  189. curl_socket_t sock_pair[2]; /* socket pair */
  190. #endif
  191. int sock_error;
  192. struct Curl_addrinfo *res;
  193. #ifdef HAVE_GETADDRINFO
  194. struct addrinfo hints;
  195. #endif
  196. struct thread_data *td; /* for thread-self cleanup */
  197. };
  198. struct thread_data {
  199. curl_thread_t thread_hnd;
  200. unsigned int poll_interval;
  201. timediff_t interval_end;
  202. struct thread_sync_data tsd;
  203. /* 'reserved' memory must be available in case the thread is orphaned */
  204. void *reserved;
  205. };
  206. static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
  207. {
  208. return &(conn->async.tdata->tsd);
  209. }
  210. /* Destroy resolver thread synchronization data */
  211. static
  212. void destroy_thread_sync_data(struct thread_sync_data *tsd)
  213. {
  214. if(tsd->mtx) {
  215. Curl_mutex_destroy(tsd->mtx);
  216. free(tsd->mtx);
  217. }
  218. free(tsd->hostname);
  219. if(tsd->res)
  220. Curl_freeaddrinfo(tsd->res);
  221. #ifdef USE_SOCKETPAIR
  222. /*
  223. * close one end of the socket pair (may be done in resolver thread);
  224. * the other end (for reading) is always closed in the parent thread.
  225. */
  226. if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
  227. sclose(tsd->sock_pair[1]);
  228. }
  229. #endif
  230. memset(tsd, 0, sizeof(*tsd));
  231. }
  232. /* Initialize resolver thread synchronization data */
  233. static
  234. int init_thread_sync_data(struct thread_data *td,
  235. const char *hostname,
  236. int port,
  237. const struct addrinfo *hints)
  238. {
  239. struct thread_sync_data *tsd = &td->tsd;
  240. memset(tsd, 0, sizeof(*tsd));
  241. tsd->td = td;
  242. tsd->port = port;
  243. /* Treat the request as done until the thread actually starts so any early
  244. * cleanup gets done properly.
  245. */
  246. tsd->done = 1;
  247. #ifdef HAVE_GETADDRINFO
  248. DEBUGASSERT(hints);
  249. tsd->hints = *hints;
  250. #else
  251. (void) hints;
  252. #endif
  253. tsd->mtx = malloc(sizeof(curl_mutex_t));
  254. if(tsd->mtx == NULL)
  255. goto err_exit;
  256. if(Curl_mutex_init(tsd->mtx)) {
  257. free(tsd->mtx);
  258. tsd->mtx = NULL;
  259. goto err_exit;
  260. }
  261. #ifdef USE_SOCKETPAIR
  262. /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
  263. if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
  264. tsd->sock_pair[0] = CURL_SOCKET_BAD;
  265. tsd->sock_pair[1] = CURL_SOCKET_BAD;
  266. goto err_exit;
  267. }
  268. #endif
  269. tsd->sock_error = CURL_ASYNC_SUCCESS;
  270. /* Copying hostname string because original can be destroyed by parent
  271. * thread during gethostbyname execution.
  272. */
  273. tsd->hostname = strdup(hostname);
  274. if(!tsd->hostname)
  275. goto err_exit;
  276. return 1;
  277. err_exit:
  278. /* Memory allocation failed */
  279. destroy_thread_sync_data(tsd);
  280. return 0;
  281. }
  282. static int getaddrinfo_complete(struct connectdata *conn)
  283. {
  284. struct thread_sync_data *tsd = conn_thread_sync_data(conn);
  285. int rc;
  286. rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
  287. /* The tsd->res structure has been copied to async.dns and perhaps the DNS
  288. cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
  289. */
  290. tsd->res = NULL;
  291. return rc;
  292. }
  293. #ifdef HAVE_GETADDRINFO
  294. /*
  295. * getaddrinfo_thread() resolves a name and then exits.
  296. *
  297. * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
  298. * and wait on it.
  299. */
  300. static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
  301. {
  302. struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  303. struct thread_data *td = tsd->td;
  304. struct thread_list *orphan = NULL;
  305. char service[12];
  306. int rc;
  307. #ifdef USE_SOCKETPAIR
  308. char buf[1];
  309. #endif
  310. msnprintf(service, sizeof(service), "%d", tsd->port);
  311. rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
  312. if(rc != 0) {
  313. tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
  314. if(tsd->sock_error == 0)
  315. tsd->sock_error = RESOLVER_ENOMEM;
  316. }
  317. else {
  318. Curl_addrinfo_set_port(tsd->res, tsd->port);
  319. }
  320. Curl_mutex_acquire(tsd->mtx);
  321. if(tsd->done) {
  322. /* too late, gotta clean up the mess */
  323. Curl_mutex_release(tsd->mtx);
  324. destroy_thread_sync_data(tsd);
  325. orphan = (struct thread_list *)td->reserved;
  326. free(td);
  327. }
  328. else {
  329. #ifdef USE_SOCKETPAIR
  330. if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
  331. /* DNS has been resolved, signal client task */
  332. buf[0] = 1;
  333. if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
  334. /* update sock_erro to errno */
  335. tsd->sock_error = SOCKERRNO;
  336. }
  337. }
  338. #endif
  339. tsd->done = 1;
  340. Curl_mutex_release(tsd->mtx);
  341. }
  342. if(orphan)
  343. signal_orphan_is_exiting(orphan);
  344. return 0;
  345. }
  346. #else /* HAVE_GETADDRINFO */
  347. /*
  348. * gethostbyname_thread() resolves a name and then exits.
  349. */
  350. static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
  351. {
  352. struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  353. struct thread_data *td = tsd->td;
  354. struct thread_list *orphan = NULL;
  355. tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
  356. if(!tsd->res) {
  357. tsd->sock_error = SOCKERRNO;
  358. if(tsd->sock_error == 0)
  359. tsd->sock_error = RESOLVER_ENOMEM;
  360. }
  361. Curl_mutex_acquire(tsd->mtx);
  362. if(tsd->done) {
  363. /* too late, gotta clean up the mess */
  364. Curl_mutex_release(tsd->mtx);
  365. destroy_thread_sync_data(tsd);
  366. orphan = (struct thread_list *)td->reserved;
  367. free(td);
  368. }
  369. else {
  370. tsd->done = 1;
  371. Curl_mutex_release(tsd->mtx);
  372. }
  373. if(orphan)
  374. signal_orphan_is_exiting(orphan);
  375. return 0;
  376. }
  377. #endif /* HAVE_GETADDRINFO */
  378. /*
  379. * destroy_async_data() cleans up async resolver data and thread handle.
  380. */
  381. static void destroy_async_data(struct Curl_async *async)
  382. {
  383. if(async->tdata) {
  384. struct thread_data *td = async->tdata;
  385. int done;
  386. #ifdef USE_SOCKETPAIR
  387. curl_socket_t sock_rd = td->tsd.sock_pair[0];
  388. struct connectdata *conn = td->tsd.conn;
  389. #endif
  390. /* We can't wait any longer for the resolver thread so if it's not done
  391. * then it must be orphaned.
  392. *
  393. * 1) add thread to orphaned threads list
  394. * 2) set thread done (this signals to thread it has been orphaned)
  395. *
  396. * An orphaned thread does most of its own cleanup, and any remaining
  397. * cleanup is handled during global cleanup.
  398. */
  399. Curl_mutex_acquire(td->tsd.mtx);
  400. if(!td->tsd.done && td->thread_hnd != curl_thread_t_null) {
  401. struct thread_list *orphan = (struct thread_list *)td->reserved;
  402. Curl_mutex_acquire(&orphaned_threads.mutex);
  403. #ifdef DEBUGBUILD
  404. {
  405. struct thread_list empty;
  406. memset(&empty, 0, sizeof(empty));
  407. DEBUGASSERT(!memcmp(&empty, orphan, sizeof(empty)));
  408. }
  409. #endif
  410. orphan->handle = td->thread_hnd;
  411. orphan->exiting = false;
  412. if(orphaned_threads.last) {
  413. orphaned_threads.last->next = orphan;
  414. orphan->prev = orphaned_threads.last;
  415. }
  416. else {
  417. orphaned_threads.first = orphan;
  418. orphan->prev = NULL;
  419. }
  420. orphaned_threads.last = orphan;
  421. orphan->next = NULL;
  422. Curl_mutex_release(&orphaned_threads.mutex);
  423. }
  424. done = td->tsd.done;
  425. td->tsd.done = 1;
  426. Curl_mutex_release(td->tsd.mtx);
  427. if(done) {
  428. if(td->thread_hnd != curl_thread_t_null)
  429. Curl_thread_join(&td->thread_hnd);
  430. destroy_thread_sync_data(&td->tsd);
  431. free(td->reserved);
  432. free(td);
  433. }
  434. #ifdef USE_SOCKETPAIR
  435. /*
  436. * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
  437. * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
  438. */
  439. if(conn)
  440. Curl_multi_closed(conn->data, sock_rd);
  441. sclose(sock_rd);
  442. #endif
  443. }
  444. async->tdata = NULL;
  445. free(async->hostname);
  446. async->hostname = NULL;
  447. }
  448. /*
  449. * init_resolve_thread() starts a new thread that performs the actual
  450. * resolve. This function returns before the resolve is done.
  451. *
  452. * Returns FALSE in case of failure, otherwise TRUE.
  453. */
  454. static bool init_resolve_thread(struct connectdata *conn,
  455. const char *hostname, int port,
  456. const struct addrinfo *hints)
  457. {
  458. struct thread_data *td = calloc(1, sizeof(struct thread_data));
  459. int err = ENOMEM;
  460. conn->async.tdata = td;
  461. if(!td)
  462. goto errno_exit;
  463. conn->async.port = port;
  464. conn->async.done = FALSE;
  465. conn->async.status = 0;
  466. conn->async.dns = NULL;
  467. td->thread_hnd = curl_thread_t_null;
  468. td->reserved = calloc(1, sizeof(struct thread_list));
  469. if(!td->reserved || !init_thread_sync_data(td, hostname, port, hints)) {
  470. conn->async.tdata = NULL;
  471. free(td->reserved);
  472. free(td);
  473. goto errno_exit;
  474. }
  475. free(conn->async.hostname);
  476. conn->async.hostname = strdup(hostname);
  477. if(!conn->async.hostname)
  478. goto err_exit;
  479. /* The thread will set this to 1 when complete. */
  480. td->tsd.done = 0;
  481. #ifdef HAVE_GETADDRINFO
  482. td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
  483. #else
  484. td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
  485. #endif
  486. if(td->thread_hnd == curl_thread_t_null) {
  487. /* The thread never started, so mark it as done here for proper cleanup. */
  488. td->tsd.done = 1;
  489. err = errno;
  490. goto err_exit;
  491. }
  492. return TRUE;
  493. err_exit:
  494. destroy_async_data(&conn->async);
  495. errno_exit:
  496. errno = err;
  497. return FALSE;
  498. }
  499. /*
  500. * resolver_error() calls failf() with the appropriate message after a resolve
  501. * error
  502. */
  503. static CURLcode resolver_error(struct connectdata *conn)
  504. {
  505. const char *host_or_proxy;
  506. CURLcode result;
  507. #ifndef CURL_DISABLE_PROXY
  508. if(conn->bits.httpproxy) {
  509. host_or_proxy = "proxy";
  510. result = CURLE_COULDNT_RESOLVE_PROXY;
  511. }
  512. else
  513. #endif
  514. {
  515. host_or_proxy = "host";
  516. result = CURLE_COULDNT_RESOLVE_HOST;
  517. }
  518. failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
  519. conn->async.hostname);
  520. return result;
  521. }
  522. /*
  523. * 'entry' may be NULL and then no data is returned
  524. */
  525. static CURLcode thread_wait_resolv(struct connectdata *conn,
  526. struct Curl_dns_entry **entry,
  527. bool report)
  528. {
  529. struct thread_data *td = conn->async.tdata;
  530. CURLcode result = CURLE_OK;
  531. DEBUGASSERT(conn && td);
  532. DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
  533. /* wait for the thread to resolve the name */
  534. if(Curl_thread_join(&td->thread_hnd)) {
  535. if(entry)
  536. result = getaddrinfo_complete(conn);
  537. }
  538. else
  539. DEBUGASSERT(0);
  540. conn->async.done = TRUE;
  541. if(entry)
  542. *entry = conn->async.dns;
  543. if(!conn->async.dns && report)
  544. /* a name was not resolved, report error */
  545. result = resolver_error(conn);
  546. destroy_async_data(&conn->async);
  547. if(!conn->async.dns && report)
  548. connclose(conn, "asynch resolve failed");
  549. return result;
  550. }
  551. /*
  552. * Until we gain a way to signal the resolver threads to stop early, we must
  553. * simply wait for them and ignore their results.
  554. */
  555. void Curl_resolver_kill(struct connectdata *conn)
  556. {
  557. struct thread_data *td = conn->async.tdata;
  558. /* If we're still resolving, we must wait for the threads to fully clean up,
  559. unfortunately. Otherwise, we can simply cancel to clean up any resolver
  560. data. */
  561. if(td && td->thread_hnd != curl_thread_t_null)
  562. (void)thread_wait_resolv(conn, NULL, FALSE);
  563. else
  564. Curl_resolver_cancel(conn);
  565. }
  566. /*
  567. * Curl_resolver_wait_resolv()
  568. *
  569. * Waits for a resolve to finish. This function should be avoided since using
  570. * this risk getting the multi interface to "hang".
  571. *
  572. * If 'entry' is non-NULL, make it point to the resolved dns entry
  573. *
  574. * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  575. * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  576. *
  577. * This is the version for resolves-in-a-thread.
  578. */
  579. CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
  580. struct Curl_dns_entry **entry)
  581. {
  582. return thread_wait_resolv(conn, entry, TRUE);
  583. }
  584. /*
  585. * Curl_resolver_is_resolved() is called repeatedly to check if a previous
  586. * name resolve request has completed. It should also make sure to time-out if
  587. * the operation seems to take too long.
  588. */
  589. CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
  590. struct Curl_dns_entry **entry)
  591. {
  592. struct Curl_easy *data = conn->data;
  593. struct thread_data *td = conn->async.tdata;
  594. int done = 0;
  595. DEBUGASSERT(entry);
  596. *entry = NULL;
  597. if(!td) {
  598. DEBUGASSERT(td);
  599. return CURLE_COULDNT_RESOLVE_HOST;
  600. }
  601. Curl_mutex_acquire(td->tsd.mtx);
  602. done = td->tsd.done;
  603. Curl_mutex_release(td->tsd.mtx);
  604. if(done) {
  605. getaddrinfo_complete(conn);
  606. if(!conn->async.dns) {
  607. CURLcode result = resolver_error(conn);
  608. destroy_async_data(&conn->async);
  609. return result;
  610. }
  611. destroy_async_data(&conn->async);
  612. *entry = conn->async.dns;
  613. }
  614. else {
  615. /* poll for name lookup done with exponential backoff up to 250ms */
  616. /* should be fine even if this converts to 32 bit */
  617. timediff_t elapsed = Curl_timediff(Curl_now(),
  618. data->progress.t_startsingle);
  619. if(elapsed < 0)
  620. elapsed = 0;
  621. if(td->poll_interval == 0)
  622. /* Start at 1ms poll interval */
  623. td->poll_interval = 1;
  624. else if(elapsed >= td->interval_end)
  625. /* Back-off exponentially if last interval expired */
  626. td->poll_interval *= 2;
  627. if(td->poll_interval > 250)
  628. td->poll_interval = 250;
  629. td->interval_end = elapsed + td->poll_interval;
  630. Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
  631. }
  632. return CURLE_OK;
  633. }
  634. int Curl_resolver_getsock(struct connectdata *conn,
  635. curl_socket_t *socks)
  636. {
  637. int ret_val = 0;
  638. timediff_t milli;
  639. timediff_t ms;
  640. struct Curl_easy *data = conn->data;
  641. struct resdata *reslv = (struct resdata *)data->state.resolver;
  642. #ifdef USE_SOCKETPAIR
  643. struct thread_data *td = conn->async.tdata;
  644. #else
  645. (void)socks;
  646. #endif
  647. #ifdef USE_SOCKETPAIR
  648. if(td) {
  649. /* return read fd to client for polling the DNS resolution status */
  650. socks[0] = td->tsd.sock_pair[0];
  651. DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn);
  652. td->tsd.conn = conn;
  653. ret_val = GETSOCK_READSOCK(0);
  654. }
  655. else {
  656. #endif
  657. ms = Curl_timediff(Curl_now(), reslv->start);
  658. if(ms < 3)
  659. milli = 0;
  660. else if(ms <= 50)
  661. milli = ms/3;
  662. else if(ms <= 250)
  663. milli = 50;
  664. else
  665. milli = 200;
  666. Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
  667. #ifdef USE_SOCKETPAIR
  668. }
  669. #endif
  670. return ret_val;
  671. }
  672. #ifndef HAVE_GETADDRINFO
  673. /*
  674. * Curl_getaddrinfo() - for platforms without getaddrinfo
  675. */
  676. struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
  677. const char *hostname,
  678. int port,
  679. int *waitp)
  680. {
  681. struct Curl_easy *data = conn->data;
  682. struct resdata *reslv = (struct resdata *)data->state.resolver;
  683. *waitp = 0; /* default to synchronous response */
  684. reslv->start = Curl_now();
  685. /* fire up a new resolver thread! */
  686. if(init_resolve_thread(conn, hostname, port, NULL)) {
  687. *waitp = 1; /* expect asynchronous response */
  688. return NULL;
  689. }
  690. failf(conn->data, "getaddrinfo() thread failed\n");
  691. return NULL;
  692. }
  693. #else /* !HAVE_GETADDRINFO */
  694. /*
  695. * Curl_resolver_getaddrinfo() - for getaddrinfo
  696. */
  697. struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
  698. const char *hostname,
  699. int port,
  700. int *waitp)
  701. {
  702. struct addrinfo hints;
  703. int pf = PF_INET;
  704. struct Curl_easy *data = conn->data;
  705. struct resdata *reslv = (struct resdata *)data->state.resolver;
  706. *waitp = 0; /* default to synchronous response */
  707. #ifdef CURLRES_IPV6
  708. /*
  709. * Check if a limited name resolve has been requested.
  710. */
  711. switch(conn->ip_version) {
  712. case CURL_IPRESOLVE_V4:
  713. pf = PF_INET;
  714. break;
  715. case CURL_IPRESOLVE_V6:
  716. pf = PF_INET6;
  717. break;
  718. default:
  719. pf = PF_UNSPEC;
  720. break;
  721. }
  722. if((pf != PF_INET) && !Curl_ipv6works(conn))
  723. /* The stack seems to be a non-IPv6 one */
  724. pf = PF_INET;
  725. #endif /* CURLRES_IPV6 */
  726. memset(&hints, 0, sizeof(hints));
  727. hints.ai_family = pf;
  728. hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
  729. SOCK_STREAM : SOCK_DGRAM;
  730. reslv->start = Curl_now();
  731. /* fire up a new resolver thread! */
  732. if(init_resolve_thread(conn, hostname, port, &hints)) {
  733. *waitp = 1; /* expect asynchronous response */
  734. return NULL;
  735. }
  736. failf(data, "getaddrinfo() thread failed to start\n");
  737. return NULL;
  738. }
  739. #endif /* !HAVE_GETADDRINFO */
  740. CURLcode Curl_set_dns_servers(struct Curl_easy *data,
  741. char *servers)
  742. {
  743. (void)data;
  744. (void)servers;
  745. return CURLE_NOT_BUILT_IN;
  746. }
  747. CURLcode Curl_set_dns_interface(struct Curl_easy *data,
  748. const char *interf)
  749. {
  750. (void)data;
  751. (void)interf;
  752. return CURLE_NOT_BUILT_IN;
  753. }
  754. CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
  755. const char *local_ip4)
  756. {
  757. (void)data;
  758. (void)local_ip4;
  759. return CURLE_NOT_BUILT_IN;
  760. }
  761. CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
  762. const char *local_ip6)
  763. {
  764. (void)data;
  765. (void)local_ip6;
  766. return CURLE_NOT_BUILT_IN;
  767. }
  768. /* Helper function to wait and destroy some or all orphaned threads.
  769. *
  770. * WAIT_DESTROY_ALL:
  771. * Wait and destroy all orphaned threads. This operation is not safe to specify
  772. * in code that could run in any thread that may be orphaned (ie any resolver
  773. * thread). Waiting on all orphaned threads may take some time. This operation
  774. * must be specified in the call from global cleanup, and ideally nowhere else.
  775. *
  776. * WAIT_DESTROY_EXITING_THREADS_ONLY:
  777. * Wait and destroy only orphaned threads that are in the process of or have
  778. * since exited (ie those with .exiting set true). This is fast.
  779. *
  780. * When the calling thread owns orphaned_threads.mutex it must not call this
  781. * function or deadlock my occur.
  782. */
  783. static void wait_and_destroy_orphaned_threads(int flags)
  784. {
  785. struct thread_list *thread = NULL;
  786. Curl_mutex_acquire(&orphaned_threads.mutex);
  787. if((flags & WAIT_DESTROY_EXITING_THREADS_ONLY)) {
  788. struct thread_list *p, *next;
  789. struct thread_list *first = NULL, *last = NULL;
  790. if(!orphaned_threads.exiting_count) {
  791. Curl_mutex_release(&orphaned_threads.mutex);
  792. return;
  793. }
  794. for(p = orphaned_threads.first; p; p = next) {
  795. next = p->next;
  796. if(!p->exiting)
  797. continue;
  798. /* remove thread list item from orphaned_threads */
  799. if(p->prev)
  800. p->prev->next = p->next;
  801. if(p->next)
  802. p->next->prev = p->prev;
  803. if(orphaned_threads.first == p)
  804. orphaned_threads.first = p->next;
  805. if(orphaned_threads.last == p)
  806. orphaned_threads.last = p->prev;
  807. /* add thread list item to new thread list */
  808. if(last) {
  809. last->next = p;
  810. p->prev = last;
  811. }
  812. else {
  813. first = p;
  814. p->prev = NULL;
  815. }
  816. last = p;
  817. p->next = NULL;
  818. }
  819. thread = first;
  820. orphaned_threads.exiting_count = 0;
  821. }
  822. else if((flags & WAIT_DESTROY_ALL)) {
  823. thread = orphaned_threads.first;
  824. orphaned_threads.first = NULL;
  825. orphaned_threads.last = NULL;
  826. orphaned_threads.exiting_count = 0;
  827. }
  828. Curl_mutex_release(&orphaned_threads.mutex);
  829. /* Wait and free. Must be done unlocked or there could be deadlock. */
  830. while(thread) {
  831. struct thread_list *next = thread->next;
  832. Curl_thread_join(&thread->handle);
  833. free(thread);
  834. thread = next;
  835. }
  836. }
  837. /* Helper function that must be called from an orphaned thread right before it
  838. exits. */
  839. static void signal_orphan_is_exiting(struct thread_list *orphan)
  840. {
  841. DEBUGASSERT(orphan->handle && !orphan->exiting);
  842. wait_and_destroy_orphaned_threads(WAIT_DESTROY_EXITING_THREADS_ONLY);
  843. Curl_mutex_acquire(&orphaned_threads.mutex);
  844. orphan->exiting = true;
  845. orphaned_threads.exiting_count++;
  846. Curl_mutex_release(&orphaned_threads.mutex);
  847. }
  848. #endif /* CURLRES_THREADED */