X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fhost.c;h=e9df830d68585b351e078495826a5a458a3279cd;hp=148ba036cec31d0e98e982b21ce99909baf7b5bc;hb=cb4003403509b46d2f6ef6936baf969906ff1430;hpb=1a6058b1ec98baf1dce0574bec5079ae0db0f0c0 diff --git a/src/host.c b/src/host.c index 148ba036..e9df830d 100644 --- a/src/host.c +++ b/src/host.c @@ -1,23 +1,24 @@ -/* Dealing with host names. - Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc. +/* Host name resolution and matching. + Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. -This file is part of Wget. +This file is part of GNU Wget. -This program is free software; you can redistribute it and/or modify +GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, +GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software +along with Wget; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include #include #include @@ -34,10 +35,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #else # include # include -# include +# ifndef __BEOS__ +# include +# endif # include #endif /* WINDOWS */ +#ifndef NO_ADDRESS +#define NO_ADDRESS NO_DATA +#endif + #ifdef HAVE_SYS_UTSNAME_H # include #endif @@ -53,277 +60,535 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ extern int errno; #endif -/* Mapping between all known hosts to their addresses (n.n.n.n). */ -struct hash_table *host_name_address_map; +#ifndef h_errno +# ifndef __CYGWIN__ +extern int h_errno; +# endif +#endif + +#ifdef INET6 +int ip_default_family = AF_INET6; +#else +int ip_default_family = AF_INET; +#endif + +/* Mapping between known hosts and to lists of their addresses. */ + +static struct hash_table *host_name_addresses_map; + +/* Lists of addresses. This should eventually be extended to handle + IPv6. */ -/* Mapping between all known addresses (n.n.n.n) to their hosts. This - is the inverse of host_name_address_map. These two tables share - the strdup'ed strings. */ -struct hash_table *host_address_name_map; +struct address_list { + int count; /* number of adrresses */ + ip_address *addresses; /* pointer to the string of addresses */ -/* Mapping between auxilliary (slave) and master host names. */ -struct hash_table *host_slave_master_map; + int faulty; /* number of addresses known not to work. */ + int refcount; /* so we know whether to free it or not. */ +}; -/* Utility function: like xstrdup(), but also lowercases S. */ +/* Get the bounds of the address list. */ -static char * -xstrdup_lower (const char *s) +void +address_list_get_bounds (struct address_list *al, int *start, int *end) { - char *copy = xstrdup (s); - char *p = copy; - for (; *p; p++) - *p = TOLOWER (*p); - return copy; + *start = al->faulty; + *end = al->count; } -/* The same as gethostbyname, but supports internet addresses of the - form `N.N.N.N'. On some systems gethostbyname() knows how to do - this automatically. */ -struct hostent * -ngethostbyname (const char *name) +/* Copy address number INDEX to IP_STORE. */ + +void +address_list_copy_one (struct address_list *al, int index, ip_address *ip_store) { - struct hostent *hp; - unsigned long addr; + assert (index >= al->faulty && index < al->count && ip_store!=NULL ); + memcpy (ip_store, al->addresses + index, sizeof (ip_address)); +} - addr = (unsigned long)inet_addr (name); - if ((int)addr != -1) - hp = gethostbyaddr ((char *)&addr, sizeof (addr), AF_INET); - else - hp = gethostbyname (name); - return hp; +/* Check whether two address lists have all their IPs in common. */ + +int +address_list_match_all (struct address_list *al1, struct address_list *al2) +{ + if (al1 == al2) + return 1; + if (al1->count != al2->count) + return 0; + return 0 == memcmp (al1->addresses, al2->addresses, + al1->count * sizeof (ip_address)); } -/* Add host name HOST with the address ADDR_TEXT to the cache. - Normally this means that the (HOST, ADDR_TEXT) pair will be to - host_name_address_map and to host_address_name_map. (It is the - caller's responsibility to make sure that HOST is not already in - host_name_address_map.) +/* Mark the INDEXth element of AL as faulty, so that the next time + this address list is used, the faulty element will be skipped. */ + +void +address_list_set_faulty (struct address_list *al, int index) +{ + /* We assume that the address list is traversed in order, so that a + "faulty" attempt is always preceded with all-faulty addresses, + and this is how Wget uses it. */ + assert (index == al->faulty); + + ++al->faulty; + if (al->faulty >= al->count) + /* All addresses have been proven faulty. Since there's not much + sense in returning the user an empty address list the next + time, we'll rather make them all clean, so that they can be + retried anew. */ + al->faulty = 0; +} - If the ADDR_TEXT has already been seen and belongs to another host, - HOST will be added to host_slave_master_map instead. */ +#ifdef INET6 +/** + * address_list_from_addrinfo + * + * This function transform an addrinfo links list in and address_list. + * + * Input: + * addrinfo* Linkt list of addrinfo + * + * Output: + * address_list* New allocated address_list + */ +static struct address_list * +address_list_from_addrinfo (struct addrinfo *ai) +{ + struct address_list *al; + struct addrinfo *ai_head = ai; + int cnt = 0; + int i; + + for (ai = ai_head; ai; ai = ai->ai_next) + if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) + ++cnt; + if (cnt == 0) + return NULL; + + al = xmalloc (sizeof (struct address_list)); + al->addresses = xmalloc (cnt * sizeof (ip_address)); + al->count = cnt; + al->faulty = 0; + al->refcount = 1; + + for (i = 0, ai = ai_head; ai; ai = ai->ai_next) + if (ai->ai_family == AF_INET6) + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr; + memcpy (al->addresses + i, &sin6->sin6_addr, 16); + ++i; + } + else if (ai->ai_family == AF_INET) + { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i); + ++i; + } + assert (i == cnt); + return al; +} +#else +/* Create an address_list out of a NULL-terminated list of addresses, + as returned by gethostbyname. */ +static struct address_list * +address_list_new (char **h_addr_list) +{ + int count = 0, i; + + struct address_list *al = xmalloc (sizeof (struct address_list)); + + while (h_addr_list[count]) + ++count; + assert (count > 0); + al->count = count; + al->faulty = 0; + al->addresses = xmalloc (count * sizeof (ip_address)); + al->refcount = 1; + + for (i = 0; i < count; i++) + memcpy (al->addresses + i, h_addr_list[i], sizeof (ip_address)); + + return al; +} +#endif + +/* Like address_list_new, but initialized with only one address. */ + +static struct address_list * +address_list_new_one (ip_address *addr) +{ + struct address_list *al = xmalloc (sizeof (struct address_list)); + al->count = 1; + al->faulty = 0; + al->addresses = xmalloc (sizeof (ip_address)); + al->refcount = 1; + memcpy (al->addresses, addr, sizeof (ip_address)); + + return al; +} static void -add_host_to_cache (const char *host, const char *addr_text) +address_list_delete (struct address_list *al) { - char *canonical_name = hash_table_get (host_address_name_map, addr_text); - if (canonical_name) - { - DEBUGP (("Mapping %s to %s in host_slave_master_map.\n", - host, canonical_name)); - /* We've already dealt with that host under another name. */ - hash_table_put (host_slave_master_map, - xstrdup_lower (host), - xstrdup_lower (canonical_name)); - } - else + xfree (al->addresses); + xfree (al); +} + +void +address_list_release (struct address_list *al) +{ + --al->refcount; + DEBUGP (("Releasing %p (new refcount %d).\n", al, al->refcount)); + if (al->refcount <= 0) { - /* This is really the first time we're dealing with that host. */ - char *h_copy = xstrdup_lower (host); - char *a_copy = xstrdup (addr_text); - DEBUGP (("Caching %s <-> %s\n", h_copy, a_copy)); - hash_table_put (host_name_address_map, h_copy, a_copy); - hash_table_put (host_address_name_map, a_copy, h_copy); + DEBUGP (("Deleting unused %p.\n", al)); + address_list_delete (al); } } - -/* Store the address of HOSTNAME, internet-style (four octets in - network order), to WHERE. First try to get the address from the - cache; if it is not available, call the DNS functions and update - the cache. - - Return 1 on successful finding of the hostname, 0 otherwise. */ -int -store_hostaddress (unsigned char *where, const char *hostname) + +/** + * wget_sockaddr_set_address + * + * This function takes an wget_sockaddr and fill in the protocol type, + * the port number and the address, there NULL in address means wildcard. + * Unsuported adress family will abort the whole programm. + * + * Input: + * wget_sockaddr* The space to be filled + * int The wished protocol + * unsigned short The port + * const ip_address The Binary IP adress + * + * Return: + * - Only modify 1. param + */ +void +wget_sockaddr_set_address (wget_sockaddr *sa, + int ip_family, unsigned short port, ip_address *addr) { - unsigned long addr; - char *addr_text; - char *canonical_name; - struct hostent *hptr; - struct in_addr in; - char *inet_s; - - /* If the address is of the form d.d.d.d, there will be no trouble - with it. */ - addr = (unsigned long)inet_addr (hostname); - /* If we have the numeric address, just store it. */ - if ((int)addr != -1) + if (ip_family == AF_INET) { - /* ADDR is defined to be in network byte order, meaning the code - works on little and big endian 32-bit architectures without - change. On big endian 64-bit architectures we need to be - careful to copy the correct four bytes. */ - int offset; - have_addr: -#ifdef WORDS_BIGENDIAN - offset = sizeof (unsigned long) - 4; -#else - offset = 0; -#endif - memcpy (where, (char *)&addr + offset, 4); - return 1; + sa->sin.sin_family = ip_family; + sa->sin.sin_port = htons (port); + if (addr == NULL) + memset ((unsigned char*)&sa->sin.sin_addr, 0, sizeof(ip_address)); + else + memcpy ((unsigned char*)&sa->sin.sin_addr, addr, sizeof(ip_address)); + return; } - - /* By now we know that the address is not of the form d.d.d.d. Try - to find it in our cache of host addresses. */ - addr_text = hash_table_get (host_name_address_map, hostname); - if (addr_text) +#ifdef INET6 + if (ip_family == AF_INET6) { - DEBUGP (("Found %s in host_name_address_map: %s\n", - hostname, addr_text)); - addr = (unsigned long)inet_addr (addr_text); - goto have_addr; + sa->sin6.sin6_family = ip_family; + sa->sin6.sin6_port = htons (port); + if (addr == NULL) + memset (&sa->sin6.sin6_addr, 0 , sizeof(ip_address)); + else + memcpy (&sa->sin6.sin6_addr, addr, sizeof(ip_address)); + return; } +#endif + abort(); +} - /* Maybe this host is known to us under another name. If so, we'll - find it in host_slave_master_map, and use the master name to find - its address in host_name_address_map. */ - canonical_name = hash_table_get (host_slave_master_map, hostname); - if (canonical_name) +/** + * wget_sockaddr_set_port + * + * This funtion only fill the port of the socket information. + * If the protocol is not supported nothing is done. + * Unsuported adress family will abort the whole programm. + * + * Require: + * that the IP-Protocol already is set. + * + * Input: + * wget_sockaddr* The space there port should be entered + * unsigned int The port that should be entered in host order + * + * Return: + * - Only modify 1. param + */ +void +wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port) +{ + if (sa->sa.sa_family == AF_INET) + { + sa->sin.sin_port = htons (port); + return; + } +#ifdef INET6 + if (sa->sa.sa_family == AF_INET6) { - addr_text = hash_table_get (host_name_address_map, canonical_name); - assert (addr_text != NULL); - DEBUGP (("Found %s as slave of %s -> %s\n", - hostname, canonical_name, addr_text)); - addr = (unsigned long)inet_addr (addr_text); - goto have_addr; + sa->sin6.sin6_port = htons (port); + return; } +#endif + abort(); +} + +/** + * wget_sockaddr_get_addr + * + * This function return the adress from an sockaddr as byte string. + * Unsuported adress family will abort the whole programm. + * + * Require: + * that the IP-Protocol already is set. + * + * Input: + * wget_sockaddr* Socket Information + * + * Output: + * unsigned char * IP address as byte string. + */ +void * +wget_sockaddr_get_addr (wget_sockaddr *sa) +{ + if (sa->sa.sa_family == AF_INET) + return &sa->sin.sin_addr; +#ifdef INET6 + if (sa->sa.sa_family == AF_INET6) + return &sa->sin6.sin6_addr; +#endif + abort(); + /* unreached */ + return NULL; +} + +/** + * wget_sockaddr_get_port + * + * This function only return the port from the input structure + * Unsuported adress family will abort the whole programm. + * + * Require: + * that the IP-Protocol already is set. + * + * Input: + * wget_sockaddr* Information where to get the port + * + * Output: + * unsigned short Port Number in host order. + */ +unsigned short +wget_sockaddr_get_port (const wget_sockaddr *sa) +{ + if (sa->sa.sa_family == AF_INET) + return htons (sa->sin.sin_port); +#ifdef INET6 + if (sa->sa.sa_family == AF_INET6) + return htons (sa->sin6.sin6_port); +#endif + abort(); + /* do not complain about return nothing */ + return -1; +} + +/** + * sockaddr_len + * + * This function return the length of the sockaddr corresponding to + * the acutall prefered protocol for (bind, connect etc...) + * Unsuported adress family will abort the whole programm. + * + * Require: + * that the IP-Protocol already is set. + * + * Input: + * - Public IP-Family Information + * + * Output: + * int structure length for socket options + */ +int +sockaddr_len () +{ + if (ip_default_family == AF_INET) + return sizeof (struct sockaddr_in); +#ifdef INET6 + if (ip_default_family == AF_INET6) + return sizeof (struct sockaddr_in6); +#endif + abort(); + /* do not complain about return nothing */ + return 0; +} + +/** + * Map an IPv4 adress to the internal adress format. + */ +void +map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) +{ +#ifdef INET6 + static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + memcpy ((char *)ip + 12, ipv4 , 4); + memcpy ((char *)ip + 0, ipv64, 12); +#else + if ((char *)ip != (char *)ipv4) + memcpy (ip, ipv4, 4); +#endif +} - /* Since all else has failed, let's try gethostbyname(). Note that - we use gethostbyname() rather than ngethostbyname(), because we - already know that the address is not numerical. */ - hptr = gethostbyname (hostname); - if (!hptr) +/* Detect whether an IP adress represents an IPv4 address and, if so, + copy it to IPV4. 0 is returned on failure. + This operation always succeeds when Wget is compiled without IPv6. + If IPV4 is NULL, don't copy, just detect. */ + +int +map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) +{ +#ifdef INET6 + static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; + if (0 != memcmp (ip, ipv64, 12)) return 0; - /* Copy the address of the host to socket description. */ - memcpy (where, hptr->h_addr_list[0], hptr->h_length); - assert (hptr->h_length == 4); - - /* Now that we've gone through the truoble of calling - gethostbyname(), we can store this valuable information to the - cache. First, we have to look for it by address to know if it's - already in the cache by another name. */ - /* Originally, we copied to in.s_addr, but it appears to be missing - on some systems. */ - memcpy (&in, *hptr->h_addr_list, sizeof (in)); - inet_s = inet_ntoa (in); - add_host_to_cache (hostname, inet_s); + if (ipv4) + memcpy (ipv4, (char *)ip + 12, 4); +#else + if (ipv4) + memcpy (ipv4, (char *)ip, 4); +#endif return 1; } + +/* Pretty-print ADDR. When compiled without IPv6, this is the same as + inet_ntoa. With IPv6, it either prints an IPv6 address or an IPv4 + address. */ -/* Determine the "real" name of HOST, as perceived by Wget. If HOST - is referenced by more than one name, "real" name is considered to - be the first one encountered in the past. */ char * -realhost (const char *host) +pretty_print_address (ip_address *addr) { - struct in_addr in; - struct hostent *hptr; - char *master_name; +#ifdef INET6 + ip4_address addr4; + static char buf[128]; - DEBUGP (("Checking for %s in host_name_address_map.\n", host)); - if (hash_table_exists (host_name_address_map, host)) - { - DEBUGP (("Found; %s was already used, by that name.\n", host)); - return xstrdup_lower (host); - } + if (map_ip_to_ipv4 (addr, &addr4)) + return inet_ntoa (*(struct in_addr *)&addr4); - DEBUGP (("Checking for %s in host_slave_master_map.\n", host)); - master_name = hash_table_get (host_slave_master_map, host); - if (master_name) - { - has_master: - DEBUGP (("Found; %s was already used, by the name %s.\n", - host, master_name)); - return xstrdup (master_name); - } + if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf))) + return ""; + return buf; +#endif + return inet_ntoa (*(struct in_addr *)addr); +} - DEBUGP (("First time I hear about %s by that name; looking it up.\n", - host)); - hptr = ngethostbyname (host); - if (hptr) +/* Add host name HOST with the address ADDR_TEXT to the cache. + ADDR_LIST is a NULL-terminated list of addresses, as in struct + hostent. */ + +static void +cache_host_lookup (const char *host, struct address_list *al) +{ + if (!host_name_addresses_map) + host_name_addresses_map = make_nocase_string_hash_table (0); + + ++al->refcount; + hash_table_put (host_name_addresses_map, xstrdup_lower (host), al); + +#ifdef DEBUG + if (opt.debug) { - char *inet_s; - /* Originally, we copied to in.s_addr, but it appears to be - missing on some systems. */ - memcpy (&in, *hptr->h_addr_list, sizeof (in)); - inet_s = inet_ntoa (in); - - add_host_to_cache (host, inet_s); - - /* add_host_to_cache() can establish a slave-master mapping. */ - DEBUGP (("Checking again for %s in host_slave_master_map.\n", host)); - master_name = hash_table_get (host_slave_master_map, host); - if (master_name) - goto has_master; + int i; + debug_logprintf ("Caching %s =>", host); + for (i = 0; i < al->count; i++) + debug_logprintf (" %s", pretty_print_address (al->addresses + i)); + debug_logprintf ("\n"); } - - return xstrdup_lower (host); +#endif } -/* Compare two hostnames (out of URL-s if the arguments are URL-s), - taking care of aliases. It uses realhost() to determine a unique - hostname for each of two hosts. If simple_check is non-zero, only - strcmp() is used for comparison. */ -int -same_host (const char *u1, const char *u2) +struct address_list * +lookup_host (const char *host, int silent) { - const char *s; - char *p1, *p2; - char *real1, *real2; - - /* Skip protocol, if present. */ - u1 += skip_url (u1); - u2 += skip_url (u2); - u1 += skip_proto (u1); - u2 += skip_proto (u2); - - /* Skip username ans password, if present. */ - u1 += skip_uname (u1); - u2 += skip_uname (u2); - - for (s = u1; *u1 && *u1 != '/' && *u1 != ':'; u1++); - p1 = strdupdelim (s, u1); - for (s = u2; *u2 && *u2 != '/' && *u2 != ':'; u2++); - p2 = strdupdelim (s, u2); - DEBUGP (("Comparing hosts %s and %s...\n", p1, p2)); - if (strcasecmp (p1, p2) == 0) - { - xfree (p1); - xfree (p2); - DEBUGP (("They are quite alike.\n")); - return 1; - } - else if (opt.simple_check) - { - xfree (p1); - xfree (p2); - DEBUGP (("Since checking is simple, I'd say they are not the same.\n")); - return 0; - } - real1 = realhost (p1); - real2 = realhost (p2); - xfree (p1); - xfree (p2); - if (strcasecmp (real1, real2) == 0) + struct address_list *al = NULL; + unsigned long addr_ipv4; /* #### use a 32-bit type here. */ + ip_address addr; + + /* First, try to check whether the address is already a numeric + address. */ + +#ifdef INET6 + if (inet_pton (AF_INET6, host, &addr) > 0) + return address_list_new_one (&addr); +#endif + + addr_ipv4 = (unsigned long)inet_addr (host); + if ((int)addr_ipv4 != -1) { - DEBUGP (("They are alike, after realhost()->%s.\n", real1)); - xfree (real1); - xfree (real2); - return 1; + /* ADDR is defined to be in network byte order, which is what + this returns, so we can just copy it to STORE_IP. However, + on big endian 64-bit architectures the value will be stored + in the *last*, not first four bytes. OFFSET makes sure that + we copy the correct four bytes. */ + int offset = 0; +#ifdef WORDS_BIGENDIAN + offset = sizeof (unsigned long) - sizeof (ip_address); +#endif + map_ipv4_to_ip ((ip4_address *)((char *)&addr_ipv4 + offset), &addr); + return address_list_new_one (&addr); } - else + + if (host_name_addresses_map) { - DEBUGP (("They are not the same (%s, %s).\n", real1, real2)); - xfree (real1); - xfree (real2); - return 0; + al = hash_table_get (host_name_addresses_map, host); + + if (al) + { + DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al)); + ++al->refcount; + return al; + } } -} + if (!silent) + logprintf (LOG_VERBOSE, _("Resolving %s... "), host); + +#ifdef INET6 + { + struct addrinfo hints, *ai; + int err; + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + err = getaddrinfo (host, NULL, &hints, &ai); + + if (err != 0 || ai == NULL) + { + if (!silent) + logprintf (LOG_VERBOSE, _("failed: %s.\n"), gai_strerror (err)); + return NULL; + } + al = address_list_from_addrinfo (ai); + freeaddrinfo (ai); + } +#else + { + struct hostent *hptr = gethostbyname (host); + if (!hptr) + { + if (!silent) + logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno)); + return NULL; + } + /* Do all systems have h_addr_list, or is it a newer thing? If + the latter, use address_list_new_one. */ + al = address_list_new (hptr->h_addr_list); + } +#endif + + if (!silent) + logprintf (LOG_VERBOSE, _("done.\n")); + + /* Cache the lookup information. */ + cache_host_lookup (host, al); + + return al; +} + /* Determine whether a URL is acceptable to be followed, according to a list of domains to accept. */ int -accept_domain (struct urlinfo *u) +accept_domain (struct url *u) { assert (u->host != NULL); if (opt.domains) @@ -362,130 +627,6 @@ sufmatch (const char **list, const char *what) return 0; } -/* Return email address of the form username@FQDN suitable for - anonymous FTP passwords. This process is error-prone, and the - escape hatch is the MY_HOST preprocessor constant, which can be - used to hard-code either your hostname or FQDN at compile-time. - - If the FQDN cannot be determined, a warning is printed, and the - function returns a short `username@' form, accepted by most - anonymous servers. - - The returned string is generated by malloc() and should be freed - using free(). - - If not even the username cannot be divined, it means things are - seriously fucked up, and Wget exits. */ -char * -ftp_getaddress (void) -{ - static char *address; - - /* Do the drill only the first time, as it won't change. */ - if (!address) - { - char userid[32]; /* 9 should be enough for Unix, but - I'd rather be on the safe side. */ - char *host, *fqdn; - - if (!pwd_cuserid (userid)) - { - logprintf (LOG_ALWAYS, _("%s: Cannot determine user-id.\n"), - exec_name); - exit (1); - } -#ifdef MY_HOST - STRDUP_ALLOCA (host, MY_HOST); -#else /* not MY_HOST */ -#ifdef HAVE_UNAME - { - struct utsname ubuf; - if (uname (&ubuf) < 0) - { - logprintf (LOG_ALWAYS, _("%s: Warning: uname failed: %s\n"), - exec_name, strerror (errno)); - fqdn = ""; - goto giveup; - } - STRDUP_ALLOCA (host, ubuf.nodename); - } -#else /* not HAVE_UNAME */ -#ifdef HAVE_GETHOSTNAME - host = alloca (256); - if (gethostname (host, 256) < 0) - { - logprintf (LOG_ALWAYS, _("%s: Warning: gethostname failed\n"), - exec_name); - fqdn = ""; - goto giveup; - } -#else /* not HAVE_GETHOSTNAME */ - #error Cannot determine host name. -#endif /* not HAVE_GETHOSTNAME */ -#endif /* not HAVE_UNAME */ -#endif /* not MY_HOST */ - /* If the address we got so far contains a period, don't bother - anymore. */ - if (strchr (host, '.')) - fqdn = host; - else - { - /* #### I've seen the following scheme fail on at least one - system! Do we care? */ - char *tmpstore; - /* According to Richard Stevens, the correct way to find the - FQDN is to (1) find the host name, (2) find its IP - address using gethostbyname(), and (3) get the FQDN using - gethostbyaddr(). So that's what we'll do. Step one has - been done above. */ - /* (2) */ - struct hostent *hp = gethostbyname (host); - if (!hp || !hp->h_addr_list) - { - logprintf (LOG_ALWAYS, _("\ -%s: Warning: cannot determine local IP address.\n"), - exec_name); - fqdn = ""; - goto giveup; - } - /* Copy the argument, so the call to gethostbyaddr doesn't - clobber it -- just in case. */ - tmpstore = (char *)alloca (hp->h_length); - memcpy (tmpstore, *hp->h_addr_list, hp->h_length); - /* (3) */ - hp = gethostbyaddr (tmpstore, hp->h_length, hp->h_addrtype); - if (!hp || !hp->h_name) - { - logprintf (LOG_ALWAYS, _("\ -%s: Warning: cannot reverse-lookup local IP address.\n"), - exec_name); - fqdn = ""; - goto giveup; - } - if (!strchr (hp->h_name, '.')) - { -#if 0 - /* This gets ticked pretty often. Karl Berry reports - that there can be valid reasons for the local host - name not to be an FQDN, so I've decided to remove the - annoying warning. */ - logprintf (LOG_ALWAYS, _("\ -%s: Warning: reverse-lookup of local address did not yield FQDN!\n"), - exec_name); -#endif - fqdn = ""; - goto giveup; - } - /* Once we're here, hp->h_name contains the correct FQDN. */ - STRDUP_ALLOCA (fqdn, hp->h_name); - } - giveup: - address = (char *)xmalloc (strlen (userid) + 1 + strlen (fqdn) + 1); - sprintf (address, "%s@%s", userid, fqdn); - } - return address; -} - /* Print error messages for host errors. */ char * herrmsg (int error) @@ -502,23 +643,27 @@ herrmsg (int error) return _("Unknown error"); } -void -clean_hosts (void) +static int +host_cleanup_mapper (void *key, void *value, void *arg_ignored) { - /* host_name_address_map and host_address_name_map share the - strings. Because of that, calling free_keys_and_values once - suffices for both. */ - free_keys_and_values (host_name_address_map); - hash_table_destroy (host_name_address_map); - hash_table_destroy (host_address_name_map); - free_keys_and_values (host_slave_master_map); - hash_table_destroy (host_slave_master_map); + struct address_list *al; + + xfree (key); /* host */ + + al = (struct address_list *)value; + assert (al->refcount == 1); + address_list_delete (al); + + return 0; } void -host_init (void) +host_cleanup (void) { - host_name_address_map = make_string_hash_table (0); - host_address_name_map = make_string_hash_table (0); - host_slave_master_map = make_string_hash_table (0); + if (host_name_addresses_map) + { + hash_table_map (host_name_addresses_map, host_cleanup_mapper, NULL); + hash_table_destroy (host_name_addresses_map); + host_name_addresses_map = NULL; + } }