Simplify check for NEED_MALLOC_H, and make more explicit that NEED_MALLOC_H shall...
[platform/upstream/curl.git] / lib / hostip.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2006, 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  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #include <string.h>
27
28 #ifdef NEED_MALLOC_H
29 #include <malloc.h>
30 #endif
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_STDLIB_H
47 #include <stdlib.h>     /* required for free() prototypes */
48 #endif
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>     /* for the close() proto */
51 #endif
52 #ifdef  VMS
53 #include <in.h>
54 #include <inet.h>
55 #include <stdlib.h>
56 #endif
57
58 #ifdef HAVE_SETJMP_H
59 #include <setjmp.h>
60 #endif
61
62 #ifdef HAVE_PROCESS_H
63 #include <process.h>
64 #endif
65
66 #include "urldata.h"
67 #include "sendf.h"
68 #include "hostip.h"
69 #include "hash.h"
70 #include "share.h"
71 #include "strerror.h"
72 #include "url.h"
73 #include "inet_ntop.h"
74
75 #define _MPRINTF_REPLACE /* use our functions only */
76 #include <curl/mprintf.h>
77
78 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
79 #include "inet_ntoa_r.h"
80 #endif
81
82 #include "memory.h"
83 /* The last #include file should be: */
84 #include "memdebug.h"
85
86 /*
87  * hostip.c explained
88  * ==================
89  *
90  * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
91  * source file are these:
92  *
93  * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
94  * that. The host may not be able to resolve IPv6, but we don't really have to
95  * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
96  * defined.
97  *
98  * CURLRES_ARES - is defined if libcurl is built to use c-ares for
99  * asynchronous name resolves. This can be Windows or *nix.
100  *
101  * CURLRES_THREADED - is defined if libcurl is built to run under (native)
102  * Windows, and then the name resolve will be done in a new thread, and the
103  * supported API will be the same as for ares-builds.
104  *
105  * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
106  * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
107  * defined.
108  *
109  * The host*.c sources files are split up like this:
110  *
111  * hostip.c   - method-independent resolver functions and utility functions
112  * hostasyn.c - functions for asynchronous name resolves
113  * hostsyn.c  - functions for synchronous name resolves
114  * hostares.c - functions for ares-using name resolves
115  * hostthre.c - functions for threaded name resolves
116  * hostip4.c  - ipv4-specific functions
117  * hostip6.c  - ipv6-specific functions
118  *
119  * The hostip.h is the united header file for all this. It defines the
120  * CURLRES_* defines based on the config*.h and setup.h defines.
121  */
122
123 /* These two symbols are for the global DNS cache */
124 static struct curl_hash hostname_cache;
125 static int host_cache_initialized;
126
127 static void freednsentry(void *freethis);
128
129 /*
130  * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
131  * Global DNS cache is general badness. Do not use. This will be removed in
132  * a future version. Use the share interface instead!
133  */
134 void Curl_global_host_cache_init(void)
135 {
136   if (!host_cache_initialized) {
137     Curl_hash_init(&hostname_cache, 7, freednsentry);
138     host_cache_initialized = 1;
139   }
140 }
141
142 /*
143  * Return a pointer to the global cache
144  */
145 struct curl_hash *Curl_global_host_cache_get(void)
146 {
147   return &hostname_cache;
148 }
149
150 /*
151  * Destroy and cleanup the global DNS cache
152  */
153 void Curl_global_host_cache_dtor(void)
154 {
155   if (host_cache_initialized) {
156     Curl_hash_clean(&hostname_cache);
157     host_cache_initialized = 0;
158   }
159 }
160
161 /*
162  * Return # of adresses in a Curl_addrinfo struct
163  */
164 int Curl_num_addresses(const Curl_addrinfo *addr)
165 {
166   int i;
167   for (i = 0; addr; addr = addr->ai_next, i++)
168     ;  /* empty loop */
169   return i;
170 }
171
172 /*
173  * Curl_printable_address() returns a printable version of the 1st address
174  * given in the 'ip' argument. The result will be stored in the buf that is
175  * bufsize bytes big.
176  *
177  * If the conversion fails, it returns NULL.
178  */
179 const char *Curl_printable_address(const Curl_addrinfo *ip,
180                                    char *buf, size_t bufsize)
181 {
182   const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
183   int af = ip->ai_family;
184 #ifdef CURLRES_IPV6
185   const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
186 #else
187   const void *ip6 = NULL;
188 #endif
189
190   return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
191 }
192
193 /*
194  * Return a hostcache id string for the providing host + port, to be used by
195  * the DNS caching.
196  */
197 static char *
198 create_hostcache_id(const char *server, int port)
199 {
200   /* create and return the new allocated entry */
201   return aprintf("%s:%d", server, port);
202 }
203
204 struct hostcache_prune_data {
205   int cache_timeout;
206   time_t now;
207 };
208
209 /*
210  * This function is set as a callback to be called for every entry in the DNS
211  * cache when we want to prune old unused entries.
212  *
213  * Returning non-zero means remove the entry, return 0 to keep it in the
214  * cache.
215  */
216 static int
217 hostcache_timestamp_remove(void *datap, void *hc)
218 {
219   struct hostcache_prune_data *data =
220     (struct hostcache_prune_data *) datap;
221   struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
222
223   if ((data->now - c->timestamp < data->cache_timeout) ||
224       c->inuse) {
225     /* please don't remove */
226     return 0;
227   }
228
229   /* fine, remove */
230   return 1;
231 }
232
233 /*
234  * Prune the DNS cache. This assumes that a lock has already been taken.
235  */
236 static void
237 hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now)
238 {
239   struct hostcache_prune_data user;
240
241   user.cache_timeout = cache_timeout;
242   user.now = now;
243
244   Curl_hash_clean_with_criterium(hostcache,
245                                  (void *) &user,
246                                  hostcache_timestamp_remove);
247 }
248
249 /*
250  * Library-wide function for pruning the DNS cache. This function takes and
251  * returns the appropriate locks.
252  */
253 void Curl_hostcache_prune(struct SessionHandle *data)
254 {
255   time_t now;
256
257   if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
258     /* cache forever means never prune, and NULL hostcache means
259        we can't do it */
260     return;
261
262   if(data->share)
263     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
264
265   time(&now);
266
267   /* Remove outdated and unused entries from the hostcache */
268   hostcache_prune(data->dns.hostcache,
269                   data->set.dns_cache_timeout,
270                   now);
271
272   if(data->share)
273     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
274 }
275
276 static int
277 remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
278 {
279   struct hostcache_prune_data user;
280
281   if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
282     /* cache forever means never prune, and NULL hostcache means
283        we can't do it */
284     return 0;
285
286   time(&user.now);
287   user.cache_timeout = data->set.dns_cache_timeout;
288
289   if ( !hostcache_timestamp_remove(&user,dns) )
290     return 0;
291
292   /* ok, we do need to clear the cache. although we need to remove just a
293      single entry we clean the entire hash, as no explicit delete function
294      is provided */
295   if(data->share)
296     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
297
298   Curl_hash_clean_with_criterium(data->dns.hostcache,
299                                  (void *) &user,
300                                  hostcache_timestamp_remove);
301
302   if(data->share)
303     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
304
305   return 1;
306 }
307
308
309 #ifdef HAVE_SIGSETJMP
310 /* Beware this is a global and unique instance. This is used to store the
311    return address that we can jump back to from inside a signal handler. This
312    is not thread-safe stuff. */
313 sigjmp_buf curl_jmpenv;
314 #endif
315
316
317 /*
318  * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
319  *
320  * When calling Curl_resolv() has resulted in a response with a returned
321  * address, we call this function to store the information in the dns
322  * cache etc
323  *
324  * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
325  */
326 struct Curl_dns_entry *
327 Curl_cache_addr(struct SessionHandle *data,
328                 Curl_addrinfo *addr,
329                 const char *hostname,
330                 int port)
331 {
332   char *entry_id;
333   size_t entry_len;
334   struct Curl_dns_entry *dns;
335   struct Curl_dns_entry *dns2;
336   time_t now;
337
338   /* Create an entry id, based upon the hostname and port */
339   entry_id = create_hostcache_id(hostname, port);
340   /* If we can't create the entry id, fail */
341   if (!entry_id)
342     return NULL;
343   entry_len = strlen(entry_id);
344
345   /* Create a new cache entry */
346   dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
347   if (!dns) {
348     free(entry_id);
349     return NULL;
350   }
351
352   dns->inuse = 0;   /* init to not used */
353   dns->addr = addr; /* this is the address(es) */
354
355   /* Store the resolved data in our DNS cache. This function may return a
356      pointer to an existing struct already present in the hash, and it may
357      return the same argument we pass in. Make no assumptions. */
358   dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
359                        (void *)dns);
360   if(!dns2) {
361     /* Major badness, run away. */
362     free(dns);
363     free(entry_id);
364     return NULL;
365   }
366   time(&now);
367   dns = dns2;
368
369   dns->timestamp = now; /* used now */
370   dns->inuse++;         /* mark entry as in-use */
371
372   /* free the allocated entry_id again */
373   free(entry_id);
374
375   return dns;
376 }
377
378 /*
379  * Curl_resolv() is the main name resolve function within libcurl. It resolves
380  * a name and returns a pointer to the entry in the 'entry' argument (if one
381  * is provided). This function might return immediately if we're using asynch
382  * resolves. See the return codes.
383  *
384  * The cache entry we return will get its 'inuse' counter increased when this
385  * function is used. You MUST call Curl_resolv_unlock() later (when you're
386  * done using this struct) to decrease the counter again.
387  *
388  * Return codes:
389  *
390  * CURLRESOLV_ERROR   (-1) = error, no pointer
391  * CURLRESOLV_RESOLVED (0) = OK, pointer provided
392  * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
393  */
394
395 int Curl_resolv(struct connectdata *conn,
396                 const char *hostname,
397                 int port,
398                 struct Curl_dns_entry **entry)
399 {
400   char *entry_id = NULL;
401   struct Curl_dns_entry *dns = NULL;
402   size_t entry_len;
403   int wait;
404   struct SessionHandle *data = conn->data;
405   CURLcode result;
406   int rc;
407   *entry = NULL;
408
409 #ifdef HAVE_SIGSETJMP
410   /* this allows us to time-out from the name resolver, as the timeout
411      will generate a signal and we will siglongjmp() from that here */
412   if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
413     /* this is coming from a siglongjmp() */
414     failf(data, "name lookup timed out");
415     return CURLRESOLV_ERROR;
416   }
417 #endif
418
419   /* Create an entry id, based upon the hostname and port */
420   entry_id = create_hostcache_id(hostname, port);
421   /* If we can't create the entry id, fail */
422   if (!entry_id)
423     return CURLRESOLV_ERROR;
424
425   entry_len = strlen(entry_id);
426
427   if(data->share)
428     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
429
430   /* See if its already in our dns cache */
431   dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
432
433   if(data->share)
434     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
435
436   /* free the allocated entry_id again */
437   free(entry_id);
438
439   /* See whether the returned entry is stale. Deliberately done after the
440      locked block */
441   if ( remove_entry_if_stale(data,dns) )
442     dns = NULL; /* the memory deallocation is being handled by the hash */
443
444   rc = CURLRESOLV_ERROR; /* default to failure */
445
446   if (!dns) {
447     /* The entry was not in the cache. Resolve it to IP address */
448
449     Curl_addrinfo *addr;
450
451     /* Check what IP specifics the app has requested and if we can provide it.
452      * If not, bail out. */
453     if(!Curl_ipvalid(data))
454       return CURLRESOLV_ERROR;
455
456     /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
457        value indicating that we need to wait for the response to the resolve
458        call */
459     addr = Curl_getaddrinfo(conn, hostname, port, &wait);
460
461     if (!addr) {
462       if(wait) {
463         /* the response to our resolve call will come asynchronously at
464            a later time, good or bad */
465         /* First, check that we haven't received the info by now */
466         result = Curl_is_resolved(conn, &dns);
467         if(result) /* error detected */
468           return CURLRESOLV_ERROR;
469         if(dns)
470           rc = CURLRESOLV_RESOLVED; /* pointer provided */
471         else
472           rc = CURLRESOLV_PENDING; /* no info yet */
473       }
474     }
475     else {
476       if(data->share)
477         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
478
479       /* we got a response, store it in the cache */
480       dns = Curl_cache_addr(data, addr, hostname, port);
481
482       if(data->share)
483         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
484
485       if(!dns)
486         /* returned failure, bail out nicely */
487         Curl_freeaddrinfo(addr);
488       else
489         rc = CURLRESOLV_RESOLVED;
490     }
491   }
492   else {
493     if(data->share)
494       Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
495     dns->inuse++; /* we use it! */
496     if(data->share)
497       Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
498     rc = CURLRESOLV_RESOLVED;
499   }
500
501   *entry = dns;
502
503   return rc;
504 }
505
506 /*
507  * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
508  * made, the struct may be destroyed due to pruning. It is important that only
509  * one unlock is made for each Curl_resolv() call.
510  */
511 void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
512 {
513   curlassert(dns && (dns->inuse>0));
514
515   if(data->share)
516     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
517
518   dns->inuse--;
519
520   if(data->share)
521     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
522 }
523
524 /*
525  * File-internal: free a cache dns entry.
526  */
527 static void freednsentry(void *freethis)
528 {
529   struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
530
531   Curl_freeaddrinfo(p->addr);
532
533   free(p);
534 }
535
536 /*
537  * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
538  */
539 struct curl_hash *Curl_mk_dnscache(void)
540 {
541   return Curl_hash_alloc(7, freednsentry);
542 }
543
544 #ifdef CURLRES_ADDRINFO_COPY
545
546 /* align on even 64bit boundaries */
547 #define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
548
549 /*
550  * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
551  * returns a pointer to the malloc()ed copy. You need to call free() on the
552  * returned buffer when you're done with it.
553  */
554 Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
555 {
556   const struct hostent *orig = org;
557
558   return Curl_he2ai(orig, port);
559 }
560 #endif /* CURLRES_ADDRINFO_COPY */
561
562 /***********************************************************************
563  * Only for plain-ipv4 and c-ares builds
564  **********************************************************************/
565
566 #if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
567 /*
568  * This is a function for freeing name information in a protocol independent
569  * way.
570  */
571 void Curl_freeaddrinfo(Curl_addrinfo *ai)
572 {
573   Curl_addrinfo *next;
574
575   /* walk over the list and free all entries */
576   while(ai) {
577     next = ai->ai_next;
578     free(ai);
579     ai = next;
580   }
581 }
582
583 struct namebuf {
584   struct hostent hostentry;
585   char *h_addr_list[2];
586   struct in_addr addrentry;
587   char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
588 };
589
590 /*
591  * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
592  * together with a pointer to the string version of the address, and it
593  * returns a Curl_addrinfo chain filled in correctly with information for this
594  * address/host.
595  *
596  * The input parameters ARE NOT checked for validity but they are expected
597  * to have been checked already when this is called.
598  */
599 Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
600 {
601   Curl_addrinfo *ai;
602   struct hostent *h;
603   struct in_addr *addrentry;
604   struct namebuf buffer;
605   struct namebuf *buf = &buffer;
606
607   h = &buf->hostentry;
608   h->h_addr_list = &buf->h_addr_list[0];
609   addrentry = &buf->addrentry;
610   addrentry->s_addr = num;
611   h->h_addr_list[0] = (char*)addrentry;
612   h->h_addr_list[1] = NULL;
613   h->h_addrtype = AF_INET;
614   h->h_length = sizeof(*addrentry);
615   h->h_name = &buf->h_name[0];
616   h->h_aliases = NULL;
617
618   /* Now store the dotted version of the address */
619   snprintf((char *)h->h_name, 16, "%s", hostname);
620
621   ai = Curl_he2ai(h, port);
622
623   return ai;
624 }
625 #endif