Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 2000 - 2001 Pekka Riikonen
+ Copyright (C) 2000 - 2005 Pekka Riikonen
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
static void silc_idcache_destructor(void *key, void *context,
void *user_context);
static SilcIDCacheList silc_idcache_list_alloc();
-static void silc_idcache_list_add(SilcIDCacheList list,
+static void silc_idcache_list_add(SilcIDCacheList list,
SilcIDCacheEntry cache);
/*
SilcHashTable context_table;
SilcIDCacheDestructor destructor;
SilcIdType type;
+ unsigned int delete_id : 1;
+ unsigned int delete_name : 1;
};
-/*
+/*
ID Cache list.
-
+
This is returned when searching the cache. Enumeration functions are
provided to traverse the list; actually this is used as table not as
list. :)
*/
struct SilcIDCacheListStruct {
- SilcIDCacheEntry cache[64];
+ SilcIDCacheEntry cache[128];
SilcIDCacheEntry *cache_dyn;
- uint32 cache_dyn_count;
- uint32 cache_count;
- uint32 pos;
+ SilcUInt32 cache_dyn_count;
+ SilcUInt32 cache_count;
+ SilcUInt32 pos;
+ bool dyn;
};
/* Allocates new ID cache object. The initial amount of allocated entries
- can be sent as argument. If `count' is 0 the system uses default values.
+ can be sent as argument. If `count' is 0 the system uses default values.
The `id_type' defines the types of the ID's that will be saved to the
cache. */
-SilcIDCache silc_idcache_alloc(uint32 count, SilcIdType id_type,
- SilcIDCacheDestructor destructor)
+SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
+ SilcIDCacheDestructor destructor,
+ bool delete_id, bool delete_name)
{
SilcIDCache cache;
SILC_LOG_DEBUG(("Allocating new cache"));
cache = silc_calloc(1, sizeof(*cache));
- cache->id_table = silc_hash_table_alloc(count, silc_hash_id,
- (void *)(uint32)id_type,
- silc_hash_id_compare,
- (void *)(uint32)id_type,
- silc_idcache_destructor, NULL,
- FALSE);
- cache->name_table = silc_hash_table_alloc(count, silc_hash_string, NULL,
- silc_hash_string_compare, NULL,
- NULL, NULL, FALSE);
+ if (!cache)
+ return NULL;
+ cache->id_table = silc_hash_table_alloc(count, silc_hash_id,
+ SILC_32_TO_PTR(id_type),
+ silc_hash_id_compare,
+ SILC_32_TO_PTR(id_type),
+ silc_idcache_destructor,
+ cache, TRUE);
+ cache->name_table = silc_hash_table_alloc(count, silc_hash_utf8_string, NULL,
+ silc_hash_utf8_compare, NULL,
+ NULL, NULL, TRUE);
cache->context_table = silc_hash_table_alloc(count, silc_hash_ptr, NULL,
- NULL, NULL, NULL, NULL, FALSE);
+ NULL, NULL, NULL, NULL, TRUE);
cache->destructor = destructor;
cache->type = id_type;
+ cache->delete_id = delete_id;
+ cache->delete_name = delete_name;
+
+ if (!cache->id_table || !cache->name_table || !cache->context_table) {
+ if (cache->id_table)
+ silc_hash_table_free(cache->id_table);
+ if (cache->name_table)
+ silc_hash_table_free(cache->name_table);
+ if (cache->context_table)
+ silc_hash_table_free(cache->context_table);
+ silc_free(cache);
+ return NULL;
+ }
return cache;
}
If the `expire' is TRUE the entry expires in default time and if FALSE
the entry never expires from the cache. */
-bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
- void *context, int expire)
+bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
+ void *context, int expire, SilcIDCacheEntry *ret)
{
SilcIDCacheEntry c;
- uint32 curtime = time(NULL);
SILC_LOG_DEBUG(("Adding cache entry"));
/* Allocate new cache entry */
c = silc_calloc(1, sizeof(*c));
+ if (!c)
+ return FALSE;
c->id = id;
c->name = name;
- c->expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
+ c->expire = expire;
c->context = context;
/* Add the new entry to the hash tables */
if (context)
silc_hash_table_add(cache->context_table, context, c);
- /* See whether we have time to rehash the tables */
- if ((silc_hash_table_count(cache->id_table) / 2) >
- silc_hash_table_size(cache->id_table)) {
- silc_hash_table_rehash(cache->id_table, 0);
- silc_hash_table_rehash(cache->name_table, 0);
- silc_hash_table_rehash(cache->context_table, 0);
- }
+ if (ret)
+ *ret = c;
return TRUE;
}
static void silc_idcache_destructor(void *key, void *context,
void *user_context)
{
- silc_free(context);
+ SilcIDCacheEntry c = context;
+ if (c) {
+ SilcIDCache cache = user_context;
+ if (cache) {
+ if (cache->delete_id)
+ silc_free(c->id);
+ if (cache->delete_name)
+ silc_free(c->name);
+ }
+ memset(c, 'F', sizeof(*c));
+ silc_free(c);
+ }
}
/* Delete cache entry from cache. */
ret = silc_hash_table_del(cache->context_table, old->context);
if (old->id)
ret = silc_hash_table_del(cache->id_table, old->id);
+ else {
+ silc_idcache_destructor(NULL, old, NULL);
+ ret = TRUE;
+ }
return ret;
}
functions are NULL then default values are used. */
bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
- SilcHashFunction hash,
+ SilcHashFunction hash,
void *hash_context,
- SilcHashCompare compare,
+ SilcHashCompare compare,
void *compare_context)
{
SilcIDCacheEntry c;
SILC_LOG_DEBUG(("Deleting cache entry"));
if (!silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)&c,
- hash, hash_context, compare,
+ hash, hash_context, compare,
compare_context))
return FALSE;
ret = silc_hash_table_del(cache->context_table, c->context);
if (c->id)
ret = silc_hash_table_del_ext(cache->id_table, c->id, hash,
- hash_context, compare, compare_context);
-
+ hash_context, compare, compare_context,
+ NULL, NULL);
return ret;
}
ret = silc_hash_table_del(cache->context_table, c->context);
if (c->id)
ret = silc_hash_table_del_by_context(cache->id_table, c->id, c);
+ else {
+ silc_idcache_destructor(NULL, c, NULL);
+ ret = TRUE;
+ }
return ret;
}
return TRUE;
}
+static void silc_idcache_destructor_dummy(void *key, void *context,
+ void *user_context)
+{
+ /* Dummy - nothing */
+}
+
/* Foreach callback fro silc_idcache_purge. */
static void silc_idcache_purge_foreach(void *key, void *context,
void *user_context)
{
SilcIDCache cache = (SilcIDCache)user_context;
- uint32 curtime = time(NULL);
+ SilcUInt32 curtime = time(NULL);
SilcIDCacheEntry c = (SilcIDCacheEntry)context;
+ bool ret = FALSE;
- if (c->expire && c->expire < curtime) {
- /* Call the destructor */
- if (cache->destructor)
- cache->destructor(cache, c);
+ if (!context)
+ return;
- /* Delete the entry */
- silc_idcache_del(cache, c);
+ if (c->expire && c->expire < curtime) {
+ /* Remove the entry from the hash tables */
+ if (c->name)
+ ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
+ if (c->context)
+ ret = silc_hash_table_del(cache->context_table, c->context);
+ if (c->id)
+ ret =
+ silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
+ NULL, NULL, NULL, NULL,
+ silc_idcache_destructor_dummy,
+ NULL);
+ if (ret == TRUE) {
+ /* Call the destructor */
+ if (cache->destructor)
+ cache->destructor(cache, c);
+
+ /* Free the entry, it has been deleted from the hash tables */
+ silc_idcache_destructor(NULL, c, NULL);
+ }
}
}
bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
{
- SilcIDCacheEntry entry;
+ SilcIDCacheEntry c;
bool ret = FALSE;
- if (!silc_hash_table_find(cache->context_table, context, NULL,
- (void *)&entry))
+ if (!silc_hash_table_find(cache->context_table, context, NULL,
+ (void *)&c))
return FALSE;
- /* Call the destructor */
- if (cache->destructor)
- cache->destructor(cache, entry);
-
- if (entry->name)
- ret = silc_hash_table_del_by_context(cache->name_table, entry->name,
- entry);
- if (entry->context)
- ret = silc_hash_table_del(cache->context_table, entry->context);
- if (entry->id)
- ret = silc_hash_table_del_by_context(cache->id_table, entry->id, entry);
+ /* Remove the entry from the hash tables */
+ if (c->name)
+ ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
+ if (c->context)
+ ret = silc_hash_table_del(cache->context_table, c->context);
+ if (c->id)
+ ret =
+ silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
+ NULL, NULL, NULL, NULL,
+ silc_idcache_destructor_dummy, NULL);
+ if (ret == TRUE) {
+ /* Call the destructor */
+ if (cache->destructor)
+ cache->destructor(cache, c);
+
+ /* Free the entry, it has been deleted from the hash tables */
+ silc_idcache_destructor(NULL, c, NULL);
+ }
return ret;
}
void *user_context)
{
SilcIDCacheList list = (SilcIDCacheList)user_context;
+ if (!context)
+ return;
silc_idcache_list_add(list, (SilcIDCacheEntry)context);
}
return TRUE;
list = silc_idcache_list_alloc();
+ if (!list)
+ return FALSE;
silc_hash_table_foreach(cache->id_table, silc_idcache_get_all_foreach, list);
if (silc_idcache_list_count(list) == 0) {
/* Find ID Cache entry by ID. May return multiple entries. */
-bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
SilcIDCacheList *ret)
{
SilcIDCacheList list;
list = silc_idcache_list_alloc();
+ if (!list)
+ return FALSE;
if (!ret)
return TRUE;
If `hash' is NULL then the default hash funtion is used and if `compare'
is NULL default comparison function is used. */
-bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
- SilcHashFunction hash,
+bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
+ SilcHashFunction hash,
void *hash_context,
- SilcHashCompare compare,
+ SilcHashCompare compare,
void *compare_context,
SilcIDCacheEntry *ret)
{
return silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)ret,
- hash, hash_context, compare,
+ hash, hash_context, compare,
compare_context);
}
/* Find one specific ID entry. */
-bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
+bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
SilcIDCacheEntry *ret)
{
return silc_hash_table_find(cache->id_table, id, NULL, (void *)ret);
/* Finds cache entry by context. */
-bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
SilcIDCacheEntry *ret)
{
- return silc_hash_table_find(cache->context_table, context, NULL,
+ return silc_hash_table_find(cache->context_table, context, NULL,
(void *)ret);
}
SilcIDCacheList list;
list = silc_idcache_list_alloc();
+ if (!list)
+ return FALSE;
if (!ret)
return TRUE;
- silc_hash_table_find_foreach(cache->name_table, name,
+ silc_hash_table_find_foreach(cache->name_table, name,
silc_idcache_get_all_foreach, list);
if (silc_idcache_list_count(list) == 0) {
SilcIDCacheList list;
list = silc_calloc(1, sizeof(*list));
+ if (!list)
+ return FALSE;
return list;
}
/* Try to add to static cache */
if (!list->cache_dyn_count)
- for (i = 0; i < sizeof(list->cache); i++) {
+ for (i = 0; i < (sizeof(list->cache) / sizeof(list->cache[0])); i++) {
if (!list->cache[i]) {
list->cache[i] = cache;
list->cache_count++;
if (i >= list->cache_dyn_count) {
int k;
- i += 5;
- list->cache_dyn = silc_realloc(list->cache_dyn,
- sizeof(*list->cache) * (i));
+ i = list->cache_dyn_count;
+ list->cache_dyn = silc_realloc(list->cache_dyn,
+ sizeof(*list->cache_dyn) * (i + 5));
+ if (!list->cache_dyn)
+ return;
/* NULL the reallocated area */
- for (k = list->cache_dyn_count; k < i; k++)
+ for (k = i; k < (i + 5); k++)
list->cache_dyn[k] = NULL;
- list->cache_dyn[list->cache_dyn_count] = cache;
- list->cache_dyn_count = i;
+ list->cache_dyn[i] = cache;
list->cache_count++;
+ list->cache_dyn_count += 5;
}
}
if (!list->cache[list->pos])
return FALSE;
-
+
if (ret)
*ret = list->cache[list->pos];
bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
{
- int dyn = FALSE;
list->pos++;
- if (list->pos >= sizeof(list->cache)) {
+ if (!list->dyn &&
+ list->pos >= (sizeof(list->cache) / sizeof(list->cache[0]))) {
list->pos = 0;
- dyn = TRUE;
+ list->dyn = TRUE;
}
- if (dyn && list->pos >= list->cache_dyn_count)
+ if (list->dyn && list->pos >= list->cache_dyn_count)
return FALSE;
- if (!dyn && !list->cache[list->pos])
+ if (!list->dyn && !list->cache[list->pos])
return FALSE;
-
- if (dyn && !list->cache_dyn[list->pos])
+
+ if (list->dyn && !list->cache_dyn[list->pos])
return FALSE;
-
+
if (ret) {
- if (!dyn)
+ if (!list->dyn)
*ret = list->cache[list->pos];
else
*ret = list->cache_dyn[list->pos];
}
-
+
return TRUE;
}