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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15