/* MiddleMan filtering proxy server Copyright (C) 2002 Jason McLaughlin This program 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, 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 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "proto.h" #include "hash.h" /* return a slot index for a string */ unsigned int hash_key(int max, char *string) { int i; unsigned int ret = 0; i = strlen(string); while (i--) { ret <<= i; ret += string[i]; } return ret % max; } /* create a hash table */ HASH_TABLE *hash_create(int size) { HASH_TABLE *hash_table; hash_table = xmalloc(sizeof(HASH_TABLE)); hash_table->hit = 0; hash_table->miss = 0; hash_table->size = size; hash_table->hash_list = xmalloc(sizeof(struct HASH_LIST *) * size); memset(hash_table->hash_list, 0, sizeof(struct HASH_LIST *) * size); return hash_table; } /* insert item into hash table */ void hash_insert(HASH_TABLE * hash_table, char *ref, void *string) { unsigned int key; struct HASH_LIST *hash_list; ASSERT(hash_table); if (hash_search(hash_table, ref) != NULL) return; key = hash_key(hash_table->size, ref); hash_list = hash_table->hash_list[key]; HASH_LIST_ADD(hash_list, ref, string); if (hash_table->hash_list[key] == NULL) hash_table->hash_list[key] = hash_list; } /* purge item from hash table */ void hash_purge(HASH_TABLE * hash_table, char *ref) { unsigned int key; struct HASH_LIST *hash_list, *prev = NULL; ASSERT(hash_table); key = hash_key(hash_table->size, ref); hash_list = hash_table->hash_list[key]; while (hash_list != NULL) { if (!strcasecmp(hash_list->ref, ref)) { if (hash_table->hash_list[key] == hash_list) hash_table->hash_list[key] = hash_list->next; else if (prev != NULL) prev->next = hash_list->next; xfree(hash_list->ref); xfree(hash_list->data); xfree(hash_list); break; } prev = hash_list; hash_list = hash_list->next; } } /* search for item in hash table */ char *hash_search(HASH_TABLE * hash_table, char *ref) { unsigned int key; struct HASH_LIST *hash_list; ASSERT(hash_table); key = hash_key(hash_table->size, ref); hash_list = hash_table->hash_list[key]; while (hash_list != NULL) { if (!strcasecmp(hash_list->ref, ref)) { hash_table->hit++; return hash_list->data; } hash_list = hash_list->next; } hash_table->miss++; return NULL; } /* wipe out a hash table and free all used memory */ void hash_destroy(HASH_TABLE * hash_table) { int i; struct HASH_LIST *hash_list, *tmp_list; ASSERT(hash_table); for (i = 0; i < hash_table->size; i++) { hash_list = hash_table->hash_list[i]; while (hash_list != NULL) { tmp_list = hash_list->next; xfree(hash_list->ref); xfree(hash_list->data); xfree(hash_list); hash_list = tmp_list; } } xfree(hash_table->hash_list); xfree(hash_table); } /* remove old items from hash table */ int hash_expire(HASH_TABLE * hash_table, unsigned int age) { int i, x = 0; time_t t; struct HASH_LIST *hash_list, *tmp_list, *prev = NULL; ASSERT(hash_table); t = time(NULL); for (i = 0; i < hash_table->size; i++) { hash_list = hash_table->hash_list[i]; while (hash_list != NULL) { tmp_list = hash_list->next; if (hash_list->age <= (t - age)) { if (hash_table->hash_list[i] == hash_list) hash_table->hash_list[i] = tmp_list; else if (prev != NULL) prev->next = tmp_list; xfree(hash_list->ref); xfree(hash_list->data); xfree(hash_list); x++; } else prev = hash_list; hash_list = tmp_list; } } return x; }