undns 0.4.0a

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ /*
2
+ * Copyright (c) 2002
3
+ * Neil Spring and the University of Washington.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * 3. The name of the author(s) may not be used to endorse or promote
15
+ * products derived from this software without specific prior
16
+ * written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifndef _hashes_h
31
+ #define _hashes_h
32
+ #include <sys/types.h>
33
+ #include <netinet/in.h>
34
+ typedef char *hash_cptr;
35
+ unsigned int mac_hash(const void *key);
36
+ unsigned int ip_hash(const void *key); // treats void * as u_int *
37
+ unsigned int port_hash(const void *key); // treats void * as u_int
38
+ unsigned int string_hash(const char *key);
39
+ unsigned int pstring_hash(const hash_cptr *key);
40
+ unsigned int sockaddr_in_hash(const struct sockaddr_in *v);
41
+
42
+ boolean mac_isequal(const void *v1, const void *v2);
43
+ boolean ip_isequal(const void *v1, const void *v2);
44
+ boolean port_isequal(const void *key1, const void *key2);
45
+ boolean string_isequal(const char *string1, const char *string2);
46
+ boolean pstring_isequal(const hash_cptr *string1, const hash_cptr *string2);
47
+ boolean sockaddr_in_isequal(const struct sockaddr_in *v1, const struct sockaddr_in *v2);
48
+ #endif
@@ -0,0 +1,518 @@
1
+ /*
2
+ * Copyright (c) 2002
3
+ * Neil Spring and the University of Washington.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * 3. The name of the author(s) may not be used to endorse or promote
15
+ * products derived from this software without specific prior
16
+ * written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifdef HAVE_CONFIG_H
31
+ #include <config.h>
32
+ #endif
33
+ #ifdef HAVE_LIBPTHREAD
34
+ #include <pthread.h>
35
+ int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind); // grr...
36
+ #else
37
+ // typedef void *pthread_mutex_t;
38
+ #define pthread_mutex_lock(x) (0)
39
+ #define pthread_mutex_unlock(x) (0)
40
+ #define pthread_mutex_init(x,y) (0)
41
+ #define pthread_mutexattr_init(x,y) (0)
42
+ #define pthread_mutexattr_setkind_np(x,y) (0)
43
+ #define pthread_mutexattr_destroy(x,y) (0)
44
+ #define pthread_mutex_destroy(x) (0)
45
+ #endif
46
+ #include <stdlib.h>
47
+ #include <string.h>
48
+ #include <assert.h>
49
+ #include <stdio.h>
50
+ #include "hashtable.h"
51
+ #include "progress.h"
52
+ #ifdef WITH_DMALLOC
53
+ #include <dmalloc.h>
54
+ #endif
55
+
56
+ typedef struct hashentry_struct {
57
+ struct hashentry_struct *next;
58
+ unsigned int hashkey;
59
+ const void *keyval;
60
+ } hashentry;
61
+
62
+ struct hashtable_struct {
63
+ hashentry **table;
64
+ unsigned int table_size;
65
+ unsigned int (*hash)(const void *key);
66
+ boolean (*isequal)(const void *key1, const void *key2);
67
+ /*@null@*/ void (*free_keyval)(void *key);
68
+ #ifdef _REENTRANT
69
+ pthread_mutex_t mutex;
70
+ #endif
71
+ };
72
+
73
+ hashtable ht_new(unsigned int size,
74
+ unsigned int (*hash)(const void *key),
75
+ boolean (*isequal)(const void *key1,
76
+ const void *key2),
77
+ /*@null@*/ void (*free_keyval)(void *key)) {
78
+ hashtable ht = malloc(sizeof(struct hashtable_struct));
79
+ #ifdef _REENTRANT
80
+ pthread_mutexattr_t attrib;
81
+ #endif
82
+ assert(ht!=NULL);
83
+ ht->table = (hashentry **)malloc(sizeof(hashentry *)*size);
84
+ assert(ht->table!=NULL);
85
+ memset(ht->table, 0, size * sizeof(hashentry *));
86
+ ht->table_size = size;
87
+ ht->hash = hash;
88
+ ht->isequal = isequal;
89
+ ht->free_keyval = free_keyval;
90
+ #ifdef _REENTRANT
91
+ #ifdef PTHREAD_MUTEX_RECURSIVE_NP
92
+ (void)pthread_mutexattr_init(&attrib);
93
+ // (void)pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
94
+ // (void)pthread_mutexattr_setkind(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
95
+ (void)pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
96
+ (void)pthread_mutex_init(&ht->mutex, &attrib);
97
+ (void)pthread_mutexattr_destroy(&attrib);
98
+ #endif
99
+ #endif
100
+ return(ht);
101
+ }
102
+
103
+ #ifdef _REENTRANT
104
+ #define LOCK assert(pthread_mutex_lock(&ht->mutex)==0)
105
+ #define UNLOCK assert(pthread_mutex_unlock(&ht->mutex)==0)
106
+ #else
107
+ #define LOCK do { } while(0)
108
+ #define UNLOCK do { } while(0)
109
+ #endif
110
+
111
+ void ht_insert(hashtable ht, const void *keyval) {
112
+ hashentry *he;
113
+ assert(ht!=NULL);
114
+ he = malloc_ordie(sizeof(hashentry));
115
+ he->hashkey = ht->hash(keyval);
116
+ he->keyval = keyval;
117
+ LOCK;
118
+ he->next = ht->table[he->hashkey%ht->table_size];
119
+ ht->table[he->hashkey%ht->table_size] = he;
120
+ UNLOCK;
121
+ }
122
+
123
+ void ht_free_entry(hashtable ht, const void *keyval) {
124
+ if(ht->free_keyval!= NULL)
125
+ ht->free_keyval((void *)keyval);
126
+ }
127
+
128
+ void ht_delete(/*@only@*/ hashtable ht, boolean show_progress) {
129
+ unsigned int i;
130
+ if(show_progress) {
131
+ progress_label("ht_delete");
132
+ progress_reset();
133
+ }
134
+ LOCK;
135
+ for(i=0; i<ht->table_size; i++) {
136
+ hashentry *he = ht->table[i];
137
+ hashentry *prvhe;
138
+ if(show_progress && (i % 100)==0)
139
+ progress((float)i / (float)ht->table_size);
140
+ while(he) {
141
+ /* remove from the list */
142
+ prvhe = he;
143
+ he=he->next;
144
+ /* then free the data -- avoiding dodgy free-calls-remove cycles. */
145
+ ht_free_entry(ht, prvhe->keyval);
146
+ free(prvhe);
147
+ }
148
+ }
149
+ UNLOCK;
150
+ if(show_progress)
151
+ progress(1.0);
152
+ free(ht->table);
153
+ free(ht);
154
+ }
155
+
156
+ /* returns true if found and removed */
157
+ /* returns false if not there */
158
+ /* does not free, regardless of the value of
159
+ ht->free_keyval, invoked only when deleting. */
160
+ boolean ht_remove(hashtable ht, const void *key) {
161
+ unsigned int hkey;
162
+ hashentry *he, *prehe;
163
+ assert(ht!=NULL);
164
+ hkey = ht->hash(key);
165
+ prehe = NULL;
166
+ LOCK;
167
+ he = ht->table[hkey%ht->table_size];
168
+ while(he!=NULL) {
169
+ if(he->hashkey == hkey && ht->isequal(he->keyval,key)) {
170
+ if(prehe != NULL) {
171
+ prehe->next = he->next;
172
+ } else {
173
+ ht->table[hkey%ht->table_size] = he->next;
174
+ }
175
+ UNLOCK;
176
+ free(he);
177
+ return TRUE;
178
+ }
179
+ prehe = he;
180
+ he = he->next;
181
+ }
182
+ UNLOCK;
183
+ return FALSE;
184
+ }
185
+
186
+ void *ht_lookup(hashtable ht,
187
+ const void *key) {
188
+ unsigned int hkey;
189
+ hashentry *he;
190
+ assert(ht!=NULL);
191
+ hkey = ht->hash(key);
192
+ LOCK;
193
+ he = ht->table[hkey%ht->table_size];
194
+ while(he!=NULL) {
195
+ if(he->hashkey == hkey && ht->isequal(he->keyval,key)) {
196
+ UNLOCK;
197
+ return((void *)he->keyval);
198
+ }
199
+ he = he->next;
200
+ }
201
+ UNLOCK;
202
+ return NULL;
203
+ }
204
+
205
+ /*@dependent@*/
206
+ void *ht_lookup_nofail(hashtable ht,
207
+ const void *key,
208
+ ht_constructor_cb constructor) {
209
+ void *ret = ht_lookup(ht, key);
210
+ if(ret == NULL) {
211
+ ret = constructor(key);
212
+ if(ret != NULL) {
213
+ ht_insert(ht,ret);
214
+ }
215
+ }
216
+ return(ret);
217
+ }
218
+
219
+ typedef struct ht_iterate_pairs_pthread_struct {
220
+ hashtable ht;
221
+ unsigned int nThreads;
222
+ unsigned int chunkSize;
223
+ boolean (*callback)(const void *keyval, const void *keyval2);
224
+ int threadId;
225
+ } ht_iterate_pairs_pthread_struct;
226
+
227
+ static int ht_iterate_pairs_advance(unsigned int * istart,unsigned int *iend,unsigned int *jstart,unsigned int *jend,unsigned int tablesize,unsigned int chunksize);
228
+
229
+ static int ht_iterate_pairs_advance_k(unsigned int * istart, unsigned int *iend, unsigned int *jstart,unsigned int *jend, unsigned int tablesize, unsigned int chunksize,int k)
230
+ {
231
+ int i;
232
+ for(i=0;i<k;i++)
233
+ if( ht_iterate_pairs_advance(istart,iend,jstart,jend,tablesize,chunksize))
234
+ return 1;
235
+ return 0;
236
+ }
237
+ void * ht_iterate_pairs_pthreadstub(void * args )
238
+ //hashtable ht, int nThreads, int chunkSize,
239
+ // boolean (*callback)(const void *keyval, const void *keyval2)) {
240
+ {
241
+
242
+ ht_iterate_pairs_pthread_struct *data = (ht_iterate_pairs_pthread_struct*)args;
243
+ unsigned int i,j;
244
+ unsigned int istart, jstart;
245
+ unsigned int iend,jend;
246
+ hashtable ht;
247
+ boolean (*callback)(const void *keyval, const void *keyval2) = data->callback;
248
+ istart=jstart=0;
249
+ ht = data->ht;
250
+ iend=min(istart+data->chunkSize,ht->table_size);
251
+ jend=min(jstart+data->chunkSize,ht->table_size);
252
+ // fprintf(stderr,"hello from thread %d\n", data->threadId);
253
+ if(!ht_iterate_pairs_advance_k(&istart,&iend,&jstart,&jend,ht->table_size,data->chunkSize,data->threadId)) {
254
+ do {
255
+ assert(istart < iend);
256
+ assert(jstart < jend);
257
+ // fprintf(stderr,"thread %d: i=%d to %d; j=%d to %d\n", data->threadId, istart, iend, jstart, jend);
258
+ for(i=istart; i<iend ; i++) {
259
+ hashentry *he1 = ht->table[i];
260
+ while(he1 ) {
261
+ // fprintf(stderr,"thread %d: i=%d, j=%d to %d\n", data->threadId, i, jstart, min(i,jend));
262
+ for(j=jstart; j<min(i+1,jend) ; j++) {
263
+ hashentry *he2 = (i==j) ? he1->next : ht->table[j];
264
+ while(he2 ) {
265
+ callback(he1->keyval, he2->keyval);
266
+ he2=he2->next;
267
+ }
268
+ }
269
+ he1=he1->next;
270
+ }
271
+ }
272
+ assert(istart < iend);
273
+ assert(jstart < jend);
274
+ } while(!ht_iterate_pairs_advance_k(&istart,&iend,&jstart,&jend,ht->table_size,data->chunkSize,data->nThreads));
275
+ }
276
+ free(args);
277
+ return NULL;
278
+ }
279
+ #ifdef _REENTRANT
280
+
281
+ boolean ht_iterate_pairs(hashtable ht, unsigned int nThreads, unsigned int chunkSize,
282
+ boolean (*callback)(const void *keyval, const void *keyval2)) {
283
+ unsigned int threadId;
284
+ pthread_t * threads;
285
+ void * ignore;
286
+ int err;
287
+
288
+ if(ht == NULL) return FALSE;
289
+ ht_iterate_pairs_pthread_struct * data;
290
+ assert(nThreads<100);
291
+ assert(chunkSize < ht->table_size);
292
+
293
+ threads = malloc(sizeof(pthread_t) * nThreads);
294
+ assert(threads);
295
+ for(threadId=0; threadId<nThreads; threadId++)
296
+ {
297
+ data = (ht_iterate_pairs_pthread_struct * ) malloc(sizeof(ht_iterate_pairs_pthread_struct));
298
+ assert(data);
299
+ data->ht=ht;
300
+ data->nThreads=nThreads;
301
+ data->chunkSize=chunkSize;
302
+ data->callback=callback;
303
+ data->threadId=threadId;
304
+ err = pthread_create(&threads[threadId],NULL,ht_iterate_pairs_pthreadstub,(void *)data);
305
+ assert(!err);
306
+ }
307
+ for(threadId=0; threadId<nThreads; threadId++)
308
+ pthread_join(threads[threadId], &ignore);
309
+
310
+ return TRUE;
311
+ }
312
+
313
+ #else
314
+ boolean ht_iterate_pairs(hashtable ht, unsigned int nThreads, unsigned int chunkSize,
315
+ boolean (*callback)(const void *keyval, const void *keyval2)) {
316
+ unsigned int threadId;
317
+ /* probably should make nThreads be 1 or abort if not 1.... */
318
+ if(ht == NULL) return FALSE;
319
+ ht_iterate_pairs_pthread_struct * data;
320
+ assert(nThreads<100);
321
+ assert(chunkSize < ht->table_size);
322
+
323
+ for(threadId=0; threadId<nThreads; threadId++)
324
+ {
325
+ data = (ht_iterate_pairs_pthread_struct * ) malloc(sizeof(ht_iterate_pairs_pthread_struct));
326
+ assert(data);
327
+ data->ht=ht;
328
+ data->nThreads=nThreads;
329
+ data->chunkSize=chunkSize;
330
+ data->callback=callback;
331
+ data->threadId=threadId;
332
+ ht_iterate_pairs_pthreadstub(data);
333
+ }
334
+ return TRUE;
335
+ }
336
+
337
+ #endif
338
+ static int ht_iterate_pairs_advance(unsigned int * istart,unsigned int *iend,unsigned int *jstart,unsigned int *jend,unsigned int tablesize, unsigned int chunksize)
339
+ {
340
+ *jstart=*jend;
341
+ *jend=min(*jend+chunksize,*iend);
342
+ if( *jstart >= *iend )
343
+ {
344
+ *istart=*iend;
345
+ *iend=min(*iend+chunksize,tablesize);
346
+ *jstart=0;
347
+ *jend=chunksize;
348
+ if(*istart >= tablesize)
349
+ return 1; // done scanning
350
+ }
351
+ assert(*istart < *iend);
352
+ if(! (*jstart < *jend)) {
353
+ fprintf(stderr, "new jstart = %d, jend = %d\n", *jstart, *jend);
354
+ abort();
355
+ }
356
+ return 0;
357
+ }
358
+
359
+
360
+ boolean ht_iterate(hashtable ht,
361
+ boolean (*callback)(const void *keyval, void *user),
362
+ void *user) {
363
+ unsigned int i;
364
+ boolean cont = TRUE;
365
+ if(ht == NULL) return FALSE;
366
+ LOCK;
367
+ for(i=0; i<ht->table_size && cont; i++) {
368
+ hashentry *he = ht->table[i];
369
+ while(he && cont) {
370
+ cont = callback(he->keyval, user);
371
+ he=he->next;
372
+ }
373
+ }
374
+ UNLOCK;
375
+ return cont;
376
+ }
377
+
378
+ boolean ht_iterate_nc(hashtable ht,
379
+ boolean (*callback)(void *keyval, void *user),
380
+ void *user) {
381
+ unsigned int i;
382
+ boolean cont = TRUE;
383
+ if(ht == NULL) return FALSE;
384
+ LOCK;
385
+ for(i=0; i<ht->table_size && cont; i++) {
386
+ hashentry *he = ht->table[i];
387
+ while(he && cont) {
388
+ cont = callback((void *) (he->keyval), user);
389
+ he=he->next;
390
+ }
391
+ }
392
+ UNLOCK;
393
+ return cont;
394
+ }
395
+
396
+ unsigned int ht_delete_if(hashtable ht,
397
+ ht_delete_if_cb callback,
398
+ void *user) {
399
+ unsigned int i;
400
+ unsigned int count = 0;
401
+ if(ht == NULL) return FALSE;
402
+ LOCK;
403
+ for(i=0; i<ht->table_size; i++) {
404
+ hashentry *he = ht->table[i];
405
+ hashentry *prehe = NULL;
406
+ while(he != NULL) {
407
+ if(callback((void *)he->keyval, user)) {
408
+ if(prehe != NULL) {
409
+ prehe->next = he->next;
410
+ free(he); count++;
411
+ he = prehe->next;
412
+ } else {
413
+ ht->table[i] = he->next;
414
+ free(he); count++;
415
+ he = ht->table[i];
416
+ }
417
+ } else {
418
+ prehe = he;
419
+ he=he->next;
420
+ }
421
+ }
422
+ }
423
+ UNLOCK;
424
+ return count;
425
+ }
426
+
427
+
428
+ void ht_occupancyjgr(const hashtable ht, const char *fname) {
429
+ unsigned int i;
430
+ int hist[101];
431
+ FILE *fp;
432
+ fp=fopen(fname,"w");
433
+ if(fp != NULL) {
434
+ memset(hist,0,sizeof(hist));
435
+ for(i=0;i<ht->table_size; i++) {
436
+ const hashentry *he = ht->table[i];
437
+ int c;
438
+ for(c=0; he!= NULL; he=he->next, c++);
439
+ hist[min(c,100)] ++;
440
+ }
441
+ fprintf(fp, "newgraph xaxis label : length of chain\n"
442
+ "yaxis label : number of chains\n"
443
+ "newcurve pts\n");
444
+ for(i=0;i<=100;i++) {
445
+ fprintf(fp, "%u %d\n", i, hist[i]);
446
+ }
447
+ fclose(fp);
448
+ }
449
+ }
450
+
451
+ unsigned int hash_8byte(const void *k) {
452
+ unsigned int a = *(const unsigned int *)k;
453
+ unsigned int b = *(const unsigned int *)k+1;
454
+ return(a*b);
455
+ }
456
+ boolean isequal_8byte(const void *ia, const void *ib) {
457
+ int a = *(int *)ia, b = *(int*)ib;
458
+ int a2 = *((int *)ia+1), b2 = *((int*)ib+1);
459
+ return(a==b && a2==b2);
460
+ }
461
+
462
+ unsigned int hash_k_int(const int *k) {
463
+ return(*k);
464
+ }
465
+ unsigned int hash_int(const void *k) {
466
+ return(hash_k_int((const int *)k));
467
+ }
468
+
469
+ boolean isequal_k_int(const int *a, const int *b) {
470
+ return((*a)==(*b));
471
+ }
472
+
473
+ boolean isequal_int(const void *ia, const void *ib) {
474
+ return(isequal_k_int((const int *)ia, (const int*)ib));
475
+ }
476
+
477
+ unsigned int hash_ushort(const void *k) {
478
+ unsigned short a = *(const unsigned short *)k;
479
+ return(a);
480
+ }
481
+
482
+ boolean isequal_ushort(const void *ia, const void *ib) {
483
+ unsigned short a = *(const unsigned short *)ia;
484
+ unsigned short b = *(const unsigned short *)ib;
485
+ return(a==b);
486
+ }
487
+
488
+ #include <sys/types.h>
489
+ #include <netinet/in.h>
490
+ unsigned int hash_k_saddr(const struct in_addr *k) {
491
+ return(k->s_addr);
492
+ }
493
+ boolean isequal_k_saddr(const struct in_addr *a, const struct in_addr *b) {
494
+ return(a->s_addr==b->s_addr);
495
+ }
496
+
497
+ unsigned int hash_k_uint(const unsigned int *k) {
498
+ return(*k);
499
+ }
500
+ boolean isequal_k_uint(const unsigned int *a, const unsigned int *b) {
501
+ return((*a)==(*b));
502
+ }
503
+
504
+ static boolean counter(const void *v __attribute__ ((unused)),
505
+ void *count) {
506
+ (*(unsigned long *)count)++;
507
+ assert((*(unsigned long *)count) < 200000);
508
+ return TRUE;
509
+ }
510
+ unsigned long ht_count(hashtable ht) {
511
+ unsigned long count=0;
512
+ if(ht!=NULL)
513
+ (void)ht_iterate(ht, counter, &count);
514
+ return count;
515
+ }
516
+
517
+
518
+