diff options
Diffstat (limited to 'Source/charon/utils')
-rw-r--r-- | Source/charon/utils/allocator.c | 347 | ||||
-rw-r--r-- | Source/charon/utils/allocator.h | 223 | ||||
-rw-r--r-- | Source/charon/utils/linked_list.c | 2 | ||||
-rw-r--r-- | Source/charon/utils/logger.c | 284 | ||||
-rw-r--r-- | Source/charon/utils/logger.h | 154 | ||||
-rw-r--r-- | Source/charon/utils/logger_manager.c | 461 | ||||
-rw-r--r-- | Source/charon/utils/logger_manager.h | 140 | ||||
-rw-r--r-- | Source/charon/utils/tester.c | 206 | ||||
-rw-r--r-- | Source/charon/utils/tester.h | 114 |
9 files changed, 1930 insertions, 1 deletions
diff --git a/Source/charon/utils/allocator.c b/Source/charon/utils/allocator.c new file mode 100644 index 000000000..290b1de3b --- /dev/null +++ b/Source/charon/utils/allocator.c @@ -0,0 +1,347 @@ +/** + * @file allocator.c + * + * @brief Memory allocation with LEAK_DETECTION support + * + * Thread-save implementation + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> + +#include "allocator.h" + +#ifdef LEAK_DETECTIVE + +/** + * Header of each allocated memory area + * + * Used to detect memory leaks + */ +typedef union memory_hdr_u memory_hdr_t; + +union memory_hdr_u { + struct { + /** + * Filename withing memory was allocated + */ + const char *filename; + /** + * Line number in given file + */ + size_t line; + /** + * Allocated memory size. Needed for reallocation + */ + size_t size_of_memory; + /** + * Link to the previous and next memory area + */ + memory_hdr_t *older, *newer; + } info; /* info */ + /** + * force maximal alignment ? + */ + unsigned long junk; +}; + +/** + * @brief Private allocator_t object. + * + * Contains private variables of allocator_t object. + */ +typedef struct private_allocator_s private_allocator_t; + +struct private_allocator_s +{ + /** + * Public part of an allocator_t object. + */ + allocator_t public; + + /** + * Global list of allocations + * + * Thread-save through mutex + */ + memory_hdr_t *allocations; + + /** + * Mutex used to make sure, all functions are thread-save + */ + pthread_mutex_t mutex; + + /** + * Allocates memory with LEAK_DETECTION and + * returns an empty data area filled with zeros. + * + * @param this private_allocator_t object + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @param use_mutex If FALSE no mutex is used for allocation + * @return + * - pointer to allocated memory area if successful + * - NULL otherwise + */ + void * (*allocate_special) (private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex); +}; + +/** + * Implements private_allocator_t's function allocate_special. + * See #private_allocator_s.allocate_special for description. + */ +static void *allocate_special(private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex) +{ + memory_hdr_t *allocated_memory = malloc(sizeof(memory_hdr_t) + bytes); + + if (allocated_memory == NULL) + { + return allocated_memory; + } + + if (use_mutex) + { + pthread_mutex_lock( &(this->mutex)); + } + + allocated_memory->info.line = line; + allocated_memory->info.filename = file; + allocated_memory->info.size_of_memory = bytes; + allocated_memory->info.older = this->allocations; + if (this->allocations != NULL) + { + this->allocations->info.newer = allocated_memory; + } + this->allocations = allocated_memory; + allocated_memory->info.newer = NULL; + + /* fill memory with zero's */ + memset(allocated_memory+1, '\0', bytes); + if (use_mutex) + { + pthread_mutex_unlock(&(this->mutex)); + } + + /* real memory starts after header */ + return (allocated_memory+1); +} + +/** + * Implements allocator_t's function allocate. + * See #allocator_s.allocate for description. + */ +static void * allocate(allocator_t *allocator,size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + return (this->allocate_special(this,bytes, file,line,TRUE)); +} + +/** + * Implements allocator_t's function allocate_as_chunk. + * See #allocator_s.allocate_as_chunk for description. + */ +static chunk_t allocate_as_chunk(allocator_t *allocator,size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + chunk_t new_chunk; + new_chunk.ptr = this->allocate_special(this,bytes, file,line,TRUE); + new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes; + return new_chunk; +} + +/* + * Implements allocator_t's free_pointer function. + * See #allocator_s.free_pointer for description. + */ +static void free_pointer(allocator_t *allocator, void * pointer) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *allocated_memory; + + if (pointer == NULL) + { + return; + } + pthread_mutex_lock( &(this->mutex)); + allocated_memory = ((memory_hdr_t *)pointer) - 1; + + if (allocated_memory->info.older != NULL) + { + assert(allocated_memory->info.older->info.newer == allocated_memory); + allocated_memory->info.older->info.newer = allocated_memory->info.newer; + } + if (allocated_memory->info.newer == NULL) + { + assert(allocated_memory == this->allocations); + this->allocations = allocated_memory->info.older; + } + else + { + assert(allocated_memory->info.newer->info.older == allocated_memory); + allocated_memory->info.newer->info.older = allocated_memory->info.older; + } + pthread_mutex_unlock(&(this->mutex)); + free(allocated_memory); +} + +/* + * Implements allocator_t's reallocate function. + * See #allocator_s.reallocate for description. + */ +static void * reallocate(allocator_t *allocator, void * old, size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *allocated_memory; + + if (old == NULL) + { + return NULL; + } + + pthread_mutex_lock( &(this->mutex)); + allocated_memory = ((memory_hdr_t *)old) - 1; + + void *new_space = this->allocate_special(this,bytes,file,line,FALSE); + + if (new_space == NULL) + { + pthread_mutex_unlock(&(this->mutex)); + this->public.free_pointer(&(this->public),old); + return NULL; + } + + + /* the smaller size is copied to avoid overflows */ + memcpy(new_space,old,(allocated_memory->info.size_of_memory < bytes) ? allocated_memory->info.size_of_memory : bytes); + pthread_mutex_unlock(&(this->mutex)); + this->public.free_pointer(&(this->public),old); + + return new_space; +} + +/* + * Implements allocator_t's clone_bytes function. + * See #allocator_s.clone_bytes for description. + */ +static void * clone_bytes(allocator_t *allocator,void * to_clone, size_t bytes, char * file, int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + + if (to_clone == NULL) + { + return NULL; + } + + + void *new_space = this->allocate_special(this,bytes,file,line,TRUE); + + if (new_space == NULL) + { + return NULL; + } + + memcpy(new_space,to_clone,bytes); + + return new_space; +} + +/* + * Implements allocator_t's report_memory_leaks allocate. + * See #allocator_s.report_memory_leaks for description. + */ +static void allocator_report_memory_leaks(allocator_t *allocator) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *p = this->allocations; + memory_hdr_t *pprev = NULL; + unsigned long n = 0; + + pthread_mutex_lock(&(this->mutex)); + + while (p != NULL) + { + assert(pprev == p->info.newer); + pprev = p; + p = p->info.older; + n++; + if (p == NULL || pprev->info.filename != p->info.filename) + { + if (n != 1) + fprintf(stderr,"LEAK: \"%lu * File %s, Line %d\"\n", n, pprev->info.filename,pprev->info.line); + else + fprintf(stderr,"LEAK: \"%s, Line %d\"\n", pprev->info.filename,pprev->info.line); + n = 0; + } + } + pthread_mutex_unlock( &(this->mutex)); +} + +/** + * Only initiation of allocator object. + * + * All allocation macros use this object. + */ +static private_allocator_t allocator = { + public: {allocate: allocate, + allocate_as_chunk: allocate_as_chunk, + free_pointer: free_pointer, + reallocate: reallocate, + clone_bytes : clone_bytes, + report_memory_leaks: allocator_report_memory_leaks}, + allocations: NULL, + allocate_special : allocate_special, + mutex: PTHREAD_MUTEX_INITIALIZER +}; + +allocator_t *global_allocator = &(allocator.public); +#else /* !LEAK_DETECTION */ + + +chunk_t allocator_alloc_as_chunk(size_t bytes) +{ + chunk_t new_chunk; + new_chunk.ptr = malloc(bytes); + new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes; + return new_chunk; + +} + +void * allocator_clone_bytes(void * pointer, size_t size) +{ + void *data; + data = malloc(size); + if (data == NULL){ return NULL;} + memcpy(data,pointer,size); + return (data); +} + + +void allocator_free_chunk(chunk_t chunk) +{ + free(chunk.ptr); +} + + +#endif /* LEAK_DETECTION */ + + diff --git a/Source/charon/utils/allocator.h b/Source/charon/utils/allocator.h new file mode 100644 index 000000000..ab8f59bfd --- /dev/null +++ b/Source/charon/utils/allocator.h @@ -0,0 +1,223 @@ +/** + * @file allocator.h + * + * @brief Memory allocation with LEAK_DETECTION support + * + * Thread-save implementation + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef ALLOCATOR_H_ +#define ALLOCATOR_H_ + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#include "../types.h" + + +/** + * Macro to allocate a special type + * + * @param thing object on which a sizeof is performed + * @return + * - Pointer to allocated memory if successful + * - NULL otherwise + */ +#define allocator_alloc_thing_as_chunk(thing) (allocator_alloc_as_chunk(sizeof(thing))) + +/** + * Macro to allocate a special type as chunk_t + * + * @param thing object on which a sizeof is performed + * @return + * - chunk_t pointing to allocated memory if successful + * - chunk_t containing empty pointer + */ +#define allocator_alloc_thing(thing) (allocator_alloc(sizeof(thing))) + +#ifdef LEAK_DETECTIVE + + /** + * @brief Allocater object use to detect memory leaks. + * + */ + typedef struct allocator_s allocator_t; + + struct allocator_s { + + /** + * Allocates memory with LEAK_DETECTION and + * returns an empty data area filled with zeros. + * + * @warning Use this function not directly, only with assigned macros + * #allocator_alloc and #allocator_alloc_thing. + * + * @param this allocator_t object + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @return + * - pointer to allocated memory area if successful + * - NULL otherwise + */ + void * (*allocate) (allocator_t *this,size_t bytes, char * file,int line); + + /** + * Allocates memory with LEAK_DETECTION and + * returns an chunk pointing to an empy data area filled with zeros. + * + * @warning Use this function not directly, only with assigned macros + * #allocator_alloc_as_chunk and #allocator_alloc_thing_as_chunk. + * + * @param this allocator_t object + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @return + * - pointer to allocated memory area if successful + * - NULL otherwise + */ + chunk_t (*allocate_as_chunk) (allocator_t *this,size_t bytes, char * file,int line); + + /** + * Reallocates memory with LEAK_DETECTION and + * returns an empty data area filled with zeros + * + * @warning Use this function not directly, only with assigned macro + * #allocator_realloc + * + * @param this allocator_t object + * @param old pointer to the old data area + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @return - pointer to reallocated memory area if successful + * - NULL otherwise + */ + void * (*reallocate) (allocator_t *this,void * old, size_t bytes, char * file, int line); + + /** + * Clones memory with LEAK_DETECTION and + * returns a cloned data area. + * + * @warning Use this function not directly, only with assigned macro + * #allocator_clone_bytes + * + * @param this allocator_t object + * @param old pointer to the old data area + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @return - pointer to reallocated memory area if successful + * - NULL otherwise + */ + void * (*clone_bytes) (allocator_t *this,void * to_clone, size_t bytes, char * file, int line); + + /** + * Frees memory with LEAK_DETECTION + * + * @warning Use this function not directly, only with assigned macro + * #allocator_free + * + * @param this allocator_t object + * @param pointer pointer to the data area to free + */ + void (*free_pointer) (allocator_t *this,void * pointer); + + /** + * Report memory leaks to stderr + * + * @warning Use this function not directly, only with assigned macro + * #report_memory_leaks + * + * @param this allocator_t object + */ + void (*report_memory_leaks) (allocator_t *this); + }; + + + /** + * @brief Global allocater_t object. + * + * Only accessed over macros. + */ + extern allocator_t *global_allocator; + + + /** + * Macro to allocate some memory + * + * @see #allocator_s.allocate for description + */ + #define allocator_alloc(bytes) (global_allocator->allocate(global_allocator,bytes,__FILE__,__LINE__)) + + /** + * Macro to allocate some memory for a chunk_t + * + * @see #allocator_s.allocate_as_chunk for description + */ + #define allocator_alloc_as_chunk(bytes) (global_allocator->allocate_as_chunk(global_allocator,bytes,__FILE__,__LINE__)) + + /** + * Macro to reallocate some memory + * + * @see #allocator_s.reallocate for description + */ + #define allocator_realloc(old,bytes) (global_allocator->reallocate(global_allocator,old,bytes,__FILE__, __LINE__)) + + /** + * Macro to clone some memory + * + * @see #allocator_s.*clone_bytes for description + */ + #define allocator_clone_bytes(old,bytes) (global_allocator->clone_bytes(global_allocator,old,bytes,__FILE__, __LINE__)) + + /** + * Macro to free some memory + * + * @see #allocator_s.free for description + */ + #define allocator_free(pointer) (global_allocator->free_pointer(global_allocator,pointer)) + /** + * Macro to free a chunk + */ + #define allocator_free_chunk(chunk){ \ + global_allocator->free_pointer(global_allocator,chunk.ptr); \ + chunk.ptr = NULL; \ + chunk.len = 0; \ + } + /** + * Macro to report memory leaks + * + * @see #allocator_s.report_memory_leaks for description + */ + #define report_memory_leaks(void) (global_allocator->report_memory_leaks(global_allocator)) +#else + #define allocator_alloc(bytes) (malloc(bytes)) + + chunk_t allocator_alloc_as_chunk(size_t bytes); + + #define allocator_realloc(old,bytes) (realloc(old,bytes)) + #define allocator_free(pointer) (free(pointer)) + void * allocator_clone_bytes(void * pointer, size_t size); + void allocator_free_chunk(chunk_t chunk); + #define report_memory_leaks(void) {} +#endif + +#endif /*ALLOCATOR_H_*/ diff --git a/Source/charon/utils/linked_list.c b/Source/charon/utils/linked_list.c index b842886c0..785377ee9 100644 --- a/Source/charon/utils/linked_list.c +++ b/Source/charon/utils/linked_list.c @@ -24,7 +24,7 @@ #include "linked_list.h" -#include "../allocator.h" +#include "allocator.h" typedef struct linked_list_element_s linked_list_element_t; diff --git a/Source/charon/utils/logger.c b/Source/charon/utils/logger.c new file mode 100644 index 000000000..714f8b95e --- /dev/null +++ b/Source/charon/utils/logger.c @@ -0,0 +1,284 @@ +/** + * @file logger.c + * + * @brief Logger object, allows fine-controlled logging + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include <syslog.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <time.h> + +#include "logger.h" + +#include "../daemon.h" +#include "allocator.h" + +/** + * Maximum length of al log entry (only used for logger_s.log) + */ +#define MAX_LOG 8192 + +/** + * @brief The logger object. + */ +typedef struct private_logger_s private_logger_t; +struct private_logger_s { + /** + * Public data + */ + logger_t public; + /** + * Detail-level of logger. + */ + logger_level_t level; + /** + * Name of logger. + */ + char *name; + /** + * File to write log output to . + * NULL for syslog. + */ + FILE *output; + + /* private functions */ + /** + * Logs a message to the associated log file. + */ + void (*log_to_file) (private_logger_t *this, char *format, ...); +}; + +/** + * Implements logger_t-function log. + * @see logger_s.log. + * + * Yes, logg is wrong written :-). + */ +static status_t logg(private_logger_t *this, logger_level_t loglevel, char *format, ...) +{ + if ((this->level & loglevel) == loglevel) + { + char buffer[MAX_LOG]; + va_list args; + + if (this->output == NULL) + { + /* syslog */ + snprintf(buffer, MAX_LOG, "%s: %s", this->name, format); + va_start(args, format); + vsyslog(LOG_INFO, buffer, args); + va_end(args); + } + else + { + /* File output */ + snprintf(buffer, MAX_LOG, "File %s: %s", this->name, format); + va_start(args, format); + this->log_to_file(this, buffer, args); + va_end(args); + } + + } + return SUCCESS; +} + +/** + * Implements private_logger_t-function log_to_file. + * @see private_logger_s.log_to_file. + */ +static void log_to_file(private_logger_t *this,char *format, ...) +{ + char buffer[MAX_LOG]; + va_list args; + time_t current_time; + current_time = time(NULL); + + snprintf(buffer, MAX_LOG, "%s\n", format); + va_start(args, format); + vfprintf(this->output, buffer, args); + va_end(args); +} + +/** + * Implements logger_t-function destroy. + * @see logger_s.log_bytes. + */ +static status_t log_bytes(private_logger_t *this, logger_level_t loglevel, char *label, char *bytes, size_t len) +{ + if ((this->level & loglevel) == loglevel) + { + char buffer[64]; + char *buffer_pos; + char *bytes_pos, *bytes_roof; + int i; + + if (this->output == NULL) + { + syslog(LOG_INFO, "%s: %s (%d bytes)", this->name, label, len); + }else + { + this->log_to_file(this,"%s: %s (%d bytes)", this->name, label, len); + } + + bytes_pos = bytes; + bytes_roof = bytes + len; + buffer_pos = buffer; + + for (i = 1; bytes_pos < bytes_roof; i++) + { + static const char hexdig[] = "0123456789ABCDEF"; + *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF]; + *buffer_pos++ = hexdig[ *bytes_pos & 0xF]; + if ((i % 16) == 0) + { + *buffer_pos++ = '\0'; + buffer_pos = buffer; + if (this->output == NULL) + { + syslog(LOG_INFO, "| %s", buffer); + } + else + { + this->log_to_file(this, "| %s", buffer); + } + } + else if ((i % 8) == 0) + { + *buffer_pos++ = ' '; + *buffer_pos++ = ' '; + *buffer_pos++ = ' '; + } + else if ((i % 4) == 0) + { + *buffer_pos++ = ' '; + *buffer_pos++ = ' '; + } + else + { + *buffer_pos++ = ' '; + } + + bytes_pos++; + } + + *buffer_pos++ = '\0'; + buffer_pos = buffer; + if (this->output == NULL) + { + syslog(LOG_INFO, "| %s", buffer); + } + else + { + this->log_to_file(this, "| %s", buffer); + } + } + + return SUCCESS; +} + + +/** + * Implements logger_t-function log_chunk. + * @see logger_s.log_chunk. + */ +static status_t log_chunk(logger_t *this, logger_level_t loglevel, char *label, chunk_t *chunk) +{ + this->log_bytes(this, loglevel, label, chunk->ptr, chunk->len); + return SUCCESS; +} + + +/** + * Implements logger_t-function enable_level. + * @see logger_s.enable_level. + */ +static status_t enable_level(private_logger_t *this, logger_level_t log_level) +{ + this->level |= log_level; + return SUCCESS; +} + +/** + * Implements logger_t-function disable_level. + * @see logger_s.disable_level. + */ +static status_t disable_level(private_logger_t *this, logger_level_t log_level) +{ + this->level &= ~log_level; + return SUCCESS; +} + +/** + * Implements logger_t-function destroy. + * @see logger_s.destroy. + */ +static status_t destroy(private_logger_t *this) +{ + allocator_free(this->name); + allocator_free(this); + return SUCCESS; +} + +/* + * Described in Header + */ +logger_t *logger_create(char *logger_name, logger_level_t log_level,FILE * output) +{ + private_logger_t *this = allocator_alloc_thing(private_logger_t); + + if (this == NULL) + { + return NULL; + } + + if (logger_name == NULL) + { + logger_name = ""; + } + + this->public.log = (status_t(*)(logger_t*,logger_level_t,char*,...))logg; + this->public.log_bytes = (status_t(*)(logger_t*, logger_level_t, char*,char*,size_t))log_bytes; + this->public.log_chunk = log_chunk; + this->public.enable_level = (status_t(*)(logger_t*,logger_level_t))enable_level; + this->public.disable_level = (status_t(*)(logger_t*,logger_level_t))disable_level; + this->public.destroy = (status_t(*)(logger_t*))destroy; + + this->log_to_file = log_to_file; + + /* private variables */ + this->level = log_level; + this->name = allocator_alloc(strlen(logger_name) + 1); + if (this->name == NULL) + { + allocator_free(this); + return NULL; + } + strcpy(this->name,logger_name); + this->output = output; + + + if (output == NULL) + { + openlog(DEAMON_NAME, 0, LOG_DAEMON); + } + + return (logger_t*)this; +} diff --git a/Source/charon/utils/logger.h b/Source/charon/utils/logger.h new file mode 100644 index 000000000..db6d25d60 --- /dev/null +++ b/Source/charon/utils/logger.h @@ -0,0 +1,154 @@ +/** + * @file logger.h + * + * @brief Logger object, allows fine-controlled logging + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include <stdio.h> +#include "../types.h" + +/** + * Log Levels supported by the logger object + */ +typedef enum logger_level_e logger_level_t; +enum logger_level_e { + /** + * basic control messages + */ + CONTROL = 1, + /** + * detailed control messages + */ + CONTROL_MORE = 2, + /** + * raw data dumps not containing private data + */ + RAW = 4, + /** + * private data dumps + */ + PRIVATE = 8, + /** + * print errors + */ + ERROR = 16, + + /** + * All Lol Levels + */ + ALL = 255 +}; + +/** + * @brief The logger object + */ +typedef struct logger_s logger_t; +struct logger_s { + + /** + * @brief Log an entry, using printf()-like params. + * + * The specefied loglevels must ALL be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of loglevels + * @param format printf like format string + * @param ... printf like parameters + * @return + * - SUCCESS in any case + */ + status_t (*log) (logger_t *this, logger_level_t log_level, char *format, ...); + + /** + * @brief Log some bytes, useful for debugging. + * + * The specefied loglevels must ALL be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of loglevels + * @param label a labeling name, logged with the bytes + * @param bytes pointer to the bytes to dump + * @param len number of bytes to dump + * @return + * - SUCCESS in any case + */ + status_t (*log_bytes) (logger_t *this, logger_level_t loglevel, char *label, char *bytes, size_t len); + + /** + * @brief Log a chunk, useful for debugging. + * + * The specefied loglevels must ALL be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of loglevels + * @param label a labeling name, logged with the bytes + * @param chunk pointer to a chunk to log + * @return + * - SUCCESS in any case + */ + status_t (*log_chunk) (logger_t *this, logger_level_t loglevel, char *label, chunk_t *chunk); + + /** + * @brief Enables a loglevel for the current logger_t object. + * + * @param this logger_t object + * @param log_level loglevel to enable + * @return + * - SUCCESS in any case + */ + status_t (*enable_level) (logger_t *this, logger_level_t log_level); + + /** + * @brief Disables a loglevel for the current logger_t object. + * + * @param this logger_t object + * @param log_level loglevel to enable + * @return + * - SUCCESS in any case + */ + status_t (*disable_level) (logger_t *this, logger_level_t log_level); + + /** + * @brief destroys a logger_t object. + * + * @param this logger_t object + * @return + * - SUCCESS in any case + */ + status_t (*destroy) (logger_t *this); +}; + +/** + * @brief Constructor to create a logger_t object. + * + * @param logger_name Name for the logger_t object + * @param log_level or'ed set of log_levels to assign to the new logger_t object + * @param output FILE * if log has to go on a file output, NULL for syslog + * @return logger_t object or NULL if failed + */ +logger_t *logger_create(char *logger_name, logger_level_t log_level,FILE * output); + + +#endif /*LOGGER_H_*/ diff --git a/Source/charon/utils/logger_manager.c b/Source/charon/utils/logger_manager.c new file mode 100644 index 000000000..22c1059f0 --- /dev/null +++ b/Source/charon/utils/logger_manager.c @@ -0,0 +1,461 @@ +/** + * @file logger_manager.c + * + * @brief Logger manager. Manages globaly all logger objects + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + + +#include "logger_manager.h" + +#include "allocator.h" +#include "linked_list.h" + +/** + * Maximum length of a logger name + */ +#define MAX_LOGGER_NAME 30 + +typedef struct private_logger_manager_s private_logger_manager_t; +struct private_logger_manager_s { + /** + * Public data. + */ + logger_manager_t public; + + /** + * Managed loggers. + */ + linked_list_t *loggers; + + /** + * Log Levels. + */ + linked_list_t *logger_levels; + + /** + * Used to manage logger list. + */ + pthread_mutex_t mutex; + + /** + * Default logger level for a created logger used if no specific logger_level is set + */ + logger_level_t default_log_level; + + /** + * Sets set logger_level of a specific context. + * @param this calling object + * @param context context to set level + * @param logger_level logger_level to set + * @param enable enable specific level or disable it + * @return SUCCESS + */ + status_t (*set_logger_level) (private_logger_manager_t *this, logger_context_t context,logger_level_t logger_level,bool enable); + +}; + +/** + * Entry in the logger_levels linked list + */ +typedef struct logger_levels_entry_s logger_levels_entry_t; + +struct logger_levels_entry_s{ + logger_context_t context; + logger_level_t level; +}; + +/** + * Entry in the loggers linked list + */ +typedef struct loggers_entry_s loggers_entry_t; + +struct loggers_entry_s{ + logger_context_t context; + logger_t *logger; +}; + +/** + * Implements logger_manager_t-function create_logger. + * @see logger_manager_s.create_logger. + */ +static logger_t *create_logger(private_logger_manager_t *this, logger_context_t context, char * name) +{ + + char * context_name; + FILE * output = NULL; + char buffer[MAX_LOGGER_NAME]; + loggers_entry_t *entry; + logger_t *logger; + logger_level_t logger_level = this->public.get_logger_level(&(this->public),context); + + switch(context) + { + case PARSER: + context_name = "PARSER"; + break; + case GENERATOR: + context_name = "GENERATOR"; + break; + case IKE_SA: + context_name = "IKE_SA"; + break; + case MESSAGE: + context_name = "MESSAGE"; + break; + case WORKER_THREAD: + context_name = "WORKER_THREAD"; + break; + case EVENT_THREAD: + context_name = "EVENT_THREAD"; + break; + case SENDER_THREAD: + context_name = "SENDER_THREAD"; + break; + case RECEIVER_THREAD: + context_name = "RECEIVER_THREAD"; + break; + case THREAD_POOL: + context_name = "THREAD_POOL"; + break; + case TESTER: + context_name = "TESTER"; + output = stdout; + break; + default: + context_name = "NO CONTEXT"; + break; + } + + pthread_mutex_lock(&(this->mutex)); + if (name != NULL) + { + snprintf(buffer, MAX_LOGGER_NAME, "%s - %s",context_name,name); + /* create logger with default log_level */ + logger = logger_create(buffer,logger_level,output); + } + else + { + logger = logger_create(context_name,logger_level,output); + } + + + if (logger == NULL) + { + pthread_mutex_unlock(&(this->mutex)); + return NULL; + } + + entry = allocator_alloc_thing(loggers_entry_t); + + if (entry == NULL) + { + logger->destroy(logger); + pthread_mutex_unlock(&(this->mutex)); + return NULL; + } + + entry->context = context; + entry->logger = logger; + + if (this->loggers->insert_last(this->loggers,entry) != SUCCESS) + { + allocator_free(entry); + logger->destroy(logger); + pthread_mutex_unlock(&(this->mutex)); + return NULL; + } + + pthread_mutex_unlock(&(this->mutex)); + return logger; + +} + +static logger_level_t get_logger_level (private_logger_manager_t *this, logger_context_t context) +{ + linked_list_iterator_t *iterator; + logger_level_t logger_level = this->default_log_level; + + pthread_mutex_lock(&(this->mutex)); + + if (this->logger_levels->create_iterator(this->logger_levels,&iterator,TRUE) != SUCCESS) + { + pthread_mutex_unlock(&(this->mutex)); + return logger_level; + } + while (iterator->has_next(iterator)) + { + + logger_levels_entry_t * entry; + if (iterator->current(iterator,(void **)&entry) != SUCCESS) + { + break; + } + if (entry->context == context) + { + logger_level = entry->level; + break; + } + } + + iterator->destroy(iterator); + + pthread_mutex_unlock(&(this->mutex)); + return logger_level; +} + +/** + * Implements logger_manager_t-function destroy_logger. + * @see logger_manager_s.destroy_logger. + */ +static status_t destroy_logger (private_logger_manager_t *this,logger_t *logger) +{ + + linked_list_iterator_t *iterator; + status_t status; + + pthread_mutex_lock(&(this->mutex)); + if (this->loggers->create_iterator(this->loggers,&iterator,TRUE) != SUCCESS) + { + pthread_mutex_unlock(&(this->mutex)); + return OUT_OF_RES; + } + + while (iterator->has_next(iterator)) + { + + loggers_entry_t * entry; + status = iterator->current(iterator,(void **)&entry); + if (status != SUCCESS) + { + break; + } + status = NOT_FOUND; + if (entry->logger == logger) + { + this->loggers->remove(this->loggers,iterator); + allocator_free(entry); + logger->destroy(logger); + status = SUCCESS; + break; + } + } + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + return status; +} + +/** + * Implements private_logger_manager_t-function set_logger_level. + * @see private_logger_manager_s.set_logger_level. + */ +static status_t set_logger_level (private_logger_manager_t *this, logger_context_t context,logger_level_t logger_level,bool enable) +{ + + linked_list_iterator_t *iterator; + status_t status; + + pthread_mutex_lock(&(this->mutex)); + if (this->logger_levels->create_iterator(this->logger_levels,&iterator,TRUE) != SUCCESS) + { + pthread_mutex_unlock(&(this->mutex)); + return OUT_OF_RES; + } + + status = NOT_FOUND; + while (iterator->has_next(iterator)) + { + logger_levels_entry_t * entry; + status = iterator->current(iterator,(void **)&entry); + if (status != SUCCESS) + { + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + return status; + } + status = NOT_FOUND; + if (entry->context == context) + { + if (enable) + { + entry->level |= logger_level; + } + else + { + entry->level &= ~logger_level; + } + + status = SUCCESS; + break; + } + } + iterator->destroy(iterator); + + if (status == NOT_FOUND) + { + + logger_levels_entry_t *entry = allocator_alloc_thing(logger_levels_entry_t); + if (entry == NULL) + { + pthread_mutex_unlock(&(this->mutex)); + return OUT_OF_RES; + } + entry->context = context; + entry->level = (enable) ? logger_level : this->default_log_level; + + status = this->logger_levels->insert_last(this->logger_levels,entry); + if (status != SUCCESS) + { + pthread_mutex_unlock(&(this->mutex)); + return status; + } + } + + if (this->loggers->create_iterator(this->loggers,&iterator,TRUE) != SUCCESS) + { + pthread_mutex_unlock(&(this->mutex)); + return OUT_OF_RES; + } + + while (iterator->has_next(iterator)) + { + + loggers_entry_t * entry; + status = iterator->current(iterator,(void **)&entry); + if (status != SUCCESS) + { + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + return status; + } + if (entry->context == context) + { + if (enable) + { + status = entry->logger->enable_level(entry->logger,logger_level); + } + else + { + status = entry->logger->disable_level(entry->logger,logger_level); + } + + } + } + + iterator->destroy(iterator); + pthread_mutex_unlock(&(this->mutex)); + return SUCCESS; +} + +/** + * Implements logger_manager_t-function enable_logger_level. + * @see logger_manager_s.enable_logger_level. + */ +static status_t enable_logger_level (private_logger_manager_t *this, logger_context_t context,logger_level_t logger_level) +{ + return set_logger_level(this,context,logger_level,TRUE); +} + +/** + * Implements logger_manager_t-function disable_logger_level. + * @see logger_manager_s.disable_logger_level. + */ +static status_t disable_logger_level (private_logger_manager_t *this, logger_context_t context,logger_level_t logger_level) +{ + return set_logger_level(this,context,logger_level,FALSE); +} + +/** + * Implements logger_manager_t-function destroy. + * @see logger_manager_s.destroy. + */ +static status_t destroy(private_logger_manager_t *this) +{ + while (this->loggers->get_count(this->loggers) > 0) + { + loggers_entry_t *current_entry; + + this->loggers->remove_first(this->loggers,(void **)¤t_entry); + + /* destroy logger object */ + current_entry->logger->destroy(current_entry->logger); + + /* entry can be destroyed */ + allocator_free(current_entry); + } + + while (this->logger_levels->get_count(this->logger_levels) > 0) + { + logger_levels_entry_t *current_entry; + + this->logger_levels->remove_first(this->logger_levels,(void **)¤t_entry); + + /* entry can be destroyed */ + allocator_free(current_entry); + } + + this->loggers->destroy(this->loggers); + this->logger_levels->destroy(this->logger_levels); + pthread_mutex_destroy(&(this->mutex)); + + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header + */ +logger_manager_t *logger_manager_create(logger_level_t default_log_level) +{ + private_logger_manager_t *this = allocator_alloc_thing(private_logger_manager_t); + + if (this == NULL) + { + return NULL; + } + + this->public.create_logger = (logger_t *(*)(logger_manager_t*,logger_context_t context, char *))create_logger; + this->public.destroy_logger = (status_t(*)(logger_manager_t*,logger_t *logger))destroy_logger; + this->public.destroy = (status_t(*)(logger_manager_t*))destroy; + this->public.get_logger_level = (logger_level_t (*)(logger_manager_t *, logger_context_t)) get_logger_level; + this->public.enable_logger_level = (status_t (*)(logger_manager_t *, logger_context_t,logger_level_t)) enable_logger_level; + this->public.disable_logger_level = (status_t (*)(logger_manager_t *, logger_context_t,logger_level_t)) disable_logger_level; + this->set_logger_level = (status_t (*)(private_logger_manager_t *, logger_context_t,logger_level_t,bool)) set_logger_level; + + /* private variables */ + this->loggers = linked_list_create(); + + if (this->loggers == NULL) + { + allocator_free(this); + return NULL; + } + this->logger_levels = linked_list_create(); + if (this->logger_levels == NULL) + { + this->loggers->destroy(this->loggers); + allocator_free(this); + return NULL; + } + this->default_log_level = default_log_level; + + pthread_mutex_init(&(this->mutex), NULL); + + return (logger_manager_t*)this; +} + diff --git a/Source/charon/utils/logger_manager.h b/Source/charon/utils/logger_manager.h new file mode 100644 index 000000000..4a2707732 --- /dev/null +++ b/Source/charon/utils/logger_manager.h @@ -0,0 +1,140 @@ +/** + * @file logger_manager.h + * + * @brief Logger manager. Manages globaly all logger objects + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef LOGGER_MANAGER_H_ +#define LOGGER_MANAGER_H_ + +#include <pthread.h> + +#include "logger.h" + +/** + * @brief Context of a specific logger + */ +typedef enum logger_context_e logger_context_t; + +enum logger_context_e{ + PARSER, + GENERATOR, + IKE_SA, + MESSAGE, + THREAD_POOL, + WORKER_THREAD, + EVENT_THREAD, + SENDER_THREAD, + RECEIVER_THREAD, + TESTER, +}; + + +/** + * @brief The logger_manager_t object + */ +typedef struct logger_manager_s logger_manager_t; + +struct logger_manager_s { + + /** + * @brief Gets a logger_t object for a specific logger context. + * + * @warning logger_t objects which are not destroyed over function + * #logger_manager_s.destroy_logger are destroyed in logger_managers + * destroy function. Don't use logger_t's own destroy function with + * managed logger_t objects. + * + * @param this logger_manager_t object + * @param context logger_context to use the logger for. + * @param[out] logger pointer to a a place where the new logger is stored + * @param name name for the new logger. Context name is already included + * and has not to be specified. + * @return + * - logger_t on SUCCESS + * - NULL otherwise + */ + logger_t *(*create_logger) (logger_manager_t *this, logger_context_t context, char *name); + + + /** + * @brief Destroys a logger_t object which is not used anymore + * + * @warning logger_t objects which are not destroyed over function + * #logger_manager_s.destroy_logger are destroyed in logger_managers + * destroy function. + * + * @param this logger_manager_t object + * @param logger pointer to the logger which has to be destroyed + * @return + * - SUCCESS + * - OUT_OF_RES + * - NOT_FOUND + */ + status_t (*destroy_logger) (logger_manager_t *this,logger_t *logger); + + /** + * Returns the set logger_level of a specific context or 0. + * @param this calling object + * @param context context to check level + * @return logger_level for the given logger_context + */ + logger_level_t (*get_logger_level) (logger_manager_t *this, logger_context_t context); + + /** + * Enables a logger_level of a specific context. + * @param this calling object + * @param context context to set level + * @param logger_level logger_level to eanble + * @return SUCCESS + */ + status_t (*enable_logger_level) (logger_manager_t *this, logger_context_t context,logger_level_t logger_level); + + + /** + * Disables a logger_level of a specific context. + * @param this calling object + * @param context context to set level + * @param logger_level logger_level to disable + * @return SUCCESS + */ + status_t (*disable_logger_level) (logger_manager_t *this, logger_context_t context,logger_level_t logger_level); + + + /** + * @brief destroys a logger_manager_t object. + * + * @param this logger_manager_t object + * @return + * - SUCCESS in any case + */ + status_t (*destroy) (logger_manager_t *this); +}; + +/** + * @brief Constructor to create a logger_manager_t object. + * + * @param default_log_level default log level for a context + * @return logger_manager_t object or NULL if failed + * + */ +logger_manager_t *logger_manager_create(logger_level_t default_log_level); + + +#endif /*LOGGER_MANAGER_H_*/ diff --git a/Source/charon/utils/tester.c b/Source/charon/utils/tester.c new file mode 100644 index 000000000..ce2c7fff1 --- /dev/null +++ b/Source/charon/utils/tester.c @@ -0,0 +1,206 @@ +/** + * @file tester.c + * + * @brief Test module for automatic testing + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + + +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <sys/time.h> + +#include "tester.h" + +#include "allocator.h" +#include "linked_list.h" +#include "../queues/job_queue.h" + +/** + * @brief Private Variables and Functions of tester class + * + */ +typedef struct private_tester_s private_tester_t; + +struct private_tester_s { + tester_t public; + + + /* Private functions */ + void (*run_test) (tester_t *tester, void (*test_function) (tester_t * tester), char * test_name); + + + /* Private values */ + FILE* output; + int tests_count; + int failed_tests_count; + int failed_asserts_count; + bool display_succeeded_asserts; + pthread_mutex_t mutex; +}; + +/* + * Implementation of function perform_tests + */ +static status_t perform_tests(tester_t *tester,test_t **tests) +{ + private_tester_t *this =(private_tester_t*) tester; + int current_test = 0; + fprintf(this->output,"\nStart testing...\n\n"); + fprintf(this->output,"_____________________________________________________________________\n"); + fprintf(this->output,"Testname | running time\n"); + fprintf(this->output,"_______________________________________________________|_____________\n"); + + while (tests[current_test] != NULL) + { + this->run_test(tester,tests[current_test]->test_function,tests[current_test]->test_name); + current_test++; + } + fprintf(this->output,"=====================================================================\n"); + fprintf(this->output,"End testing. %d of %d tests succeeded\n",this->tests_count - this->failed_tests_count,this->tests_count); + fprintf(this->output,"=====================================================================\n"); + return SUCCESS; +} + +/* + * Implementation of function perform_test + */ +static status_t perform_test(tester_t *tester, test_t *test) +{ + test_t *tests[] = {test, NULL}; + return (perform_tests(tester,tests)); +} + +/** + * Returns the difference of to timeval structs in microseconds + * + * @param end_time end time + * @param start_time start time + * + * @warning this function is also defined in the event queue + * in later improvements, this function can be added to a general + * class type! + * + * @return difference in microseconds + */ +static long time_difference(struct timeval *end_time, struct timeval *start_time) +{ + long seconds, microseconds; + + seconds = (end_time->tv_sec - start_time->tv_sec); + microseconds = (end_time->tv_usec - start_time->tv_usec); + return ((seconds * 1000000) + microseconds); +} + + +/** + * Implementation of function run_test + */ +static void run_test(tester_t *tester, void (*test_function) (tester_t * tester), char * test_name) +{ + struct timeval start_time, end_time; + long timediff; + private_tester_t *this = (private_tester_t *) tester; + this->tests_count++; + this->failed_asserts_count = 0; + fprintf(this->output,"%-55s", test_name); + gettimeofday(&start_time,NULL); + test_function(tester); + gettimeofday(&end_time,NULL); + timediff = time_difference(&end_time, &start_time); + + if (this->failed_asserts_count > 0) + { + fprintf(this->output,"FAILED: %-47s|%10ld us\n",test_name,timediff); + }else + { + fprintf(this->output,"|%10ld us\n",timediff); + } + if (this->failed_asserts_count > 0) + { + this->failed_tests_count++; + } +} + +/** + * Implementation of function assert_true + */ +static void assert_true(tester_t *tester, bool to_be_true,char * assert_name) +{ + private_tester_t *this = (private_tester_t *) tester; + + if (assert_name == NULL) + { + assert_name = "unknown"; + } + + pthread_mutex_lock(&(this->mutex)); + if (!to_be_true) + { + this->failed_asserts_count++; + fprintf(this->output," check '%s' failed!\n", assert_name); + }else + { + if (this->display_succeeded_asserts) + { + fprintf(this->output," check '%s' succeeded\n", assert_name); + } + } + pthread_mutex_unlock(&(this->mutex)); +} + +/** + * Implementation of function assert_false + */ +static void assert_false(tester_t *tester, bool to_be_false,char * assert_name) +{ + tester->assert_true(tester,(!to_be_false),assert_name); +} + +/** + * Implements the destroy function + */ +static status_t destroy(tester_t *tester) +{ + private_tester_t *this = (private_tester_t*) tester; + pthread_mutex_destroy(&(this->mutex)); + allocator_free(this); + return SUCCESS; +} + +tester_t *tester_create(FILE *output, bool display_succeeded_asserts) +{ + private_tester_t *this = allocator_alloc_thing(private_tester_t); + + this->public.destroy = destroy; + this->public.perform_tests = perform_tests; + this->public.perform_test = perform_test; + this->public.assert_true = assert_true; + this->public.assert_false = assert_false; + + + this->run_test = run_test; + this->display_succeeded_asserts = display_succeeded_asserts; + this->failed_tests_count = 0; + this->tests_count = 0; + this->output = output; + pthread_mutex_init(&(this->mutex),NULL); + + return &(this->public); +} diff --git a/Source/charon/utils/tester.h b/Source/charon/utils/tester.h new file mode 100644 index 000000000..69b7de002 --- /dev/null +++ b/Source/charon/utils/tester.h @@ -0,0 +1,114 @@ +/** + * @file tester.h + * + * @brief Test module for automatic testing + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef TESTER_H_ +#define TESTER_H_ + +#include <stdio.h> + +#include "../types.h" + + + +/** + * @brief Specifies a test + */ +typedef struct test_s test_t; + +/** + * @brief A tester object to perform tests with + */ +typedef struct tester_s tester_t; + +struct test_s{ + void (*test_function) (tester_t * tester); + char * test_name; +}; + +struct tester_s { + + /** + * @brief Tests all testcases in array tests with specific tester object + * + * @param tester tester object + * @param pointer to a array of test_t-pointers. + * the last item has to be NULL. + * @return SUCCESSFUL if succeeded, FAILED otherwise + */ + status_t (*perform_tests) (tester_t *tester,test_t **tests); + + /** + * @brief run a specific test case + * + * @param this tester object + * @param test pointer to a test_t object which will be performed + * @param Name of the Test + */ + status_t (*perform_test) (tester_t *tester, test_t *test); + + /** + * @brief is called in a testcase to check a specific situation for TRUE + * + * Log-Values to the tester output are protected from multiple access + * + * @warning this function should only be called in a test_function + * + * @param this tester object + * @param to_be_true assert which has to be TRUE + * @param Name of the assertion + */ + void (*assert_true) (tester_t *tester, bool to_be_true, char *assert_name); + + /** + * @brief is called in a testcase to check a specific situation for FALSE + * + * Log-Values to the tester output are protected from multiple access + * + * @warning this function should only be called in a test_function + * + * @param this tester object + * @param to_be_false assert which has to be FALSE + * @param Name of the assertion + */ + void (*assert_false) (tester_t *tester, bool to_be_false, char *assert_name); + + /** + * @brief Destroys a tester object + * + * @param tester tester object + * @return SUCCESSFUL if succeeded, FAILED otherwise + */ + status_t (*destroy) (tester_t *tester); +}; + +/** + * @brief creates a tester object needed to perform tests + * + * @param output test output is written to this output + * @param display_succeeded_asserts has to be TRUE, if all asserts should be displayed, + * else otherwise + * + * @return tester object + */ +tester_t *tester_create(FILE *output, bool display_succeeded_asserts); + +#endif /*TESTER_H_*/ |