]> sjero.net Git - wget/blob - src/host.c
[svn] A lot of host name changes.
[wget] / src / host.c
1 /* Dealing with host names.
2    Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #ifdef HAVE_STRING_H
25 # include <string.h>
26 #else
27 # include <strings.h>
28 #endif
29 #include <assert.h>
30 #include <sys/types.h>
31
32 #ifdef WINDOWS
33 # include <winsock.h>
34 #else
35 # include <sys/socket.h>
36 # include <netinet/in.h>
37 #ifndef __BEOS__
38 # include <arpa/inet.h>
39 #endif
40 # include <netdb.h>
41 #endif /* WINDOWS */
42
43 #ifndef NO_ADDRESS
44 #define NO_ADDRESS NO_DATA
45 #endif
46
47 #ifdef HAVE_SYS_UTSNAME_H
48 # include <sys/utsname.h>
49 #endif
50 #include <errno.h>
51
52 #include "wget.h"
53 #include "utils.h"
54 #include "host.h"
55 #include "url.h"
56 #include "hash.h"
57
58 #ifndef errno
59 extern int errno;
60 #endif
61
62 #define IP4_ADDRESS_LENGTH 4
63
64 /* Mapping between known hosts and to lists of their addresses. */
65
66 struct hash_table *host_name_addresses_map;
67 \f
68 /* Lists of addresses.  This should eventually be extended to handle
69    IPv6.  */
70
71 struct address_list {
72   int count;                    /* number of adrresses */
73   unsigned char *buffer;        /* buffer which holds all of them. */
74
75   int refcount;                 /* so we know whether to free it or
76                                    not. */
77 };
78
79 #define ADDR_LOCATION(al, index) ((al)->buffer + index * IP4_ADDRESS_LENGTH)
80
81 /* Return the number of addresses in the list. */
82
83 int
84 address_list_count (struct address_list *al)
85 {
86   return al->count;
87 }
88
89 /* Copy address number INDEX to IP_STORE.  */
90
91 void
92 address_list_copy_one (struct address_list *al, int index,
93                        unsigned char *ip_store)
94 {
95   memcpy (ip_store, ADDR_LOCATION (al, index), IP4_ADDRESS_LENGTH);
96 }
97
98 /* Check whether two address lists have all their IPs in common.  */
99
100 int
101 address_list_match_all (struct address_list *al1, struct address_list *al2)
102 {
103   if (al1 == al2)
104     return 1;
105   if (al1->count != al2->count)
106     return 0;
107   return 0 == memcmp (al1->buffer, al2->buffer,
108                       al1->count * IP4_ADDRESS_LENGTH);
109 }
110
111 /* Create an address_list out of a NULL-terminated list of addresses,
112    as returned by gethostbyname.  */
113
114 static struct address_list *
115 address_list_new (char **h_addr_list)
116 {
117   int count = 0, i;
118
119   struct address_list *al = xmalloc (sizeof (struct address_list));
120
121   while (h_addr_list[count])
122     ++count;
123   assert (count > 0);
124   al->count    = count;
125   al->buffer   = xmalloc (count * IP4_ADDRESS_LENGTH);
126   al->refcount = 1;
127
128   for (i = 0; i < count; i++)
129     memcpy (ADDR_LOCATION (al, i), h_addr_list[i], IP4_ADDRESS_LENGTH);
130
131   return al;
132 }
133
134 static void
135 address_list_delete (struct address_list *al)
136 {
137   xfree (al->buffer);
138   xfree (al);
139 }
140
141 void
142 address_list_release (struct address_list *al)
143 {
144   --al->refcount;
145   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
146   if (al->refcount <= 0)
147     {
148       DEBUGP (("Deleting unused %p.\n", al));
149       address_list_delete (al);
150     }
151 }
152 \f
153 /* The same as inet_ntoa, but without the need for a cast, or for
154    #including the netinet stuff.  */
155
156 char *
157 pretty_print_address (const unsigned char *addr)
158 {
159   return inet_ntoa (*(struct in_addr *)addr);
160 }
161
162 /* Add host name HOST with the address ADDR_TEXT to the cache.
163    ADDR_LIST is a NULL-terminated list of addresses, as in struct
164    hostent.  */
165
166 static void
167 cache_host_lookup (const char *host, struct address_list *al)
168 {
169   if (!host_name_addresses_map)
170     host_name_addresses_map = make_nocase_string_hash_table (0);
171
172   ++al->refcount;
173   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
174
175 #ifdef DEBUG
176   if (opt.debug)
177     {
178       int i;
179       debug_logprintf ("Caching %s =>", host);
180       for (i = 0; i < al->count; i++)
181         debug_logprintf (" %s",
182                          pretty_print_address (ADDR_LOCATION (al, i)));
183       debug_logprintf ("\n");
184     }
185 #endif
186 }
187
188 struct address_list *
189 lookup_host (const char *host, int silent)
190 {
191   struct address_list *al = NULL;
192   unsigned long addr;
193   struct hostent *hptr;
194
195   /* If the address is of the form d.d.d.d, no further lookup is
196      needed.  */
197   addr = (unsigned long)inet_addr (host);
198   if ((int)addr != -1)
199     {
200       unsigned char tmpstore[IP4_ADDRESS_LENGTH];
201       char *lst[] = { tmpstore, NULL };
202
203       /* ADDR is defined to be in network byte order, which is what
204          this returns, so we can just copy it to STORE_IP.  However,
205          on big endian 64-bit architectures the value will be stored
206          in the *last*, not first four bytes.  OFFSET makes sure that
207          we copy the correct four bytes.  */
208       int offset;
209 #ifdef WORDS_BIGENDIAN
210       offset = sizeof (unsigned long) - IP4_ADDRESS_LENGTH;
211 #else
212       offset = 0;
213 #endif
214       memcpy (tmpstore, (char *)&addr + offset, IP4_ADDRESS_LENGTH);
215       return address_list_new (lst);
216     }
217
218   /* By now we know that the host name we got is not of the form
219      d.d.d.d.  Try to find it in our cache of host names.  */
220   if (host_name_addresses_map)
221     al = hash_table_get (host_name_addresses_map, host);
222
223   if (al)
224     {
225       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
226       ++al->refcount;
227       return al;
228     }
229
230   if (!silent)
231     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
232
233   /* Look up the host using gethostbyname().  Note that we use
234      gethostbyname() rather than ngethostbyname(), because we already
235      know that the address is not numerical.  */
236   hptr = gethostbyname (host);
237   if (!hptr)
238     {
239       if (!silent)
240         logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
241       return NULL;
242     }
243
244   if (!silent)
245     logprintf (LOG_VERBOSE, _("done.\n"));
246
247   al = address_list_new (hptr->h_addr_list);
248
249   /* Cache the lookup information. */
250   cache_host_lookup (host, al);
251
252   return al;
253 }
254 \f
255 /* Determine whether a URL is acceptable to be followed, according to
256    a list of domains to accept.  */
257 int
258 accept_domain (struct url *u)
259 {
260   assert (u->host != NULL);
261   if (opt.domains)
262     {
263       if (!sufmatch ((const char **)opt.domains, u->host))
264         return 0;
265     }
266   if (opt.exclude_domains)
267     {
268       if (sufmatch ((const char **)opt.exclude_domains, u->host))
269         return 0;
270     }
271   return 1;
272 }
273
274 /* Check whether WHAT is matched in LIST, each element of LIST being a
275    pattern to match WHAT against, using backward matching (see
276    match_backwards() in utils.c).
277
278    If an element of LIST matched, 1 is returned, 0 otherwise.  */
279 int
280 sufmatch (const char **list, const char *what)
281 {
282   int i, j, k, lw;
283
284   lw = strlen (what);
285   for (i = 0; list[i]; i++)
286     {
287       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
288         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
289           break;
290       /* The domain must be first to reach to beginning.  */
291       if (j == -1)
292         return 1;
293     }
294   return 0;
295 }
296
297 /* Print error messages for host errors.  */
298 char *
299 herrmsg (int error)
300 {
301   /* Can't use switch since some constants are equal (at least on my
302      system), and the compiler signals "duplicate case value".  */
303   if (error == HOST_NOT_FOUND
304       || error == NO_RECOVERY
305       || error == NO_DATA
306       || error == NO_ADDRESS
307       || error == TRY_AGAIN)
308     return _("Host not found");
309   else
310     return _("Unknown error");
311 }
312
313 static int
314 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
315 {
316   struct address_list *al;
317
318   xfree (key);                  /* host */
319
320   al = (struct address_list *)value;
321   assert (al->refcount == 1);
322   address_list_delete (al);
323
324   return 0;
325 }
326
327 void
328 host_cleanup (void)
329 {
330   if (host_name_addresses_map)
331     {
332       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
333       hash_table_destroy (host_name_addresses_map);
334       host_name_addresses_map = NULL;
335     }
336 }