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