诸暨麻将添加redis
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

828 rivejä
24 KiB

  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2013, 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 http://curl.haxx.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. #ifdef HAVE_NETINET_IN_H
  24. #include <netinet/in.h>
  25. #endif
  26. #ifdef HAVE_NETDB_H
  27. #include <netdb.h>
  28. #endif
  29. #ifdef HAVE_ARPA_INET_H
  30. #include <arpa/inet.h>
  31. #endif
  32. #ifdef __VMS
  33. #include <in.h>
  34. #include <inet.h>
  35. #endif
  36. #ifdef HAVE_SETJMP_H
  37. #include <setjmp.h>
  38. #endif
  39. #ifdef HAVE_SIGNAL_H
  40. #include <signal.h>
  41. #endif
  42. #ifdef HAVE_PROCESS_H
  43. #include <process.h>
  44. #endif
  45. #include "urldata.h"
  46. #include "sendf.h"
  47. #include "hostip.h"
  48. #include "hash.h"
  49. #include "share.h"
  50. #include "strerror.h"
  51. #include "url.h"
  52. #include "inet_ntop.h"
  53. #include "warnless.h"
  54. #define _MPRINTF_REPLACE /* use our functions only */
  55. #include <curl/mprintf.h>
  56. #include "curl_memory.h"
  57. /* The last #include file should be: */
  58. #include "memdebug.h"
  59. #if defined(CURLRES_SYNCH) && \
  60. defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
  61. /* alarm-based timeouts can only be used with all the dependencies satisfied */
  62. #define USE_ALARM_TIMEOUT
  63. #endif
  64. /*
  65. * hostip.c explained
  66. * ==================
  67. *
  68. * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
  69. * source file are these:
  70. *
  71. * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
  72. * that. The host may not be able to resolve IPv6, but we don't really have to
  73. * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
  74. * defined.
  75. *
  76. * CURLRES_ARES - is defined if libcurl is built to use c-ares for
  77. * asynchronous name resolves. This can be Windows or *nix.
  78. *
  79. * CURLRES_THREADED - is defined if libcurl is built to run under (native)
  80. * Windows, and then the name resolve will be done in a new thread, and the
  81. * supported API will be the same as for ares-builds.
  82. *
  83. * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
  84. * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
  85. * defined.
  86. *
  87. * The host*.c sources files are split up like this:
  88. *
  89. * hostip.c - method-independent resolver functions and utility functions
  90. * hostasyn.c - functions for asynchronous name resolves
  91. * hostsyn.c - functions for synchronous name resolves
  92. * hostip4.c - ipv4-specific functions
  93. * hostip6.c - ipv6-specific functions
  94. *
  95. * The two asynchronous name resolver backends are implemented in:
  96. * asyn-ares.c - functions for ares-using name resolves
  97. * asyn-thread.c - functions for threaded name resolves
  98. * The hostip.h is the united header file for all this. It defines the
  99. * CURLRES_* defines based on the config*.h and curl_setup.h defines.
  100. */
  101. /* These two symbols are for the global DNS cache */
  102. static struct curl_hash hostname_cache;
  103. static int host_cache_initialized;
  104. static void freednsentry(void *freethis);
  105. /*
  106. * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
  107. * Global DNS cache is general badness. Do not use. This will be removed in
  108. * a future version. Use the share interface instead!
  109. *
  110. * Returns a struct curl_hash pointer on success, NULL on failure.
  111. */
  112. struct curl_hash *Curl_global_host_cache_init(void)
  113. {
  114. int rc = 0;
  115. if(!host_cache_initialized) {
  116. rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
  117. Curl_str_key_compare, freednsentry);
  118. if(!rc)
  119. host_cache_initialized = 1;
  120. }
  121. return rc?NULL:&hostname_cache;
  122. }
  123. /*
  124. * Destroy and cleanup the global DNS cache
  125. */
  126. void Curl_global_host_cache_dtor(void)
  127. {
  128. if(host_cache_initialized) {
  129. /* first make sure that any custom "CURLOPT_RESOLVE" names are
  130. cleared off */
  131. Curl_hostcache_clean(NULL, &hostname_cache);
  132. /* then free the remaining hash completely */
  133. Curl_hash_clean(&hostname_cache);
  134. host_cache_initialized = 0;
  135. }
  136. }
  137. /*
  138. * Return # of adresses in a Curl_addrinfo struct
  139. */
  140. int Curl_num_addresses(const Curl_addrinfo *addr)
  141. {
  142. int i = 0;
  143. while(addr) {
  144. addr = addr->ai_next;
  145. i++;
  146. }
  147. return i;
  148. }
  149. /*
  150. * Curl_printable_address() returns a printable version of the 1st address
  151. * given in the 'ai' argument. The result will be stored in the buf that is
  152. * bufsize bytes big.
  153. *
  154. * If the conversion fails, it returns NULL.
  155. */
  156. const char *
  157. Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
  158. {
  159. const struct sockaddr_in *sa4;
  160. const struct in_addr *ipaddr4;
  161. #ifdef ENABLE_IPV6
  162. const struct sockaddr_in6 *sa6;
  163. const struct in6_addr *ipaddr6;
  164. #endif
  165. switch (ai->ai_family) {
  166. case AF_INET:
  167. sa4 = (const void *)ai->ai_addr;
  168. ipaddr4 = &sa4->sin_addr;
  169. return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
  170. bufsize);
  171. #ifdef ENABLE_IPV6
  172. case AF_INET6:
  173. sa6 = (const void *)ai->ai_addr;
  174. ipaddr6 = &sa6->sin6_addr;
  175. return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
  176. bufsize);
  177. #endif
  178. default:
  179. break;
  180. }
  181. return NULL;
  182. }
  183. /*
  184. * Return a hostcache id string for the provided host + port, to be used by
  185. * the DNS caching.
  186. */
  187. static char *
  188. create_hostcache_id(const char *name, int port)
  189. {
  190. /* create and return the new allocated entry */
  191. char *id = aprintf("%s:%d", name, port);
  192. char *ptr = id;
  193. if(ptr) {
  194. /* lower case the name part */
  195. while(*ptr && (*ptr != ':')) {
  196. *ptr = (char)TOLOWER(*ptr);
  197. ptr++;
  198. }
  199. }
  200. return id;
  201. }
  202. struct hostcache_prune_data {
  203. long cache_timeout;
  204. time_t now;
  205. };
  206. /*
  207. * This function is set as a callback to be called for every entry in the DNS
  208. * cache when we want to prune old unused entries.
  209. *
  210. * Returning non-zero means remove the entry, return 0 to keep it in the
  211. * cache.
  212. */
  213. static int
  214. hostcache_timestamp_remove(void *datap, void *hc)
  215. {
  216. struct hostcache_prune_data *data =
  217. (struct hostcache_prune_data *) datap;
  218. struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
  219. return (data->now - c->timestamp >= data->cache_timeout);
  220. }
  221. /*
  222. * Prune the DNS cache. This assumes that a lock has already been taken.
  223. */
  224. static void
  225. hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
  226. {
  227. struct hostcache_prune_data user;
  228. user.cache_timeout = cache_timeout;
  229. user.now = now;
  230. Curl_hash_clean_with_criterium(hostcache,
  231. (void *) &user,
  232. hostcache_timestamp_remove);
  233. }
  234. /*
  235. * Library-wide function for pruning the DNS cache. This function takes and
  236. * returns the appropriate locks.
  237. */
  238. void Curl_hostcache_prune(struct SessionHandle *data)
  239. {
  240. time_t now;
  241. if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
  242. /* cache forever means never prune, and NULL hostcache means
  243. we can't do it */
  244. return;
  245. if(data->share)
  246. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  247. time(&now);
  248. /* Remove outdated and unused entries from the hostcache */
  249. hostcache_prune(data->dns.hostcache,
  250. data->set.dns_cache_timeout,
  251. now);
  252. if(data->share)
  253. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  254. }
  255. /*
  256. * Check if the entry should be pruned. Assumes a locked cache.
  257. */
  258. static int
  259. remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
  260. {
  261. struct hostcache_prune_data user;
  262. if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
  263. /* cache forever means never prune, and NULL hostcache means
  264. we can't do it */
  265. return 0;
  266. time(&user.now);
  267. user.cache_timeout = data->set.dns_cache_timeout;
  268. if(!hostcache_timestamp_remove(&user,dns) )
  269. return 0;
  270. Curl_hash_clean_with_criterium(data->dns.hostcache,
  271. (void *) &user,
  272. hostcache_timestamp_remove);
  273. return 1;
  274. }
  275. #ifdef HAVE_SIGSETJMP
  276. /* Beware this is a global and unique instance. This is used to store the
  277. return address that we can jump back to from inside a signal handler. This
  278. is not thread-safe stuff. */
  279. sigjmp_buf curl_jmpenv;
  280. #endif
  281. /*
  282. * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
  283. *
  284. * When calling Curl_resolv() has resulted in a response with a returned
  285. * address, we call this function to store the information in the dns
  286. * cache etc
  287. *
  288. * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
  289. */
  290. struct Curl_dns_entry *
  291. Curl_cache_addr(struct SessionHandle *data,
  292. Curl_addrinfo *addr,
  293. const char *hostname,
  294. int port)
  295. {
  296. char *entry_id;
  297. size_t entry_len;
  298. struct Curl_dns_entry *dns;
  299. struct Curl_dns_entry *dns2;
  300. /* Create an entry id, based upon the hostname and port */
  301. entry_id = create_hostcache_id(hostname, port);
  302. /* If we can't create the entry id, fail */
  303. if(!entry_id)
  304. return NULL;
  305. entry_len = strlen(entry_id);
  306. /* Create a new cache entry */
  307. dns = calloc(1, sizeof(struct Curl_dns_entry));
  308. if(!dns) {
  309. free(entry_id);
  310. return NULL;
  311. }
  312. dns->inuse = 0; /* init to not used */
  313. dns->addr = addr; /* this is the address(es) */
  314. time(&dns->timestamp);
  315. if(dns->timestamp == 0)
  316. dns->timestamp = 1; /* zero indicates that entry isn't in hash table */
  317. /* Store the resolved data in our DNS cache. */
  318. dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
  319. (void *)dns);
  320. if(!dns2) {
  321. free(dns);
  322. free(entry_id);
  323. return NULL;
  324. }
  325. dns = dns2;
  326. dns->inuse++; /* mark entry as in-use */
  327. /* free the allocated entry_id */
  328. free(entry_id);
  329. return dns;
  330. }
  331. /*
  332. * Curl_resolv() is the main name resolve function within libcurl. It resolves
  333. * a name and returns a pointer to the entry in the 'entry' argument (if one
  334. * is provided). This function might return immediately if we're using asynch
  335. * resolves. See the return codes.
  336. *
  337. * The cache entry we return will get its 'inuse' counter increased when this
  338. * function is used. You MUST call Curl_resolv_unlock() later (when you're
  339. * done using this struct) to decrease the counter again.
  340. *
  341. * In debug mode, we specifically test for an interface name "LocalHost"
  342. * and resolve "localhost" instead as a means to permit test cases
  343. * to connect to a local test server with any host name.
  344. *
  345. * Return codes:
  346. *
  347. * CURLRESOLV_ERROR (-1) = error, no pointer
  348. * CURLRESOLV_RESOLVED (0) = OK, pointer provided
  349. * CURLRESOLV_PENDING (1) = waiting for response, no pointer
  350. */
  351. int Curl_resolv(struct connectdata *conn,
  352. const char *hostname,
  353. int port,
  354. struct Curl_dns_entry **entry)
  355. {
  356. char *entry_id = NULL;
  357. struct Curl_dns_entry *dns = NULL;
  358. size_t entry_len;
  359. struct SessionHandle *data = conn->data;
  360. CURLcode result;
  361. int rc = CURLRESOLV_ERROR; /* default to failure */
  362. *entry = NULL;
  363. /* Create an entry id, based upon the hostname and port */
  364. entry_id = create_hostcache_id(hostname, port);
  365. /* If we can't create the entry id, fail */
  366. if(!entry_id)
  367. return rc;
  368. entry_len = strlen(entry_id);
  369. if(data->share)
  370. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  371. /* See if its already in our dns cache */
  372. dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
  373. /* free the allocated entry_id again */
  374. free(entry_id);
  375. /* See whether the returned entry is stale. Done before we release lock */
  376. if(remove_entry_if_stale(data, dns))
  377. dns = NULL; /* the memory deallocation is being handled by the hash */
  378. if(dns) {
  379. dns->inuse++; /* we use it! */
  380. rc = CURLRESOLV_RESOLVED;
  381. }
  382. if(data->share)
  383. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  384. if(!dns) {
  385. /* The entry was not in the cache. Resolve it to IP address */
  386. Curl_addrinfo *addr;
  387. int respwait;
  388. /* Check what IP specifics the app has requested and if we can provide it.
  389. * If not, bail out. */
  390. if(!Curl_ipvalid(conn))
  391. return CURLRESOLV_ERROR;
  392. /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
  393. non-zero value indicating that we need to wait for the response to the
  394. resolve call */
  395. addr = Curl_getaddrinfo(conn,
  396. #ifdef DEBUGBUILD
  397. (data->set.str[STRING_DEVICE]
  398. && !strcmp(data->set.str[STRING_DEVICE],
  399. "LocalHost"))?"localhost":
  400. #endif
  401. hostname, port, &respwait);
  402. if(!addr) {
  403. if(respwait) {
  404. /* the response to our resolve call will come asynchronously at
  405. a later time, good or bad */
  406. /* First, check that we haven't received the info by now */
  407. result = Curl_resolver_is_resolved(conn, &dns);
  408. if(result) /* error detected */
  409. return CURLRESOLV_ERROR;
  410. if(dns)
  411. rc = CURLRESOLV_RESOLVED; /* pointer provided */
  412. else
  413. rc = CURLRESOLV_PENDING; /* no info yet */
  414. }
  415. }
  416. else {
  417. if(data->share)
  418. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  419. /* we got a response, store it in the cache */
  420. dns = Curl_cache_addr(data, addr, hostname, port);
  421. if(data->share)
  422. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  423. if(!dns)
  424. /* returned failure, bail out nicely */
  425. Curl_freeaddrinfo(addr);
  426. else
  427. rc = CURLRESOLV_RESOLVED;
  428. }
  429. }
  430. *entry = dns;
  431. return rc;
  432. }
  433. #ifdef USE_ALARM_TIMEOUT
  434. /*
  435. * This signal handler jumps back into the main libcurl code and continues
  436. * execution. This effectively causes the remainder of the application to run
  437. * within a signal handler which is nonportable and could lead to problems.
  438. */
  439. static
  440. RETSIGTYPE alarmfunc(int sig)
  441. {
  442. /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
  443. (void)sig;
  444. siglongjmp(curl_jmpenv, 1);
  445. return;
  446. }
  447. #endif /* USE_ALARM_TIMEOUT */
  448. /*
  449. * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
  450. * timeout. This function might return immediately if we're using asynch
  451. * resolves. See the return codes.
  452. *
  453. * The cache entry we return will get its 'inuse' counter increased when this
  454. * function is used. You MUST call Curl_resolv_unlock() later (when you're
  455. * done using this struct) to decrease the counter again.
  456. *
  457. * If built with a synchronous resolver and use of signals is not
  458. * disabled by the application, then a nonzero timeout will cause a
  459. * timeout after the specified number of milliseconds. Otherwise, timeout
  460. * is ignored.
  461. *
  462. * Return codes:
  463. *
  464. * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
  465. * CURLRESOLV_ERROR (-1) = error, no pointer
  466. * CURLRESOLV_RESOLVED (0) = OK, pointer provided
  467. * CURLRESOLV_PENDING (1) = waiting for response, no pointer
  468. */
  469. int Curl_resolv_timeout(struct connectdata *conn,
  470. const char *hostname,
  471. int port,
  472. struct Curl_dns_entry **entry,
  473. long timeoutms)
  474. {
  475. #ifdef USE_ALARM_TIMEOUT
  476. #ifdef HAVE_SIGACTION
  477. struct sigaction keep_sigact; /* store the old struct here */
  478. volatile bool keep_copysig = FALSE; /* wether old sigact has been saved */
  479. struct sigaction sigact;
  480. #else
  481. #ifdef HAVE_SIGNAL
  482. void (*keep_sigact)(int); /* store the old handler here */
  483. #endif /* HAVE_SIGNAL */
  484. #endif /* HAVE_SIGACTION */
  485. volatile long timeout;
  486. volatile unsigned int prev_alarm = 0;
  487. struct SessionHandle *data = conn->data;
  488. #endif /* USE_ALARM_TIMEOUT */
  489. int rc;
  490. *entry = NULL;
  491. if(timeoutms < 0)
  492. /* got an already expired timeout */
  493. return CURLRESOLV_TIMEDOUT;
  494. #ifdef USE_ALARM_TIMEOUT
  495. if(data->set.no_signal)
  496. /* Ignore the timeout when signals are disabled */
  497. timeout = 0;
  498. else
  499. timeout = timeoutms;
  500. if(!timeout)
  501. /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
  502. return Curl_resolv(conn, hostname, port, entry);
  503. if(timeout < 1000)
  504. /* The alarm() function only provides integer second resolution, so if
  505. we want to wait less than one second we must bail out already now. */
  506. return CURLRESOLV_TIMEDOUT;
  507. /*************************************************************
  508. * Set signal handler to catch SIGALRM
  509. * Store the old value to be able to set it back later!
  510. *************************************************************/
  511. #ifdef HAVE_SIGACTION
  512. sigaction(SIGALRM, NULL, &sigact);
  513. keep_sigact = sigact;
  514. keep_copysig = TRUE; /* yes, we have a copy */
  515. sigact.sa_handler = alarmfunc;
  516. #ifdef SA_RESTART
  517. /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
  518. sigact.sa_flags &= ~SA_RESTART;
  519. #endif
  520. /* now set the new struct */
  521. sigaction(SIGALRM, &sigact, NULL);
  522. #else /* HAVE_SIGACTION */
  523. /* no sigaction(), revert to the much lamer signal() */
  524. #ifdef HAVE_SIGNAL
  525. keep_sigact = signal(SIGALRM, alarmfunc);
  526. #endif
  527. #endif /* HAVE_SIGACTION */
  528. /* alarm() makes a signal get sent when the timeout fires off, and that
  529. will abort system calls */
  530. prev_alarm = alarm(curlx_sltoui(timeout/1000L));
  531. /* This allows us to time-out from the name resolver, as the timeout
  532. will generate a signal and we will siglongjmp() from that here.
  533. This technique has problems (see alarmfunc).
  534. This should be the last thing we do before calling Curl_resolv(),
  535. as otherwise we'd have to worry about variables that get modified
  536. before we invoke Curl_resolv() (and thus use "volatile"). */
  537. if(sigsetjmp(curl_jmpenv, 1)) {
  538. /* this is coming from a siglongjmp() after an alarm signal */
  539. failf(data, "name lookup timed out");
  540. rc = CURLRESOLV_ERROR;
  541. goto clean_up;
  542. }
  543. #else
  544. #ifndef CURLRES_ASYNCH
  545. if(timeoutms)
  546. infof(conn->data, "timeout on name lookup is not supported\n");
  547. #else
  548. (void)timeoutms; /* timeoutms not used with an async resolver */
  549. #endif
  550. #endif /* USE_ALARM_TIMEOUT */
  551. /* Perform the actual name resolution. This might be interrupted by an
  552. * alarm if it takes too long.
  553. */
  554. rc = Curl_resolv(conn, hostname, port, entry);
  555. #ifdef USE_ALARM_TIMEOUT
  556. clean_up:
  557. if(!prev_alarm)
  558. /* deactivate a possibly active alarm before uninstalling the handler */
  559. alarm(0);
  560. #ifdef HAVE_SIGACTION
  561. if(keep_copysig) {
  562. /* we got a struct as it looked before, now put that one back nice
  563. and clean */
  564. sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
  565. }
  566. #else
  567. #ifdef HAVE_SIGNAL
  568. /* restore the previous SIGALRM handler */
  569. signal(SIGALRM, keep_sigact);
  570. #endif
  571. #endif /* HAVE_SIGACTION */
  572. /* switch back the alarm() to either zero or to what it was before minus
  573. the time we spent until now! */
  574. if(prev_alarm) {
  575. /* there was an alarm() set before us, now put it back */
  576. unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
  577. /* the alarm period is counted in even number of seconds */
  578. unsigned long alarm_set = prev_alarm - elapsed_ms/1000;
  579. if(!alarm_set ||
  580. ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
  581. /* if the alarm time-left reached zero or turned "negative" (counted
  582. with unsigned values), we should fire off a SIGALRM here, but we
  583. won't, and zero would be to switch it off so we never set it to
  584. less than 1! */
  585. alarm(1);
  586. rc = CURLRESOLV_TIMEDOUT;
  587. failf(data, "Previous alarm fired off!");
  588. }
  589. else
  590. alarm((unsigned int)alarm_set);
  591. }
  592. #endif /* USE_ALARM_TIMEOUT */
  593. return rc;
  594. }
  595. /*
  596. * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
  597. * made, the struct may be destroyed due to pruning. It is important that only
  598. * one unlock is made for each Curl_resolv() call.
  599. *
  600. * May be called with 'data' == NULL for global cache.
  601. */
  602. void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
  603. {
  604. DEBUGASSERT(dns && (dns->inuse>0));
  605. if(data && data->share)
  606. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  607. dns->inuse--;
  608. /* only free if nobody is using AND it is not in hostcache (timestamp ==
  609. 0) */
  610. if(dns->inuse == 0 && dns->timestamp == 0) {
  611. Curl_freeaddrinfo(dns->addr);
  612. free(dns);
  613. }
  614. if(data && data->share)
  615. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  616. }
  617. /*
  618. * File-internal: free a cache dns entry.
  619. */
  620. static void freednsentry(void *freethis)
  621. {
  622. struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
  623. /* mark the entry as not in hostcache */
  624. p->timestamp = 0;
  625. if(p->inuse == 0) {
  626. Curl_freeaddrinfo(p->addr);
  627. free(p);
  628. }
  629. }
  630. /*
  631. * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
  632. */
  633. struct curl_hash *Curl_mk_dnscache(void)
  634. {
  635. return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
  636. }
  637. static int hostcache_inuse(void *data, void *hc)
  638. {
  639. struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
  640. if(c->inuse == 1)
  641. Curl_resolv_unlock(data, c);
  642. return 1; /* free all entries */
  643. }
  644. /*
  645. * Curl_hostcache_clean()
  646. *
  647. * This _can_ be called with 'data' == NULL but then of course no locking
  648. * can be done!
  649. */
  650. void Curl_hostcache_clean(struct SessionHandle *data,
  651. struct curl_hash *hash)
  652. {
  653. /* Entries added to the hostcache with the CURLOPT_RESOLVE function are
  654. * still present in the cache with the inuse counter set to 1. Detect them
  655. * and cleanup!
  656. */
  657. Curl_hash_clean_with_criterium(hash, data, hostcache_inuse);
  658. }
  659. CURLcode Curl_loadhostpairs(struct SessionHandle *data)
  660. {
  661. struct curl_slist *hostp;
  662. char hostname[256];
  663. char address[256];
  664. int port;
  665. for(hostp = data->change.resolve; hostp; hostp = hostp->next ) {
  666. if(!hostp->data)
  667. continue;
  668. if(hostp->data[0] == '-') {
  669. /* TODO: mark an entry for removal */
  670. }
  671. else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
  672. address)) {
  673. struct Curl_dns_entry *dns;
  674. Curl_addrinfo *addr;
  675. char *entry_id;
  676. size_t entry_len;
  677. addr = Curl_str2addr(address, port);
  678. if(!addr) {
  679. infof(data, "Resolve %s found illegal!\n", hostp->data);
  680. continue;
  681. }
  682. /* Create an entry id, based upon the hostname and port */
  683. entry_id = create_hostcache_id(hostname, port);
  684. /* If we can't create the entry id, fail */
  685. if(!entry_id) {
  686. Curl_freeaddrinfo(addr);
  687. return CURLE_OUT_OF_MEMORY;
  688. }
  689. entry_len = strlen(entry_id);
  690. if(data->share)
  691. Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
  692. /* See if its already in our dns cache */
  693. dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
  694. /* free the allocated entry_id again */
  695. free(entry_id);
  696. if(!dns)
  697. /* if not in the cache already, put this host in the cache */
  698. dns = Curl_cache_addr(data, addr, hostname, port);
  699. else
  700. /* this is a duplicate, free it again */
  701. Curl_freeaddrinfo(addr);
  702. if(data->share)
  703. Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
  704. if(!dns) {
  705. Curl_freeaddrinfo(addr);
  706. return CURLE_OUT_OF_MEMORY;
  707. }
  708. infof(data, "Added %s:%d:%s to DNS cache\n",
  709. hostname, port, address);
  710. }
  711. }
  712. data->change.resolve = NULL; /* dealt with now */
  713. return CURLE_OK;
  714. }