updates.
[silc.git] / lib / silccore / idcache.c
index 5f322004d7350d00fb5a894e32d10260424a4bfa..c59d4f77531ba9587164c58eb4f6f0707c44befd 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.3  2000/07/12 05:54:01  priikone
- *     Major rewrite of whole ID Cache system.
- *
- * Revision 1.2  2000/07/05 06:06:35  priikone
- *     Global cosmetic change.
- *
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "idcache.h"
@@ -55,7 +42,7 @@ static void silc_idcache_list_add(SilcIDCacheList list,
        Table of the cache entries allocated by silc_idcache_add function.
        This table is reallocated when new entry is added into the cache.
 
-   unsigned int cache_count
+   uint32 cache_count
 
        Number of cache entries in the cache.
 
@@ -74,12 +61,20 @@ static void silc_idcache_list_add(SilcIDCacheList list,
        is to provide faster access to the cache when searching by data.
        This is updated by silc_idcache_add and sorting functions.
 
+   SilcIDCacheDestructor destructor
+
+       Destructor callback that is called when an cache entry expires or is
+       purged from the ID cache. The application must not free cache entry
+       because the library will do it automatically. The appliation, however,
+       is responsible of freeing any data in the entry.
+
 */
 struct SilcIDCacheStruct {
   SilcIDCacheEntry cache;
-  unsigned int cache_count;
+  uint32 cache_count;
   int sorted;
   int fast_access[256];
+  SilcIDCacheDestructor destructor;
 };
 
 /* 
@@ -99,24 +94,26 @@ struct SilcIDCacheStruct {
 struct SilcIDCacheListStruct {
   SilcIDCacheEntry cache[64];
   SilcIDCacheEntry *cache_dyn;
-  unsigned int cache_dyn_count;
-  unsigned int cache_count;
-  unsigned int pos;
+  uint32 cache_dyn_count;
+  uint32 cache_count;
+  uint32 pos;
 };
 
 /* 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. */
 
-SilcIDCache silc_idcache_alloc(unsigned int count)
+SilcIDCache silc_idcache_alloc(uint32 count,
+                              SilcIDCacheDestructor destructor)
 {
   SilcIDCache cache;
 
-  SILC_LOG_DEBUG(("Allocating new cache")),
+  SILC_LOG_DEBUG(("Allocating new cache"));
 
   cache = silc_calloc(1, sizeof(*cache));
   cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
   cache->cache_count = count ? count : 5;
   memset(cache->fast_access, -1, sizeof(cache->fast_access));
+  cache->destructor = destructor;
 
   return cache;
 }
@@ -178,7 +175,7 @@ void silc_idcache_sort_by_data(SilcIDCache cache)
 /* Find ID Cache entry by data. The data maybe anything that must
    match exactly. Returns list of cache entries. */
 
-int silc_idcache_find_by_data(SilcIDCache cache, char *data, 
+int silc_idcache_find_by_data(SilcIDCache cache, unsigned char *data, 
                              SilcIDCacheList *ret)
 {
   int i;
@@ -194,18 +191,23 @@ int silc_idcache_find_by_data(SilcIDCache cache, char *data,
   else
     i = 0;
 
+  if (i == -1)
+    i = 0;
+
   for (i = i; i < cache->cache_count; i++) {
     if (cache->sorted && cache->cache[i].data &&
        cache->cache[i].data[0] != data[0])
       break;
 
     if (cache->cache[i].data && 
-       !memcmp(cache->cache[i].data, data, strlen(data)))
+       !memcmp(cache->cache[i].data, data, cache->cache[i].data_len))
       silc_idcache_list_add(list, &(cache->cache[i]));
   }
 
-  if (!silc_idcache_list_count(list))
+  if (!silc_idcache_list_count(list)) {
+    silc_idcache_list_free(list);
     return FALSE;
+  }
 
   if (ret)
     *ret = list;
@@ -218,7 +220,7 @@ int silc_idcache_find_by_data(SilcIDCache cache, char *data,
 /* Find ID Cache entry by data. The data maybe anything that must
    match exactly. Returns one cache entry. */
 
-int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
+int silc_idcache_find_by_data_one(SilcIDCache cache, unsigned char *data,
                                  SilcIDCacheEntry *ret)
 {
   int i;
@@ -231,9 +233,12 @@ int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
   else
     i = 0;
 
+  if (i == -1)
+    i = 0;
+
   for (i = i; i < cache->cache_count; i++)
     if (cache->cache[i].data && 
-       !memcmp(cache->cache[i].data, data, strlen(data))) {
+       !memcmp(cache->cache[i].data, data, cache->cache[i].data_len)) {
       if (ret)
        *ret = &(cache->cache[i]);
       return TRUE;
@@ -246,7 +251,7 @@ int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
    match. This ignores data case-sensitivity when searching with this
    function. Returns list of cache entries. */
 
-int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data, 
+int silc_idcache_find_by_data_loose(SilcIDCache cache, unsigned char *data, 
                                    SilcIDCacheList *ret)
 {
   int i, c;
@@ -264,6 +269,9 @@ int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
   else
     i = 0;
 
+  if (i == -1)
+    i = 0;
+
   for (i = i; i < cache->cache_count; i++) {
     if (cache->sorted && cache->cache[i].data &&
        cache->cache[i].data[0] != (char)c)
@@ -289,8 +297,10 @@ int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
     }
   }
     
-  if (!silc_idcache_list_count(list))
+  if (!silc_idcache_list_count(list)) {
+    silc_idcache_list_free(list);
     return FALSE;
+  }
 
   if (ret)
     *ret = list;
@@ -300,28 +310,35 @@ int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
   return TRUE;
 }
 
-/* Find ID Cache entry by ID. Returns list of cache entries. */
-/* XXX this may be useless, need for list really? */
+/* Find ID Cache entry by ID. Returns list of cache entries. If `id' is
+   SILC_ID_CACHE_ANY this returns all ID's of type `type'. */
 
 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
                            SilcIDCacheList *ret)
 {
-  int i, id_len;
+  int i;
   SilcIDCacheList list;
 
   if (!cache || !cache->cache || !id)
     return FALSE;
 
-  id_len = silc_id_get_len(type);
-
   list = silc_idcache_list_alloc();
 
-  for (i = 0; i < cache->cache_count; i++)
-    if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
-      silc_idcache_list_add(list, &(cache->cache[i]));
+  if (id != SILC_ID_CACHE_ANY) {
+    for (i = 0; i < cache->cache_count; i++)
+      if (cache->cache[i].id && SILC_ID_COMPARE_TYPE(cache->cache[i].id, 
+                                                    id, type))
+       silc_idcache_list_add(list, &(cache->cache[i]));
+  } else {
+    for (i = 0; i < cache->cache_count; i++)
+      if (cache->cache[i].id && cache->cache[i].type == type)
+       silc_idcache_list_add(list, &(cache->cache[i]));
+  }
 
-  if (!silc_idcache_list_count(list))
+  if (!silc_idcache_list_count(list)) {
+    silc_idcache_list_free(list);
     return FALSE;
+  }
 
   if (ret)
     *ret = list;
@@ -336,15 +353,14 @@ int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type, 
                                SilcIDCacheEntry *ret)
 {
-  int i, id_len;
+  int i;
 
   if (!cache || !cache->cache || !id)
     return FALSE;
 
-  id_len = silc_id_get_len(type);
-
   for (i = 0; i < cache->cache_count; i++)
-    if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
+    if (cache->cache[i].id && SILC_ID_COMPARE_TYPE(cache->cache[i].id, 
+                                                  id, type)) {
       if (ret)
        *ret = &(cache->cache[i]);
       return TRUE;
@@ -378,12 +394,13 @@ int silc_idcache_find_by_context(SilcIDCache cache, void *context,
    cache must be sorted in order for the fast access feature to work,
    however, it is not mandatory. */
 
-int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
-                    void *id, void *context, int sort)
+int silc_idcache_add(SilcIDCache cache, unsigned char *data, 
+                    uint32 data_len, SilcIdType id_type, void *id, 
+                    void *context, int sort, int expire)
 {
   int i;
-  unsigned int count;
-  unsigned long curtime = time(NULL);
+  uint32 count;
+  uint32 curtime = time(NULL);
   SilcIDCacheEntry c;
 
   if (!cache || !cache->cache)
@@ -405,11 +422,12 @@ int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
     return FALSE;
 
   for (i = 0; i < count; i++) {
-    if (c[i].data == NULL) {
+    if (c[i].data == NULL && c[i].id == NULL) {
       c[i].data = data;
+      c[i].data_len = data_len;
       c[i].type = id_type;
       c[i].id = id;
-      c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
+      c[i].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
       c[i].context = context;
       break;
     }
@@ -422,9 +440,10 @@ int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
       c[i].id = NULL;
     }
     c[count].data = data;
+    c[count].data_len = data_len;
     c[count].type = id_type;
     c[count].id = id;
-    c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
+    c[count].expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
     c[count].context = context;
     count += 5;
   }
@@ -450,7 +469,7 @@ int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
 
 /* XXX */
 
-int silc_idcache_del_by_data(SilcIDCache cache, char *data)
+int silc_idcache_del_by_data(SilcIDCache cache, unsigned char *data)
 {
 
   return TRUE;
@@ -460,15 +479,14 @@ int silc_idcache_del_by_data(SilcIDCache cache, char *data)
 
 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
 {
-  int i, id_len;
+  int i;
 
   if (!cache || !cache->cache || !id)
     return FALSE;
 
-  id_len = silc_id_get_len(type);
-
   for (i = 0; i < cache->cache_count; i++)
-    if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
+    if (cache->cache[i].id && SILC_ID_COMPARE_TYPE(cache->cache[i].id, 
+                                                  id, type)) {
       cache->cache[i].id = NULL;
       cache->cache[i].data = NULL;
       cache->cache[i].type = 0;
@@ -499,7 +517,7 @@ int silc_idcache_del_all(SilcIDCache cache)
 int silc_idcache_purge(SilcIDCache cache)
 {
   SilcIDCacheEntry c;
-  unsigned long curtime = time(NULL);
+  uint32 curtime = time(NULL);
   int i;
 
   if (!cache || !cache->cache)
@@ -508,8 +526,12 @@ int silc_idcache_purge(SilcIDCache cache)
   c = cache->cache;
 
   for (i = 0; i < cache->cache_count; i++) {
-    if (c[i].data && 
-       (c[i].expire == 0 || c[i].expire < curtime)) {
+    if (c[i].data && c[i].expire && c[i].expire < curtime) {
+
+      /* Call the destructor */
+      if (cache->destructor)
+       cache->destructor(cache, &c[i]);
+
       c[i].id = NULL;
       c[i].data = NULL;
       c[i].type = 0;
@@ -521,6 +543,27 @@ int silc_idcache_purge(SilcIDCache cache)
   return TRUE;
 }
 
+/* Purges the specific entry by context. */
+
+int silc_idcache_purge_by_context(SilcIDCache cache, void *context)
+{
+  SilcIDCacheEntry entry;
+
+  if (!silc_idcache_find_by_context(cache, context, &entry))
+    return FALSE;
+
+  /* Call the destructor */
+  if (cache->destructor)
+    cache->destructor(cache, entry);
+  
+  entry->id = NULL;
+  entry->data = NULL;
+  entry->type = 0;
+  entry->expire = 0;
+  entry->context = NULL;
+  return TRUE;
+}
+
 /* Allocates ID cache list. */
 
 static SilcIDCacheList silc_idcache_list_alloc()