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.4 2000/07/17 11:46:36 priikone
26 * Revision 1.3 2000/07/12 05:54:01 priikone
27 * Major rewrite of whole ID Cache system.
29 * Revision 1.2 2000/07/05 06:06:35 priikone
30 * Global cosmetic change.
32 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
33 * Imported from internal CVS/Added Log headers.
38 #include "silcincludes.h"
41 /* Static prototypes */
42 static int silc_idcache_sorter(const void *a, const void *b);
43 static SilcIDCacheList silc_idcache_list_alloc();
44 static void silc_idcache_list_add(SilcIDCacheList list,
45 SilcIDCacheEntry cache);
50 This is context for the ID cache system. This includes all the cache
51 entries and other internal data. This is read-only object and not
52 visible outside this cache system.
54 Fields are as follows:
56 SilcIDCacheEntry cache
58 Table of the cache entries allocated by silc_idcache_add function.
59 This table is reallocated when new entry is added into the cache.
61 unsigned int cache_count
63 Number of cache entries in the cache.
67 Boolean value to indicate whether the cache is sorted or not. If
68 cache is not sorted the fast access (described next) cannot be used.
69 Sorting can be done by calling sorting function or when adding new
74 Table to provide fast access into the cache by index. When searching
75 by data this table is used to get the index to the first occurence
76 of that data (or part of the data) in the cache. Purpose of this
77 is to provide faster access to the cache when searching by data.
78 This is updated by silc_idcache_add and sorting functions.
81 struct SilcIDCacheStruct {
82 SilcIDCacheEntry cache;
83 unsigned int cache_count;
91 This is returned when searching the cache. Enumeration functions are
92 provided to traverse the list; actually this is used as table not as
95 By default the found cache entries are saved into the static cache
96 table to provide access without reallocation. However, if the static
97 table is full, rest of the cache entries are dynamically allocated
98 into `cache_dyn' table. Traversing functions automatically handles
102 struct SilcIDCacheListStruct {
103 SilcIDCacheEntry cache[64];
104 SilcIDCacheEntry *cache_dyn;
105 unsigned int cache_dyn_count;
106 unsigned int cache_count;
110 /* Allocates new ID cache object. The initial amount of allocated entries
111 can be sent as argument. If `count' is 0 the system uses default values. */
113 SilcIDCache silc_idcache_alloc(unsigned int count)
117 SILC_LOG_DEBUG(("Allocating new cache"));
119 cache = silc_calloc(1, sizeof(*cache));
120 cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
121 cache->cache_count = count ? count : 5;
122 memset(cache->fast_access, -1, sizeof(cache->fast_access));
127 /* Free's ID cache object and cache entries */
129 void silc_idcache_free(SilcIDCache cache)
132 silc_free(cache->cache);
137 /* qsort() sorter function. */
139 static int silc_idcache_sorter(const void *a, const void *b)
141 SilcIDCacheEntry a1, b1;
143 a1 = (SilcIDCacheEntry)a;
144 b1 = (SilcIDCacheEntry)b;
146 if (!a1->data && !b1->data)
155 return a1->data[0] - b1->data[0];
158 /* Sorts given cache by data. After sorting this updates the fast access
159 table that can be used to access the cache faster. */
161 void silc_idcache_sort_by_data(SilcIDCache cache)
165 qsort(cache->cache, cache->cache_count,
166 sizeof(*cache->cache), silc_idcache_sorter);
168 memset(cache->fast_access, -1, sizeof(cache->fast_access));
170 /* Update the fast access table (this of course takes its own time when
171 the cache is very large). */
172 for (i = 0; i < cache->cache_count; i++) {
173 if (cache->cache[i].data &&
174 cache->fast_access[(int)cache->cache[i].data[0]] == -1)
175 cache->fast_access[(int)cache->cache[i].data[0]] = i;
178 cache->sorted = TRUE;
181 /* Find ID Cache entry by data. The data maybe anything that must
182 match exactly. Returns list of cache entries. */
184 int silc_idcache_find_by_data(SilcIDCache cache, char *data,
185 SilcIDCacheList *ret)
188 SilcIDCacheList list;
190 if (!cache || !cache->cache || !data)
193 list = silc_idcache_list_alloc();
196 i = cache->fast_access[(int)data[0]];
200 for (i = i; i < cache->cache_count; i++) {
201 if (cache->sorted && cache->cache[i].data &&
202 cache->cache[i].data[0] != data[0])
205 if (cache->cache[i].data &&
206 !memcmp(cache->cache[i].data, data, strlen(data)))
207 silc_idcache_list_add(list, &(cache->cache[i]));
210 if (!silc_idcache_list_count(list))
216 silc_idcache_list_free(list);
221 /* Find ID Cache entry by data. The data maybe anything that must
222 match exactly. Returns one cache entry. */
224 int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
225 SilcIDCacheEntry *ret)
229 if (!cache || !cache->cache || !data)
233 i = cache->fast_access[(int)data[0]];
237 for (i = i; i < cache->cache_count; i++)
238 if (cache->cache[i].data &&
239 !memcmp(cache->cache[i].data, data, strlen(data))) {
241 *ret = &(cache->cache[i]);
248 /* Find ID Cache entry by data, loosely. The data don't have to be 100%
249 match. This ignores data case-sensitivity when searching with this
250 function. Returns list of cache entries. */
252 int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
253 SilcIDCacheList *ret)
256 SilcIDCacheList list;
258 if (!cache || !cache->cache || !data)
261 list = silc_idcache_list_alloc();
263 c = tolower((int)data[0]);
266 i = cache->fast_access[c];
270 for (i = i; i < cache->cache_count; i++) {
271 if (cache->sorted && cache->cache[i].data &&
272 cache->cache[i].data[0] != (char)c)
275 if (cache->cache[i].data &&
276 !strcasecmp(cache->cache[i].data, data))
277 silc_idcache_list_add(list, &(cache->cache[i]));
281 c = toupper((int)data[0]);
282 i = cache->fast_access[c];
284 for (i = i; i < cache->cache_count; i++) {
285 if (cache->sorted && cache->cache[i].data &&
286 cache->cache[i].data[0] != (char)c)
289 if (cache->cache[i].data &&
290 !strcasecmp(cache->cache[i].data, data))
291 silc_idcache_list_add(list, &(cache->cache[i]));
295 if (!silc_idcache_list_count(list))
301 silc_idcache_list_free(list);
306 /* Find ID Cache entry by ID. Returns list of cache entries. */
307 /* XXX this may be useless, need for list really? */
309 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
310 SilcIDCacheList *ret)
313 SilcIDCacheList list;
315 if (!cache || !cache->cache || !id)
318 id_len = silc_id_get_len(type);
320 list = silc_idcache_list_alloc();
322 for (i = 0; i < cache->cache_count; i++)
323 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
324 silc_idcache_list_add(list, &(cache->cache[i]));
326 if (!silc_idcache_list_count(list))
332 silc_idcache_list_free(list);
337 /* Find ID Cache entry by ID. Returns one cache entry. */
339 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
340 SilcIDCacheEntry *ret)
344 if (!cache || !cache->cache || !id)
347 id_len = silc_id_get_len(type);
349 for (i = 0; i < cache->cache_count; i++)
350 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
352 *ret = &(cache->cache[i]);
359 /* Finds cache entry by context. */
361 int silc_idcache_find_by_context(SilcIDCache cache, void *context,
362 SilcIDCacheEntry *ret)
366 if (!cache || !cache->cache || !context)
369 for (i = 0; i < cache->cache_count; i++)
370 if (cache->cache[i].context && cache->cache[i].context == context) {
372 *ret = &(cache->cache[i]);
379 /* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
380 then the cache is sorted after the new entry has been added. The
381 cache must be sorted in order for the fast access feature to work,
382 however, it is not mandatory. */
384 int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
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) {
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, 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);