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