suricata
util-hashlist.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Chained hash table implementation
24  *
25  * The 'Free' pointer can be used to have the API free your
26  * hashed data. If it's NULL it's the callers responsibility
27  */
28 
29 #include "suricata-common.h"
30 #include "util-hashlist.h"
31 #include "util-debug.h"
32 #include "util-memcmp.h"
33 
35  uint32_t (*Hash)(struct HashListTable_ *, void *, uint16_t),
36  char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *))
37 {
38  sc_errno = SC_OK;
39  HashListTable *ht = NULL;
40 
41  if (size == 0) {
43  goto error;
44  }
45 
46  if (Hash == NULL) {
48  goto error;
49  }
50 
51  /* setup the filter */
52  ht = SCCalloc(1, sizeof(HashListTable));
53  if (unlikely(ht == NULL)) {
55  goto error;
56  }
57  ht->array_size = size;
58  ht->Hash = Hash;
59  ht->Free = Free;
60 
61  if (Compare != NULL)
62  ht->Compare = Compare;
63  else
65 
66  /* setup the bitarray */
67  ht->array = SCCalloc(ht->array_size, sizeof(HashListTableBucket *));
68  if (ht->array == NULL) {
70  goto error;
71  }
72 
73  ht->listhead = NULL;
74  ht->listtail = NULL;
75  return ht;
76 
77 error:
78  if (ht != NULL) {
79  if (ht->array != NULL)
80  SCFree(ht->array);
81 
82  SCFree(ht);
83  }
84  return NULL;
85 }
86 
88 {
89  uint32_t i = 0;
90 
91  if (ht == NULL)
92  return;
93 
94  /* free the buckets */
95  for (i = 0; i < ht->array_size; i++) {
96  HashListTableBucket *hashbucket = ht->array[i];
97  while (hashbucket != NULL) {
98  HashListTableBucket *next_hashbucket = hashbucket->bucknext;
99  if (ht->Free != NULL)
100  ht->Free(hashbucket->data);
101  SCFree(hashbucket);
102  hashbucket = next_hashbucket;
103  }
104  }
105 
106  /* free the array */
107  if (ht->array != NULL)
108  SCFree(ht->array);
109 
110  SCFree(ht);
111 }
112 
113 int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
114 {
115  if (ht == NULL || data == NULL)
116  return -1;
117 
118  uint32_t hash = ht->Hash(ht, data, datalen);
119 
120  SCLogDebug("ht %p hash %"PRIu32"", ht, hash);
121 
123  if (unlikely(hb == NULL))
124  goto error;
125  hb->data = data;
126  hb->size = datalen;
127  hb->bucknext = NULL;
128  hb->listnext = NULL;
129  hb->listprev = NULL;
130 
131  if (ht->array[hash] == NULL) {
132  ht->array[hash] = hb;
133  } else {
134  hb->bucknext = ht->array[hash];
135  ht->array[hash] = hb;
136  }
137 
138  if (ht->listtail == NULL) {
139  ht->listhead = hb;
140  ht->listtail = hb;
141  } else {
142  hb->listprev = ht->listtail;
143  ht->listtail->listnext = hb;
144  ht->listtail = hb;
145  }
146 
147  return 0;
148 
149 error:
150  return -1;
151 }
152 
153 int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen)
154 {
155  uint32_t hash = ht->Hash(ht, data, datalen);
156 
157  SCLogDebug("ht %p hash %"PRIu32"", ht, hash);
158 
159  if (ht->array[hash] == NULL) {
160  SCLogDebug("ht->array[hash] NULL");
161  return -1;
162  }
163 
164  /* fast track for just one data part */
165  if (ht->array[hash]->bucknext == NULL) {
166  HashListTableBucket *hb = ht->array[hash];
167 
168  if (ht->Compare(hb->data,hb->size,data,datalen) == 1) {
169  /* remove from the list */
170  if (hb->listprev == NULL) {
171  ht->listhead = hb->listnext;
172  } else {
173  hb->listprev->listnext = hb->listnext;
174  }
175  if (hb->listnext == NULL) {
176  ht->listtail = hb->listprev;
177  } else {
178  hb->listnext->listprev = hb->listprev;
179  }
180 
181  if (ht->Free != NULL)
182  ht->Free(hb->data);
183 
184  SCFree(ht->array[hash]);
185  ht->array[hash] = NULL;
186  return 0;
187  }
188 
189  SCLogDebug("fast track default case");
190  return -1;
191  }
192 
193  /* more data in this bucket */
194  HashListTableBucket *hashbucket = ht->array[hash], *prev_hashbucket = NULL;
195  do {
196  if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1) {
197 
198  /* remove from the list */
199  if (hashbucket->listprev == NULL) {
200  ht->listhead = hashbucket->listnext;
201  } else {
202  hashbucket->listprev->listnext = hashbucket->listnext;
203  }
204  if (hashbucket->listnext == NULL) {
205  ht->listtail = hashbucket->listprev;
206  } else {
207  hashbucket->listnext->listprev = hashbucket->listprev;
208  }
209 
210  if (prev_hashbucket == NULL) {
211  /* root bucket */
212  ht->array[hash] = hashbucket->bucknext;
213  } else {
214  /* child bucket */
215  prev_hashbucket->bucknext = hashbucket->bucknext;
216  }
217 
218  /* remove this */
219  if (ht->Free != NULL)
220  ht->Free(hashbucket->data);
221  SCFree(hashbucket);
222  return 0;
223  }
224 
225  prev_hashbucket = hashbucket;
226  hashbucket = hashbucket->bucknext;
227  } while (hashbucket != NULL);
228 
229  SCLogDebug("slow track default case");
230  return -1;
231 }
232 
233 char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2)
234 {
235  if (len1 != len2)
236  return 0;
237 
238  if (SCMemcmp(data1,data2,len1) != 0)
239  return 0;
240 
241  return 1;
242 }
243 
244 void *HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
245 {
246 
247  if (ht == NULL) {
248  SCLogDebug("Hash List table is NULL");
249  return NULL;
250  }
251 
252  uint32_t hash = ht->Hash(ht, data, datalen);
253 
254  if (ht->array[hash] == NULL) {
255  return NULL;
256  }
257 
258  HashListTableBucket *hashbucket = ht->array[hash];
259  do {
260  if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1)
261  return hashbucket->data;
262 
263  hashbucket = hashbucket->bucknext;
264  } while (hashbucket != NULL);
265 
266  return NULL;
267 }
268 
269 uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen)
270 {
271  uint8_t *d = (uint8_t *)data;
272  uint32_t i;
273  uint32_t hash = 0;
274 
275  for (i = 0; i < datalen; i++) {
276  if (i == 0) hash += (((uint32_t)*d++));
277  else if (i == 1) hash += (((uint32_t)*d++) * datalen);
278  else hash *= (((uint32_t)*d++) * i) + datalen + i;
279  }
280 
281  hash *= datalen;
282  hash %= ht->array_size;
283  return hash;
284 }
285 
287 {
288  return ht->listhead;
289 }
290 
291 /*
292  * ONLY TESTS BELOW THIS COMMENT
293  */
294 
295 #ifdef UNITTESTS
296 static int HashListTableTestInit01 (void)
297 {
299  if (ht == NULL)
300  return 0;
301 
302  HashListTableFree(ht);
303  return 1;
304 }
305 
306 /* no hash function, so it should fail */
307 static int HashListTableTestInit02 (void)
308 {
309  HashListTable *ht = HashListTableInit(1024, NULL, NULL, NULL);
310  if (ht == NULL)
311  return 1;
312 
313  HashListTableFree(ht);
314  return 0;
315 }
316 
317 static int HashListTableTestInit03 (void)
318 {
319  int result = 0;
321  if (ht == NULL)
322  return 0;
323 
324  if (ht->Hash == HashListTableGenericHash)
325  result = 1;
326 
327  HashListTableFree(ht);
328  return result;
329 }
330 
331 static int HashListTableTestInit04 (void)
332 {
334  if (ht == NULL)
335  return 1;
336 
337  HashListTableFree(ht);
338  return 0;
339 }
340 
341 static int HashListTableTestAdd01 (void)
342 {
343  int result = 0;
345  if (ht == NULL)
346  goto end;
347 
348  int r = HashListTableAdd(ht, (char *)"test", 0);
349  if (r != 0)
350  goto end;
351 
352  /* all is good! */
353  result = 1;
354 end:
355  if (ht != NULL) HashListTableFree(ht);
356  return result;
357 }
358 
359 static int HashListTableTestAdd02 (void)
360 {
361  int result = 0;
363  if (ht == NULL)
364  goto end;
365 
366  int r = HashListTableAdd(ht, NULL, 4);
367  if (r == 0)
368  goto end;
369 
370  /* all is good! */
371  result = 1;
372 end:
373  if (ht != NULL) HashListTableFree(ht);
374  return result;
375 }
376 
377 static int HashListTableTestAdd03 (void)
378 {
379  int result = 0;
381  if (ht == NULL)
382  goto end;
383 
384  int r = HashListTableAdd(ht, (char *)"test", 0);
385  if (r != 0)
386  goto end;
387 
388  if (ht->listhead == NULL) {
389  printf("ht->listhead == NULL: ");
390  goto end;
391  }
392 
393  if (ht->listtail == NULL) {
394  printf("ht->listtail == NULL: ");
395  goto end;
396  }
397 
398  /* all is good! */
399  result = 1;
400 end:
401  if (ht != NULL) HashListTableFree(ht);
402  return result;
403 }
404 
405 static int HashListTableTestAdd04 (void)
406 {
407  int result = 0;
409  if (ht == NULL)
410  goto end;
411 
412  int r = HashListTableAdd(ht, (char *)"test", 4);
413  if (r != 0)
414  goto end;
415 
416  char *rp = HashListTableLookup(ht, (char *)"test", 4);
417  if (rp == NULL)
418  goto end;
419 
421  if (htb == NULL) {
422  printf("htb == NULL: ");
423  goto end;
424  }
425 
426  char *rp2 = HashListTableGetListData(htb);
427  if (rp2 == NULL) {
428  printf("rp2 == NULL: ");
429  goto end;
430  }
431 
432  if (rp != rp2) {
433  printf("rp != rp2: ");
434  goto end;
435  }
436 
437  /* all is good! */
438  result = 1;
439 end:
440  if (ht != NULL) HashListTableFree(ht);
441  return result;
442 }
443 
444 static int HashListTableTestFull01 (void)
445 {
446  int result = 0;
448  if (ht == NULL)
449  goto end;
450 
451  int r = HashListTableAdd(ht, (char *)"test", 4);
452  if (r != 0)
453  goto end;
454 
455  char *rp = HashListTableLookup(ht, (char *)"test", 4);
456  if (rp == NULL)
457  goto end;
458 
459  r = HashListTableRemove(ht, (char *)"test", 4);
460  if (r != 0)
461  goto end;
462 
463  /* all is good! */
464  result = 1;
465 end:
466  if (ht != NULL) HashListTableFree(ht);
467  return result;
468 }
469 
470 static int HashListTableTestFull02 (void)
471 {
472  int result = 0;
474  if (ht == NULL)
475  goto end;
476 
477  int r = HashListTableAdd(ht, (char *)"test", 4);
478  if (r != 0)
479  goto end;
480 
481  char *rp = HashListTableLookup(ht, (char *)"test", 4);
482  if (rp == NULL)
483  goto end;
484 
485  r = HashListTableRemove(ht, (char *)"test2", 5);
486  if (r == 0)
487  goto end;
488 
489  /* all is good! */
490  result = 1;
491 end:
492  if (ht != NULL) HashListTableFree(ht);
493  return result;
494 }
495 #endif /* UNITTESTS */
496 
498 {
499 #ifdef UNITTESTS
500  UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01);
501  UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02);
502  UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03);
503  UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04);
504 
505  UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01);
506  UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02);
507  UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03);
508  UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04);
509 
510  UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01);
511  UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02);
512 #endif /* UNITTESTS */
513 }
514 
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:56
util-hashlist.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:101
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SC_EINVAL
@ SC_EINVAL
Definition: util-error.h:30
HashListTable_::Free
void(* Free)(void *)
Definition: util-hashlist.h:44
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:286
HashListTableBucket_::size
uint16_t size
Definition: util-hashlist.h:30
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:244
HashListTableBucket_::listprev
struct HashListTableBucket_ * listprev
Definition: util-hashlist.h:33
SC_ENOMEM
@ SC_ENOMEM
Definition: util-error.h:29
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:113
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
util-memcmp.h
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:34
util-debug.h
HashTable_::Compare
char(* Compare)(void *, uint16_t, void *, uint16_t)
Definition: util-hash.h:43
HashListTableDefaultCompare
char HashListTableDefaultCompare(void *data1, uint16_t len1, void *data2, uint16_t len2)
Definition: util-hashlist.c:233
HashListTableGenericHash
uint32_t HashListTableGenericHash(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:269
HashListTable_::Compare
char(* Compare)(void *, uint16_t, void *, uint16_t)
Definition: util-hashlist.h:43
HashListTable_::Hash
uint32_t(* Hash)(struct HashListTable_ *, void *, uint16_t)
Definition: util-hashlist.h:42
SC_OK
@ SC_OK
Definition: util-error.h:27
HashListTable_::listtail
HashListTableBucket * listtail
Definition: util-hashlist.h:40
HashListTable_
Definition: util-hashlist.h:37
HashListTable_::listhead
HashListTableBucket * listhead
Definition: util-hashlist.h:39
HashListTable_::array
HashListTableBucket ** array
Definition: util-hashlist.h:38
suricata-common.h
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:87
HashListTableBucket_::listnext
struct HashListTableBucket_ * listnext
Definition: util-hashlist.h:32
SCFree
#define SCFree(p)
Definition: util-mem.h:61
HashListTableRegisterTests
void HashListTableRegisterTests(void)
Definition: util-hashlist.c:497
HashListTableBucket_::data
void * data
Definition: util-hashlist.h:29
HashListTableBucket_
Definition: util-hashlist.h:28
HashListTableRemove
int HashListTableRemove(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:153
sc_errno
thread_local SCError sc_errno
Definition: util-error.c:31
HashListTableBucket_::bucknext
struct HashListTableBucket_ * bucknext
Definition: util-hashlist.h:31
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:289
HashTable_::Free
void(* Free)(void *)
Definition: util-hash.h:44
HashTable_::Hash
uint32_t(* Hash)(struct HashTable_ *, void *, uint16_t)
Definition: util-hash.h:42