1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
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.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
28 #ifdef HAVE_NETINET_IN6_H
29 #include <netinet/in6.h>
34 #ifdef HAVE_ARPA_INET_H
35 #include <arpa/inet.h>
60 #include "inet_ntop.h"
63 /* The last 3 #include files should be in this order */
64 #include "curl_printf.h"
65 #include "curl_memory.h"
68 #if defined(CURLRES_SYNCH) && \
69 defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
70 /* alarm-based timeouts can only be used with all the dependencies satisfied */
71 #define USE_ALARM_TIMEOUT
78 * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
79 * source file are these:
81 * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
82 * that. The host may not be able to resolve IPv6, but we don't really have to
83 * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
86 * CURLRES_ARES - is defined if libcurl is built to use c-ares for
87 * asynchronous name resolves. This can be Windows or *nix.
89 * CURLRES_THREADED - is defined if libcurl is built to run under (native)
90 * Windows, and then the name resolve will be done in a new thread, and the
91 * supported API will be the same as for ares-builds.
93 * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
94 * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
97 * The host*.c sources files are split up like this:
99 * hostip.c - method-independent resolver functions and utility functions
100 * hostasyn.c - functions for asynchronous name resolves
101 * hostsyn.c - functions for synchronous name resolves
102 * hostip4.c - IPv4 specific functions
103 * hostip6.c - IPv6 specific functions
105 * The two asynchronous name resolver backends are implemented in:
106 * asyn-ares.c - functions for ares-using name resolves
107 * asyn-thread.c - functions for threaded name resolves
109 * The hostip.h is the united header file for all this. It defines the
110 * CURLRES_* defines based on the config*.h and curl_setup.h defines.
113 /* These two symbols are for the global DNS cache */
114 static struct curl_hash hostname_cache;
115 static int host_cache_initialized;
117 static void freednsentry(void *freethis);
120 * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
121 * Global DNS cache is general badness. Do not use. This will be removed in
122 * a future version. Use the share interface instead!
124 * Returns a struct curl_hash pointer on success, NULL on failure.
126 struct curl_hash *Curl_global_host_cache_init(void)
129 if(!host_cache_initialized) {
130 rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
131 Curl_str_key_compare, freednsentry);
133 host_cache_initialized = 1;
135 return rc?NULL:&hostname_cache;
139 * Destroy and cleanup the global DNS cache
141 void Curl_global_host_cache_dtor(void)
143 if(host_cache_initialized) {
144 Curl_hash_destroy(&hostname_cache);
145 host_cache_initialized = 0;
150 * Return # of addresses in a Curl_addrinfo struct
152 int Curl_num_addresses(const Curl_addrinfo *addr)
156 addr = addr->ai_next;
163 * Curl_printable_address() returns a printable version of the 1st address
164 * given in the 'ai' argument. The result will be stored in the buf that is
167 * If the conversion fails, it returns NULL.
170 Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
172 const struct sockaddr_in *sa4;
173 const struct in_addr *ipaddr4;
175 const struct sockaddr_in6 *sa6;
176 const struct in6_addr *ipaddr6;
179 switch(ai->ai_family) {
181 sa4 = (const void *)ai->ai_addr;
182 ipaddr4 = &sa4->sin_addr;
183 return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
187 sa6 = (const void *)ai->ai_addr;
188 ipaddr6 = &sa6->sin6_addr;
189 return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
199 * Return a hostcache id string for the provided host + port, to be used by
203 create_hostcache_id(const char *name, int port)
205 /* create and return the new allocated entry */
206 char *id = aprintf("%s:%d", name, port);
209 /* lower case the name part */
210 while(*ptr && (*ptr != ':')) {
211 *ptr = (char)TOLOWER(*ptr);
218 struct hostcache_prune_data {
224 * This function is set as a callback to be called for every entry in the DNS
225 * cache when we want to prune old unused entries.
227 * Returning non-zero means remove the entry, return 0 to keep it in the
231 hostcache_timestamp_remove(void *datap, void *hc)
233 struct hostcache_prune_data *data =
234 (struct hostcache_prune_data *) datap;
235 struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
237 return (0 != c->timestamp)
238 && (data->now - c->timestamp >= data->cache_timeout);
242 * Prune the DNS cache. This assumes that a lock has already been taken.
245 hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
247 struct hostcache_prune_data user;
249 user.cache_timeout = cache_timeout;
252 Curl_hash_clean_with_criterium(hostcache,
254 hostcache_timestamp_remove);
258 * Library-wide function for pruning the DNS cache. This function takes and
259 * returns the appropriate locks.
261 void Curl_hostcache_prune(struct Curl_easy *data)
265 if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
266 /* cache forever means never prune, and NULL hostcache means
271 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
275 /* Remove outdated and unused entries from the hostcache */
276 hostcache_prune(data->dns.hostcache,
277 data->set.dns_cache_timeout,
281 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
284 #ifdef HAVE_SIGSETJMP
285 /* Beware this is a global and unique instance. This is used to store the
286 return address that we can jump back to from inside a signal handler. This
287 is not thread-safe stuff. */
288 sigjmp_buf curl_jmpenv;
291 /* lookup address, returns entry if found and not stale */
292 static struct Curl_dns_entry *
293 fetch_addr(struct connectdata *conn,
294 const char *hostname,
297 char *entry_id = NULL;
298 struct Curl_dns_entry *dns = NULL;
300 struct Curl_easy *data = conn->data;
302 /* Create an entry id, based upon the hostname and port */
303 entry_id = create_hostcache_id(hostname, port);
304 /* If we can't create the entry id, fail */
308 entry_len = strlen(entry_id);
310 /* See if its already in our dns cache */
311 dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
313 if(dns && (data->set.dns_cache_timeout != -1)) {
314 /* See whether the returned entry is stale. Done before we release lock */
315 struct hostcache_prune_data user;
318 user.cache_timeout = data->set.dns_cache_timeout;
320 if(hostcache_timestamp_remove(&user, dns)) {
321 infof(data, "Hostname in DNS cache was stale, zapped\n");
322 dns = NULL; /* the memory deallocation is being handled by the hash */
323 Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
327 /* free the allocated entry_id again */
334 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
336 * Curl_resolv() checks initially and multi_runsingle() checks each time
337 * it discovers the handle in the state WAITRESOLVE whether the hostname
338 * has already been resolved and the address has already been stored in
339 * the DNS cache. This short circuits waiting for a lot of pending
340 * lookups for the same hostname requested by different handles.
342 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
344 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
345 * use, or we'll leak memory!
347 struct Curl_dns_entry *
348 Curl_fetch_addr(struct connectdata *conn,
349 const char *hostname,
352 struct Curl_easy *data = conn->data;
353 struct Curl_dns_entry *dns = NULL;
356 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
358 dns = fetch_addr(conn, hostname, port);
361 dns->inuse++; /* we use it! */
364 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
370 * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
372 * When calling Curl_resolv() has resulted in a response with a returned
373 * address, we call this function to store the information in the dns
376 * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
378 struct Curl_dns_entry *
379 Curl_cache_addr(struct Curl_easy *data,
381 const char *hostname,
386 struct Curl_dns_entry *dns;
387 struct Curl_dns_entry *dns2;
389 /* Create an entry id, based upon the hostname and port */
390 entry_id = create_hostcache_id(hostname, port);
391 /* If we can't create the entry id, fail */
394 entry_len = strlen(entry_id);
396 /* Create a new cache entry */
397 dns = calloc(1, sizeof(struct Curl_dns_entry));
403 dns->inuse = 1; /* the cache has the first reference */
404 dns->addr = addr; /* this is the address(es) */
405 time(&dns->timestamp);
406 if(dns->timestamp == 0)
407 dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */
409 /* Store the resolved data in our DNS cache. */
410 dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
419 dns->inuse++; /* mark entry as in-use */
421 /* free the allocated entry_id */
428 * Curl_resolv() is the main name resolve function within libcurl. It resolves
429 * a name and returns a pointer to the entry in the 'entry' argument (if one
430 * is provided). This function might return immediately if we're using asynch
431 * resolves. See the return codes.
433 * The cache entry we return will get its 'inuse' counter increased when this
434 * function is used. You MUST call Curl_resolv_unlock() later (when you're
435 * done using this struct) to decrease the counter again.
437 * In debug mode, we specifically test for an interface name "LocalHost"
438 * and resolve "localhost" instead as a means to permit test cases
439 * to connect to a local test server with any host name.
443 * CURLRESOLV_ERROR (-1) = error, no pointer
444 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
445 * CURLRESOLV_PENDING (1) = waiting for response, no pointer
448 int Curl_resolv(struct connectdata *conn,
449 const char *hostname,
451 struct Curl_dns_entry **entry)
453 struct Curl_dns_entry *dns = NULL;
454 struct Curl_easy *data = conn->data;
456 int rc = CURLRESOLV_ERROR; /* default to failure */
461 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
463 dns = fetch_addr(conn, hostname, port);
466 infof(data, "Hostname %s was found in DNS cache\n", hostname);
467 dns->inuse++; /* we use it! */
468 rc = CURLRESOLV_RESOLVED;
472 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
475 /* The entry was not in the cache. Resolve it to IP address */
480 /* Check what IP specifics the app has requested and if we can provide it.
481 * If not, bail out. */
482 if(!Curl_ipvalid(conn))
483 return CURLRESOLV_ERROR;
485 /* notify the resolver start callback */
486 if(data->set.resolver_start) {
488 Curl_set_in_callback(data, true);
489 st = data->set.resolver_start(data->state.resolver, NULL,
490 data->set.resolver_start_client);
491 Curl_set_in_callback(data, false);
493 return CURLRESOLV_ERROR;
496 /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
497 non-zero value indicating that we need to wait for the response to the
499 addr = Curl_getaddrinfo(conn,
501 (data->set.str[STRING_DEVICE]
502 && !strcmp(data->set.str[STRING_DEVICE],
503 "LocalHost"))?"localhost":
505 hostname, port, &respwait);
509 /* the response to our resolve call will come asynchronously at
510 a later time, good or bad */
511 /* First, check that we haven't received the info by now */
512 result = Curl_resolver_is_resolved(conn, &dns);
513 if(result) /* error detected */
514 return CURLRESOLV_ERROR;
516 rc = CURLRESOLV_RESOLVED; /* pointer provided */
518 rc = CURLRESOLV_PENDING; /* no info yet */
523 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
525 /* we got a response, store it in the cache */
526 dns = Curl_cache_addr(data, addr, hostname, port);
529 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
532 /* returned failure, bail out nicely */
533 Curl_freeaddrinfo(addr);
535 rc = CURLRESOLV_RESOLVED;
544 #ifdef USE_ALARM_TIMEOUT
546 * This signal handler jumps back into the main libcurl code and continues
547 * execution. This effectively causes the remainder of the application to run
548 * within a signal handler which is nonportable and could lead to problems.
551 RETSIGTYPE alarmfunc(int sig)
553 /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
555 siglongjmp(curl_jmpenv, 1);
557 #endif /* USE_ALARM_TIMEOUT */
560 * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
561 * timeout. This function might return immediately if we're using asynch
562 * resolves. See the return codes.
564 * The cache entry we return will get its 'inuse' counter increased when this
565 * function is used. You MUST call Curl_resolv_unlock() later (when you're
566 * done using this struct) to decrease the counter again.
568 * If built with a synchronous resolver and use of signals is not
569 * disabled by the application, then a nonzero timeout will cause a
570 * timeout after the specified number of milliseconds. Otherwise, timeout
575 * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
576 * CURLRESOLV_ERROR (-1) = error, no pointer
577 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
578 * CURLRESOLV_PENDING (1) = waiting for response, no pointer
581 int Curl_resolv_timeout(struct connectdata *conn,
582 const char *hostname,
584 struct Curl_dns_entry **entry,
587 #ifdef USE_ALARM_TIMEOUT
588 #ifdef HAVE_SIGACTION
589 struct sigaction keep_sigact; /* store the old struct here */
590 volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */
591 struct sigaction sigact;
594 void (*keep_sigact)(int); /* store the old handler here */
595 #endif /* HAVE_SIGNAL */
596 #endif /* HAVE_SIGACTION */
597 volatile long timeout;
598 volatile unsigned int prev_alarm = 0;
599 struct Curl_easy *data = conn->data;
600 #endif /* USE_ALARM_TIMEOUT */
606 /* got an already expired timeout */
607 return CURLRESOLV_TIMEDOUT;
609 #ifdef USE_ALARM_TIMEOUT
610 if(data->set.no_signal)
611 /* Ignore the timeout when signals are disabled */
614 timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms;
617 /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
618 return Curl_resolv(conn, hostname, port, entry);
621 /* The alarm() function only provides integer second resolution, so if
622 we want to wait less than one second we must bail out already now. */
624 "remaining timeout of %ld too small to resolve via SIGALRM method",
626 return CURLRESOLV_TIMEDOUT;
628 /* This allows us to time-out from the name resolver, as the timeout
629 will generate a signal and we will siglongjmp() from that here.
630 This technique has problems (see alarmfunc).
631 This should be the last thing we do before calling Curl_resolv(),
632 as otherwise we'd have to worry about variables that get modified
633 before we invoke Curl_resolv() (and thus use "volatile"). */
634 if(sigsetjmp(curl_jmpenv, 1)) {
635 /* this is coming from a siglongjmp() after an alarm signal */
636 failf(data, "name lookup timed out");
637 rc = CURLRESOLV_ERROR;
641 /*************************************************************
642 * Set signal handler to catch SIGALRM
643 * Store the old value to be able to set it back later!
644 *************************************************************/
645 #ifdef HAVE_SIGACTION
646 sigaction(SIGALRM, NULL, &sigact);
647 keep_sigact = sigact;
648 keep_copysig = TRUE; /* yes, we have a copy */
649 sigact.sa_handler = alarmfunc;
651 /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
652 sigact.sa_flags &= ~SA_RESTART;
654 /* now set the new struct */
655 sigaction(SIGALRM, &sigact, NULL);
656 #else /* HAVE_SIGACTION */
657 /* no sigaction(), revert to the much lamer signal() */
659 keep_sigact = signal(SIGALRM, alarmfunc);
661 #endif /* HAVE_SIGACTION */
663 /* alarm() makes a signal get sent when the timeout fires off, and that
664 will abort system calls */
665 prev_alarm = alarm(curlx_sltoui(timeout/1000L));
669 #ifndef CURLRES_ASYNCH
671 infof(conn->data, "timeout on name lookup is not supported\n");
673 (void)timeoutms; /* timeoutms not used with an async resolver */
675 #endif /* USE_ALARM_TIMEOUT */
677 /* Perform the actual name resolution. This might be interrupted by an
678 * alarm if it takes too long.
680 rc = Curl_resolv(conn, hostname, port, entry);
682 #ifdef USE_ALARM_TIMEOUT
686 /* deactivate a possibly active alarm before uninstalling the handler */
689 #ifdef HAVE_SIGACTION
691 /* we got a struct as it looked before, now put that one back nice
693 sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
697 /* restore the previous SIGALRM handler */
698 signal(SIGALRM, keep_sigact);
700 #endif /* HAVE_SIGACTION */
702 /* switch back the alarm() to either zero or to what it was before minus
703 the time we spent until now! */
705 /* there was an alarm() set before us, now put it back */
706 timediff_t elapsed_secs = Curl_timediff(Curl_now(),
707 conn->created) / 1000;
709 /* the alarm period is counted in even number of seconds */
710 unsigned long alarm_set = prev_alarm - elapsed_secs;
713 ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
714 /* if the alarm time-left reached zero or turned "negative" (counted
715 with unsigned values), we should fire off a SIGALRM here, but we
716 won't, and zero would be to switch it off so we never set it to
719 rc = CURLRESOLV_TIMEDOUT;
720 failf(data, "Previous alarm fired off!");
723 alarm((unsigned int)alarm_set);
725 #endif /* USE_ALARM_TIMEOUT */
731 * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
732 * made, the struct may be destroyed due to pruning. It is important that only
733 * one unlock is made for each Curl_resolv() call.
735 * May be called with 'data' == NULL for global cache.
737 void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
739 if(data && data->share)
740 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
744 if(data && data->share)
745 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
749 * File-internal: release cache dns entry reference, free if inuse drops to 0
751 static void freednsentry(void *freethis)
753 struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
754 DEBUGASSERT(dns && (dns->inuse>0));
757 if(dns->inuse == 0) {
758 Curl_freeaddrinfo(dns->addr);
764 * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
766 int Curl_mk_dnscache(struct curl_hash *hash)
768 return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
773 * Curl_hostcache_clean()
775 * This _can_ be called with 'data' == NULL but then of course no locking
779 void Curl_hostcache_clean(struct Curl_easy *data,
780 struct curl_hash *hash)
782 if(data && data->share)
783 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
785 Curl_hash_clean(hash);
787 if(data && data->share)
788 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
792 CURLcode Curl_loadhostpairs(struct Curl_easy *data)
794 struct curl_slist *hostp;
798 for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
801 if(hostp->data[0] == '-') {
805 if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
806 infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
811 /* Create an entry id, based upon the hostname and port */
812 entry_id = create_hostcache_id(hostname, port);
813 /* If we can't create the entry id, fail */
815 return CURLE_OUT_OF_MEMORY;
818 entry_len = strlen(entry_id);
821 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
823 /* delete entry, ignore if it didn't exist */
824 Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
827 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
829 /* free the allocated entry_id again */
833 struct Curl_dns_entry *dns;
834 Curl_addrinfo *head = NULL, *tail = NULL;
838 char *addresses = NULL;
844 unsigned long tmp_port;
847 host_end = strchr(hostp->data, ':');
849 ((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
852 memcpy(hostname, hostp->data, host_end - hostp->data);
853 hostname[host_end - hostp->data] = '\0';
855 port_ptr = host_end + 1;
856 tmp_port = strtoul(port_ptr, &end_ptr, 10);
857 if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':')
860 port = (int)tmp_port;
861 addresses = end_ptr + 1;
867 addr_begin = end_ptr + 1;
868 addr_end = strchr(addr_begin, ',');
870 addr_end = addr_begin + strlen(addr_begin);
873 /* allow IP(v6) address within [brackets] */
874 if(*addr_begin == '[') {
875 if(addr_end == addr_begin || *(addr_end - 1) != ']')
881 alen = addr_end - addr_begin;
885 if(alen >= sizeof(address))
888 memcpy(address, addr_begin, alen);
889 address[alen] = '\0';
892 if(strchr(address, ':')) {
893 infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n",
899 ai = Curl_str2addr(address, port);
901 infof(data, "Resolve address '%s' found illegal!\n", address);
907 tail = tail->ai_next;
920 infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
922 Curl_freeaddrinfo(head);
926 /* Create an entry id, based upon the hostname and port */
927 entry_id = create_hostcache_id(hostname, port);
928 /* If we can't create the entry id, fail */
930 Curl_freeaddrinfo(head);
931 return CURLE_OUT_OF_MEMORY;
933 entry_len = strlen(entry_id);
936 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
938 /* See if its already in our dns cache */
939 dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
941 /* free the allocated entry_id again */
945 /* if not in the cache already, put this host in the cache */
946 dns = Curl_cache_addr(data, head, hostname, port);
948 dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
949 /* release the returned reference; the cache itself will keep the
955 /* this is a duplicate, free it again */
956 infof(data, "RESOLVE %s:%d is already cached, %s not stored!\n",
957 hostname, port, addresses);
958 Curl_freeaddrinfo(head);
962 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
965 Curl_freeaddrinfo(head);
966 return CURLE_OUT_OF_MEMORY;
968 infof(data, "Added %s:%d:%s to DNS cache\n",
969 hostname, port, addresses);
972 data->change.resolve = NULL; /* dealt with now */