]> git.ipfire.org Git - thirdparty/dhcp.git/blame - omapip/hash.c
- Replaced ./configure shellscripting with GNU Autoconf. [ISC-Bugs #16405b]
[thirdparty/dhcp.git] / omapip / hash.c
CommitLineData
d7837182
TL
1/* hash.c
2
3 Routines for manipulating hash tables... */
4
5/*
88cd8aca 6 * Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1995-2003 by Internet Software Consortium
d7837182 8 *
98311e4b
DH
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
d7837182 12 *
98311e4b
DH
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
d7837182 20 *
98311e4b
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
49733f31 26 *
98311e4b 27 * This software has been written for Internet Systems Consortium
49733f31 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 29 * To learn more about Internet Systems Consortium, see
49733f31
TL
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
d7837182
TL
33 */
34
35#ifndef lint
36static char copyright[] =
fe5b0fdd 37"$Id: hash.c,v 1.14 2007/05/19 18:47:15 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
d7837182
TL
38#endif /* not lint */
39
fe5b0fdd
DH
40#include "dhcpd.h"
41
c62871ba 42#include <omapip/omapip_p.h>
fe5b0fdd 43#include <limits.h>
7d9784f6 44#include <ctype.h>
d7837182 45
fe5b0fdd 46static unsigned
f7fdb216
DH
47find_length(const void *key,
48 unsigned (*do_hash)(const void *, unsigned, unsigned))
49{
50 if (do_hash == do_case_hash || do_hash == do_string_hash)
51 return strlen((const char *)key);
52 if (do_hash == do_number_hash)
53 return sizeof(unsigned);
54 if (do_hash == do_ip4_hash)
55 return 4;
56
57 log_fatal("Impossible condition at %s:%d.", MDL);
d19e2cf7 58 return 0; /* Silence compiler warnings. */
f7fdb216 59}
c62871ba 60
98311e4b
DH
61int new_hash_table (tp, count, file, line)
62 struct hash_table **tp;
f7fdb216 63 unsigned count;
c62871ba
DN
64 const char *file;
65 int line;
66{
98311e4b 67 struct hash_table *rval;
272ef1bc 68 unsigned extra;
98311e4b
DH
69
70 if (!tp) {
71 log_error ("%s(%d): new_hash_table called with null pointer.",
72 file, line);
73#if defined (POINTER_DEBUG)
74 abort ();
75#endif
76 return 0;
77 }
78 if (*tp) {
79 log_error ("%s(%d): non-null target for new_hash_table.",
80 file, line);
81#if defined (POINTER_DEBUG)
82 abort ();
83#endif
84 }
272ef1bc
SK
85
86 /* There is one hash bucket in the structure. Allocate extra
87 * memory beyond the end of the structure to fulfill the requested
88 * count ("count - 1"). Do not let there be less than one.
89 */
90 if (count <= 1)
91 extra = 0;
92 else
93 extra = count - 1;
94
95 rval = dmalloc(sizeof(struct hash_table) +
96 (extra * sizeof(struct hash_bucket *)), file, line);
98311e4b
DH
97 if (!rval)
98 return 0;
c62871ba 99 rval -> hash_count = count;
98311e4b
DH
100 *tp = rval;
101 return 1;
c62871ba
DN
102}
103
98311e4b
DH
104void free_hash_table (tp, file, line)
105 struct hash_table **tp;
c62871ba
DN
106 const char *file;
107 int line;
108{
d758ad8c
TL
109 int i;
110 struct hash_bucket *hbc, *hbn = (struct hash_bucket *)0;
98311e4b 111 struct hash_table *ptr = *tp;
d758ad8c
TL
112
113#if defined (DEBUG_MEMORY_LEAKAGE) || \
114 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
115 for (i = 0; i < ptr -> hash_count; i++) {
116 for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
117 hbn = hbc -> next;
118 if (ptr -> dereferencer && hbc -> value)
119 (*ptr -> dereferencer) (&hbc -> value, MDL);
120 }
121 for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) {
122 hbn = hbc -> next;
123 free_hash_bucket (hbc, MDL);
124 }
125 ptr -> buckets [i] = (struct hash_bucket *)0;
126 }
127#endif
128
fe5b0fdd 129 dfree((void *)ptr, MDL);
98311e4b 130 *tp = (struct hash_table *)0;
c62871ba
DN
131}
132
133struct hash_bucket *free_hash_buckets;
134
d758ad8c
TL
135#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
136struct hash_bucket *hash_bucket_hunks;
137
138void relinquish_hash_bucket_hunks ()
139{
140 struct hash_bucket *c, *n, **p;
141
142 /* Account for all the hash buckets on the free list. */
143 p = &free_hash_buckets;
144 for (c = free_hash_buckets; c; c = c -> next) {
145 for (n = hash_bucket_hunks; n; n = n -> next) {
146 if (c > n && c < n + 127) {
147 *p = c -> next;
148 n -> len++;
149 break;
150 }
151 }
152 /* If we didn't delete the hash bucket from the free list,
153 advance the pointer. */
154 if (!n)
155 p = &c -> next;
156 }
157
158 for (c = hash_bucket_hunks; c; c = n) {
159 n = c -> next;
160 if (c -> len != 126) {
161 log_info ("hashbucket %lx hash_buckets %d free %u",
162 (unsigned long)c, 127, c -> len);
163 }
164 dfree (c, MDL);
165 }
166}
167#endif
168
c62871ba
DN
169struct hash_bucket *new_hash_bucket (file, line)
170 const char *file;
171 int line;
172{
173 struct hash_bucket *rval;
d758ad8c 174 int i = 0;
c62871ba
DN
175 if (!free_hash_buckets) {
176 rval = dmalloc (127 * sizeof (struct hash_bucket),
177 file, line);
178 if (!rval)
179 return rval;
d758ad8c
TL
180# if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
181 rval -> next = hash_bucket_hunks;
182 hash_bucket_hunks = rval;
183 hash_bucket_hunks -> len = 0;
184 i++;
185 rval++;
186#endif
187 for (; i < 127; i++) {
c62871ba
DN
188 rval -> next = free_hash_buckets;
189 free_hash_buckets = rval;
190 rval++;
191 }
192 }
193 rval = free_hash_buckets;
194 free_hash_buckets = rval -> next;
195 return rval;
196}
197
198void free_hash_bucket (ptr, file, line)
199 struct hash_bucket *ptr;
200 const char *file;
201 int line;
202{
d758ad8c
TL
203 struct hash_bucket *hp;
204#if defined (DEBUG_MALLOC_POOL)
205 for (hp = free_hash_buckets; hp; hp = hp -> next) {
206 if (hp == ptr) {
207 log_error ("hash bucket freed twice!");
208 abort ();
209 }
210 }
211#endif
c62871ba
DN
212 ptr -> next = free_hash_buckets;
213 free_hash_buckets = ptr;
214}
089fb364 215
f7fdb216
DH
216int new_hash(struct hash_table **rp,
217 hash_reference referencer,
218 hash_dereference dereferencer,
219 unsigned hsize,
220 unsigned (*hasher)(const void *, unsigned, unsigned),
221 const char *file, int line)
d7837182 222{
f7fdb216
DH
223 if (hsize == 0)
224 hsize = DEFAULT_HASH_SIZE;
225
226 if (!new_hash_table (rp, hsize, file, line))
98311e4b 227 return 0;
f7fdb216
DH
228
229 memset ((*rp)->buckets, 0, hsize * sizeof(struct hash_bucket *));
230
231 (*rp)->referencer = referencer;
232 (*rp)->dereferencer = dereferencer;
233 (*rp)->do_hash = hasher;
234
235 if (hasher == do_case_hash)
236 (*rp)->cmp = casecmp;
237 else
238 (*rp)->cmp = memcmp;
239
98311e4b 240 return 1;
d7837182
TL
241}
242
f7fdb216
DH
243unsigned
244do_case_hash(const void *name, unsigned len, unsigned size)
d7837182 245{
f7fdb216
DH
246 register unsigned accum = 0;
247 register const unsigned char *s = name;
d7837182 248 int i = len;
7d9784f6
TL
249 register unsigned c;
250
251 while (i--) {
252 /* Make the hash case-insensitive. */
253 c = *s++;
f7fdb216
DH
254 if (isascii(c))
255 c = tolower(c);
7d9784f6
TL
256
257 /* Add the character in... */
d5ef2946
TL
258 accum = (accum << 1) + c;
259
7d9784f6 260 /* Add carry back in... */
d5ef2946
TL
261 while (accum > 65535) {
262 accum = (accum & 65535) + (accum >> 16);
7d9784f6 263 }
f7fdb216 264
7d9784f6
TL
265 }
266 return accum % size;
267}
268
f7fdb216
DH
269unsigned
270do_string_hash(const void *name, unsigned len, unsigned size)
7d9784f6 271{
f7fdb216 272 register unsigned accum = 0;
7d9784f6
TL
273 register const unsigned char *s = (const unsigned char *)name;
274 int i = len;
275
34bef96b
TL
276 while (i--) {
277 /* Add the character in... */
d5ef2946
TL
278 accum = (accum << 1) + *s++;
279
34bef96b 280 /* Add carry back in... */
d5ef2946
TL
281 while (accum > 65535) {
282 accum = (accum & 65535) + (accum >> 16);
d7837182
TL
283 }
284 }
285 return accum % size;
286}
287
6708d944
DH
288/* Client identifiers are generally 32-bits of ordinary
289 * non-randomness followed by 24-bits of unordinary randomness.
290 * So, end-align in 24-bit chunks, and xor any preceding data
291 * just to mix it up a little.
292 */
293unsigned
294do_id_hash(const void *name, unsigned len, unsigned size)
295{
296 register unsigned accum = 0;
297 register const unsigned char *s = (const unsigned char *)name;
298 const unsigned char *end = s + len;
299
300 if (len == 0)
301 return 0;
302
303 /* The switch indexes our starting position into the do/while loop,
304 * taking up the remainder after hashing in all the other bytes in
305 * threes.
306 */
307 switch (len % 3) {
308 do {
309 case 0:
310 accum ^= *s++ << 16;
311 case 2:
312 accum ^= *s++ << 8;
313 case 1:
314 accum ^= *s++;
315 } while (s < end);
316
317 break;
318 }
319
320 return accum % size;
321}
322
f7fdb216
DH
323unsigned
324do_number_hash(const void *key, unsigned len, unsigned size)
325{
326 register unsigned number = *((const unsigned *)key);
327
328 return number % size;
329}
330
331unsigned
332do_ip4_hash(const void *key, unsigned len, unsigned size)
333{
334 u_int32_t number;
335
336 memcpy(&number, key, 4);
337
338 number = ntohl(number);
339
340 return number % size;
341}
342
6708d944
DH
343unsigned char *
344hash_report(struct hash_table *table)
345{
346 static unsigned char retbuf[sizeof("Contents/Size (%): "
347 "2147483647/2147483647 "
348 "(2147483647%). "
349 "Min/max: 2147483647/2147483647")];
350 unsigned curlen, pct, contents=0, minlen=UINT_MAX, maxlen=0;
351 unsigned i;
352 struct hash_bucket *bp;
353
354 if (table->hash_count == 0)
355 return "Invalid hash table.";
356
357 for (i = 0 ; i < table->hash_count ; i++) {
358 curlen = 0;
359
360 bp = table->buckets[i];
361 while (bp != NULL) {
362 curlen++;
363 bp = bp->next;
364 }
365
366 if (curlen < minlen)
367 minlen = curlen;
368 if (curlen > maxlen)
369 maxlen = curlen;
370
371 contents += curlen;
372 }
373
374 if (contents >= (UINT_MAX / 100))
375 pct = contents / ((table->hash_count / 100) + 1);
376 else
377 pct = (contents * 100) / table->hash_count;
378
379 if (contents > 2147483647 ||
380 table->hash_count > 2147483647 ||
381 pct > 2147483647 ||
382 minlen > 2147483647 ||
383 maxlen > 2147483647)
384 return "Report out of range for display.";
385
386 sprintf(retbuf, "Contents/Size (%%): %u/%u (%u%%). Min/max: %u/%u",
387 contents, table->hash_count, pct, minlen, maxlen);
388
389 return retbuf;
390}
391
f7fdb216 392void add_hash (table, key, len, pointer, file, line)
d7837182 393 struct hash_table *table;
b1b7b521 394 unsigned len;
f7fdb216 395 const void *key;
20916cae
TL
396 hashed_object_t *pointer;
397 const char *file;
398 int line;
d7837182 399{
a0330332
TL
400 int hashno;
401 struct hash_bucket *bp;
0cae26a7 402 void *foo;
a0330332
TL
403
404 if (!table)
405 return;
406
48036271 407 if (!len)
f7fdb216 408 len = find_length(key, table->do_hash);
48036271 409
f7fdb216 410 hashno = (*table->do_hash)(key, len, table->hash_count);
20916cae 411 bp = new_hash_bucket (file, line);
a0330332 412
d7837182 413 if (!bp) {
f7fdb216 414 log_error ("Can't add entry to hash table: no memory.");
d7837182
TL
415 return;
416 }
f7fdb216 417 bp -> name = key;
0cae26a7
TL
418 if (table -> referencer) {
419 foo = &bp -> value;
20916cae 420 (*(table -> referencer)) (foo, pointer, file, line);
0cae26a7
TL
421 } else
422 bp -> value = pointer;
d7837182 423 bp -> next = table -> buckets [hashno];
97ca1699 424 bp -> len = len;
d7837182
TL
425 table -> buckets [hashno] = bp;
426}
427
f7fdb216 428void delete_hash_entry (table, key, len, file, line)
d7837182 429 struct hash_table *table;
b1b7b521 430 unsigned len;
f7fdb216 431 const void *key;
20916cae
TL
432 const char *file;
433 int line;
d7837182 434{
a0330332 435 int hashno;
d7837182 436 struct hash_bucket *bp, *pbp = (struct hash_bucket *)0;
0cae26a7 437 void *foo;
d7837182 438
a0330332
TL
439 if (!table)
440 return;
441
48036271 442 if (!len)
f7fdb216 443 len = find_length(key, table->do_hash);
48036271 444
f7fdb216 445 hashno = (*table->do_hash)(key, len, table->hash_count);
a0330332 446
d7837182
TL
447 /* Go through the list looking for an entry that matches;
448 if we find it, delete it. */
449 for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
69858972 450 if ((!bp -> len &&
f7fdb216 451 !strcmp ((const char *)bp->name, key)) ||
d7837182 452 (bp -> len == len &&
f7fdb216 453 !(table -> cmp)(bp->name, key, len))) {
d7837182
TL
454 if (pbp) {
455 pbp -> next = bp -> next;
456 } else {
457 table -> buckets [hashno] = bp -> next;
458 }
d758ad8c 459 if (bp -> value && table -> dereferencer) {
0cae26a7 460 foo = &bp -> value;
20916cae 461 (*(table -> dereferencer)) (foo, file, line);
0cae26a7 462 }
20916cae 463 free_hash_bucket (bp, file, line);
d7837182
TL
464 break;
465 }
4c4c7907 466 pbp = bp; /* jwg, 9/6/96 - nice catch! */
d7837182
TL
467 }
468}
469
f7fdb216 470int hash_lookup (vp, table, key, len, file, line)
20916cae 471 hashed_object_t **vp;
d7837182 472 struct hash_table *table;
f7fdb216 473 const void *key;
b1b7b521 474 unsigned len;
20916cae
TL
475 const char *file;
476 int line;
d7837182 477{
a0330332 478 int hashno;
d7837182
TL
479 struct hash_bucket *bp;
480
a0330332 481 if (!table)
20916cae 482 return 0;
48036271 483 if (!len)
f7fdb216 484 len = find_length(key, table->do_hash);
48036271 485
272ef1bc
SK
486 if (*vp != NULL) {
487 log_fatal("Internal inconsistency: storage value has not been "
488 "initialized to zero (from %s:%d).", file, line);
489 }
490
f7fdb216 491 hashno = (*table->do_hash)(key, len, table->hash_count);
a0330332 492
48036271
TL
493 for (bp = table -> buckets [hashno]; bp; bp = bp -> next) {
494 if (len == bp -> len
f7fdb216 495 && !(*table->cmp)(bp->name, key, len)) {
20916cae
TL
496 if (table -> referencer)
497 (*table -> referencer) (vp, bp -> value,
498 file, line);
499 else
500 *vp = bp -> value;
501 return 1;
502 }
d7837182 503 }
20916cae 504 return 0;
d7837182
TL
505}
506
d0411fbd
TL
507int hash_foreach (struct hash_table *table, hash_foreach_func func)
508{
509 int i;
510 struct hash_bucket *bp, *next;
511 int count = 0;
512
513 if (!table)
514 return 0;
515
516 for (i = 0; i < table -> hash_count; i++) {
517 bp = table -> buckets [i];
518 while (bp) {
519 next = bp -> next;
06e77c34
DH
520 if ((*func)(bp->name, bp->len, bp->value)
521 != ISC_R_SUCCESS)
522 return count;
d0411fbd
TL
523 bp = next;
524 count++;
525 }
526 }
527 return count;
528}
529
d19e2cf7 530int casecmp (const void *v1, const void *v2, size_t len)
7d9784f6 531{
d19e2cf7 532 size_t i;
7d9784f6
TL
533 const char *s = v1;
534 const char *t = v2;
535
536 for (i = 0; i < len; i++)
537 {
538 int c1, c2;
d19e2cf7
DH
539 if (isascii(s[i]))
540 c1 = tolower(s[i]);
7d9784f6 541 else
d19e2cf7
DH
542 c1 = s[i];
543
544 if (isascii(t[i]))
545 c2 = tolower(t[i]);
7d9784f6 546 else
d19e2cf7
DH
547 c2 = t[i];
548
7d9784f6
TL
549 if (c1 < c2)
550 return -1;
551 if (c1 > c2)
552 return 1;
553 }
554 return 0;
555}