|
|
1.1 root 1: /*
2: * IPFlow Collector
3: * Copyright (c) 2003 Christophe Fillot.
4: * E-mail: [email protected]
5: *
6: * registry.c: Object Registry.
7: */
8:
9: #define _GNU_SOURCE
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #include <stdarg.h>
14: #include <unistd.h>
15: #include <errno.h>
16: #include <signal.h>
17: #include <fcntl.h>
18: #include <ctype.h>
19: #include <time.h>
20: #include <pthread.h>
21: #include <sys/time.h>
22: #include <sys/stat.h>
23: #include <sys/types.h>
24: #include <sys/wait.h>
25: #include <assert.h>
26:
27: #include "utils.h"
28: #include "hash.h"
29: #include "mempool.h"
30: #include "registry.h"
31:
32: #define DEBUG_REGISTRY 0
33:
34: static registry_t *registry = NULL;
35:
36: #define REGISTRY_LOCK() pthread_mutex_lock(®istry->lock)
37: #define REGISTRY_UNLOCK() pthread_mutex_unlock(®istry->lock)
38:
39: /* Initialize registry */
40: int registry_init(void)
41: {
42: registry_entry_t *p;
43: pthread_mutexattr_t attr;
44: size_t len;
45: int i;
46:
47: registry = malloc(sizeof(*registry));
48: assert(registry != NULL);
49:
50: pthread_mutexattr_init(&attr);
51: pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
52: pthread_mutex_init(®istry->lock,&attr);
53:
54: /* initialize registry memory pool */
55: mp_create_fixed_pool(®istry->mp,"registry");
56:
57: registry->ht_name_entries = REGISTRY_HT_NAME_ENTRIES;
58: registry->ht_type_entries = REGISTRY_MAX_TYPES;
59:
60: /* initialize hash table for names, with sentinels */
61: len = registry->ht_name_entries * sizeof(registry_entry_t);
62: registry->ht_names = mp_alloc(®istry->mp,len);
63: assert(registry->ht_names != NULL);
64:
65: for(i=0;i<registry->ht_name_entries;i++) {
66: p = ®istry->ht_names[i];
67: p->hname_next = p->hname_prev = p;
68: }
69:
70: /* initialize hash table for types, with sentinels */
71: len = registry->ht_type_entries * sizeof(registry_entry_t);
72: registry->ht_types = mp_alloc(®istry->mp,len);
73: assert(registry->ht_types != NULL);
74:
75: for(i=0;i<registry->ht_type_entries;i++) {
76: p = ®istry->ht_types[i];
77: p->htype_next = p->htype_prev = p;
78: }
79:
80: return(0);
81: }
82:
83: /* Insert a new entry */
84: static void registry_insert_entry(registry_entry_t *entry)
85: {
86: registry_entry_t *bucket;
87: u_int h_index;
88:
89: /* insert new entry in hash table for names */
90: h_index = str_hash(entry->name) % registry->ht_name_entries;
91: bucket = ®istry->ht_names[h_index];
92:
93: entry->hname_next = bucket->hname_next;
94: entry->hname_prev = bucket;
95: bucket->hname_next->hname_prev = entry;
96: bucket->hname_next = entry;
97:
98: /* insert new entry in hash table for object types */
99: bucket = ®istry->ht_types[entry->object_type];
100:
101: entry->htype_next = bucket->htype_next;
102: entry->htype_prev = bucket;
103: bucket->htype_next->htype_prev = entry;
104: bucket->htype_next = entry;
105: }
106:
107: /* Remove a registry entry */
108: void registry_remove_entry(registry_entry_t *entry)
109: {
110: entry->hname_prev->hname_next = entry->hname_next;
111: entry->hname_next->hname_prev = entry->hname_prev;
112:
113: entry->htype_prev->htype_next = entry->htype_next;
114: entry->htype_next->htype_prev = entry->htype_prev;
115:
116: mp_free(entry);
117: }
118:
119: /* Locate an entry */
120: static inline registry_entry_t *registry_find_entry(char *name,int object_type)
121: {
122: registry_entry_t *entry,*bucket;
123: u_int h_index;
124:
125: h_index = str_hash(name) % registry->ht_name_entries;
126: bucket = ®istry->ht_names[h_index];
127:
128: for(entry=bucket->hname_next;entry!=bucket;entry=entry->hname_next)
129: if (!strcmp(entry->name,name) && (entry->object_type == object_type))
130: return entry;
131:
132: return NULL;
133: }
134:
135: /* Add a new entry to the registry */
136: int registry_add(char *name,int object_type,void *data)
137: {
138: registry_entry_t *entry;
139:
140: if (!name)
141: return(-1);
142:
143: REGISTRY_LOCK();
144:
145: /* check if we have already a reference for this name */
146: if ((entry = registry_find_entry(name,object_type))) {
147: REGISTRY_UNLOCK();
148: return(-1);
149: }
150:
151: /* create a new entry */
152: if (!(entry = mp_alloc(®istry->mp,sizeof(*entry)))) {
153: REGISTRY_UNLOCK();
154: return(-1);
155: }
156:
157: entry->name = name;
158: entry->data = data;
159: entry->object_type = object_type;
160: entry->ref_count = 1; /* consider object is referenced by the caller */
161: registry_insert_entry(entry);
162:
163: REGISTRY_UNLOCK();
164: return(0);
165: }
166:
167: /* Delete an entry from the registry */
168: int registry_delete(char *name,int object_type)
169: {
170: registry_entry_t *entry;
171:
172: if (!name) return(-1);
173:
174: REGISTRY_LOCK();
175:
176: if (!(entry = registry_find_entry(name,object_type))) {
177: REGISTRY_UNLOCK();
178: return(-1);
179: }
180:
181: /* if the entry is referenced, just decrement ref counter */
182: if (--entry->ref_count > 0) {
183: REGISTRY_UNLOCK();
184: return(0);
185: }
186:
187: registry_remove_entry(entry);
188: REGISTRY_UNLOCK();
189: return(0);
190: }
191:
192: /* Find an entry (increment the reference count) */
193: void *registry_find(char *name,int object_type)
194: {
195: registry_entry_t *entry;
196: void *data;
197:
198: if (!name) return NULL;
199:
200: REGISTRY_LOCK();
201:
202: if ((entry = registry_find_entry(name,object_type))) {
203: entry->ref_count++;
204: data = entry->data;
205: } else
206: data = NULL;
207:
208: REGISTRY_UNLOCK();
209: return data;
210: }
211:
212: /* Check if entry exists (does not change reference count) */
213: void *registry_exists(char *name,int object_type)
214: {
215: registry_entry_t *entry;
216: void *data = NULL;
217:
218: if (!name)
219: return NULL;
220:
221: REGISTRY_LOCK();
222: entry = registry_find_entry(name,object_type);
223: if (entry)
224: data = entry->data;
225: REGISTRY_UNLOCK();
226: return data;
227: }
228:
229: /* Release a reference of an entry (decrement the reference count) */
230: int registry_unref(char *name,int object_type)
231: {
232: registry_entry_t *entry;
233: int res = -1;
234:
235: if (!name) return(-1);
236:
237: REGISTRY_LOCK();
238:
239: if ((entry = registry_find_entry(name,object_type)))
240: {
241: entry->ref_count--;
242:
243: #if DEBUG_REGISTRY
244: printf("Registry: object %s: ref_count = %d after unref.\n",
245: name, entry->ref_count);
246: #endif
247:
248: if (entry->ref_count < 0) {
249: fprintf(stderr,"Registry: object %s (type %d): negative ref_count.\n",
250: name, object_type);
251: } else
252: res = 0;
253: }
254:
255: REGISTRY_UNLOCK();
256: return(res);
257: }
258:
259: /*
260: * Execute action on an object if its reference count is less or equal to
261: * the specified count.
262: */
263: int registry_exec_refcount(char *name,int object_type,int max_ref,int reg_del,
264: registry_exec obj_action,void *opt_arg)
265: {
266: registry_entry_t *entry;
267: int res = -1;
268: int status;
269:
270: if (!name) return(-1);
271:
272: REGISTRY_LOCK();
273:
274: entry = registry_find_entry(name,object_type);
275:
276: if (entry)
277: {
278: if (entry->ref_count <= max_ref)
279: {
280: status = TRUE;
281:
282: if (obj_action != NULL)
283: status = obj_action(entry->data,opt_arg);
284:
285: if (reg_del && status)
286: registry_remove_entry(entry);
287:
288: res = 1;
289: } else
290: res = 0;
291: }
292:
293: REGISTRY_UNLOCK();
294: return(res);
295: }
296:
297: /* Delete object if unused */
298: int registry_delete_if_unused(char *name,int object_type,
299: registry_exec obj_destructor,void *opt_arg)
300: {
301: return(registry_exec_refcount(name,object_type,0,TRUE,
302: obj_destructor,opt_arg));
303: }
304:
305: /* Execute a callback function for all objects of specified type */
306: int registry_foreach_type(int object_type,registry_foreach cb,
307: void *opt,int *err)
308: {
309: registry_entry_t *p,*bucket,*next;
310: int count = 0;
311:
312: REGISTRY_LOCK();
313:
314: bucket = ®istry->ht_types[object_type];
315:
316: for(p=bucket->htype_next;p!=bucket;p=next) {
317: next = p->htype_next;
318: if (cb) cb(p,opt,err);
319: count++;
320: }
321:
322: REGISTRY_UNLOCK();
323: return(count);
324: }
325:
326: /* Delete all objects of the specified type */
327: int registry_delete_type(int object_type,registry_exec cb,void *opt)
328: {
329: registry_entry_t *p,*bucket,*next;
330: int count = 0;
331: int status;
332:
333: REGISTRY_LOCK();
334:
335: bucket = ®istry->ht_types[object_type];
336:
337: for(p=bucket->htype_next;p!=bucket;p=next) {
338: next = p->htype_next;
339:
340: if (p->ref_count == 0) {
341: status = TRUE;
342:
343: if (cb != NULL)
344: status = cb(p->data,opt);
345:
346: if (status) {
347: registry_remove_entry(p);
348: count++;
349: }
350: } else {
351: fprintf(stderr,"registry_delete_type: object \"%s\" (type %d) still "
352: "referenced (count=%d)\n",p->name,object_type,p->ref_count);
353: }
354: }
355:
356: REGISTRY_UNLOCK();
357: return(count);
358: }
359:
360: /* Dump the registry */
361: void registry_dump(void)
362: {
363: registry_entry_t *p,*bucket;
364: int i;
365:
366: REGISTRY_LOCK();
367:
368: printf("Registry dump:\n");
369:
370: printf(" Objects (from name hash table):\n");
371:
372: /* dump hash table of names */
373: for(i=0;i<registry->ht_name_entries;i++)
374: {
375: bucket = ®istry->ht_names[i];
376:
377: for(p=bucket->hname_next;p!=bucket;p=p->hname_next)
378: printf(" %s (type %d, ref_count=%d)\n",
379: p->name,p->object_type,p->ref_count);
380: }
381:
382: printf("\n Objects classed by types:\n");
383:
384: /* dump hash table of types */
385: for(i=0;i<registry->ht_type_entries;i++)
386: {
387: printf(" Type %d: ",i);
388:
389: bucket = ®istry->ht_types[i];
390: for(p=bucket->htype_next;p!=bucket;p=p->htype_next)
391: printf("%s(%d) ",p->name,p->ref_count);
392:
393: printf("\n");
394: }
395:
396: REGISTRY_UNLOCK();
397: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.