suricata
util-thash.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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  */
24 
25 #include "suricata-common.h"
26 #include "conf.h"
27 
28 #include "util-debug.h"
29 #include "util-thash.h"
30 
31 #include "util-random.h"
32 #include "util-misc.h"
33 #include "util-byte.h"
34 
35 #include "util-hash-lookup3.h"
36 
37 static THashData *THashGetUsed(THashTableContext *ctx);
38 static void THashDataEnqueue (THashDataQueue *q, THashData *h);
39 
40 static void THashDataMoveToSpare(THashTableContext *ctx, THashData *h)
41 {
42  THashDataEnqueue(&ctx->spare_q, h);
43  (void) SC_ATOMIC_SUB(ctx->counter, 1);
44 }
45 
46 static THashDataQueue *THashDataQueueInit (THashDataQueue *q)
47 {
48  if (q != NULL) {
49  memset(q, 0, sizeof(THashDataQueue));
50  HQLOCK_INIT(q);
51  }
52  return q;
53 }
54 
56 {
58  if (q == NULL) {
59  SCLogError(SC_ERR_FATAL, "Fatal error encountered in THashDataQueueNew. Exiting...");
60  exit(EXIT_SUCCESS);
61  }
62  q = THashDataQueueInit(q);
63  return q;
64 }
65 
66 /**
67  * \brief Destroy a queue
68  *
69  * \param q the queue to destroy
70  */
71 static void THashDataQueueDestroy (THashDataQueue *q)
72 {
73  HQLOCK_DESTROY(q);
74 }
75 
76 /**
77  * \brief add to queue
78  *
79  * \param q queue
80  * \param h data
81  */
82 static void THashDataEnqueue (THashDataQueue *q, THashData *h)
83 {
84 #ifdef DEBUG
85  BUG_ON(q == NULL || h == NULL);
86 #endif
87 
88  HQLOCK_LOCK(q);
89 
90  /* more data in queue */
91  if (q->top != NULL) {
92  h->next = q->top;
93  q->top->prev = h;
94  q->top = h;
95  /* only data */
96  } else {
97  q->top = h;
98  q->bot = h;
99  }
100  q->len++;
101 #ifdef DBG_PERF
102  if (q->len > q->dbg_maxlen)
103  q->dbg_maxlen = q->len;
104 #endif /* DBG_PERF */
105  HQLOCK_UNLOCK(q);
106 }
107 
108 /**
109  * \brief remove data from the queue
110  *
111  * \param q queue
112  *
113  * \retval h data or NULL if empty list.
114  */
115 static THashData *THashDataDequeue (THashDataQueue *q)
116 {
117  HQLOCK_LOCK(q);
118 
119  THashData *h = q->bot;
120  if (h == NULL) {
121  HQLOCK_UNLOCK(q);
122  return NULL;
123  }
124 
125  /* more packets in queue */
126  if (q->bot->prev != NULL) {
127  q->bot = q->bot->prev;
128  q->bot->next = NULL;
129  /* just the one we remove, so now empty */
130  } else {
131  q->top = NULL;
132  q->bot = NULL;
133  }
134 
135 #ifdef DEBUG
136  BUG_ON(q->len == 0);
137 #endif
138  if (q->len > 0)
139  q->len--;
140 
141  h->next = NULL;
142  h->prev = NULL;
143 
144  HQLOCK_UNLOCK(q);
145  return h;
146 }
147 
148 #if 0
149 static uint32_t THashDataQueueLen(THashDataQueue *q)
150 {
151  uint32_t len;
152  HQLOCK_LOCK(q);
153  len = q->len;
154  HQLOCK_UNLOCK(q);
155  return len;
156 }
157 #endif
158 
159 static THashData *THashDataAlloc(THashTableContext *ctx)
160 {
161  const size_t data_size = THASH_DATA_SIZE(ctx);
162 
163  if (!(THASH_CHECK_MEMCAP(ctx, data_size))) {
164  return NULL;
165  }
166 
167  (void) SC_ATOMIC_ADD(ctx->memuse, data_size);
168 
169  THashData *h = SCCalloc(1, data_size);
170  if (unlikely(h == NULL))
171  goto error;
172 
173  /* points to data right after THashData block */
174  h->data = (uint8_t *)h + sizeof(THashData);
175 
176 // memset(h, 0x00, data_size);
177 
178  SCMutexInit(&h->m, NULL);
179  SC_ATOMIC_INIT(h->use_cnt);
180  return h;
181 
182 error:
183  return NULL;
184 }
185 
186 static void THashDataFree(THashTableContext *ctx, THashData *h)
187 {
188  if (h != NULL) {
189  if (h->data != NULL) {
190  ctx->config.DataFree(h->data);
191  }
192  SCMutexDestroy(&h->m);
193  SCFree(h);
194  (void) SC_ATOMIC_SUB(ctx->memuse, THASH_DATA_SIZE(ctx));
195  }
196 }
197 
198 #define THASH_DEFAULT_HASHSIZE 4096
199 #define THASH_DEFAULT_MEMCAP 16777216
200 #define THASH_DEFAULT_PREALLOC 1000
201 
202 #define GET_VAR(prefix,name) \
203  snprintf(varname, sizeof(varname), "%s.%s", (prefix), (name))
204 
205 /** \brief initialize the configuration
206  * \warning Not thread safe */
207 static int THashInitConfig(THashTableContext *ctx, const char *cnf_prefix)
208 {
209  char varname[256];
210 
211  SCLogDebug("initializing thash engine...");
212 
213  /* Check if we have memcap and hash_size defined at config */
214  const char *conf_val;
215  uint32_t configval = 0;
216 
217  /** set config values for memcap, prealloc and hash_size */
218  GET_VAR(cnf_prefix, "memcap");
219  if ((ConfGet(varname, &conf_val)) == 1)
220  {
221  if (ParseSizeStringU64(conf_val, &ctx->config.memcap) < 0) {
222  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing %s "
223  "from conf file - %s. Killing engine",
224  varname, conf_val);
225  return -1;
226  }
227  }
228  GET_VAR(cnf_prefix, "hash-size");
229  if ((ConfGet(varname, &conf_val)) == 1)
230  {
231  if (StringParseUint32(&configval, 10, strlen(conf_val),
232  conf_val) > 0) {
233  ctx->config.hash_size = configval;
234  }
235  }
236 
237  GET_VAR(cnf_prefix, "prealloc");
238  if ((ConfGet(varname, &conf_val)) == 1)
239  {
240  if (StringParseUint32(&configval, 10, strlen(conf_val),
241  conf_val) > 0) {
242  ctx->config.prealloc = configval;
243  } else {
244  WarnInvalidConfEntry(varname, "%"PRIu32, ctx->config.prealloc);
245  }
246  }
247 
248  /* alloc hash memory */
249  uint64_t hash_size = ctx->config.hash_size * sizeof(THashHashRow);
250  if (!(THASH_CHECK_MEMCAP(ctx, hash_size))) {
251  SCLogError(SC_ERR_THASH_INIT, "allocating hash failed: "
252  "max hash memcap is smaller than projected hash size. "
253  "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
254  "total hash size by multiplying \"hash-size\" with %"PRIuMAX", "
255  "which is the hash bucket size.", ctx->config.memcap, hash_size,
256  (uintmax_t)sizeof(THashHashRow));
257  return -1;
258  }
259  ctx->array = SCMallocAligned(ctx->config.hash_size * sizeof(THashHashRow), CLS);
260  if (unlikely(ctx->array == NULL)) {
261  SCLogError(SC_ERR_THASH_INIT, "Fatal error encountered in THashInitConfig. Exiting...");
262  return -1;
263  }
264  memset(ctx->array, 0, ctx->config.hash_size * sizeof(THashHashRow));
265 
266  uint32_t i = 0;
267  for (i = 0; i < ctx->config.hash_size; i++) {
268  HRLOCK_INIT(&ctx->array[i]);
269  }
270  (void) SC_ATOMIC_ADD(ctx->memuse, (ctx->config.hash_size * sizeof(THashHashRow)));
271 
272  /* pre allocate prealloc */
273  for (i = 0; i < ctx->config.prealloc; i++) {
274  if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) {
275  SCLogError(SC_ERR_THASH_INIT, "preallocating data failed: "
276  "max thash memcap reached. Memcap %"PRIu64", "
277  "Memuse %"PRIu64".", ctx->config.memcap,
278  ((uint64_t)SC_ATOMIC_GET(ctx->memuse) + THASH_DATA_SIZE(ctx)));
279  return -1;
280  }
281 
282  THashData *h = THashDataAlloc(ctx);
283  if (h == NULL) {
284  SCLogError(SC_ERR_THASH_INIT, "preallocating data failed: %s", strerror(errno));
285  return -1;
286  }
287  THashDataEnqueue(&ctx->spare_q,h);
288  }
289 
290  return 0;
291 }
292 
293 THashTableContext *THashInit(const char *cnf_prefix, size_t data_size,
294  int (*DataSet)(void *, void *), void (*DataFree)(void *), uint32_t (*DataHash)(void *),
295  bool (*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
296 {
297  THashTableContext *ctx = SCCalloc(1, sizeof(*ctx));
298  BUG_ON(!ctx);
299 
300  ctx->config.data_size = data_size;
301  ctx->config.DataSet = DataSet;
302  ctx->config.DataFree = DataFree;
303  ctx->config.DataHash = DataHash;
304  ctx->config.DataCompare = DataCompare;
305 
306  /* set defaults */
307  ctx->config.hash_rand = (uint32_t)RandomGet();
309  /* Reset memcap in case of loading from file to the highest possible value
310  unless defined by the rule keyword */
311  if (memcap > 0) {
312  ctx->config.memcap = memcap;
313  } else {
314 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
315  // limit hash size to default when fuzzing
317 #else
318  ctx->config.memcap = reset_memcap ? UINT64_MAX : THASH_DEFAULT_MEMCAP;
319 #endif
320  }
322 
323  SC_ATOMIC_INIT(ctx->counter);
324  SC_ATOMIC_INIT(ctx->memuse);
325  SC_ATOMIC_INIT(ctx->prune_idx);
326  THashDataQueueInit(&ctx->spare_q);
327 
328  if (THashInitConfig(ctx, cnf_prefix) < 0) {
329  THashShutdown(ctx);
330  ctx = NULL;
331  }
332  return ctx;
333 }
334 
335 /* \brief Set memcap to current memuse
336  * */
338 {
339  ctx->config.memcap = MAX(SC_ATOMIC_GET(ctx->memuse), THASH_DEFAULT_MEMCAP);
340  SCLogDebug("memcap after load set to: %" PRIu64, ctx->config.memcap);
341 }
342 
343 /** \brief shutdown the flow engine
344  * \warning Not thread safe */
346 {
347  THashData *h;
348  uint32_t u;
349 
350  /* free spare queue */
351  while ((h = THashDataDequeue(&ctx->spare_q))) {
352  BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0);
353  THashDataFree(ctx, h);
354  }
355 
356  /* clear and free the hash */
357  if (ctx->array != NULL) {
358  for (u = 0; u < ctx->config.hash_size; u++) {
359  h = ctx->array[u].head;
360  while (h) {
361  THashData *n = h->next;
362  THashDataFree(ctx, h);
363  h = n;
364  }
365 
366  HRLOCK_DESTROY(&ctx->array[u]);
367  }
368  SCFreeAligned(ctx->array);
369  ctx->array = NULL;
370  }
371  (void) SC_ATOMIC_SUB(ctx->memuse, ctx->config.hash_size * sizeof(THashHashRow));
372  THashDataQueueDestroy(&ctx->spare_q);
373  SCFree(ctx);
374  return;
375 }
376 
377 /** \brief Walk the hash
378  *
379  */
380 int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, void *output_ctx)
381 {
382  uint32_t u;
383 
384  if (ctx->array == NULL)
385  return -1;
386 
387  bool err = false;
388  for (u = 0; u < ctx->config.hash_size; u++) {
389  THashHashRow *hb = &ctx->array[u];
390  HRLOCK_LOCK(hb);
391  THashData *h = hb->head;
392  while (h) {
393  char output_string[1024] = "";
394  int size = FormatterFunc(h->data, output_string, sizeof(output_string));
395  if (size > 0) {
396  if (OutputterFunc(output_ctx, (const uint8_t *)output_string, size) < 0) {
397  err = true;
398  break;
399  }
400  }
401  h = h->next;
402  }
403  HRLOCK_UNLOCK(hb);
404  if (err == true)
405  return -1;
406  }
407  return 0;
408 }
409 
410 /** \brief Cleanup the thash engine
411  *
412  * Cleanup the thash engine from tag and threshold.
413  *
414  */
416 {
417  uint32_t u;
418 
419  if (ctx->array == NULL)
420  return;
421 
422  for (u = 0; u < ctx->config.hash_size; u++) {
423  THashHashRow *hb = &ctx->array[u];
424  HRLOCK_LOCK(hb);
425  THashData *h = hb->head;
426  while (h) {
427  if ((SC_ATOMIC_GET(h->use_cnt) > 0)) {
428  h = h->next;
429  } else {
430  THashData *n = h->next;
431  /* remove from the hash */
432  if (h->prev != NULL)
433  h->prev->next = h->next;
434  if (h->next != NULL)
435  h->next->prev = h->prev;
436  if (hb->head == h)
437  hb->head = h->next;
438  if (hb->tail == h)
439  hb->tail = h->prev;
440  h->next = NULL;
441  h->prev = NULL;
442  THashDataMoveToSpare(ctx, h);
443  h = n;
444  }
445  }
446  HRLOCK_UNLOCK(hb);
447  }
448  return;
449 }
450 
451 /* calculate the hash key for this packet
452  *
453  * we're using:
454  * hash_rand -- set at init time
455  * source address
456  */
457 static uint32_t THashGetKey(const THashConfig *cnf, void *data)
458 {
459  uint32_t key;
460 
461  key = cnf->DataHash(data);
462  key %= cnf->hash_size;
463 
464  return key;
465 }
466 
467 static inline int THashCompare(const THashConfig *cnf, void *a, void *b)
468 {
469  if (cnf->DataCompare(a, b) == TRUE)
470  return 1;
471  return 0;
472 }
473 
474 /**
475  * \brief Get new data
476  *
477  * Get new data. We're checking memcap first and will try to make room
478  * if the memcap is reached.
479  *
480  * \retval h *LOCKED* data on succes, NULL on error.
481  */
482 static THashData *THashDataGetNew(THashTableContext *ctx, void *data)
483 {
484  THashData *h = NULL;
485 
486  /* get data from the spare queue */
487  h = THashDataDequeue(&ctx->spare_q);
488  if (h == NULL) {
489  /* If we reached the max memcap, we get used data */
490  if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) {
491  h = THashGetUsed(ctx);
492  if (h == NULL) {
493  return NULL;
494  }
495 
496  if (!SC_ATOMIC_GET(ctx->memcap_reached)) {
497  SC_ATOMIC_SET(ctx->memcap_reached, true);
498  }
499 
500  /* freed data, but it's unlocked */
501  } else {
502  /* now see if we can alloc a new data */
503  h = THashDataAlloc(ctx);
504  if (h == NULL) {
505  return NULL;
506  }
507 
508  /* data is initialized but *unlocked* */
509  }
510  } else {
511  /* data has been recycled before it went into the spare queue */
512 
513  /* data is initialized (recylced) but *unlocked* */
514  }
515 
516  // setup the data
517  BUG_ON(ctx->config.DataSet(h->data, data) != 0);
518 
519  (void) SC_ATOMIC_ADD(ctx->counter, 1);
520  SCMutexLock(&h->m);
521  return h;
522 }
523 
524 /*
525  * returns a *LOCKED* data or NULL
526  */
527 
528 struct THashDataGetResult
530 {
531  struct THashDataGetResult res = { .data = NULL, .is_new = false, };
532  THashData *h = NULL;
533 
534  /* get the key to our bucket */
535  uint32_t key = THashGetKey(&ctx->config, data);
536  /* get our hash bucket and lock it */
537  THashHashRow *hb = &ctx->array[key];
538  HRLOCK_LOCK(hb);
539 
540  /* see if the bucket already has data */
541  if (hb->head == NULL) {
542  h = THashDataGetNew(ctx, data);
543  if (h == NULL) {
544  HRLOCK_UNLOCK(hb);
545  return res;
546  }
547 
548  /* data is locked */
549  hb->head = h;
550  hb->tail = h;
551 
552  /* initialize and return */
553  (void) THashIncrUsecnt(h);
554 
555  HRLOCK_UNLOCK(hb);
556  res.data = h;
557  res.is_new = true;
558  return res;
559  }
560 
561  /* ok, we have data in the bucket. Let's find out if it is our data */
562  h = hb->head;
563 
564  /* see if this is the data we are looking for */
565  if (THashCompare(&ctx->config, h->data, data) == 0) {
566  THashData *ph = NULL; /* previous data */
567 
568  while (h) {
569  ph = h;
570  h = h->next;
571 
572  if (h == NULL) {
573  h = ph->next = THashDataGetNew(ctx, data);
574  if (h == NULL) {
575  HRLOCK_UNLOCK(hb);
576  return res;
577  }
578  hb->tail = h;
579 
580  /* data is locked */
581 
582  h->prev = ph;
583 
584  /* initialize and return */
585  (void) THashIncrUsecnt(h);
586 
587  HRLOCK_UNLOCK(hb);
588  res.data = h;
589  res.is_new = true;
590  return res;
591  }
592 
593  if (THashCompare(&ctx->config, h->data, data) != 0) {
594  /* we found our data, lets put it on top of the
595  * hash list -- this rewards active data */
596  if (h->next) {
597  h->next->prev = h->prev;
598  }
599  if (h->prev) {
600  h->prev->next = h->next;
601  }
602  if (h == hb->tail) {
603  hb->tail = h->prev;
604  }
605 
606  h->next = hb->head;
607  h->prev = NULL;
608  hb->head->prev = h;
609  hb->head = h;
610 
611  /* found our data, lock & return */
612  SCMutexLock(&h->m);
613  (void) THashIncrUsecnt(h);
614  HRLOCK_UNLOCK(hb);
615  res.data = h;
616  res.is_new = false;
617  /* coverity[missing_unlock : FALSE] */
618  return res;
619  }
620  }
621  }
622 
623  /* lock & return */
624  SCMutexLock(&h->m);
625  (void) THashIncrUsecnt(h);
626  HRLOCK_UNLOCK(hb);
627  res.data = h;
628  res.is_new = false;
629  /* coverity[missing_unlock : FALSE] */
630  return res;
631 }
632 
633 /** \brief look up data in the hash
634  *
635  * \param data data to look up
636  *
637  * \retval h *LOCKED* data or NULL
638  */
640 {
641  THashData *h = NULL;
642 
643  /* get the key to our bucket */
644  uint32_t key = THashGetKey(&ctx->config, data);
645  /* get our hash bucket and lock it */
646  THashHashRow *hb = &ctx->array[key];
647  HRLOCK_LOCK(hb);
648 
649  if (hb->head == NULL) {
650  HRLOCK_UNLOCK(hb);
651  return h;
652  }
653 
654  /* ok, we have data in the bucket. Let's find out if it is our data */
655  h = hb->head;
656 
657  /* see if this is the data we are looking for */
658  if (THashCompare(&ctx->config, h->data, data) == 0) {
659  while (h) {
660  h = h->next;
661  if (h == NULL) {
662  HRLOCK_UNLOCK(hb);
663  return h;
664  }
665 
666  if (THashCompare(&ctx->config, h->data, data) != 0) {
667  /* we found our data, lets put it on top of the
668  * hash list -- this rewards active data */
669  if (h->next) {
670  h->next->prev = h->prev;
671  }
672  if (h->prev) {
673  h->prev->next = h->next;
674  }
675  if (h == hb->tail) {
676  hb->tail = h->prev;
677  }
678 
679  h->next = hb->head;
680  h->prev = NULL;
681  hb->head->prev = h;
682  hb->head = h;
683 
684  /* found our data, lock & return */
685  SCMutexLock(&h->m);
686  (void) THashIncrUsecnt(h);
687  HRLOCK_UNLOCK(hb);
688  return h;
689  }
690  }
691  }
692 
693  /* lock & return */
694  SCMutexLock(&h->m);
695  (void) THashIncrUsecnt(h);
696  HRLOCK_UNLOCK(hb);
697  return h;
698 }
699 
700 /** \internal
701  * \brief Get data from the hash directly.
702  *
703  * Called in conditions where the spare queue is empty and memcap is
704  * reached.
705  *
706  * Walks the hash until data can be freed. "prune_idx" atomic int makes
707  * sure we don't start at the top each time since that would clear the top
708  * of the hash leading to longer and longer search times under high
709  * pressure (observed).
710  *
711  * \retval h data or NULL
712  */
713 static THashData *THashGetUsed(THashTableContext *ctx)
714 {
715  uint32_t idx = SC_ATOMIC_GET(ctx->prune_idx) % ctx->config.hash_size;
716  uint32_t cnt = ctx->config.hash_size;
717 
718  while (cnt--) {
719  if (++idx >= ctx->config.hash_size)
720  idx = 0;
721 
722  THashHashRow *hb = &ctx->array[idx];
723 
724  if (HRLOCK_TRYLOCK(hb) != 0)
725  continue;
726 
727  THashData *h = hb->tail;
728  if (h == NULL) {
729  HRLOCK_UNLOCK(hb);
730  continue;
731  }
732 
733  if (SCMutexTrylock(&h->m) != 0) {
734  HRLOCK_UNLOCK(hb);
735  continue;
736  }
737 
738  if (SC_ATOMIC_GET(h->use_cnt) > 0) {
739  HRLOCK_UNLOCK(hb);
740  SCMutexUnlock(&h->m);
741  continue;
742  }
743 
744  /* remove from the hash */
745  if (h->prev != NULL)
746  h->prev->next = h->next;
747  if (h->next != NULL)
748  h->next->prev = h->prev;
749  if (hb->head == h)
750  hb->head = h->next;
751  if (hb->tail == h)
752  hb->tail = h->prev;
753 
754  h->next = NULL;
755  h->prev = NULL;
756  HRLOCK_UNLOCK(hb);
757 
758  if (h->data != NULL) {
759  ctx->config.DataFree(h->data);
760  }
761  SCMutexUnlock(&h->m);
762 
763  (void) SC_ATOMIC_ADD(ctx->prune_idx, (ctx->config.hash_size - cnt));
764  return h;
765  }
766 
767  return NULL;
768 }
769 
770 /**
771  * \retval int -1 not found
772  * \retval int 0 found, but it was busy (ref cnt)
773  * \retval int 1 found and removed */
775 {
776  /* get the key to our bucket */
777  uint32_t key = THashGetKey(&ctx->config, data);
778  /* get our hash bucket and lock it */
779  THashHashRow *hb = &ctx->array[key];
780 
781  HRLOCK_LOCK(hb);
782  THashData *h = hb->head;
783  while (h != NULL) {
784  /* see if this is the data we are looking for */
785  if (THashCompare(&ctx->config, h->data, data) == 0) {
786  h = h->next;
787  continue;
788  }
789 
790  SCMutexLock(&h->m);
791  if (SC_ATOMIC_GET(h->use_cnt) > 0) {
792  SCMutexUnlock(&h->m);
793  HRLOCK_UNLOCK(hb);
794  return 0;
795  }
796 
797  /* remove from the hash */
798  if (h->prev != NULL)
799  h->prev->next = h->next;
800  if (h->next != NULL)
801  h->next->prev = h->prev;
802  if (hb->head == h)
803  hb->head = h->next;
804  if (hb->tail == h)
805  hb->tail = h->prev;
806 
807  h->next = NULL;
808  h->prev = NULL;
809  SCMutexUnlock(&h->m);
810  HRLOCK_UNLOCK(hb);
811  THashDataFree(ctx, h);
812  SCLogDebug("found and removed");
813  return 1;
814  }
815 
816  HRLOCK_UNLOCK(hb);
817  SCLogDebug("data not found");
818  return -1;
819 }
HRLOCK_DESTROY
#define HRLOCK_DESTROY(fb)
Definition: host.h:50
util-byte.h
HQLOCK_LOCK
#define HQLOCK_LOCK(q)
Definition: host-queue.h:67
len
uint8_t len
Definition: app-layer-dnp3.h:2
THashCleanup
void THashCleanup(THashTableContext *ctx)
Cleanup the thash engine.
Definition: util-thash.c:415
THashDataGetResult::data
THashData * data
Definition: util-thash.h:206
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
CLS
#define CLS
Definition: suricata-common.h:45
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:387
HQLOCK_DESTROY
#define HQLOCK_DESTROY(q)
Definition: host-queue.h:66
THashOutputFunc
int(* THashOutputFunc)(void *output_ctx, const uint8_t *data, const uint32_t data_len)
Definition: util-thash.h:125
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:202
THashData_::prev
struct THashData_ * prev
Definition: util-thash.h:96
THashDataConfig_::DataFree
void(* DataFree)(void *)
Definition: util-thash.h:136
THashRemoveFromHash
int THashRemoveFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:774
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
THashData_::next
struct THashData_ * next
Definition: util-thash.h:95
THashConsolidateMemcap
void THashConsolidateMemcap(THashTableContext *ctx)
Definition: util-thash.c:337
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
THashDataQueue_
Definition: util-thash.h:106
THashDataConfig_::DataHash
uint32_t(* DataHash)(void *)
Definition: util-thash.h:137
RandomGet
long int RandomGet(void)
Definition: util-random.c:129
THashDataConfig_::DataCompare
bool(* DataCompare)(void *, void *)
Definition: util-thash.h:138
MAX
#define MAX(x, y)
Definition: suricata-common.h:381
hashsize
#define hashsize(n)
Definition: util-hash-lookup3.c:67
THashDataConfig_::DataSet
int(* DataSet)(void *dst, void *src)
Definition: util-thash.h:135
HRLOCK_LOCK
#define HRLOCK_LOCK(fb)
Definition: host.h:51
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:330
HRLOCK_UNLOCK
#define HRLOCK_UNLOCK(fb)
Definition: host.h:53
THashDataConfig_::prealloc
uint32_t prealloc
Definition: util-thash.h:132
THashDataConfig_::hash_size
uint32_t hash_size
Definition: util-thash.h:131
util-debug.h
THASH_DEFAULT_HASHSIZE
#define THASH_DEFAULT_HASHSIZE
Definition: util-thash.c:198
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
THashTableContext_
Definition: util-thash.h:143
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
THASH_DATA_SIZE
#define THASH_DATA_SIZE(ctx)
Definition: util-thash.h:141
THashDataQueue_::bot
THashData * bot
Definition: util-thash.h:108
THashData_::m
SCMutex m
Definition: util-thash.h:88
TRUE
#define TRUE
Definition: suricata-common.h:33
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:282
THashInit
THashTableContext * THashInit(const char *cnf_prefix, size_t data_size, int(*DataSet)(void *, void *), void(*DataFree)(void *), uint32_t(*DataHash)(void *), bool(*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
Definition: util-thash.c:293
THashTableContext_::array
THashHashRow * array
Definition: util-thash.h:145
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:342
THashDataGetResult
Definition: util-thash.h:205
THashDataConfig_::memcap
uint64_t memcap
Definition: util-thash.h:129
SCFreeAligned
#define SCFreeAligned(p)
Definition: util-mem.h:77
GET_VAR
#define GET_VAR(prefix, name)
Definition: util-thash.c:202
conf.h
HRLOCK_INIT
#define HRLOCK_INIT(fb)
Definition: host.h:49
THashTableContext_::spare_q
THashDataQueue spare_q
Definition: util-thash.h:151
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
WarnInvalidConfEntry
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:37
THashShutdown
void THashShutdown(THashTableContext *ctx)
shutdown the flow engine
Definition: util-thash.c:345
HQLOCK_UNLOCK
#define HQLOCK_UNLOCK(q)
Definition: host-queue.h:69
StringParseUint32
int StringParseUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:313
THashData_::data
void * data
Definition: util-thash.h:93
THashData_
Definition: util-thash.h:86
THashDataQueue_::len
uint32_t len
Definition: util-thash.h:109
suricata-common.h
THASH_DEFAULT_MEMCAP
#define THASH_DEFAULT_MEMCAP
Definition: util-thash.c:199
SCMallocAligned
#define SCMallocAligned(size, align)
Definition: util-mem.h:68
HQLOCK_INIT
#define HQLOCK_INIT(q)
Definition: host-queue.h:65
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
THashGetFromHash
struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:529
THashLookupFromHash
THashData * THashLookupFromHash(THashTableContext *ctx, void *data)
look up data in the hash
Definition: util-thash.c:639
util-hash-lookup3.h
SC_ERR_THASH_INIT
@ SC_ERR_THASH_INIT
Definition: util-error.h:354
THASH_DEFAULT_PREALLOC
#define THASH_DEFAULT_PREALLOC
Definition: util-thash.c:200
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
THashDataConfig_
Definition: util-thash.h:128
THashWalk
int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, void *output_ctx)
Walk the hash.
Definition: util-thash.c:380
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
THashFormatFunc
int(* THashFormatFunc)(const void *in_data, char *output, size_t output_size)
Definition: util-thash.h:126
util-random.h
HRLOCK_TRYLOCK
#define HRLOCK_TRYLOCK(fb)
Definition: host.h:52
THashDataConfig_::data_size
uint32_t data_size
Definition: util-thash.h:134
THashDataConfig_::hash_rand
uint32_t hash_rand
Definition: util-thash.h:130
THashIncrUsecnt
#define THashIncrUsecnt(h)
Definition: util-thash.h:169
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
util-misc.h
util-thash.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
THASH_CHECK_MEMCAP
#define THASH_CHECK_MEMCAP(ctx, size)
check if a memory alloc would fit in the memcap
Definition: util-thash.h:166
THashDataQueueNew
THashDataQueue * THashDataQueueNew(void)
Definition: util-thash.c:55
SCMutexTrylock
#define SCMutexTrylock(mut)
Definition: threads-debug.h:118
THashDataQueue_::top
THashData * top
Definition: util-thash.h:107
THashTableContext_::config
THashConfig config
Definition: util-thash.h:153