5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
25 /* Static prototypes */
26 static int silc_idcache_sorter(const void *a, const void *b);
27 static SilcIDCacheList silc_idcache_list_alloc();
28 static void silc_idcache_list_add(SilcIDCacheList list,
29 SilcIDCacheEntry cache);
34 This is context for the ID cache system. This includes all the cache
35 entries and other internal data. This is read-only object and not
36 visible outside this cache system.
38 Fields are as follows:
40 SilcIDCacheEntry cache
42 Table of the cache entries allocated by silc_idcache_add function.
43 This table is reallocated when new entry is added into the cache.
45 unsigned int cache_count
47 Number of cache entries in the cache.
51 Boolean value to indicate whether the cache is sorted or not. If
52 cache is not sorted the fast access (described next) cannot be used.
53 Sorting can be done by calling sorting function or when adding new
58 Table to provide fast access into the cache by index. When searching
59 by data this table is used to get the index to the first occurence
60 of that data (or part of the data) in the cache. Purpose of this
61 is to provide faster access to the cache when searching by data.
62 This is updated by silc_idcache_add and sorting functions.
65 struct SilcIDCacheStruct {
66 SilcIDCacheEntry cache;
67 unsigned int cache_count;
75 This is returned when searching the cache. Enumeration functions are
76 provided to traverse the list; actually this is used as table not as
79 By default the found cache entries are saved into the static cache
80 table to provide access without reallocation. However, if the static
81 table is full, rest of the cache entries are dynamically allocated
82 into `cache_dyn' table. Traversing functions automatically handles
86 struct SilcIDCacheListStruct {
87 SilcIDCacheEntry cache[64];
88 SilcIDCacheEntry *cache_dyn;
89 unsigned int cache_dyn_count;
90 unsigned int cache_count;
94 /* Allocates new ID cache object. The initial amount of allocated entries
95 can be sent as argument. If `count' is 0 the system uses default values. */
97 SilcIDCache silc_idcache_alloc(unsigned int count)
101 SILC_LOG_DEBUG(("Allocating new cache"));
103 cache = silc_calloc(1, sizeof(*cache));
104 cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
105 cache->cache_count = count ? count : 5;
106 memset(cache->fast_access, -1, sizeof(cache->fast_access));
111 /* Free's ID cache object and cache entries */
113 void silc_idcache_free(SilcIDCache cache)
116 silc_free(cache->cache);
121 /* qsort() sorter function. */
123 static int silc_idcache_sorter(const void *a, const void *b)
125 SilcIDCacheEntry a1, b1;
127 a1 = (SilcIDCacheEntry)a;
128 b1 = (SilcIDCacheEntry)b;
130 if (!a1->data && !b1->data)
139 return a1->data[0] - b1->data[0];
142 /* Sorts given cache by data. After sorting this updates the fast access
143 table that can be used to access the cache faster. */
145 void silc_idcache_sort_by_data(SilcIDCache cache)
149 qsort(cache->cache, cache->cache_count,
150 sizeof(*cache->cache), silc_idcache_sorter);
152 memset(cache->fast_access, -1, sizeof(cache->fast_access));
154 /* Update the fast access table (this of course takes its own time when
155 the cache is very large). */
156 for (i = 0; i < cache->cache_count; i++) {
157 if (cache->cache[i].data &&
158 cache->fast_access[(int)cache->cache[i].data[0]] == -1)
159 cache->fast_access[(int)cache->cache[i].data[0]] = i;
162 cache->sorted = TRUE;
165 /* Find ID Cache entry by data. The data maybe anything that must
166 match exactly. Returns list of cache entries. */
168 int silc_idcache_find_by_data(SilcIDCache cache, unsigned char *data,
169 SilcIDCacheList *ret)
172 SilcIDCacheList list;
174 if (!cache || !cache->cache || !data)
177 list = silc_idcache_list_alloc();
180 i = cache->fast_access[(int)data[0]];
187 for (i = i; i < cache->cache_count; i++) {
188 if (cache->sorted && cache->cache[i].data &&
189 cache->cache[i].data[0] != data[0])
192 if (cache->cache[i].data &&
193 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data)))
194 silc_idcache_list_add(list, &(cache->cache[i]));
197 if (!silc_idcache_list_count(list))
203 silc_idcache_list_free(list);
208 /* Find ID Cache entry by data. The data maybe anything that must
209 match exactly. Returns one cache entry. */
211 int silc_idcache_find_by_data_one(SilcIDCache cache, unsigned char *data,
212 SilcIDCacheEntry *ret)
216 if (!cache || !cache->cache || !data)
220 i = cache->fast_access[(int)data[0]];
227 for (i = i; i < cache->cache_count; i++)
228 if (cache->cache[i].data &&
229 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data))) {
231 *ret = &(cache->cache[i]);
238 /* Find ID Cache entry by data, loosely. The data don't have to be 100%
239 match. This ignores data case-sensitivity when searching with this
240 function. Returns list of cache entries. */
242 int silc_idcache_find_by_data_loose(SilcIDCache cache, unsigned char *data,
243 SilcIDCacheList *ret)
246 SilcIDCacheList list;
248 if (!cache || !cache->cache || !data)
251 list = silc_idcache_list_alloc();
253 c = tolower((int)data[0]);
256 i = cache->fast_access[c];
263 for (i = i; i < cache->cache_count; i++) {
264 if (cache->sorted && cache->cache[i].data &&
265 cache->cache[i].data[0] != (char)c)
268 if (cache->cache[i].data &&
269 !strcasecmp(cache->cache[i].data, data))
270 silc_idcache_list_add(list, &(cache->cache[i]));
274 c = toupper((int)data[0]);
275 i = cache->fast_access[c];
277 for (i = i; i < cache->cache_count; i++) {
278 if (cache->sorted && cache->cache[i].data &&
279 cache->cache[i].data[0] != (char)c)
282 if (cache->cache[i].data &&
283 !strcasecmp(cache->cache[i].data, data))
284 silc_idcache_list_add(list, &(cache->cache[i]));
288 if (!silc_idcache_list_count(list))
294 silc_idcache_list_free(list);
299 /* Find ID Cache entry by ID. Returns list of cache entries. If `id' is
300 SILC_ID_CACHE_ANY this returns all ID's of type `type'. */
302 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
303 SilcIDCacheList *ret)
306 SilcIDCacheList list;
308 if (!cache || !cache->cache || !id)
311 id_len = silc_id_get_len(type);
313 list = silc_idcache_list_alloc();
315 if (id != SILC_ID_CACHE_ANY) {
316 for (i = 0; i < cache->cache_count; i++)
317 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
318 silc_idcache_list_add(list, &(cache->cache[i]));
320 for (i = 0; i < cache->cache_count; i++)
321 if (cache->cache[i].id && cache->cache[i].type == type)
322 silc_idcache_list_add(list, &(cache->cache[i]));
325 if (!silc_idcache_list_count(list))
331 silc_idcache_list_free(list);
336 /* Find ID Cache entry by ID. Returns one cache entry. */
338 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
339 SilcIDCacheEntry *ret)
343 if (!cache || !cache->cache || !id)
346 id_len = silc_id_get_len(type);
348 for (i = 0; i < cache->cache_count; i++)
349 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
351 *ret = &(cache->cache[i]);
358 /* Finds cache entry by context. */
360 int silc_idcache_find_by_context(SilcIDCache cache, void *context,
361 SilcIDCacheEntry *ret)
365 if (!cache || !cache->cache || !context)
368 for (i = 0; i < cache->cache_count; i++)
369 if (cache->cache[i].context && cache->cache[i].context == context) {
371 *ret = &(cache->cache[i]);
378 /* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
379 then the cache is sorted after the new entry has been added. The
380 cache must be sorted in order for the fast access feature to work,
381 however, it is not mandatory. */
383 int silc_idcache_add(SilcIDCache cache, unsigned char *data,
385 void *id, void *context, int sort)
389 unsigned long curtime = time(NULL);
392 if (!cache || !cache->cache)
395 SILC_LOG_DEBUG(("Adding cache entry"));
398 count = cache->cache_count;
401 c = silc_calloc(5, sizeof(*c));
405 /* See if it exists already */
406 /* XXX this slows down this function. */
407 if (silc_idcache_find_by_id(cache, id, id_type, NULL))
410 for (i = 0; i < count; i++) {
411 if (c[i].data == NULL && c[i].id == NULL) {
415 c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
416 c[i].context = context;
422 c = silc_realloc(c, sizeof(*c) * (count + 5));
423 for (i = count; i < count + 5; i++) {
427 c[count].data = data;
428 c[count].type = id_type;
430 c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
431 c[count].context = context;
436 cache->cache_count = count;
437 cache->sorted = sort;
440 silc_idcache_sort_by_data(cache);
445 /* Delete cache entry from cache. */
448 int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
456 int silc_idcache_del_by_data(SilcIDCache cache, unsigned char *data)
462 /* Deletes ID cache entry by ID. */
464 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
468 if (!cache || !cache->cache || !id)
471 id_len = silc_id_get_len(type);
473 for (i = 0; i < cache->cache_count; i++)
474 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
475 cache->cache[i].id = NULL;
476 cache->cache[i].data = NULL;
477 cache->cache[i].type = 0;
478 cache->cache[i].context = NULL;
485 /* Deletes all ID entries from cache. Free's memory as well. */
487 int silc_idcache_del_all(SilcIDCache cache)
489 if (!cache || !cache->cache)
492 silc_free(cache->cache);
494 cache->cache_count = 0;
499 /* Purges the cache by removing expired cache entires. This does not
500 free any memory though. */
502 int silc_idcache_purge(SilcIDCache cache)
505 unsigned long curtime = time(NULL);
508 if (!cache || !cache->cache)
513 for (i = 0; i < cache->cache_count; i++) {
515 (c[i].expire == 0 || c[i].expire < curtime)) {
527 /* Allocates ID cache list. */
529 static SilcIDCacheList silc_idcache_list_alloc()
531 SilcIDCacheList list;
533 list = silc_calloc(1, sizeof(*list));
538 /* Adds cache entry to the ID cache list. If needed reallocates memory
541 static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
545 /* Try to add to static cache */
546 if (!list->cache_dyn_count)
547 for (i = 0; i < sizeof(list->cache); i++) {
548 if (!list->cache[i]) {
549 list->cache[i] = cache;
555 /* Static cache is full, allocate dynamic cache */
556 for (i = 0; i < list->cache_dyn_count; i++) {
557 if (!list->cache_dyn[i]) {
558 list->cache_dyn[i] = cache;
564 if (i >= list->cache_dyn_count) {
568 list->cache_dyn = silc_realloc(list->cache_dyn,
569 sizeof(*list->cache) * (i));
571 /* NULL the reallocated area */
572 for (k = list->cache_dyn_count; k < i; k++)
573 list->cache_dyn[k] = NULL;
575 list->cache_dyn[list->cache_dyn_count] = cache;
576 list->cache_dyn_count = i;
581 /* Returns number of cache entries in the ID cache list. */
583 int silc_idcache_list_count(SilcIDCacheList list)
585 return list->cache_count;
588 /* Returns first entry from the ID cache list. */
590 int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
594 if (!list->cache[list->pos])
598 *ret = list->cache[list->pos];
603 /* Returns next entry from the ID cache list. */
605 int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
610 if (list->pos >= sizeof(list->cache)) {
615 if (dyn && list->pos >= list->cache_dyn_count)
618 if (!dyn && !list->cache[list->pos])
621 if (dyn && !list->cache_dyn[list->pos])
626 *ret = list->cache[list->pos];
628 *ret = list->cache_dyn[list->pos];
634 /* Free's ID cache list. User must free the list object returned by
635 any of the searching functions. */
637 void silc_idcache_list_free(SilcIDCacheList list)
641 silc_free(list->cache_dyn);