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, 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]];
184 for (i = i; i < cache->cache_count; i++) {
185 if (cache->sorted && cache->cache[i].data &&
186 cache->cache[i].data[0] != data[0])
189 if (cache->cache[i].data &&
190 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data)))
191 silc_idcache_list_add(list, &(cache->cache[i]));
194 if (!silc_idcache_list_count(list))
200 silc_idcache_list_free(list);
205 /* Find ID Cache entry by data. The data maybe anything that must
206 match exactly. Returns one cache entry. */
208 int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
209 SilcIDCacheEntry *ret)
213 if (!cache || !cache->cache || !data)
217 i = cache->fast_access[(int)data[0]];
221 for (i = i; i < cache->cache_count; i++)
222 if (cache->cache[i].data &&
223 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data))) {
225 *ret = &(cache->cache[i]);
232 /* Find ID Cache entry by data, loosely. The data don't have to be 100%
233 match. This ignores data case-sensitivity when searching with this
234 function. Returns list of cache entries. */
236 int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
237 SilcIDCacheList *ret)
240 SilcIDCacheList list;
242 if (!cache || !cache->cache || !data)
245 list = silc_idcache_list_alloc();
247 c = tolower((int)data[0]);
250 i = cache->fast_access[c];
254 for (i = i; i < cache->cache_count; i++) {
255 if (cache->sorted && cache->cache[i].data &&
256 cache->cache[i].data[0] != (char)c)
259 if (cache->cache[i].data &&
260 !strcasecmp(cache->cache[i].data, data))
261 silc_idcache_list_add(list, &(cache->cache[i]));
265 c = toupper((int)data[0]);
266 i = cache->fast_access[c];
268 for (i = i; i < cache->cache_count; i++) {
269 if (cache->sorted && cache->cache[i].data &&
270 cache->cache[i].data[0] != (char)c)
273 if (cache->cache[i].data &&
274 !strcasecmp(cache->cache[i].data, data))
275 silc_idcache_list_add(list, &(cache->cache[i]));
279 if (!silc_idcache_list_count(list))
285 silc_idcache_list_free(list);
290 /* Find ID Cache entry by ID. Returns list of cache entries. If `id' is
291 SILC_ID_CACHE_ANY this returns all ID's of type `type'. */
293 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
294 SilcIDCacheList *ret)
297 SilcIDCacheList list;
299 if (!cache || !cache->cache || !id)
302 id_len = silc_id_get_len(type);
304 list = silc_idcache_list_alloc();
306 if (id != SILC_ID_CACHE_ANY) {
307 for (i = 0; i < cache->cache_count; i++)
308 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
309 silc_idcache_list_add(list, &(cache->cache[i]));
311 for (i = 0; i < cache->cache_count; i++)
312 if (cache->cache[i].id && cache->cache[i].type == type)
313 silc_idcache_list_add(list, &(cache->cache[i]));
316 if (!silc_idcache_list_count(list))
322 silc_idcache_list_free(list);
327 /* Find ID Cache entry by ID. Returns one cache entry. */
329 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
330 SilcIDCacheEntry *ret)
334 if (!cache || !cache->cache || !id)
337 id_len = silc_id_get_len(type);
339 for (i = 0; i < cache->cache_count; i++)
340 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
342 *ret = &(cache->cache[i]);
349 /* Finds cache entry by context. */
351 int silc_idcache_find_by_context(SilcIDCache cache, void *context,
352 SilcIDCacheEntry *ret)
356 if (!cache || !cache->cache || !context)
359 for (i = 0; i < cache->cache_count; i++)
360 if (cache->cache[i].context && cache->cache[i].context == context) {
362 *ret = &(cache->cache[i]);
369 /* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
370 then the cache is sorted after the new entry has been added. The
371 cache must be sorted in order for the fast access feature to work,
372 however, it is not mandatory. */
374 int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
375 void *id, void *context, int sort)
379 unsigned long curtime = time(NULL);
382 if (!cache || !cache->cache)
385 SILC_LOG_DEBUG(("Adding cache entry"));
388 count = cache->cache_count;
391 c = silc_calloc(5, sizeof(*c));
395 /* See if it exists already */
396 /* XXX this slows down this function. */
397 if (silc_idcache_find_by_id(cache, id, id_type, NULL))
400 for (i = 0; i < count; i++) {
401 if (c[i].data == NULL && c[i].id == NULL) {
405 c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
406 c[i].context = context;
412 c = silc_realloc(c, sizeof(*c) * (count + 5));
413 for (i = count; i < count + 5; i++) {
417 c[count].data = data;
418 c[count].type = id_type;
420 c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
421 c[count].context = context;
426 cache->cache_count = count;
427 cache->sorted = sort;
430 silc_idcache_sort_by_data(cache);
435 /* Delete cache entry from cache. */
438 int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
446 int silc_idcache_del_by_data(SilcIDCache cache, char *data)
452 /* Deletes ID cache entry by ID. */
454 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
458 if (!cache || !cache->cache || !id)
461 id_len = silc_id_get_len(type);
463 for (i = 0; i < cache->cache_count; i++)
464 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
465 cache->cache[i].id = NULL;
466 cache->cache[i].data = NULL;
467 cache->cache[i].type = 0;
468 cache->cache[i].context = NULL;
475 /* Deletes all ID entries from cache. Free's memory as well. */
477 int silc_idcache_del_all(SilcIDCache cache)
479 if (!cache || !cache->cache)
482 silc_free(cache->cache);
484 cache->cache_count = 0;
489 /* Purges the cache by removing expired cache entires. This does not
490 free any memory though. */
492 int silc_idcache_purge(SilcIDCache cache)
495 unsigned long curtime = time(NULL);
498 if (!cache || !cache->cache)
503 for (i = 0; i < cache->cache_count; i++) {
505 (c[i].expire == 0 || c[i].expire < curtime)) {
517 /* Allocates ID cache list. */
519 static SilcIDCacheList silc_idcache_list_alloc()
521 SilcIDCacheList list;
523 list = silc_calloc(1, sizeof(*list));
528 /* Adds cache entry to the ID cache list. If needed reallocates memory
531 static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
535 /* Try to add to static cache */
536 if (!list->cache_dyn_count)
537 for (i = 0; i < sizeof(list->cache); i++) {
538 if (!list->cache[i]) {
539 list->cache[i] = cache;
545 /* Static cache is full, allocate dynamic cache */
546 for (i = 0; i < list->cache_dyn_count; i++) {
547 if (!list->cache_dyn[i]) {
548 list->cache_dyn[i] = cache;
554 if (i >= list->cache_dyn_count) {
558 list->cache_dyn = silc_realloc(list->cache_dyn,
559 sizeof(*list->cache) * (i));
561 /* NULL the reallocated area */
562 for (k = list->cache_dyn_count; k < i; k++)
563 list->cache_dyn[k] = NULL;
565 list->cache_dyn[list->cache_dyn_count] = cache;
566 list->cache_dyn_count = i;
571 /* Returns number of cache entries in the ID cache list. */
573 int silc_idcache_list_count(SilcIDCacheList list)
575 return list->cache_count;
578 /* Returns first entry from the ID cache list. */
580 int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
584 if (!list->cache[list->pos])
588 *ret = list->cache[list->pos];
593 /* Returns next entry from the ID cache list. */
595 int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
600 if (list->pos >= sizeof(list->cache)) {
605 if (dyn && list->pos >= list->cache_dyn_count)
608 if (!dyn && !list->cache[list->pos])
611 if (dyn && !list->cache_dyn[list->pos])
616 *ret = list->cache[list->pos];
618 *ret = list->cache_dyn[list->pos];
624 /* Free's ID cache list. User must free the list object returned by
625 any of the searching functions. */
627 void silc_idcache_list_free(SilcIDCacheList list)
631 silc_free(list->cache_dyn);