aboutsummaryrefslogtreecommitdiffstats
path: root/Source/charon/utils
diff options
context:
space:
mode:
Diffstat (limited to 'Source/charon/utils')
-rw-r--r--Source/charon/utils/allocator.c347
-rw-r--r--Source/charon/utils/allocator.h223
-rw-r--r--Source/charon/utils/linked_list.c2
-rw-r--r--Source/charon/utils/logger.c284
-rw-r--r--Source/charon/utils/logger.h154
-rw-r--r--Source/charon/utils/logger_manager.c461
-rw-r--r--Source/charon/utils/logger_manager.h140
-rw-r--r--Source/charon/utils/tester.c206
-rw-r--r--Source/charon/utils/tester.h114
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 **)&current_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 **)&current_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_*/