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 = SCCalloc(1, sizeof(StorageList));
122  if (unlikely(entry == NULL))
123  return -1;
124 
125  entry->map.type = type;
126  entry->map.name = name;
127  entry->map.size = size;
128  entry->map.Alloc = Alloc;
129  entry->map.Free = Free;
130 
131  entry->id = storage_max_id[type]++;
132  entry->next = storage_list;
133  storage_list = entry;
134 
135  return entry->id;
136 }
137 
139 {
140  int count = 0;
141  int i;
142 
143  storage_registration_closed = 1;
144 
145  for (i = 0; i < STORAGE_MAX; i++) {
146  if (storage_max_id[i] > 0)
147  count++;
148  }
149  if (count == 0)
150  return 0;
151 
152  storage_map = SCCalloc(STORAGE_MAX, sizeof(StorageMapping *));
153  if (unlikely(storage_map == NULL)) {
154  return -1;
155  }
156 
157  for (i = 0; i < STORAGE_MAX; i++) {
158  if (storage_max_id[i] > 0) {
159  storage_map[i] = SCCalloc(storage_max_id[i], sizeof(StorageMapping));
160  if (storage_map[i] == NULL)
161  return -1;
162  }
163  }
164 
165  StorageList *entry = storage_list;
166  while (entry) {
167  if (storage_map[entry->map.type] != NULL) {
168  storage_map[entry->map.type][entry->id].name = entry->map.name;
169  storage_map[entry->map.type][entry->id].type = entry->map.type;
170  storage_map[entry->map.type][entry->id].size = entry->map.size;
171  storage_map[entry->map.type][entry->id].Alloc = entry->map.Alloc;
172  storage_map[entry->map.type][entry->id].Free = entry->map.Free;
173  }
174 
175  StorageList *next = entry->next;
176  SCFree(entry);
177  entry = next;
178  };
179  storage_list = NULL;
180 
181 #ifdef DEBUG
182  for (i = 0; i < STORAGE_MAX; i++) {
183  if (storage_map[i] == NULL)
184  continue;
185 
186  int j;
187  for (j = 0; j < storage_max_id[i]; j++) {
188  StorageMapping *m = &storage_map[i][j];
189  SCLogDebug("type \"%s\" name \"%s\" size \"%"PRIuMAX"\"",
190  StoragePrintType(m->type), m->name, (uintmax_t)m->size);
191  }
192  }
193 #endif
194  return 0;
195 }
196 
198 {
199  return storage_max_id[type];
200 }
201 
202 /** \brief get the size of the void array used to store
203  * the pointers
204  * \retval size size in bytes, can return 0 if not storage is needed
205  *
206  * \todo we could return -1 when registration isn't closed yet, however
207  * this will break lots of tests currently, so not doing it now */
209 {
210  return storage_max_id[type] * sizeof(void *);
211 }
212 
213 void *StorageGetById(const Storage *storage, const StorageEnum type, const int id)
214 {
215 #ifdef DEBUG
216  BUG_ON(!storage_registration_closed);
217 #endif
218  SCLogDebug("storage %p id %d", storage, id);
219  if (storage == NULL)
220  return NULL;
221  return storage[id].ptr;
222 }
223 
224 int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr)
225 {
226 #ifdef DEBUG
227  BUG_ON(!storage_registration_closed);
228 #endif
229  SCLogDebug("storage %p id %d", storage, id);
230  if (storage == NULL)
231  return -1;
232  storage[id].ptr = ptr;
233  return 0;
234 }
235 
237 {
238 #ifdef DEBUG
239  BUG_ON(!storage_registration_closed);
240 #endif
241  SCLogDebug("storage %p id %d", storage, id);
242 
243  StorageMapping *map = &storage_map[type][id];
244  if (storage[id].ptr == NULL && map->Alloc != NULL) {
245  storage[id].ptr = map->Alloc(map->size);
246  if (storage[id].ptr == NULL) {
247  return NULL;
248  }
249  }
250 
251  return storage[id].ptr;
252 }
253 
254 void StorageFreeById(Storage *storage, StorageEnum type, int id)
255 {
256 #ifdef DEBUG
257  BUG_ON(!storage_registration_closed);
258 #endif
259 #ifdef UNITTESTS
260  if (storage_map == NULL)
261  return;
262 #endif
263  SCLogDebug("storage %p id %d", storage, id);
264 
265  Storage *store = storage;
266  if (store != NULL) {
267  SCLogDebug("store %p", store);
268  if (store[id].ptr != NULL) {
269  StorageMapping *map = &storage_map[type][id];
270  map->Free(store[id].ptr);
271  store[id].ptr = NULL;
272  }
273  }
274 }
275 
277 {
278  if (storage == NULL)
279  return;
280 #ifdef DEBUG
281  BUG_ON(!storage_registration_closed);
282 #endif
283 #ifdef UNITTESTS
284  if (storage_map == NULL)
285  return;
286 #endif
287 
288  Storage *store = storage;
289  int i;
290  for (i = 0; i < storage_max_id[type]; i++) {
291  if (store[i].ptr != NULL) {
292  StorageMapping *map = &storage_map[type][i];
293  map->Free(store[i].ptr);
294  store[i].ptr = NULL;
295  }
296  }
297 }
298 
299 #ifdef UNITTESTS
300 
301 static void *StorageTestAlloc(unsigned int size)
302 {
303  void *x = SCMalloc(size);
304  return x;
305 }
306 static void StorageTestFree(void *x)
307 {
308  if (x)
309  SCFree(x);
310 }
311 
312 static int StorageTest01(void)
313 {
314  StorageInit();
315 
316  int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
317  if (id < 0)
318  goto error;
319  id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestAlloc, StorageTestFree);
320  if (id < 0)
321  goto error;
322  id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestAlloc, StorageTestFree);
323  if (id < 0)
324  goto error;
325 
326  if (StorageFinalize() < 0)
327  goto error;
328 
329  StorageCleanup();
330  return 1;
331 error:
332  StorageCleanup();
333  return 0;
334 }
335 
336 static int StorageTest03(void)
337 {
338  StorageInit();
339 
340  int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
341  if (id < 0)
342  goto error;
343  id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
344  if (id != -1) {
345  printf("duplicate registration should have failed: ");
346  goto error;
347  }
348 
349  id = StorageRegister(STORAGE_HOST, "test1", 6, NULL, StorageTestFree);
350  if (id != -1) {
351  printf("duplicate registration should have failed (2): ");
352  goto error;
353  }
354 
355  id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestAlloc, NULL);
356  if (id != -1) {
357  printf("duplicate registration should have failed (3): ");
358  goto error;
359  }
360 
361  id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestAlloc, StorageTestFree);
362  if (id != -1) {
363  printf("duplicate registration should have failed (4): ");
364  goto error;
365  }
366 
367  id = StorageRegister(STORAGE_HOST, "", 8, StorageTestAlloc, StorageTestFree);
368  if (id != -1) {
369  printf("duplicate registration should have failed (5): ");
370  goto error;
371  }
372 
373  id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestAlloc, StorageTestFree);
374  if (id != -1) {
375  printf("duplicate registration should have failed (6): ");
376  goto error;
377  }
378 
379  id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestAlloc, StorageTestFree);
380  if (id != -1) {
381  printf("duplicate registration should have failed (7): ");
382  goto error;
383  }
384 
385  id = StorageRegister(38, "test5", 8, StorageTestAlloc, StorageTestFree);
386  if (id != -1) {
387  printf("duplicate registration should have failed (8): ");
388  goto error;
389  }
390 
391  id = StorageRegister(-1, "test6", 8, StorageTestAlloc, StorageTestFree);
392  if (id != -1) {
393  printf("duplicate registration should have failed (9): ");
394  goto error;
395  }
396 
397  StorageCleanup();
398  return 1;
399 error:
400  StorageCleanup();
401  return 0;
402 }
403 
405 {
406  UtRegisterTest("StorageTest01", StorageTest01);
407  UtRegisterTest("StorageTest03", StorageTest03);
408 }
409 #endif
StorageMapping_
Definition: util-storage.c:31
StorageFreeAll
void StorageFreeAll(Storage *storage, StorageEnum type)
Definition: util-storage.c:276
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
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
Storage
Definition: util-storage.h:39
STORAGE_DEVICE
@ STORAGE_DEVICE
Definition: util-storage.h:33
util-debug.h
type
uint8_t type
Definition: decode-icmpv4.h:0
Storage::ptr
void * ptr
Definition: util-storage.h:40
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:404
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
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:138
StorageGetCnt
unsigned int StorageGetCnt(StorageEnum type)
Definition: util-storage.c:197
suricata-common.h
StorageSetById
int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr)
set storage for id
Definition: util-storage.c:224
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:236
StorageFreeById
void StorageFreeById(Storage *storage, StorageEnum type, int id)
Definition: util-storage.c:254
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
StorageGetById
void * StorageGetById(const Storage *storage, const StorageEnum type, const int id)
get storage for id
Definition: util-storage.c:213
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
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:208
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