]> sjero.net Git - wget/blob - src/host.c
[svn] Minor fixes prompted by `lint'.
[wget] / src / host.c
1 /* Host name resolution and matching.
2    Copyright (C) 1995, 1996, 1997, 2000, 2001 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 #ifndef h_errno
63 # ifndef __CYGWIN__
64 extern int h_errno;
65 # endif
66 #endif
67
68 #define IP4_ADDRESS_LENGTH 4
69
70 /* Mapping between known hosts and to lists of their addresses. */
71
72 static struct hash_table *host_name_addresses_map;
73 \f
74 /* Lists of addresses.  This should eventually be extended to handle
75    IPv6.  */
76
77 struct address_list {
78   int count;                    /* number of adrresses */
79   unsigned char *buffer;        /* buffer which holds all of them. */
80
81   int faulty;                   /* number of addresses known not to
82                                    work. */
83   int refcount;                 /* so we know whether to free it or
84                                    not. */
85 };
86
87 #define ADDR_LOCATION(al, index) ((al)->buffer + index * IP4_ADDRESS_LENGTH)
88
89 /* Get the bounds of the address list.  */
90
91 void
92 address_list_get_bounds (struct address_list *al, int *start, int *end)
93 {
94   *start = al->faulty;
95   *end   = al->count;
96 }
97
98 /* Copy address number INDEX to IP_STORE.  */
99
100 void
101 address_list_copy_one (struct address_list *al, int index,
102                        unsigned char *ip_store)
103 {
104   assert (index >= al->faulty && index < al->count);
105   memcpy (ip_store, ADDR_LOCATION (al, index), IP4_ADDRESS_LENGTH);
106 }
107
108 /* Check whether two address lists have all their IPs in common.  */
109
110 int
111 address_list_match_all (struct address_list *al1, struct address_list *al2)
112 {
113   if (al1 == al2)
114     return 1;
115   if (al1->count != al2->count)
116     return 0;
117   return 0 == memcmp (al1->buffer, al2->buffer,
118                       al1->count * IP4_ADDRESS_LENGTH);
119 }
120
121 /* Mark the INDEXth element of AL as faulty, so that the next time
122    this address list is used, the faulty element will be skipped.  */
123
124 void
125 address_list_set_faulty (struct address_list *al, int index)
126 {
127 #if 0
128   /* Warning: INDEX is unused, so this assumes that the address list
129      is traversed in order.  In the next release, either enable this
130      assert, or use INDEX.  */
131   assert (index == al->faulty);
132 #endif
133
134   ++al->faulty;
135   if (al->faulty >= al->count)
136     /* All addresses have been proven faulty.  Since there's not much
137        sense in returning the user an empty address list the next
138        time, we'll rather make them all clean, so that they can be
139        retried anew.  */
140     al->faulty = 0;
141 }
142
143 /* Create an address_list out of a NULL-terminated list of addresses,
144    as returned by gethostbyname.  */
145
146 static struct address_list *
147 address_list_new (char **h_addr_list)
148 {
149   int count = 0, i;
150
151   struct address_list *al = xmalloc (sizeof (struct address_list));
152
153   while (h_addr_list[count])
154     ++count;
155   assert (count > 0);
156   al->count    = count;
157   al->faulty   = 0;
158   al->buffer   = xmalloc (count * IP4_ADDRESS_LENGTH);
159   al->refcount = 1;
160
161   for (i = 0; i < count; i++)
162     memcpy (ADDR_LOCATION (al, i), h_addr_list[i], IP4_ADDRESS_LENGTH);
163
164   return al;
165 }
166
167 /* Like address_list_new, but initialized with only one address. */
168
169 static struct address_list *
170 address_list_new_one (const char *addr)
171 {
172   struct address_list *al = xmalloc (sizeof (struct address_list));
173   al->count    = 1;
174   al->faulty   = 0;
175   al->buffer   = xmalloc (IP4_ADDRESS_LENGTH);
176   al->refcount = 1;
177   memcpy (ADDR_LOCATION (al, 0), addr, IP4_ADDRESS_LENGTH);
178
179   return al;
180 }
181
182 static void
183 address_list_delete (struct address_list *al)
184 {
185   xfree (al->buffer);
186   xfree (al);
187 }
188
189 void
190 address_list_release (struct address_list *al)
191 {
192   --al->refcount;
193   DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount));
194   if (al->refcount <= 0)
195     {
196       DEBUGP (("Deleting unused %p.\n", al));
197       address_list_delete (al);
198     }
199 }
200 \f
201 /* The same as inet_ntoa, but without the need for a cast, or for
202    #including the netinet stuff.  */
203
204 char *
205 pretty_print_address (const unsigned char *addr)
206 {
207   return inet_ntoa (*(struct in_addr *)addr);
208 }
209
210 /* Add host name HOST with the address ADDR_TEXT to the cache.
211    ADDR_LIST is a NULL-terminated list of addresses, as in struct
212    hostent.  */
213
214 static void
215 cache_host_lookup (const char *host, struct address_list *al)
216 {
217   if (!host_name_addresses_map)
218     host_name_addresses_map = make_nocase_string_hash_table (0);
219
220   ++al->refcount;
221   hash_table_put (host_name_addresses_map, xstrdup_lower (host), al);
222
223 #ifdef DEBUG
224   if (opt.debug)
225     {
226       int i;
227       debug_logprintf ("Caching %s =>", host);
228       for (i = 0; i < al->count; i++)
229         debug_logprintf (" %s",
230                          pretty_print_address (ADDR_LOCATION (al, i)));
231       debug_logprintf ("\n");
232     }
233 #endif
234 }
235
236 struct address_list *
237 lookup_host (const char *host, int silent)
238 {
239   struct address_list *al = NULL;
240   unsigned long addr;
241   struct hostent *hptr;
242
243   /* If the address is of the form d.d.d.d, no further lookup is
244      needed.  */
245   addr = (unsigned long)inet_addr (host);
246   if ((int)addr != -1)
247     {
248       /* ADDR is defined to be in network byte order, which is what
249          this returns, so we can just copy it to STORE_IP.  However,
250          on big endian 64-bit architectures the value will be stored
251          in the *last*, not first four bytes.  OFFSET makes sure that
252          we copy the correct four bytes.  */
253       int offset;
254 #ifdef WORDS_BIGENDIAN
255       offset = sizeof (unsigned long) - IP4_ADDRESS_LENGTH;
256 #else
257       offset = 0;
258 #endif
259       return address_list_new_one ((char *)&addr + offset);
260     }
261
262   /* By now we know that the host name we got is not of the form
263      d.d.d.d.  Try to find it in our cache of host names.  */
264   if (host_name_addresses_map)
265     al = hash_table_get (host_name_addresses_map, host);
266
267   if (al)
268     {
269       DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
270       ++al->refcount;
271       return al;
272     }
273
274   if (!silent)
275     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
276
277   /* Look up the host using gethostbyname().  */
278   hptr = gethostbyname (host);
279   if (!hptr)
280     {
281       if (!silent)
282         logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
283       return NULL;
284     }
285
286   if (!silent)
287     logprintf (LOG_VERBOSE, _("done.\n"));
288
289   /* Do all systems have h_addr_list, or is it a newer thing?  If the
290      latter, use address_list_new_one.  */
291   al = address_list_new (hptr->h_addr_list);
292
293   /* Cache the lookup information. */
294   cache_host_lookup (host, al);
295
296   return al;
297 }
298 \f
299 /* Determine whether a URL is acceptable to be followed, according to
300    a list of domains to accept.  */
301 int
302 accept_domain (struct url *u)
303 {
304   assert (u->host != NULL);
305   if (opt.domains)
306     {
307       if (!sufmatch ((const char **)opt.domains, u->host))
308         return 0;
309     }
310   if (opt.exclude_domains)
311     {
312       if (sufmatch ((const char **)opt.exclude_domains, u->host))
313         return 0;
314     }
315   return 1;
316 }
317
318 /* Check whether WHAT is matched in LIST, each element of LIST being a
319    pattern to match WHAT against, using backward matching (see
320    match_backwards() in utils.c).
321
322    If an element of LIST matched, 1 is returned, 0 otherwise.  */
323 int
324 sufmatch (const char **list, const char *what)
325 {
326   int i, j, k, lw;
327
328   lw = strlen (what);
329   for (i = 0; list[i]; i++)
330     {
331       for (j = strlen (list[i]), k = lw; j >= 0 && k >= 0; j--, k--)
332         if (TOLOWER (list[i][j]) != TOLOWER (what[k]))
333           break;
334       /* The domain must be first to reach to beginning.  */
335       if (j == -1)
336         return 1;
337     }
338   return 0;
339 }
340
341 /* Print error messages for host errors.  */
342 char *
343 herrmsg (int error)
344 {
345   /* Can't use switch since some constants are equal (at least on my
346      system), and the compiler signals "duplicate case value".  */
347   if (error == HOST_NOT_FOUND
348       || error == NO_RECOVERY
349       || error == NO_DATA
350       || error == NO_ADDRESS
351       || error == TRY_AGAIN)
352     return _("Host not found");
353   else
354     return _("Unknown error");
355 }
356
357 static int
358 host_cleanup_mapper (void *key, void *value, void *arg_ignored)
359 {
360   struct address_list *al;
361
362   xfree (key);                  /* host */
363
364   al = (struct address_list *)value;
365   assert (al->refcount == 1);
366   address_list_delete (al);
367
368   return 0;
369 }
370
371 void
372 host_cleanup (void)
373 {
374   if (host_name_addresses_map)
375     {
376       hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL);
377       hash_table_destroy (host_name_addresses_map);
378       host_name_addresses_map = NULL;
379     }
380 }