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.
23 * Revision 1.3 2000/07/12 05:54:01 priikone
24 * Major rewrite of whole ID Cache system.
26 * Revision 1.2 2000/07/05 06:06:35 priikone
27 * Global cosmetic change.
29 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
30 * Imported from internal CVS/Added Log headers.
35 #include "silcincludes.h"
38 /* Static prototypes */
39 static int silc_idcache_sorter(const void *a, const void *b);
40 static SilcIDCacheList silc_idcache_list_alloc();
41 static void silc_idcache_list_add(SilcIDCacheList list,
42 SilcIDCacheEntry cache);
47 This is context for the ID cache system. This includes all the cache
48 entries and other internal data. This is read-only object and not
49 visible outside this cache system.
51 Fields are as follows:
53 SilcIDCacheEntry cache
55 Table of the cache entries allocated by silc_idcache_add function.
56 This table is reallocated when new entry is added into the cache.
58 unsigned int cache_count
60 Number of cache entries in the cache.
64 Boolean value to indicate whether the cache is sorted or not. If
65 cache is not sorted the fast access (described next) cannot be used.
66 Sorting can be done by calling sorting function or when adding new
71 Table to provide fast access into the cache by index. When searching
72 by data this table is used to get the index to the first occurence
73 of that data (or part of the data) in the cache. Purpose of this
74 is to provide faster access to the cache when searching by data.
75 This is updated by silc_idcache_add and sorting functions.
78 struct SilcIDCacheStruct {
79 SilcIDCacheEntry cache;
80 unsigned int cache_count;
88 This is returned when searching the cache. Enumeration functions are
89 provided to traverse the list; actually this is used as table not as
92 By default the found cache entries are saved into the static cache
93 table to provide access without reallocation. However, if the static
94 table is full, rest of the cache entries are dynamically allocated
95 into `cache_dyn' table. Traversing functions automatically handles
99 struct SilcIDCacheListStruct {
100 SilcIDCacheEntry cache[64];
101 SilcIDCacheEntry *cache_dyn;
102 unsigned int cache_dyn_count;
103 unsigned int cache_count;
107 /* Allocates new ID cache object. The initial amount of allocated entries
108 can be sent as argument. If `count' is 0 the system uses default values. */
110 SilcIDCache silc_idcache_alloc(unsigned int count)
114 SILC_LOG_DEBUG(("Allocating new cache")),
116 cache = silc_calloc(1, sizeof(*cache));
117 cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
118 cache->cache_count = count ? count : 5;
119 memset(cache->fast_access, -1, sizeof(cache->fast_access));
124 /* Free's ID cache object and cache entries */
126 void silc_idcache_free(SilcIDCache cache)
129 silc_free(cache->cache);
134 /* qsort() sorter function. */
136 static int silc_idcache_sorter(const void *a, const void *b)
138 SilcIDCacheEntry a1, b1;
140 a1 = (SilcIDCacheEntry)a;
141 b1 = (SilcIDCacheEntry)b;
143 if (!a1->data && !b1->data)
152 return a1->data[0] - b1->data[0];
155 /* Sorts given cache by data. After sorting this updates the fast access
156 table that can be used to access the cache faster. */
158 void silc_idcache_sort_by_data(SilcIDCache cache)
162 qsort(cache->cache, cache->cache_count,
163 sizeof(*cache->cache), silc_idcache_sorter);
165 memset(cache->fast_access, -1, sizeof(cache->fast_access));
167 /* Update the fast access table (this of course takes its own time when
168 the cache is very large). */
169 for (i = 0; i < cache->cache_count; i++) {
170 if (cache->cache[i].data &&
171 cache->fast_access[(int)cache->cache[i].data[0]] == -1)
172 cache->fast_access[(int)cache->cache[i].data[0]] = i;
175 cache->sorted = TRUE;
178 /* Find ID Cache entry by data. The data maybe anything that must
179 match exactly. Returns list of cache entries. */
181 int silc_idcache_find_by_data(SilcIDCache cache, char *data,
182 SilcIDCacheList *ret)
185 SilcIDCacheList list;
187 if (!cache || !cache->cache || !data)
190 list = silc_idcache_list_alloc();
193 i = cache->fast_access[(int)data[0]];
197 for (i = i; i < cache->cache_count; i++) {
198 if (cache->sorted && cache->cache[i].data &&
199 cache->cache[i].data[0] != data[0])
202 if (cache->cache[i].data &&
203 !memcmp(cache->cache[i].data, data, strlen(data)))
204 silc_idcache_list_add(list, &(cache->cache[i]));
207 if (!silc_idcache_list_count(list))
213 silc_idcache_list_free(list);
218 /* Find ID Cache entry by data. The data maybe anything that must
219 match exactly. Returns one cache entry. */
221 int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
222 SilcIDCacheEntry *ret)
226 if (!cache || !cache->cache || !data)
230 i = cache->fast_access[(int)data[0]];
234 for (i = i; i < cache->cache_count; i++)
235 if (cache->cache[i].data &&
236 !memcmp(cache->cache[i].data, data, strlen(data))) {
238 *ret = &(cache->cache[i]);
245 /* Find ID Cache entry by data, loosely. The data don't have to be 100%
246 match. This ignores data case-sensitivity when searching with this
247 function. Returns list of cache entries. */
249 int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
250 SilcIDCacheList *ret)
253 SilcIDCacheList list;
255 if (!cache || !cache->cache || !data)
258 list = silc_idcache_list_alloc();
260 c = tolower((int)data[0]);
263 i = cache->fast_access[c];
267 for (i = i; i < cache->cache_count; i++) {
268 if (cache->sorted && cache->cache[i].data &&
269 cache->cache[i].data[0] != (char)c)
272 if (cache->cache[i].data &&
273 !strcasecmp(cache->cache[i].data, data))
274 silc_idcache_list_add(list, &(cache->cache[i]));
278 c = toupper((int)data[0]);
279 i = cache->fast_access[c];
281 for (i = i; i < cache->cache_count; i++) {
282 if (cache->sorted && cache->cache[i].data &&
283 cache->cache[i].data[0] != (char)c)
286 if (cache->cache[i].data &&
287 !strcasecmp(cache->cache[i].data, data))
288 silc_idcache_list_add(list, &(cache->cache[i]));
292 if (!silc_idcache_list_count(list))
298 silc_idcache_list_free(list);
303 /* Find ID Cache entry by ID. Returns list of cache entries. */
304 /* XXX this may be useless, need for list really? */
306 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
307 SilcIDCacheList *ret)
310 SilcIDCacheList list;
312 if (!cache || !cache->cache || !id)
315 id_len = silc_id_get_len(type);
317 list = silc_idcache_list_alloc();
319 for (i = 0; i < cache->cache_count; i++)
320 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
321 silc_idcache_list_add(list, &(cache->cache[i]));
323 if (!silc_idcache_list_count(list))
329 silc_idcache_list_free(list);
334 /* Find ID Cache entry by ID. Returns one cache entry. */
336 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
337 SilcIDCacheEntry *ret)
341 if (!cache || !cache->cache || !id)
344 id_len = silc_id_get_len(type);
346 for (i = 0; i < cache->cache_count; i++)
347 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
349 *ret = &(cache->cache[i]);
356 /* Finds cache entry by context. */
358 int silc_idcache_find_by_context(SilcIDCache cache, void *context,
359 SilcIDCacheEntry *ret)
363 if (!cache || !cache->cache || !context)
366 for (i = 0; i < cache->cache_count; i++)
367 if (cache->cache[i].context && cache->cache[i].context == context) {
369 *ret = &(cache->cache[i]);
376 /* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
377 then the cache is sorted after the new entry has been added. The
378 cache must be sorted in order for the fast access feature to work,
379 however, it is not mandatory. */
381 int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
382 void *id, void *context, int sort)
386 unsigned long curtime = time(NULL);
389 if (!cache || !cache->cache)
392 SILC_LOG_DEBUG(("Adding cache entry"));
395 count = cache->cache_count;
398 c = silc_calloc(5, sizeof(*c));
402 /* See if it exists already */
403 /* XXX this slows down this function. */
404 if (silc_idcache_find_by_id(cache, id, id_type, NULL))
407 for (i = 0; i < count; i++) {
408 if (c[i].data == NULL) {
412 c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
413 c[i].context = context;
419 c = silc_realloc(c, sizeof(*c) * (count + 5));
420 for (i = count; i < count + 5; i++) {
424 c[count].data = data;
425 c[count].type = id_type;
427 c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
428 c[count].context = context;
433 cache->cache_count = count;
434 cache->sorted = sort;
437 silc_idcache_sort_by_data(cache);
442 /* Delete cache entry from cache. */
445 int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
453 int silc_idcache_del_by_data(SilcIDCache cache, char *data)
459 /* Deletes ID cache entry by ID. */
461 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
465 if (!cache || !cache->cache || !id)
468 id_len = silc_id_get_len(type);
470 for (i = 0; i < cache->cache_count; i++)
471 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
472 cache->cache[i].id = NULL;
473 cache->cache[i].data = NULL;
474 cache->cache[i].type = 0;
475 cache->cache[i].context = NULL;
482 /* Deletes all ID entries from cache. Free's memory as well. */
484 int silc_idcache_del_all(SilcIDCache cache)
486 if (!cache || !cache->cache)
489 silc_free(cache->cache);
491 cache->cache_count = 0;
496 /* Purges the cache by removing expired cache entires. This does not
497 free any memory though. */
499 int silc_idcache_purge(SilcIDCache cache)
502 unsigned long curtime = time(NULL);
505 if (!cache || !cache->cache)
510 for (i = 0; i < cache->cache_count; i++) {
512 (c[i].expire == 0 || c[i].expire < curtime)) {
524 /* Allocates ID cache list. */
526 static SilcIDCacheList silc_idcache_list_alloc()
528 SilcIDCacheList list;
530 list = silc_calloc(1, sizeof(*list));
535 /* Adds cache entry to the ID cache list. If needed reallocates memory
538 static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
542 /* Try to add to static cache */
543 if (!list->cache_dyn_count)
544 for (i = 0; i < sizeof(list->cache); i++) {
545 if (!list->cache[i]) {
546 list->cache[i] = cache;
552 /* Static cache is full, allocate dynamic cache */
553 for (i = 0; i < list->cache_dyn_count; i++) {
554 if (!list->cache_dyn[i]) {
555 list->cache_dyn[i] = cache;
561 if (i >= list->cache_dyn_count) {
565 list->cache_dyn = silc_realloc(list->cache_dyn,
566 sizeof(*list->cache) * (i));
568 /* NULL the reallocated area */
569 for (k = list->cache_dyn_count; k < i; k++)
570 list->cache_dyn[k] = NULL;
572 list->cache_dyn[list->cache_dyn_count] = cache;
573 list->cache_dyn_count = i;
578 /* Returns number of cache entries in the ID cache list. */
580 int silc_idcache_list_count(SilcIDCacheList list)
582 return list->cache_count;
585 /* Returns first entry from the ID cache list. */
587 int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
591 if (!list->cache[list->pos])
595 *ret = list->cache[list->pos];
600 /* Returns next entry from the ID cache list. */
602 int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
607 if (list->pos >= sizeof(list->cache)) {
612 if (dyn && list->pos >= list->cache_dyn_count)
615 if (!dyn && !list->cache[list->pos])
618 if (dyn && !list->cache_dyn[list->pos])
623 *ret = list->cache[list->pos];
625 *ret = list->cache_dyn[list->pos];
631 /* Free's ID cache list. User must free the list object returned by
632 any of the searching functions. */
634 void silc_idcache_list_free(SilcIDCacheList list)
638 silc_free(list->cache_dyn);