From 022c0e466e8f0f60251b32f8feb5994bb27d2cea Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 18 Jan 2013 15:50:25 +0100 Subject: [PATCH] Initial storage api work --- src/Makefile.am | 1 + src/suricata.c | 3 + src/util-storage.c | 441 +++++++++++++++++++++++++++++++++++++++++++++ src/util-storage.h | 50 +++++ 4 files changed, 495 insertions(+) create mode 100644 src/util-storage.c create mode 100644 src/util-storage.h diff --git a/src/Makefile.am b/src/Makefile.am index 42d0d0d885..c672b05297 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -321,6 +321,7 @@ util-spm-bm.c util-spm-bm.h \ util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h \ util-spm.c util-spm.h util-clock.h \ +util-storage.c util-storage.h \ util-strlcatu.c \ util-strlcpyu.c \ util-syslog.c util-syslog.h \ diff --git a/src/suricata.c b/src/suricata.c index 95b1f29376..d01330583f 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -193,6 +193,7 @@ #include "util-cuda-buffer.h" #include "util-mpm-ac.h" #endif +#include "util-storage.h" /* * we put this here, because we only use it here in main. @@ -1746,6 +1747,8 @@ int main(int argc, char **argv) #ifdef __SC_CUDA_SUPPORT__ CudaBufferRegisterUnittests(); #endif + StorageRegisterTests(); + if (list_unittests) { UtListTests(regex_arg); } else if (coverage_unittests) { diff --git a/src/util-storage.c b/src/util-storage.c new file mode 100644 index 0000000000..c829905d75 --- /dev/null +++ b/src/util-storage.c @@ -0,0 +1,441 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Storage API + */ + +#include "suricata-common.h" +#include "util-unittest.h" +#include "util-storage.h" + +typedef struct StorageMapping_ { + const char *name; + StorageEnum type; // host, flow, tx, stream, ssn, etc + unsigned int size; + int (*Init)(void *); + void (*Free)(void *); +} StorageMapping; + +/** \brief list of StorageMapping used at registration time */ +typedef struct StorageList_ { + StorageMapping map; + int id; + struct StorageList_ *next; +} StorageList; + +static StorageList *storage_list = NULL; +static int storage_max_id[STORAGE_MAX]; +static int storage_registraton_closed = 0; +static StorageMapping **storage_map = NULL; + +const char *StoragePrintType(StorageEnum type) { + switch(type) { + case STORAGE_HOST: + return "host"; + case STORAGE_FLOW: + return "flow"; + case STORAGE_MAX: + return "max"; + } + return "invalid"; +} + +void StorageInit(void) { + memset(&storage_max_id, 0x00, sizeof(storage_max_id)); + storage_list = NULL; + storage_map = NULL; + storage_registraton_closed = 0; +} + +void StorageCleanup(void) { + if (storage_map) { + int i; + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_map[i] != NULL) { + SCFree(storage_map[i]); + storage_map[i] = NULL; + } + } + SCFree(storage_map); + storage_map = NULL; + } + + StorageList *entry = storage_list; + while (entry) { + StorageList *next = entry->next; + SCFree(entry); + entry = next; + } + + storage_list = NULL; +} + +int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, int (*Init)(void *), void (*Free)(void *)) { + if (storage_registraton_closed) + return -1; + + if (type >= STORAGE_MAX || name == NULL || strlen(name) == 0 || + size == 0 || Init == NULL || Free == NULL) + return -1; + + StorageList *list = storage_list; + while (list) { + if (strcmp(name, list->map.name) == 0 && type == list->map.type) { + SCLogError(SC_ERR_INVALID_VALUE, "storage for type \"%s\" with " + "name \"%s\" already registered", StoragePrintType(type), + name); + return -1; + } + + list = list->next; + } + + StorageList *entry = SCMalloc(sizeof(StorageList)); + if (entry == NULL) + return -1; + + memset(entry, 0x00, sizeof(StorageList)); + + entry->map.type = type; + entry->map.name = name; + entry->map.size = size; + entry->map.Init = Init; + entry->map.Free = Free; + + entry->id = storage_max_id[type]++; + entry->next = storage_list; + storage_list = entry; + + return entry->id; +} + +int StorageFinalize(void) { + int count = 0; + int i; + + storage_registraton_closed = 1; + + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_max_id[i] > 0) + count++; + } + if (count == 0) + return 0; + + storage_map = SCMalloc(sizeof(StorageMapping *) * STORAGE_MAX); + if (storage_map == NULL) { + return -1; + } + memset(storage_map, 0x00, sizeof(StorageMapping *) * STORAGE_MAX); + + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_max_id[i] > 0) { + storage_map[i] = SCMalloc(sizeof(StorageMapping) * storage_max_id[i]); + if (storage_map[i] == NULL) + return -1; + memset(storage_map[i], 0x00, sizeof(StorageMapping) * storage_max_id[i]); + } + } + + StorageList *entry = storage_list; + while (entry) { + if (storage_map[entry->map.type] != NULL) { + storage_map[entry->map.type][entry->id].name = entry->map.name; + storage_map[entry->map.type][entry->id].type = entry->map.type; + storage_map[entry->map.type][entry->id].size = entry->map.size; + storage_map[entry->map.type][entry->id].Init = entry->map.Init; + storage_map[entry->map.type][entry->id].Free = entry->map.Free; + } + + entry = entry->next; + }; + +#ifdef DEBUG + for (i = 0; i < STORAGE_MAX; i++) { + if (storage_map[i] == NULL) + continue; + + int j; + for (j = 0; j < storage_max_id[i]; j++) { + StorageMapping *m = &storage_map[i][j]; + SCLogDebug("type \"%s\" name \"%s\" size \"%"PRIuMAX"\"", + StoragePrintType(m->type), m->name, (uintmax_t)m->size); + } + } +#endif + return 0; +} + +void *StorageGetById(Storage *storage, StorageEnum type, int id) { + SCLogDebug("storage %p id %d", storage, id); + if (storage == NULL) + return NULL; + return storage[id]; +} + +void *StorageAllocById(Storage **storage, StorageEnum type, int id) { + SCLogDebug("storage %p id %d", storage, id); + + StorageMapping *map = &storage_map[type][id]; + Storage *store = *storage; + if (store == NULL) { + store = SCMalloc(sizeof(void *) * storage_max_id[type]); + if (store == NULL) + return NULL; + memset(store, 0x00, sizeof(void *) * storage_max_id[type]); + } + SCLogDebug("store %p", store); + + if (store[id] == NULL) { + store[id] = SCMalloc(map->size); + if (store[id] == NULL) { + SCFree(store); + *storage = NULL; + return NULL; + } + } + + if (map->Init(store[id]) < 0) { + SCFree(store); + *storage = NULL; + return NULL; + } + + *storage = store; + return store[id]; +} + +void StorageFreeById(Storage *storage, StorageEnum type, int id) { + SCLogDebug("storage %p id %d", storage, id); + + StorageMapping *map = &storage_map[type][id]; + Storage *store = storage; + if (store != NULL) { + SCLogDebug("store %p", store); + if (store[id] != NULL) { + map->Free(store[id]); + SCFree(store[id]); + store[id] = NULL; + } + } +} + +void StorageFree(Storage **storage, StorageEnum type) { + if (*storage == NULL) + return; + + Storage *store = *storage; + int i; + for (i = 0; i < storage_max_id[type]; i++) { + StorageMapping *map = &storage_map[type][i]; + if (store[i] != NULL) { + map->Free(store[i]); + SCFree(store[i]); + store[i] = NULL; + } + } + SCFree(*storage); + storage = NULL; +} + +#ifdef UNITTESTS + +static int StorageTestInit(void *x) { + return 0; +} +void StorageTestFree(void *x) { +} + +static int StorageTest01(void) { + StorageInit(); + + int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestInit, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestInit, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestInit, StorageTestFree); + if (id < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + StorageCleanup(); + return 1; +error: + StorageCleanup(); + return 0; +} + +struct StorageTest02Data { + int abc; +}; + +static int StorageTest02Init(void *x) { + struct StorageTest02Data *data = (struct StorageTest02Data *)x; + data->abc = 1234; + return 0; +} + +static int StorageTest02(void) { + struct StorageTest02Data *test = NULL; + + StorageInit(); + + int id1 = StorageRegister(STORAGE_HOST, "test", 4, StorageTest02Init, StorageTestFree); + if (id1 < 0) { + printf("StorageRegister failed (2): "); + goto error; + } + int id2 = StorageRegister(STORAGE_HOST, "test2", 4, StorageTest02Init, StorageTestFree); + if (id2 < 0) { + printf("StorageRegister failed (2): "); + goto error; + } + + if (StorageFinalize() < 0) { + printf("StorageFinalize failed: "); + goto error; + } + + Storage *storage = NULL; + void *data = StorageAllocById(&storage, STORAGE_HOST, id1); + if (data == NULL) { + printf("StorageAllocById failed, data == NULL, storage %p: ", storage); + goto error; + } + test = (struct StorageTest02Data *)data; + if (test->abc != 1234) { + printf("setup failed, test->abc != 1234, but %d (1):", test->abc); + goto error; + } + test->abc = 4321; + + data = StorageAllocById(&storage, STORAGE_HOST, id2); + if (data == NULL) { + printf("StorageAllocById failed, data == NULL, storage %p: ", storage); + goto error; + } + test = (struct StorageTest02Data *)data; + if (test->abc != 1234) { + printf("setup failed, test->abc != 1234, but %d (2):", test->abc); + goto error; + } + + data = StorageGetById(storage, STORAGE_HOST, id1); + if (data == NULL) { + printf("StorageAllocById failed, data == NULL, storage %p: ", storage); + goto error; + } + test = (struct StorageTest02Data *)data; + if (test->abc != 4321) { + printf("setup failed, test->abc != 4321, but %d (3):", test->abc); + goto error; + } + + //StorageFreeById(storage, STORAGE_HOST, id1); + //StorageFreeById(storage, STORAGE_HOST, id2); + + StorageFree(&storage, STORAGE_HOST); + + StorageCleanup(); + return 1; +error: + StorageCleanup(); + return 0; +} + +static int StorageTest03(void) { + StorageInit(); + + int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestInit, StorageTestFree); + if (id < 0) + goto error; + id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed: "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test1", 8, NULL, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (2): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestInit, NULL); + if (id != -1) { + printf("duplicate registration should have failed (3): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (4): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, "", 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (5): "); + goto error; + } + + id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (6): "); + goto error; + } + + id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (7): "); + goto error; + } + + id = StorageRegister(38, "test5", 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (8): "); + goto error; + } + + id = StorageRegister(-1, "test6", 8, StorageTestInit, StorageTestFree); + if (id != -1) { + printf("duplicate registration should have failed (9): "); + goto error; + } + + StorageCleanup(); + return 1; +error: + StorageCleanup(); + return 0; +} + +void StorageRegisterTests(void) { + UtRegisterTest("StorageTest01", StorageTest01, 1); + UtRegisterTest("StorageTest02", StorageTest02, 1); + UtRegisterTest("StorageTest03", StorageTest03, 1); +} +#endif diff --git a/src/util-storage.h b/src/util-storage.h new file mode 100644 index 0000000000..785c4d02a8 --- /dev/null +++ b/src/util-storage.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Storage API + */ + +#ifndef __UTIL_STORAGE_H__ +#define __UTIL_STORAGE_H__ + +typedef enum StorageEnum_ { + STORAGE_HOST, + STORAGE_FLOW, + + STORAGE_MAX, +} StorageEnum; + +/** void ptr array for now */ +typedef void* Storage; + +void StorageInit(void); +void StorageCleanup(void); +int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, int (*Init)(void *), void (*Free)(void *)); +int StorageFinalize(void); + +void *StorageGetById(Storage *storage, StorageEnum type, int id); +void *StorageAllocById(Storage **storage, StorageEnum type, int id); +void StorageFreeById(Storage *storage, StorageEnum type, int id); +void StorageFree(Storage **storage, StorageEnum type); + +void StorageRegisterTests(void); +#endif