hostcache.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:10k
- /*
- * Copyright (c) 1997, 1998, 1999
- * Inferno Nettverk A/S, Norway. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. The above copyright notice, this list of conditions and the following
- * disclaimer must appear in all copies of the software, derivative works
- * or modified versions, and any portions thereof, aswell as in all
- * supporting documentation.
- * 2. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by
- * Inferno Nettverk A/S, Norway.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Inferno Nettverk A/S requests users of this software to return to
- *
- * Software Distribution Coordinator or sdc@inet.no
- * Inferno Nettverk A/S
- * Oslo Research Park
- * Gaustadal閑n 21
- * N-0349 Oslo
- * Norway
- *
- * any improvements or extensions that they make and grant Inferno Nettverk A/S
- * the rights to redistribute these changes.
- *
- */
- #include "common.h"
- static const char rcsid[] =
- "$Id: hostcache.c,v 1.15 1999/12/22 09:29:24 karls Exp $";
- __BEGIN_DECLS
- #if SOCKS_SERVER
- /* we want the real thing. */
- #undef gethostbyname
- #undef gethostbyaddr
- static struct hostent *
- hostentupdate __P((struct hostent *old, const struct hostent *new));
- /*
- * Updates "old" with the contents of "new", freeing any
- * resources currently used by "old".
- * Returns:
- * On success: "old", updated.
- * On failure: NULL.
- */
- static int
- hosthash __P((const char *name, size_t size));
- /*
- * Calculates a hashvalue for "name" and returns it's value.
- * Size of hashtable is given by "size".
- */
- static int
- addrhash __P((in_addr_t addr, size_t size));
- /*
- * Calculates a hashvalue for "addr" and returns it's value.
- * Size of hashtable is given by "size".
- */
- #endif /* SOCKS_SERVER */
- static char **
- listrealloc __P((char ***old, const char ***new, int length));
- /*
- * Reallocates "old" and copies in the contents of "new".
- * The last element of both "old" and "new" must be NULL.
- * If "length" is less than 0, each element is assumed to
- * be NUL terminated, otherwise "length" gives the total length
- * of every string.
- * Returns:
- * On success: "**old", with the contents of "new".
- * On failure: NULL.
- */
- __END_DECLS
- struct hostent *
- hostentdup(hostent)
- const struct hostent *hostent;
- {
- static struct hostent dupedinit;
- struct hostent *duped;
- if ((duped = (struct hostent *)malloc(sizeof(*duped))) == NULL)
- return NULL;
- *duped = dupedinit;
- if ((duped->h_name = strdup(hostent->h_name)) == NULL) {
- hostentfree(duped);
- return NULL;
- }
- if (listrealloc(&duped->h_aliases, (const char ***)&hostent->h_aliases, -1)
- == NULL) {
- hostentfree(duped);
- return NULL;
- }
- duped->h_addrtype = hostent->h_addrtype;
- duped->h_length = hostent->h_length;
- if (listrealloc(&duped->h_addr_list, (const char ***)&hostent->h_addr_list,
- hostent->h_length) == NULL) {
- hostentfree(duped);
- return NULL;
- }
- return duped;
- }
- void
- hostentfree(hostent)
- struct hostent *hostent;
- {
- char **p;
- if (hostent == NULL)
- return;
- free(hostent->h_name);
- hostent->h_name = NULL;
- if (hostent->h_aliases != NULL)
- for (p = hostent->h_aliases; *p != NULL; ++p)
- free(*p);
- free(hostent->h_aliases);
- hostent->h_aliases = NULL;
- if (hostent->h_addr_list != NULL)
- for (p = hostent->h_addr_list; *p != NULL; ++p)
- free(*p);
- free(hostent->h_addr_list);
- hostent->h_addr_list = NULL;
- free(hostent);
- }
- static char **
- listrealloc(old, new, length)
- char ***old;
- const char ***new;
- int length;
- {
- int i, oldi, newi;
- /* entries we can reallocate, starting at 0. */
- oldi = 0;
- if (*old != NULL)
- while ((*old)[oldi] != NULL)
- ++oldi;
- newi = 0;
- while ((*new)[newi] != NULL)
- ++newi;
- for (i = newi; i < oldi; ++i)
- free((*old)[i]);
- if ((*old = (char **)realloc(*old, sizeof(**new) * (newi + 1))) == NULL)
- return NULL;
- for (newi = 0; (*new)[newi] != NULL; ++newi, --oldi) {
- if (((*old)[newi] = (char *)realloc(oldi > 0 ? (*old)[newi] : NULL,
- length < 0 ? (strlen((*new)[newi]) + 1) : length)) == NULL)
- return NULL;
- if (length < 0)
- strcpy((*old)[newi], (*new)[newi]);
- else
- memcpy((*old)[newi], (*new)[newi], (size_t)length);
- }
- (*old)[newi] = NULL;
- return *old;
- }
- #if SOCKS_SERVER
- struct hostent *
- cgethostbyname(name)
- const char *name;
- {
- const char *function = "cgethostbyname()";
- static struct {
- unsigned allocated:1;
- char host[MAXHOSTNAMELEN];
- time_t written;
- struct hostent hostent;
- } table[SOCKD_HOSTCACHE], *freehost;
- static unsigned int hit, miss, count;
- const time_t timenow = time(NULL);
- const int hashi = hosthash(name, ELEMENTS(table));
- size_t i;
- struct hostent *hostent;
- #if SOCKD_CACHESTAT
- if (++count % SOCKD_CACHESTAT == 0)
- slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
- #endif /* SOCKD_CACHESTAT */
- for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
- if (!table[i].allocated) {
- if (freehost == NULL)
- freehost = &table[i];
- continue;
- }
- if (strcasecmp(table[i].host, name) == 0) {
- if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
- freehost = &table[i];
- break;
- }
- ++hit;
- return &table[i].hostent;
- }
- }
- ++miss;
- if ((hostent = gethostbyname(name)) == NULL)
- return NULL;
- if (freehost == NULL)
- for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
- if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
- freehost = &table[i];
- break;
- }
- if (freehost->written < table[i].written) {
- freehost = &table[i]; /* oldest. */
- break;
- }
- }
- if (hostentupdate(&freehost->hostent, hostent) == NULL) {
- freehost->allocated = 0;
- slog(LOG_WARNING, "%s: %s", NOMEM, function);
- return NULL;
- }
- SASSERTX(strlen(name) < sizeof(freehost->host));
- strcpy(freehost->host, name);
- time(&freehost->written);
- freehost->allocated = 1;
- return &freehost->hostent;
- }
- struct hostent *
- cgethostbyaddr(addr, len, type)
- const char *addr;
- int len;
- int type;
- {
- const char *function = "cgethostbyaddr()";
- static struct {
- unsigned allocated:1;
- in_addr_t addr;
- time_t written;
- struct hostent hostent;
- } table[SOCKD_ADDRESSCACHE], *freehost;
- static unsigned long int hit, miss, count;
- const time_t timenow = time(NULL);
- /* LINTED pointer casts may be troublesome */
- const int hashi
- = addrhash(((const struct in_addr *)addr)->s_addr, ELEMENTS(table));
- size_t i;
- struct hostent *hostent;
- #if SOCKD_CACHESTAT
- if (++count % SOCKD_CACHESTAT == 0)
- slog(LOG_INFO, "%s: hit: %d, miss: %d", function, hit, miss);
- #endif /* SOCKD_CACHESTAT */
- for (i = hashi, freehost = NULL; i < ELEMENTS(table); ++i) {
- if (!table[i].allocated) {
- if (freehost == NULL)
- freehost = &table[i];
- continue;
- }
- /* LINTED pointer casts may be troublesome */
- if (table[i].addr == ((const struct in_addr *)addr)->s_addr) {
- if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
- freehost = &table[i];
- break;
- }
- ++hit;
- return &table[i].hostent;
- }
- }
- ++miss;
- if ((hostent = gethostbyaddr(addr, len, type)) == NULL)
- return NULL;
- if (freehost == NULL)
- for (i = hashi, freehost = &table[i]; i < ELEMENTS(table); ++i) {
- if (difftime(timenow, table[i].written) >= SOCKD_CACHETIMEOUT) {
- freehost = &table[i];
- break;
- }
- if (freehost->written < table[i].written) {
- freehost = &table[i]; /* oldest. */
- break;
- }
- }
- if (hostentupdate(&freehost->hostent, hostent) == NULL) {
- freehost->allocated = 0;
- slog(LOG_WARNING, "%s: %s", NOMEM, function);
- return NULL;
- }
- /* LINTED pointer casts may be troublesome */
- freehost->addr = ((const struct in_addr *)addr)->s_addr;
- time(&freehost->written);
- freehost->allocated = 1;
- return &freehost->hostent;
- }
- static int
- hosthash(name, size)
- const char *name;
- size_t size;
- {
- char *end;
- unsigned int value;
- /* end at second dot. */
- if ((end = strchr(name, '.')) != NULL)
- end = strchr(end, '.');
- if (end == NULL)
- end = strchr(name, NUL);
- SASSERTX(name <= end);
- value = 0;
- while (name != end)
- value = (value << 5) + *name++; /* MAW - DS&A: Horner's rule. */
- return value % size;
- }
- static int
- addrhash(addr, size)
- in_addr_t addr;
- size_t size;
- {
- return addr % size;
- }
- static struct hostent *
- hostentupdate(old, new)
- struct hostent *old;
- const struct hostent *new;
- {
- if ((old->h_name = (char *)realloc(old->h_name, strlen(new->h_name) + 1))
- == NULL)
- return NULL;
- strcpy(old->h_name, new->h_name);
- if (listrealloc(&old->h_aliases, (const char ***)&new->h_aliases, -1)
- == NULL)
- return NULL;
- old->h_addrtype = new->h_addrtype;
- old->h_length = new->h_length;
- if (listrealloc(&old->h_addr_list, (const char ***)&new->h_addr_list,
- new->h_length) == NULL)
- return NULL;
- return old;
- }
- #endif /* SOCKS_SERVER */