suricata
util-storage.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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  * Storage API
24  */
25 
26 #include "suricata-common.h"
27 #include "util-unittest.h"
28 #include "util-storage.h"
29 #include "util-debug.h"
30 
31 typedef struct StorageMapping_ {
32  const char *name;
33  StorageEnum type; // host, flow, tx, stream, ssn, etc
34  unsigned int size;
35  void *(*Alloc)(unsigned int);
36  void (*Free)(void *);
38 
39 /** \brief list of StorageMapping used at registration time */
40 typedef struct StorageList_ {
42  int id;
43  struct StorageList_ *next;
45 
46 static StorageList *storage_list = NULL;
47 static int storage_max_id[STORAGE_MAX];
48 static int storage_registration_closed = 0;
49 static StorageMapping **storage_map = NULL;
50 
51 static const char *StoragePrintType(StorageEnum type)
52 {
53  switch(type) {
54  case STORAGE_HOST:
55  return "host";
56  case STORAGE_FLOW:
57  return "flow";
58  case STORAGE_IPPAIR:
59  return "ippair";
60  case STORAGE_DEVICE:
61  return "livedevice";
62  case STORAGE_MAX:
63  return "max";
64  }
65  return "invalid";
66 }
67 
68 void StorageInit(void)
69 {
70  memset(&storage_max_id, 0x00, sizeof(storage_max_id));
71  storage_list = NULL;
72  storage_map = NULL;
73  storage_registration_closed = 0;
74 }
75 
76 void StorageCleanup(void)
77 {
78  if (storage_map) {
79  int i;
80  for (i = 0; i < STORAGE_MAX; i++) {
81  if (storage_map[i] != NULL) {
82  SCFree(storage_map[i]);
83  storage_map[i] = NULL;
84  }
85  }
86  SCFree(storage_map);
87  storage_map = NULL;
88  }
89 
90  StorageList *entry = storage_list;
91  while (entry) {
92  StorageList *next = entry->next;
93  SCFree(entry);
94  entry = next;
95  }
96 
97  storage_list = NULL;
98 }
99 
100 int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *))
101 {
102  if (storage_registration_closed)
103  return -1;
104 
105  if (type >= STORAGE_MAX || name == NULL || strlen(name) == 0 ||
106  size == 0 || (size != sizeof(void *) && Alloc == NULL) || Free == NULL)
107  return -1;
108 
109  StorageList *list = storage_list;
110  while (list) {
111  if (strcmp(name, list->map.name) == 0 && type == list->map.type) {
112  SCLogError("storage for type \"%s\" with "
113  "name \"%s\" already registered",
114  StoragePrintType(type), name);
115  return -1;
116  }
117 
118  list = list->next;
119  }
120 
121  StorageList *entry = SCMalloc(sizeof(StorageList));
122  if (unlikely(entry == NULL))
123  return -1;
124 
125  memset(entry, 0x00, sizeof(StorageList));
126 
127  entry->map.type = type;
128  entry->map.name = name;
129  entry->map.size = size;
130  entry->map.Alloc = Alloc;
131  entry->map.Free = Free;
132 
133  entry->id = storage_max_id[type]++;
134  entry->next = storage_list;
135  storage_list = entry;
136 
137  return entry->id;
138 }
139 
141 {
142  int count = 0;
143  int i;
144 
145  storage_registration_closed = 1;
146 
147  for (i = 0; i < STORAGE_MAX; i++) {
148  if (storage_max_id[i] > 0)
149  count++;
150  }
151  if (count == 0)
152  return 0;
153 
154  storage_map = SCMalloc(sizeof(StorageMapping *) * STORAGE_MAX);
155  if (unlikely(storage_map == NULL)) {
156  return -1;
157  }
158  memset(storage_map, 0x00, sizeof(StorageMapping *) * STORAGE_MAX);
159 
160  for (i = 0; i < STORAGE_MAX; i++) {
161  if (storage_max_id[i] > 0) {
162  storage_map[i] = SCMalloc(sizeof(StorageMapping) * storage_max_id[i]);
163  if (storage_map[i] == NULL)
164  return -1;
165  memset(storage_map[i], 0x00, sizeof(StorageMapping) * storage_max_id[i]);
166  }
167  }
168 
169  StorageList *entry = storage_list;
170  while (entry) {
171  if (storage_map[entry->map.type] != NULL) {
172  storage_map[entry->map.type][entry->id].name = entry->map.name;
173  storage_map[entry->map.type][entry->id].type = entry->map.type;
174  storage_map[entry->map.type][entry->id].size = entry->map.size;
175  storage_map[entry->map.type][entry->id].Alloc = entry->map.Alloc;
176  storage_map[entry->map.type][entry->id].Free = entry->map.Free;
177  }
178 
179  StorageList *next = entry->next;
180  SCFree(entry);
181  entry = next;
182  };
183  storage_list = NULL;
184 
185 #ifdef DEBUG
186  for (i = 0; i < STORAGE_MAX; i++) {
187  if (storage_map[i] == NULL)
188  continue;
189 
190  int j;
191  for (j = 0; j < storage_max_id[i]; j++) {
192  StorageMapping *m = &storage_map[i][j];
193  SCLogDebug("type \"%s\" name \"%s\" size \"%"PRIuMAX"\"",
194  StoragePrintType(m->type), m->name, (uintmax_t)m->size);
195  }
196  }
197 #endif
198  return 0;
199 }
200 
202 {
203  return storage_max_id[type];
204 }
205 
206 /** \brief get the size of the void array used to store
207  * the pointers
208  * \retval size size in bytes, can return 0 if not storage is needed
209  *
210  * \todo we could return -1 when registration isn't closed yet, however
211  * this will break lots of tests currently, so not doing it now */
213 {
214  return storage_max_id[type] * sizeof(void *);
215 }
216 
217 void *StorageGetById(const Storage *storage, const StorageEnum type, const int id)
218 {
219 #ifdef DEBUG
220  BUG_ON(!storage_registration_closed);
221 #endif
222  SCLogDebug("storage %p id %d", storage, id);
223  if (storage == NULL)
224  return NULL;
225  return storage[id];
226 }
227 
228 int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr)
229 {
230 #ifdef DEBUG
231  BUG_ON(!storage_registration_closed);
232 #endif
233  SCLogDebug("storage %p id %d", storage, id);
234  if (storage == NULL)
235  return -1;
236  storage[id] = ptr;
237  return 0;
238 }
239 
241 {
242 #ifdef DEBUG
243  BUG_ON(!storage_registration_closed);
244 #endif
245  SCLogDebug("storage %p id %d", storage, id);
246 
247  StorageMapping *map = &storage_map[type][id];
248  if (storage[id] == NULL && map->Alloc != NULL) {
249  storage[id] = map->Alloc(map->size);
250  if (storage[id] == NULL) {
251  return NULL;
252  }
253  }
254 
255  return storage[id];
256 }
257 
258 void *StorageAllocById(Storage **storage, StorageEnum type, int id)
259 {
260 #ifdef DEBUG
261  BUG_ON(!storage_registration_closed);
262 #endif
263  SCLogDebug("storage %p id %d", storage, id);
264 
265  StorageMapping *map = &storage_map[type][id];
266  Storage *store = *storage;
267  if (store == NULL) {
268  // coverity[suspicious_sizeof : FALSE]
269  store = SCMalloc(sizeof(void *) * storage_max_id[type]);
270  if (unlikely(store == NULL))
271  return NULL;
272  memset(store, 0x00, sizeof(void *) * storage_max_id[type]);
273  }
274  SCLogDebug("store %p", store);
275 
276  if (store[id] == NULL && map->Alloc != NULL) {
277  store[id] = map->Alloc(map->size);
278  if (store[id] == NULL) {
279  SCFree(store);
280  *storage = NULL;
281  return NULL;
282  }
283  }
284 
285  *storage = store;
286  return store[id];
287 }
288 
289 void StorageFreeById(Storage *storage, StorageEnum type, int id)
290 {
291 #ifdef DEBUG
292  BUG_ON(!storage_registration_closed);
293 #endif
294 #ifdef UNITTESTS
295  if (storage_map == NULL)
296  return;
297 #endif
298  SCLogDebug("storage %p id %d", storage, id);
299 
300  Storage *store = storage;
301  if (store != NULL) {
302  SCLogDebug("store %p", store);
303  if (store[id] != NULL) {
304  StorageMapping *map = &storage_map[type][id];
305  map->Free(store[id]);
306  store[id] = NULL;
307  }
308  }
309 }
310 
312 {
313  if (storage == NULL)
314  return;
315 #ifdef DEBUG
316  BUG_ON(!storage_registration_closed);
317 #endif
318 #ifdef UNITTESTS
319  if (storage_map == NULL)
320  return;
321 #endif
322 
323  Storage *store = storage;
324  int i;
325  for (i = 0; i < storage_max_id[type]; i++) {
326  if (store[i] != NULL) {
327  StorageMapping *map = &storage_map[type][i];
328  map->Free(store[i]);
329  store[i] = NULL;
330  }
331  }
332 }
333 
335 {
336  if (*storage == NULL)
337  return;
338 
339 #ifdef DEBUG
340  BUG_ON(!storage_registration_closed);
341 #endif
342 #ifdef UNITTESTS
343  if (storage_map == NULL)
344  return;
345 #endif
346 
347  Storage *store = *storage;
348  int i;
349  for (i = 0; i < storage_max_id[type]; i++) {
350  if (store[i] != NULL) {
351  StorageMapping *map = &storage_map[type][i];
352  map->Free(store[i]);
353  store[i] = NULL;
354  }
355  }
356  SCFree(*storage);
357  *storage = NULL;
358 }
359 
360 #ifdef UNITTESTS
361 
362 static void *StorageTestAlloc(unsigned int size)
363 {
364  void *x = SCMalloc(size);
365  return x;
366 }
367 static void StorageTestFree(void *x)
368 {
369  if (x)
370  SCFree(x);
371 }
372 
373 static int StorageTest01(void)
374 {
375  StorageInit();
376 
377  int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
378  if (id < 0)
379  goto error;
380  id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestAlloc, StorageTestFree);
381  if (id < 0)
382  goto error;
383  id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestAlloc, StorageTestFree);
384  if (id < 0)
385  goto error;
386 
387  if (StorageFinalize() < 0)
388  goto error;
389 
390  StorageCleanup();
391  return 1;
392 error:
393  StorageCleanup();
394  return 0;
395 }
396 
398  int abc;
399 };
400 
401 static void *StorageTest02Init(unsigned int size)
402 {
403  struct StorageTest02Data *data = (struct StorageTest02Data *)SCMalloc(size);
404  if (data != NULL)
405  data->abc = 1234;
406  return (void *)data;
407 }
408 
409 static int StorageTest02(void)
410 {
411  struct StorageTest02Data *test = NULL;
412 
413  StorageInit();
414 
415  int id1 = StorageRegister(STORAGE_HOST, "test", 4, StorageTest02Init, StorageTestFree);
416  if (id1 < 0) {
417  printf("StorageRegister failed (2): ");
418  goto error;
419  }
420  int id2 = StorageRegister(STORAGE_HOST, "test2", 4, StorageTest02Init, StorageTestFree);
421  if (id2 < 0) {
422  printf("StorageRegister failed (2): ");
423  goto error;
424  }
425 
426  if (StorageFinalize() < 0) {
427  printf("StorageFinalize failed: ");
428  goto error;
429  }
430 
431  Storage *storage = NULL;
432  void *data = StorageAllocById(&storage, STORAGE_HOST, id1);
433  if (data == NULL) {
434  printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
435  goto error;
436  }
437  test = (struct StorageTest02Data *)data;
438  if (test->abc != 1234) {
439  printf("setup failed, test->abc != 1234, but %d (1):", test->abc);
440  goto error;
441  }
442  test->abc = 4321;
443 
444  data = StorageAllocById(&storage, STORAGE_HOST, id2);
445  if (data == NULL) {
446  printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
447  goto error;
448  }
449  test = (struct StorageTest02Data *)data;
450  if (test->abc != 1234) {
451  printf("setup failed, test->abc != 1234, but %d (2):", test->abc);
452  goto error;
453  }
454 
455  data = StorageGetById(storage, STORAGE_HOST, id1);
456  if (data == NULL) {
457  printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
458  goto error;
459  }
460  test = (struct StorageTest02Data *)data;
461  if (test->abc != 4321) {
462  printf("setup failed, test->abc != 4321, but %d (3):", test->abc);
463  goto error;
464  }
465 
466  //StorageFreeById(storage, STORAGE_HOST, id1);
467  //StorageFreeById(storage, STORAGE_HOST, id2);
468 
469  StorageFree(&storage, STORAGE_HOST);
470 
471  StorageCleanup();
472  return 1;
473 error:
474  StorageCleanup();
475  return 0;
476 }
477 
478 static int StorageTest03(void)
479 {
480  StorageInit();
481 
482  int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
483  if (id < 0)
484  goto error;
485  id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
486  if (id != -1) {
487  printf("duplicate registration should have failed: ");
488  goto error;
489  }
490 
491  id = StorageRegister(STORAGE_HOST, "test1", 6, NULL, StorageTestFree);
492  if (id != -1) {
493  printf("duplicate registration should have failed (2): ");
494  goto error;
495  }
496 
497  id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestAlloc, NULL);
498  if (id != -1) {
499  printf("duplicate registration should have failed (3): ");
500  goto error;
501  }
502 
503  id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestAlloc, StorageTestFree);
504  if (id != -1) {
505  printf("duplicate registration should have failed (4): ");
506  goto error;
507  }
508 
509  id = StorageRegister(STORAGE_HOST, "", 8, StorageTestAlloc, StorageTestFree);
510  if (id != -1) {
511  printf("duplicate registration should have failed (5): ");
512  goto error;
513  }
514 
515  id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestAlloc, StorageTestFree);
516  if (id != -1) {
517  printf("duplicate registration should have failed (6): ");
518  goto error;
519  }
520 
521  id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestAlloc, StorageTestFree);
522  if (id != -1) {
523  printf("duplicate registration should have failed (7): ");
524  goto error;
525  }
526 
527  id = StorageRegister(38, "test5", 8, StorageTestAlloc, StorageTestFree);
528  if (id != -1) {
529  printf("duplicate registration should have failed (8): ");
530  goto error;
531  }
532 
533  id = StorageRegister(-1, "test6", 8, StorageTestAlloc, StorageTestFree);
534  if (id != -1) {
535  printf("duplicate registration should have failed (9): ");
536  goto error;
537  }
538 
539  StorageCleanup();
540  return 1;
541 error:
542  StorageCleanup();
543  return 0;
544 }
545 
547 {
548  UtRegisterTest("StorageTest01", StorageTest01);
549  UtRegisterTest("StorageTest02", StorageTest02);
550  UtRegisterTest("StorageTest03", StorageTest03);
551 }
552 #endif
StorageMapping_
Definition: util-storage.c:31
StorageFreeAll
void StorageFreeAll(Storage *storage, StorageEnum type)
Definition: util-storage.c:311
StorageInit
void StorageInit(void)
Definition: util-storage.c:68
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:103
StorageList_::next
struct StorageList_ * next
Definition: util-storage.c:43
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
StorageCleanup
void StorageCleanup(void)
Definition: util-storage.c:76
STORAGE_IPPAIR
@ STORAGE_IPPAIR
Definition: util-storage.h:32
StorageTest02Data
Definition: util-storage.c:397
StorageEnum
enum StorageEnum_ StorageEnum
m
SCMutex m
Definition: flow-hash.h:6
STORAGE_HOST
@ STORAGE_HOST
Definition: util-storage.h:30
util-unittest.h
StorageList_::id
int id
Definition: util-storage.c:42
StorageAllocById
void * StorageAllocById(Storage **storage, StorageEnum type, int id)
AllocById func for when we manage the Storage ptr itself.
Definition: util-storage.c:258
STORAGE_DEVICE
@ STORAGE_DEVICE
Definition: util-storage.h:33
util-debug.h
type
uint8_t type
Definition: decode-icmpv4.h:0
StorageMapping_::Free
void(* Free)(void *)
Definition: util-storage.c:36
STORAGE_FLOW
@ STORAGE_FLOW
Definition: util-storage.h:31
StorageList_::map
StorageMapping map
Definition: util-storage.c:41
StorageList
struct StorageList_ StorageList
list of StorageMapping used at registration time
StorageRegisterTests
void StorageRegisterTests(void)
Definition: util-storage.c:546
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:295
StorageMapping_::name
const char * name
Definition: util-storage.c:32
STORAGE_MAX
@ STORAGE_MAX
Definition: util-storage.h:35
StorageMapping_::type
StorageEnum type
Definition: util-storage.c:33
StorageFinalize
int StorageFinalize(void)
Definition: util-storage.c:140
StorageGetCnt
unsigned int StorageGetCnt(StorageEnum type)
Definition: util-storage.c:201
suricata-common.h
StorageFree
void StorageFree(Storage **storage, StorageEnum type)
Definition: util-storage.c:334
StorageTest02Data::abc
int abc
Definition: util-storage.c:398
StorageSetById
int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr)
set storage for id
Definition: util-storage.c:228
StorageAllocByIdPrealloc
void * StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id)
AllocById func for prealloc'd base storage (storage ptrs are part of another memory block)
Definition: util-storage.c:240
StorageFreeById
void StorageFreeById(Storage *storage, StorageEnum type, int id)
Definition: util-storage.c:289
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
StorageMapping_::size
unsigned int size
Definition: util-storage.c:34
Storage
void * Storage
Definition: util-storage.h:39
StorageGetById
void * StorageGetById(const Storage *storage, const StorageEnum type, const int id)
get storage for id
Definition: util-storage.c:217
StorageMapping_::Alloc
void *(* Alloc)(unsigned int)
Definition: util-storage.c:35
StorageGetSize
unsigned int StorageGetSize(StorageEnum type)
get the size of the void array used to store the pointers
Definition: util-storage.c:212
util-storage.h
StorageRegister
int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void(*Free)(void *))
Register new storage.
Definition: util-storage.c:100
StorageMapping
struct StorageMapping_ StorageMapping
StorageList_
list of StorageMapping used at registration time
Definition: util-storage.c:40