diff options
Diffstat (limited to 'Source/lib/utils')
-rw-r--r-- | Source/lib/utils/Makefile.utils | 48 | ||||
-rw-r--r-- | Source/lib/utils/allocator.c | 445 | ||||
-rw-r--r-- | Source/lib/utils/allocator.h | 324 | ||||
-rw-r--r-- | Source/lib/utils/host.c | 365 | ||||
-rw-r--r-- | Source/lib/utils/host.h | 225 | ||||
-rw-r--r-- | Source/lib/utils/identification.c | 291 | ||||
-rw-r--r-- | Source/lib/utils/identification.h | 211 | ||||
-rw-r--r-- | Source/lib/utils/iterator.h | 153 | ||||
-rw-r--r-- | Source/lib/utils/linked_list.c | 729 | ||||
-rw-r--r-- | Source/lib/utils/linked_list.h | 203 | ||||
-rw-r--r-- | Source/lib/utils/logger.c | 360 | ||||
-rw-r--r-- | Source/lib/utils/logger.h | 199 | ||||
-rw-r--r-- | Source/lib/utils/logger_manager.c | 212 | ||||
-rw-r--r-- | Source/lib/utils/logger_manager.h | 155 | ||||
-rw-r--r-- | Source/lib/utils/randomizer.c | 165 | ||||
-rw-r--r-- | Source/lib/utils/randomizer.h | 110 | ||||
-rw-r--r-- | Source/lib/utils/tester.c | 257 | ||||
-rw-r--r-- | Source/lib/utils/tester.h | 148 |
18 files changed, 4600 insertions, 0 deletions
diff --git a/Source/lib/utils/Makefile.utils b/Source/lib/utils/Makefile.utils new file mode 100644 index 000000000..ab513ff7a --- /dev/null +++ b/Source/lib/utils/Makefile.utils @@ -0,0 +1,48 @@ +# 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. +# + +UTILS_DIR= $(LIB_DIR)utils/ + + +LIB_OBJS+= $(BUILD_DIR)allocator.o +$(BUILD_DIR)allocator.o : $(UTILS_DIR)allocator.c $(UTILS_DIR)allocator.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)linked_list.o +$(BUILD_DIR)linked_list.o : $(UTILS_DIR)linked_list.c $(UTILS_DIR)linked_list.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)logger.o +$(BUILD_DIR)logger.o : $(UTILS_DIR)logger.c $(UTILS_DIR)logger.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)logger_manager.o +$(BUILD_DIR)logger_manager.o : $(UTILS_DIR)logger_manager.c $(UTILS_DIR)logger_manager.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)randomizer.o +$(BUILD_DIR)randomizer.o : $(UTILS_DIR)randomizer.c $(UTILS_DIR)randomizer.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)tester.o +$(BUILD_DIR)tester.o : $(UTILS_DIR)tester.c $(UTILS_DIR)tester.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)identification.o +$(BUILD_DIR)identification.o : $(UTILS_DIR)identification.c $(UTILS_DIR)identification.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)host.o +$(BUILD_DIR)host.o : $(UTILS_DIR)host.c $(UTILS_DIR)host.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/Source/lib/utils/allocator.c b/Source/lib/utils/allocator.c new file mode 100644 index 000000000..0ed197c62 --- /dev/null +++ b/Source/lib/utils/allocator.c @@ -0,0 +1,445 @@ +/** + * @file allocator.c + * + * @brief Implementation of allocator_t. + */ + +/* + * 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 <gmp.h> + +#include "allocator.h" + + +#ifdef LEAK_DETECTIVE + +typedef union memory_hdr_t memory_hdr_t; + +/** + * @brief Header of each allocated memory area. + * + * Ideas stolen from pluto's defs.c. + * + * Used to detect memory leaks. + */ +union memory_hdr_t { + /** + * Informations. + */ + 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; + /** + * Force maximal alignment ? + * + */ + unsigned long junk; +}; + +typedef struct private_allocator_t private_allocator_t; + +/** + * @brief Private allocator_t object. + * + * Contains private variables of allocator_t object. + */ +struct private_allocator_t +{ + /** + * 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; + + /** + * Number of allocations done + */ + u_int32_t allocs; + + /** + * Number of frees done + */ + u_int32_t frees; + + /** + * 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 + */ + void * (*allocate_special) (private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex); +}; + +/** + * Implementation of private_allocator_t.allocate_special. + */ +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); + + this->allocs++; + + if (allocated_memory == NULL) + { + /* TODO LOG this case */ + exit(-1); + } + + 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); +} + +/** + * Implementation of allocator_t.allocate. + */ +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)); +} + +/** + * Implementation of allocator_t.allocate_as_chunk. + */ +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; +} + +/** + * Implementation of allocator_t.free_pointer. + */ +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; + } + this->frees++; + 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); +} + +/** + * Implementation of allocator_t.reallocate. + */ +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; + + + pthread_mutex_lock( &(this->mutex)); + allocated_memory = ((memory_hdr_t *)old) - 1; + + void *new_space = this->allocate_special(this,bytes,file,line,FALSE); + + if (old != 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; +} + +/** + * Implementation of allocator_t.clone_bytes. + */ +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; +} + +/** + * Implementation of allocator_t.clone_chunk. + */ +static chunk_t clone_chunk(allocator_t *allocator, chunk_t chunk, char * file, int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + chunk_t clone = CHUNK_INITIALIZER; + + if (chunk.ptr && chunk.len > 0) + { + clone.ptr = this->allocate_special(this,chunk.len,file,line,TRUE); + clone.len = chunk.len; + memcpy(clone.ptr, chunk.ptr, chunk.len); + } + + return clone; +} + +/** + * Implementation of allocator_t.allocator_report_memory_leaks. + */ +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 * %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)); + fprintf(stderr, "Allocator statistics: %d allocs, %d frees\n", this->allocs, this->frees); +} + +/** + * 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, + clone_chunk : clone_chunk, + report_memory_leaks: allocator_report_memory_leaks}, + allocations: NULL, + allocate_special : allocate_special, + mutex: PTHREAD_MUTEX_INITIALIZER, + allocs: 0, + frees: 0 +}; + + +allocator_t *global_allocator = &(allocator.public); + +/* + * Alloc function for gmp. + */ +void *gmp_alloc(size_t bytes) +{ + return allocator.allocate_special(&allocator, bytes, "[ gmp internal ]", 0 , TRUE); +} + +/* + * Realloc function for gmp. + */ +void *gmp_realloc(void *old, size_t old_bytes, size_t new_bytes) +{ + return global_allocator->reallocate(global_allocator, old, new_bytes, "[ gmp internal ]", 0); +} +/* + * Free function for gmp. + */ +void gmp_free(void *ptr, size_t bytes) +{ + free_pointer(global_allocator, ptr); +} + +/* + * Described in header + */ +void allocator_init() +{ + mp_set_memory_functions (gmp_alloc, gmp_realloc, gmp_free); +} + +#else /* !LEAK_DETECTION */ + +/* + * Described in header. + */ +chunk_t allocator_alloc_as_chunk(size_t bytes) +{ + chunk_t new_chunk; + new_chunk.ptr = malloc(bytes); + if (new_chunk.ptr == NULL) + { + exit(-1); + } + new_chunk.len = bytes; + return new_chunk; + +} + +/* + * Described in header. + */ +void * allocator_realloc(void * old, size_t newsize) +{ + void *data = realloc(old,newsize); + return data; +} + +/* + * Described in header. + */ +void * allocator_clone_bytes(void * pointer, size_t size) +{ + + void *data; + data = malloc(size); + + if (data == NULL){exit(-1);} + memmove(data,pointer,size); + + return (data); +} + +/** + * Described in header. + */ +chunk_t allocator_clone_chunk(chunk_t chunk) +{ + chunk_t clone = CHUNK_INITIALIZER; + + if (chunk.ptr && chunk.len > 0) + { + clone.ptr = malloc(chunk.len); + if (clone.ptr == NULL) {exit(-1);} + clone.len = chunk.len; + memcpy(clone.ptr, chunk.ptr, chunk.len); + } + + return clone; +} + +/* + * Described in header. + */ +void allocator_free_chunk(chunk_t *chunk) +{ + free(chunk->ptr); + chunk->ptr = NULL; + chunk->len = 0; +} + +#endif /* LEAK_DETECTION */ diff --git a/Source/lib/utils/allocator.h b/Source/lib/utils/allocator.h new file mode 100644 index 000000000..5b00496f6 --- /dev/null +++ b/Source/lib/utils/allocator.h @@ -0,0 +1,324 @@ +/** + * @file allocator.h + * + * @brief Interface of allocator_t. + */ + +/* + * 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 + * + * @ingroup utils + */ +#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 + * + * @ingroup utils + */ +#define allocator_alloc_thing(thing) (allocator_alloc(sizeof(thing))) + +#ifdef LEAK_DETECTIVE + + typedef struct allocator_t allocator_t; + + /** + *@brief Allocater object use to detect memory leaks. + * + * @ingroup utils + */ + struct allocator_t { + + /** + * 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 + */ + 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 + */ + 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 + */ + 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 + */ + void * (*clone_bytes) (allocator_t *this,void * to_clone, size_t bytes, char * file, int line); + + /** + * Clones a chunk with LEAK_DETECTION and returns a cloned chunk. + * + * @warning Use this function not directly, only with assigned macro + * #allocator_clone_chunk- + * + * @param this allocator_t object + * @param chunk chunk to clone + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @return pointer to reallocated memory + */ + chunk_t (*clone_chunk) (allocator_t *this, chunk_t chunk, 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 Initialize the allocator. + * + * Setup the allocator (set allocation functions for libgmp) + */ + void allocator_init(); + + /** + * @brief Global allocater_t object. + * + * Only accessed over macros. + */ + extern allocator_t *global_allocator; + + + /** + * Macro to allocate some memory. + * + * See #allocator_t.allocate for description. + * + * @ingroup utils + */ + #define allocator_alloc(bytes) (global_allocator->allocate(global_allocator,bytes,__FILE__,__LINE__)) + + /** + * Macro to allocate some memory for a chunk_t. + * + * See #allocator_t.allocate_as_chunk for description. + * + * @ingroup utils + */ + #define allocator_alloc_as_chunk(bytes) (global_allocator->allocate_as_chunk(global_allocator,bytes,__FILE__,__LINE__)) + + /** + * Macro to reallocate some memory. + * + * See #allocator_t.reallocate for description. + * + * @ingroup utils + */ + #define allocator_realloc(old,bytes) (global_allocator->reallocate(global_allocator,old,bytes,__FILE__, __LINE__)) + + /** + * Macro to clone some memory. + * + * See #allocator_t.*clone_bytes for description. + * + * @ingroup utils + */ + #define allocator_clone_bytes(old,bytes) (global_allocator->clone_bytes(global_allocator,old,bytes,__FILE__, __LINE__)) + + /** + * Macro to clone a chunk and its contents + * + * See #allocator_t.clone_chunk for description. + * + * @ingroup utils + */ + #define allocator_clone_chunk(chunk) (global_allocator->clone_chunk(global_allocator,chunk,__FILE__, __LINE__)) + + /** + * Macro to free some memory. + * + * See #allocator_t.free_pointer for description. + * + * @ingroup utils + */ + #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. + * + * @ingroup utils + */ + #define report_memory_leaks(void) (global_allocator->report_memory_leaks(global_allocator)) +#else + + /** + * Macro to allocate some memory. + * + * @ingroup utils + */ + #define allocator_alloc(bytes) (malloc(bytes)) + + /** + * Allocate some memory as chunk. + * + * @ingroup utils + */ + chunk_t allocator_alloc_as_chunk(size_t bytes); + + /** + * Reallocate some memory. + * + * @ingroup utils + */ + void * allocator_realloc(void * old, size_t newsize); + + /** + * Free allocated memory. + * + * @ingroup utils + */ + #define allocator_free(pointer) (free(pointer)) + + /** + * Clone bytes. + * + * + * @param pointer pointer to read data from + * @param size number of bytes to clone + * + * @ingroup utils + */ + void * allocator_clone_bytes(void * pointer, size_t size); + + /** + * Clone a chunk and its contents. + * + * + * @param chunk chunk to clone + * @return cloned chunk + * + * @ingroup utils + */ + chunk_t allocator_clone_chunk(chunk_t chunk); + + /** + * Frees memory used by chunk. + * + * @param chunk pointer of chunk to free + * + * @ingroup utils + */ + void allocator_free_chunk(chunk_t *chunk); + + /** + * Report memory leaks. + * + * @ingroup utils + */ + #define report_memory_leaks() {} + + /** + * Initialize the allocator. + * + * @ingroup utils + */ + #define allocator_init() {} +#endif + +#endif /*ALLOCATOR_H_*/ diff --git a/Source/lib/utils/host.c b/Source/lib/utils/host.c new file mode 100644 index 000000000..245df8b05 --- /dev/null +++ b/Source/lib/utils/host.c @@ -0,0 +1,365 @@ +/** + * @file host.c + * + * @brief Implementation of host_t. + * + */ + +/* + * 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 "host.h" + +#include <utils/allocator.h> + + +typedef struct private_host_t private_host_t; + +/** + * @brief Private Data of a host object. + */ +struct private_host_t { + /** + * Public data + */ + host_t public; + + /** + * Address family to use, such as AF_INET or AF_INET6 + */ + int family; + + /** + * string representation of host + */ + char *string; + + /** + * low-lewel structure, wich stores the address + */ + union { + struct sockaddr address; + struct sockaddr_in address4; + }; + /** + * length of address structure + */ + socklen_t socklen; +}; + + +/** + * implements host_t.get_sockaddr + */ +static sockaddr_t *get_sockaddr(private_host_t *this) +{ + return &(this->address); +} + +/** + * implements host_t.get_sockaddr_len + */ +static socklen_t *get_sockaddr_len(private_host_t *this) +{ + return &(this->socklen); +} + +/** + * Implementation of host_t.is_default_route. + */ +static bool is_default_route (private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + static u_int8_t default_route[4] = {0x00,0x00,0x00,0x00}; + + if (memcmp(default_route,&(this->address4.sin_addr.s_addr),4) == 0) + { + return TRUE; + } + return FALSE; + } + default: + { + /* empty chunk is returned */ + return FALSE; + } + } +} + +/** + * implements host_t.get_address + */ +static char *get_address(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + char *string; + /* we need to clone it, since inet_ntoa overwrites + * internal buffer on subsequent calls + */ + allocator_free(this->string); + string = inet_ntoa(this->address4.sin_addr); + this->string = allocator_alloc(strlen(string)+1); + strcpy(this->string, string); + return this->string; + } + default: + { + return "(family not supported)"; + } + } +} + +/** + * Implementation of host_t.get_address_as_chunk. + */ +static chunk_t get_address_as_chunk(private_host_t *this) +{ + chunk_t address = CHUNK_INITIALIZER; + + switch (this->family) + { + case AF_INET: + { + /* allocate 4 bytes for IPV4 address*/ + address.ptr = allocator_alloc(4); + address.len = 4; + memcpy(address.ptr,&(this->address4.sin_addr.s_addr),4); + } + default: + { + /* empty chunk is returned */ + return address; + } + } +} + +static xfrm_address_t get_xfrm_addr(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + return (xfrm_address_t)(this->address4.sin_addr.s_addr); + } + default: + { + /* todo */ + return (xfrm_address_t)(this->address4.sin_addr.s_addr); + } + } +} + +static int get_family(private_host_t *this) +{ + return this->family; +} + +/** + * implements host_t.get_port + */ +static u_int16_t get_port(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + return ntohs(this->address4.sin_port); + } + default: + { + return 0; + } + } +} + + +/** + * Implements host_t.clone. + */ +static private_host_t *clone(private_host_t *this) +{ + private_host_t *new = allocator_alloc_thing(private_host_t); + + + memcpy(new, this, sizeof(private_host_t)); + if (this->string) + { + new->string = allocator_alloc(strlen(this->string)+1); + strcpy(new->string, this->string); + } + return new; +} + +/** + * Impelements host_t.ip_equals + */ +static bool ip_equals(private_host_t *this, private_host_t *other) +{ + switch (this->family) + { + /* IPv4 */ + case AF_INET: + { + if ((this->address4.sin_family == other->address4.sin_family) && + (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr)) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Impelements host_t.equals + */ +static bool equals(private_host_t *this, private_host_t *other) +{ + switch (this->family) + { + /* IPv4 */ + case AF_INET: + { + if ((this->address4.sin_family == other->address4.sin_family) && + (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr) && + (this->address4.sin_port == other->address4.sin_port)) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Implements host_t.destroy + */ +static void destroy(private_host_t *this) +{ + allocator_free(this->string); + allocator_free(this); +} + +/** + * Creates an empty host_t object + */ +static private_host_t *host_create_empty() +{ + private_host_t *this = allocator_alloc_thing(private_host_t); + + this->public.get_sockaddr = (sockaddr_t* (*) (host_t*))get_sockaddr; + this->public.get_sockaddr_len = (socklen_t*(*) (host_t*))get_sockaddr_len; + this->public.clone = (host_t* (*) (host_t*))clone; + this->public.get_family = (int (*) (host_t*))get_family; + this->public.get_xfrm_addr = (xfrm_address_t (*) (host_t *))get_xfrm_addr; + this->public.get_address = (char* (*) (host_t *))get_address; + this->public.get_address_as_chunk = (chunk_t (*) (host_t *)) get_address_as_chunk; + this->public.get_port = (u_int16_t (*) (host_t *))get_port; + this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals; + this->public.equals = (bool (*) (host_t *,host_t *)) equals; + this->public.is_default_route = (bool (*) (host_t *)) is_default_route; + this->public.destroy = (void (*) (host_t*))destroy; + + this->string = NULL; + + return this; +} + +/* + * Described in header. + */ +host_t *host_create(int family, char *address, u_int16_t port) +{ + private_host_t *this = host_create_empty(); + + this->family = family; + + switch (family) + { + /* IPv4 */ + case AF_INET: + { + this->address4.sin_family = AF_INET; + this->address4.sin_addr.s_addr = inet_addr(address); + this->address4.sin_port = htons(port); + this->socklen = sizeof(struct sockaddr_in); + return &(this->public); + } + default: + { + allocator_free(this); + return NULL; + + } + } + +} + +/* + * Described in header. + */ +host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) +{ + private_host_t *this = host_create_empty(); + + this->family = family; + switch (family) + { + /* IPv4 */ + case AF_INET: + { + if (address.len != 4) + { + break; + } + this->address4.sin_family = AF_INET; + memcpy(&(this->address4.sin_addr.s_addr),address.ptr,4); + this->address4.sin_port = htons(port); + this->socklen = sizeof(struct sockaddr_in); + return &(this->public); + } + } + allocator_free(this); + return NULL; +} + +/* + * Described in header. + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr) +{ + chunk_t address; + + switch (sockaddr->sa_family) + { + /* IPv4 */ + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr; + address.ptr = (void*)&(sin->sin_addr.s_addr); + address.len = 4; + return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port)); + } + default: + return NULL; + } +} + diff --git a/Source/lib/utils/host.h b/Source/lib/utils/host.h new file mode 100644 index 000000000..d81efffa6 --- /dev/null +++ b/Source/lib/utils/host.h @@ -0,0 +1,225 @@ +/** + * @file host.h + * + * @brief Interface of host_t. + * + */ + +/* + * 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 HOST_H_ +#define HOST_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <linux/xfrm.h> + +#include <types.h> + + +typedef struct host_t host_t; + +/** + * @brief Representates a Host + * + * Host object, identifies a address:port pair and defines some + * useful functions on it. + * + * @b Constructors: + * - host_create() + * - host_create_from_chunk() + * - host_create_from_sockaddr() + * + * @todo Add IPv6 support + * + * @ingroup network + */ +struct host_t { + + /** + * @brief Build a clone of this host object. + * + * @param this object to clone + * @return cloned host + */ + host_t *(*clone) (host_t *this); + + /** + * @brief Get a pointer to the internal sockaddr struct. + * + * This is used for sending and receiving via sockets. + * + * @param this object to clone + * @return pointer to the internal sockaddr structure + */ + sockaddr_t *(*get_sockaddr) (host_t *this); + + /** + * @brief Get the length of the sockaddr struct. + * + * Sepending on the family, the length of the sockaddr struct + * is different. Use this function to get the length of the sockaddr + * struct returned by get_sock_addr. + * + * This is used for sending and receiving via sockets. + * + * @param this object to clone + * @return length of the sockaddr struct + */ + socklen_t *(*get_sockaddr_len) (host_t *this); + + /** + * @brief Gets the address as xfrm_address_t. + * + * This function allows the conversion to an + * xfrm_address_t, used for netlink communication + * with the kernel. + * + * @see kernel_interface_t. + * + * @param this calling object + * @return address in xfrm_address_t format + */ + xfrm_address_t (*get_xfrm_addr) (host_t *this); + + /** + * @brief Gets the family of the address + * + * @param this calling object + * @return family + */ + int (*get_family) (host_t *this); + + /** + * @brief get the address of this host + * + * Mostly used for debugging purposes. + * @warning string must NOT be freed + * + * @param this object + * @return address string, + */ + char* (*get_address) (host_t *this); + + /** + * @brief Checks if the ip address of host is set to default route. + * + * @param this calling object + * @return + * - TRUE if host has IP 0.0.0.0 for default route + * - FALSE otherwise + */ + bool (*is_default_route) (host_t *this); + + /** + * @brief get the address of this host as chunk_t + * + * @warning returned chunk has to get destroyed by caller. + * + * @param this object + * @return address string, + */ + chunk_t (*get_address_as_chunk) (host_t *this); + + /** + * @brief get the port of this host + * + * Mostly used for debugging purposes. + * + * @param this object to clone + * @return port number + */ + u_int16_t (*get_port) (host_t *this); + + /** + * @brief Compare the ips of two hosts hosts. + * + * @param this object to compare + * @param other the other to compare + * @return TRUE if addresses are equal. + */ + bool (*ip_equals) (host_t *this, host_t *other); + + /** + * @brief Compare two hosts, with port. + * + * @param this object to compare + * @param other the other to compare + * @return TRUE if addresses and ports are equal. + */ + bool (*equals) (host_t *this, host_t *other); + + /** + * @brief Destroy this host object + * + * @param this calling + * @return SUCCESS in any case + */ + void (*destroy) (host_t *this); +}; + +/** + * @brief Constructor to create a host_t object from an address string + * + * Currently supports only IPv4! + * + * @param family Address family to use for this object, such as AF_INET or AF_INET6 + * @param address string of an address, such as "152.96.193.130" + * @param port port number + * @return + * - host_t object + * - NULL, if family not supported. + * + * @ingroup network + */ +host_t *host_create(int family, char *address, u_int16_t port); + +/** + * @brief Constructor to create a host_t object from an address chunk + * + * Currently supports only IPv4! + * + * @param family Address family to use for this object, such as AF_INET or AF_INET6 + * @param address address as 4 byte chunk_t in networ order + * @param port port number + * @return + * - host_t object + * - NULL, if family not supported or chunk_t length not 4 bytes. + * + * @ingroup network + */ +host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); + +/** + * @brief Constructor to create a host_t object from a sockaddr struct + * + * Currently supports only IPv4! + * + * @param sockaddr sockaddr struct which contains family, address and port + * @return + * - host_t object + * - NULL, if family not supported. + * + * @ingroup network + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); + + +#endif /*HOST_H_*/ diff --git a/Source/lib/utils/identification.c b/Source/lib/utils/identification.c new file mode 100644 index 000000000..72d1610af --- /dev/null +++ b/Source/lib/utils/identification.c @@ -0,0 +1,291 @@ +/** + * @file identification.c + * + * @brief Implementation of identification_t. + * + */ + +/* + * 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 <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "identification.h" + +#include <utils/allocator.h> + +/** + * String mappings for id_type_t. + */ +mapping_t id_type_m[] = { + {ID_IPV4_ADDR, "ID_IPV4_ADDR"}, + {ID_FQDN, "ID_FQDN"}, + {ID_RFC822_ADDR, "ID_RFC822_ADDR"}, + {ID_IPV6_ADDR, "ID_IPV6_ADDR"}, + {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"}, + {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"}, + {ID_KEY_ID, "ID_KEY_ID"}, + {MAPPING_END, NULL} +}; + + +typedef struct private_identification_t private_identification_t; + +/** + * Private data of an identification_t object. + */ +struct private_identification_t { + /** + * Public interface. + */ + identification_t public; + + /** + * String representation of this ID. + */ + char *string; + + /** + * Encoded representation of this ID. + */ + chunk_t encoded; + + /** + * Type of this ID. + */ + id_type_t type; +}; + +static private_identification_t *identification_create(); + +/** + * Implementation of identification_t.get_encoding. + */ +static chunk_t get_encoding(private_identification_t *this) +{ + return this->encoded; +} + +/** + * Implementation of identification_t.get_type. + */ +static id_type_t get_type(private_identification_t *this) +{ + return this->type; +} + +/** + * Implementation of identification_t.get_string. + */ +static char *get_string(private_identification_t *this) +{ + return this->string; +} + +/** + * Implementation of identification_t.equals. + */ +static bool equals (private_identification_t *this,private_identification_t *other) +{ + if (this->type == other->type) + { + if (this->encoded.len != other->encoded.len) + { + return FALSE; + } + if (memcmp(this->encoded.ptr,other->encoded.ptr,this->encoded.len) == 0) + { + return TRUE; + } + } + return FALSE; +} + +/** + * Implementation of identification_t.belongs_to. + */ +static bool belongs_to(private_identification_t *this, private_identification_t *other) +{ + if (this->public.equals(&this->public, &other->public)) + { + return TRUE; + } + + if (this->type == other->type && this->type == ID_IPV4_ADDR) + { + /* is this %any (0.0.0.0)?*/ + if (*((u_int32_t*)this->encoded.ptr) == 0) + { + return TRUE; + } + /* TODO: Do we need subnet support? */ + } + return FALSE; +} + +/** + * Implementation of identification_t.clone. + */ +static identification_t *clone(private_identification_t *this) +{ + private_identification_t *clone = identification_create(); + + clone->type = this->type; + clone->encoded = allocator_clone_chunk(this->encoded); + clone->string = allocator_alloc(strlen(this->string) + 1); + strcpy(clone->string, this->string); + + return &clone->public; +} + +/** + * Implementation of identification_t.destroy. + */ +static void destroy(private_identification_t *this) +{ + allocator_free(this->string); + allocator_free(this->encoded.ptr); + allocator_free(this); +} + +/* + * Generic constructor used for the other constructors. + * + * @return private_identification_t object + */ +static private_identification_t *identification_create() +{ + private_identification_t *this = allocator_alloc_thing(private_identification_t); + + this->public.equals = (bool (*) (identification_t*,identification_t*))equals; + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to; + this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding; + this->public.get_type = (id_type_t (*) (identification_t*))get_type; + this->public.get_string = (char* (*) (identification_t*))get_string; + this->public.clone = (identification_t* (*) (identification_t*))clone; + this->public.destroy = (void (*) (identification_t*))destroy; + + this->string = NULL; + this->encoded = CHUNK_INITIALIZER; + + return this; +} + + +/* + * Described in header. + */ +identification_t *identification_create_from_string(id_type_t type, char *string) +{ + private_identification_t *this = identification_create(); + + this->type = type; + switch (type) + { + case ID_IPV4_ADDR: + { + /* convert string */ + this->encoded.len = 4; + this->encoded.ptr = allocator_alloc(this->encoded.len); + if (inet_aton(string, ((struct in_addr*)(this->encoded.ptr))) == 0) + { + allocator_free(this->encoded.ptr); + allocator_free(this); + return NULL; + } + /* clone string */ + this->string = allocator_alloc(strlen(string)+1); + strcpy(this->string, string); + return &(this->public); + } + case ID_IPV6_ADDR: + case ID_FQDN: + case ID_RFC822_ADDR: + case ID_DER_ASN1_DN: + case ID_DER_ASN1_GN: + case ID_KEY_ID: + default: + { + /* not supported */ + allocator_free(this); + return NULL; + } + } +} + +/* + * Described in header. + */ +identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded) +{ + char *string; + private_identification_t *this = identification_create(); + + this->encoded = allocator_clone_chunk(encoded); + + this->type = type; + switch (type) + { + case ID_IPV4_ADDR: + { + string = inet_ntoa(*((struct in_addr*)(encoded.ptr))); + break; + } + case ID_IPV6_ADDR: + { + string = "[ID_IPV6_ADDR]"; + break; + } + case ID_FQDN: + { + string = "[ID_FQDN]"; + break; + } + case ID_RFC822_ADDR: + { + string = "[ID_RFC822_ADDR]"; + break; + } + case ID_DER_ASN1_DN: + { + string = "[ID_DER_ASN1_DN]"; + break; + } + case ID_DER_ASN1_GN: + { + string = "[ID_DER_ASN1_GN]"; + break; + } + case ID_KEY_ID: + { + string = "[ID_KEY_ID]"; + break; + } + default: + { + string = "[unknown id_type_t]"; + } + } + + /* build string, must be cloned since + * inet_ntoa points to a subsequently + * overwritten buffer */ + this->string = allocator_alloc(strlen(string)+1); + strcpy(this->string, string); + + return &(this->public); +} diff --git a/Source/lib/utils/identification.h b/Source/lib/utils/identification.h new file mode 100644 index 000000000..b973da9a4 --- /dev/null +++ b/Source/lib/utils/identification.h @@ -0,0 +1,211 @@ +/** + * @file identification.h + * + * @brief Interface of identification_t. + * + */ + +/* + * 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 IDENTIFICATION_H_ +#define IDENTIFICATION_H_ + + +#include "types.h" + +typedef enum id_type_t id_type_t; + +/** + * @brief ID Types in a ID payload. + * + * @see + * - identification_t + * - id_payload_t + * + * @ingroup utils + */ +enum id_type_t { + + /** + * ID data is a single four (4) octet IPv4 address. + */ + ID_IPV4_ADDR = 1, + + /** + * ID data is a fully-qualified domain name string. + * An example of a ID_FQDN is, "example.com". + * The string MUST not contain any terminators (e.g., NULL, CR, etc.). + */ + ID_FQDN = 2, + + /** + * ID data is a fully-qualified RFC822 email address string, An example of + * a ID_RFC822_ADDR is, "jsmith@example.com". The string MUST + * not contain any terminators. + */ + ID_RFC822_ADDR = 3, + + /** + * ID data is a single sixteen (16) octet IPv6 address. + */ + ID_IPV6_ADDR = 5, + + /** + * ID data is the binary DER encoding of an ASN.1 X.500 Distinguished Name + * [X.501]. + */ + ID_DER_ASN1_DN = 9, + + /** + * ID data is the binary DER encoding of an ASN.1 X.500 GeneralName + * [X.509]. + */ + ID_DER_ASN1_GN = 10, + + /** + * ID data is an opaque octet stream which may be used to pass vendor- + * specific information necessary to do certain proprietary + * types of identification. + */ + ID_KEY_ID = 11 +}; + +/** + * String mappings for id_type_t. + */ +extern mapping_t id_type_m[]; + +typedef struct identification_t identification_t; + +/** + * @brief Generic identification, such as used in ID payload. + * + * The following types are possible: + * - ID_IPV4_ADDR + * - ID_FQDN* + * - ID_RFC822_ADDR* + * - ID_IPV6_ADDR* + * - ID_DER_ASN1_DN* + * - ID_DER_ASN1_GN* + * - ID_KEY_ID* + * (* = string conversion not supported) + * + * @b Constructors: + * - identification_create_from_string() + * - identification_create_from_encoding() + * + * @todo Support for other ID types then ID_IPV4_ADDR. + * + * @ingroup utils + */ +struct identification_t { + + /** + * @brief Get the encoding of this id, to send over + * the network. + * + * @warning Result points to internal data, do NOT free! + * + * @param this the identification_t object + * @return a chunk containing the encoded bytes + */ + chunk_t (*get_encoding) (identification_t *this); + + /** + * @brief Get the type of this identification. + * + * @param this the identification_t object + * @return id_type_t + */ + id_type_t (*get_type) (identification_t *this); + + /** + * @brief Get a string representation of this id. + * + * @warning Result points to internal data, do NOT free! + * + * @param this the identification_t object + * @return string + */ + char *(*get_string) (identification_t *this); + + /** + * @brief Check if two identification_t objects are equal. + * + * @param this the identification_t object + * @param other other identification_t object + * @return TRUE if the IDs are equal + */ + bool (*equals) (identification_t *this,identification_t *other); + + /** + * @brief Check if an ID belongs to a wildcard ID. + * + * An identification_t may contain wildcards, such as + * *@strongswan.org. This call checks if a given ID + * (e.g. tester@strongswan.org) belongs to a such wildcard + * ID. Returns TRUE if IDs are identical. + * + * @param this the ID containing a wildcard + * @param other the ID without wildcard + * @return TRUE if other belongs to this + */ + bool (*belongs_to) (identification_t *this, identification_t *other); + + /** + * @brief Clone a identification_t instance. + * + * @param this the identification_t object to clone + * @return clone of this + */ + identification_t *(*clone) (identification_t *this); + + /** + * @brief Destroys a identification_t object. + * + * @param this identification_t object + */ + void (*destroy) (identification_t *this); +}; + +/** + * @brief Creates an identification_t object from a string. + * + * @param type type of this id, such as ID_IPV4_ADDR + * @param string input string, which will be converted + * @return + * - created identification_t object, or + * - NULL if type not supported. + * + * @ingroup utils + */ +identification_t * identification_create_from_string(id_type_t type, char *string); + + +/** + * @brief Creates an identification_t object from an encoded chunk. + * + * @param type type of this id, such as ID_IPV4_ADDR + * @param encoded encoded bytes, such as from identification_t.get_encoding + * @return identification_t object + * + * @ingroup utils + */ +identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded); + + +#endif /* IDENTIFICATION_H_ */ diff --git a/Source/lib/utils/iterator.h b/Source/lib/utils/iterator.h new file mode 100644 index 000000000..de81db8e9 --- /dev/null +++ b/Source/lib/utils/iterator.h @@ -0,0 +1,153 @@ +/** + * @file iterator.h + * + * @brief Interface iterator_t. + * + */ + +/* + * 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 ITERATOR_H_ +#define ITERATOR_H_ + +typedef struct iterator_t iterator_t; + +/** + * @brief Iterator interface, allows iteration over collections. + * + * iterator_t defines an interface for iterating over collections. + * It allows searching, deleting, updating and inserting. + * + * Thanks to JMP for iterator lessons :-) + * + * @b Constructors: + * - via linked_list_t.create_iterator, or + * - any other class which supports the iterator_t interface + * + * @see linked_list_t + * + * @ingroup utils + */ +struct iterator_t { + + /** + * @brief Iterate over all items. + * + * The easy way to iterate over items. + * + * @param this calling object + * @param[out] value item + * @return + * - TRUE, if more elements are avaiable, + * - FALSE otherwise + */ + bool (*iterate) (iterator_t *this, void** value); + + /** + * @brief Moves to the next element, if available. + * + * A newly created iterator_t object doesn't point to any item. + * Call iterator_t.has_next first to point it to the first item. + * + * @param this calling object + * @return + * - TRUE, if more elements are avaiable, + * - FALSE otherwise + */ + bool (*has_next) (iterator_t *this); + + /** + * @brief Returns the current value at the iterator position. + * + * @param this calling object + * @param[out] value value is set to the current value at iterator position + * @return + * - SUCCESS + * - FAILED if iterator on an invalid position + */ + status_t (*current) (iterator_t *this, void **value); + + /** + * @brief Inserts a new item before the given iterator position. + * + * The iterator position is not changed after inserting + * + * @param this calling iterator + * @param[in] item value to insert in list + */ + void (*insert_before) (iterator_t *this, void *item); + + /** + * @brief Inserts a new item after the given iterator position. + * + * The iterator position is not changed after inserting. + * + * @param this calling iterator + * @param[in] item value to insert in list + */ + void (*insert_after) (iterator_t *this, void *item); + + /** + * @brief Replace the current item at current iterator position. + * + * The iterator position is not changed after replacing. + * + * @param this calling iterator + * @param[out] old_item old value will be written here(can be NULL) + * @param[in] new_item new value + * + * @return + * - SUCCESS + * - FAILED if iterator is on an invalid position + */ + status_t (*replace) (iterator_t *this, void **old_item, void *new_item); + + /** + * @brief Removes an element from list at the given iterator position. + * + * The position of the iterator is set in the following order: + * - to the item before, if available + * - otherwise to the item after, if available + * - otherwise it gets reseted + * + * @param linked_list calling object + * @return + * - SUCCESS + * - FAILED if iterator is on an invalid position + */ + status_t (*remove) (iterator_t *iterator); + + /** + * @brief Resets the iterator position. + * + * After reset, the iterator_t objects doesn't point to an element. + * A call to iterator_t.has_next is necessary to do any other operations + * with the resetted iterator. + * + * @param this calling object + */ + void (*reset) (iterator_t *this); + + /** + * @brief Destroys an iterator. + * + * @param this iterator to destroy + * + */ + void (*destroy) (iterator_t *this); +}; + +#endif /*ITERATOR_H_*/ diff --git a/Source/lib/utils/linked_list.c b/Source/lib/utils/linked_list.c new file mode 100644 index 000000000..407065d24 --- /dev/null +++ b/Source/lib/utils/linked_list.c @@ -0,0 +1,729 @@ +/** + * @file linked_list.c + * + * @brief Implementation of linked_list_t. + * + */ + +/* + * 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 "linked_list.h" + +#include <utils/allocator.h> + + + +typedef struct linked_list_element_t linked_list_element_t; + +/** + * @brief Element in a linked list. + * + * This element holds a pointer to the value it represents. + */ +struct linked_list_element_t { + + /** + * Value of a list item. + */ + void *value; + + /** + * Previous list element. + * + * NULL if first element in list. + */ + linked_list_element_t *previous; + + /** + * Next list element. + * + * NULL if last element in list. + */ + linked_list_element_t *next; + + /** + * Destroys a linked_list_element object. + * + * @param linked_list_element_t calling object + */ + void (*destroy) (linked_list_element_t *this); +}; + +/** + * Implementation of linked_list_element_t.destroy. + */ +static void linked_list_element_destroy(linked_list_element_t *this) +{ + allocator_free(this); +} + +/** + * @brief Creates an empty linked list object. + * + * @warning Only the pointer to the value is stored. + * + * @param[in] value value of item to be set + * @return linked_list_element_t object + */ + +linked_list_element_t *linked_list_element_create(void *value) +{ + linked_list_element_t *this = allocator_alloc_thing(linked_list_element_t); + + this->destroy = linked_list_element_destroy; + + this->previous=NULL; + this->next=NULL; + this->value = value; + + return (this); +} + + +typedef struct private_linked_list_t private_linked_list_t; + +/** + * Private data of a linked_list_t object. + * + */ +struct private_linked_list_t { + /** + * Public part of linked list. + */ + linked_list_t public; + + /** + * Number of items in the list. + */ + int count; + + /** + * First element in list. + * NULL if no elements in list. + */ + linked_list_element_t *first; + + /** + * Last element in list. + * NULL if no elements in list. + */ + linked_list_element_t *last; +}; + + +typedef struct private_iterator_t private_iterator_t; + +/** + * Private variables and functions of linked list iterator. + */ +struct private_iterator_t { + /** + * Public part of linked list iterator. + */ + iterator_t public; + + /** + * Associated linked list. + */ + private_linked_list_t * list; + + /** + * Current element of the iterator. + */ + linked_list_element_t *current; + + /** + * Direction of iterator. + */ + bool forward; +}; + +/** + * Implementation of iterator_t.has_next. + */ +static bool iterate(private_iterator_t *this, void** value) +{ + if (this->list->count == 0) + { + return FALSE; + } + if (this->current == NULL) + { + this->current = (this->forward) ? this->list->first : this->list->last; + *value = this->current->value; + return TRUE; + } + if (this->forward) + { + if (this->current->next == NULL) + { + return FALSE; + } + this->current = this->current->next; + *value = this->current->value; + return TRUE; + } + /* backward */ + if (this->current->previous == NULL) + { + return FALSE; + } + this->current = this->current->previous; + *value = this->current->value; + return TRUE; +} + +/** + * Implementation of iterator_t.has_next. + */ +static bool iterator_has_next(private_iterator_t *this) +{ + if (this->list->count == 0) + { + return FALSE; + } + if (this->current == NULL) + { + this->current = (this->forward) ? this->list->first : this->list->last; + return TRUE; + } + if (this->forward) + { + if (this->current->next == NULL) + { + return FALSE; + } + this->current = this->current->next; + return TRUE; + } + /* backward */ + if (this->current->previous == NULL) + { + return FALSE; + } + this->current = this->current->previous; + return TRUE; +} + +/** + * Implementation of iterator_t.current. + */ +static status_t iterator_current(private_iterator_t *this, void **value) +{ + if (this->current == NULL) + { + return NOT_FOUND; + } + *value = this->current->value; + return SUCCESS; +} + +/** + * Implementation of iterator_t.reset. + */ +static void iterator_reset(private_iterator_t *this) +{ + this->current = NULL; +} + +/** + * Implementation of iterator_t.remove. + */ +static status_t remove(private_iterator_t *this) +{ + linked_list_element_t *new_current; + + if (this->current == NULL) + { + return NOT_FOUND; + } + + if (this->list->count == 0) + { + return NOT_FOUND; + } + /* find out the new iterator position */ + if (this->current->previous != NULL) + { + new_current = this->current->previous; + } + else if (this->current->next != NULL) + { + new_current = this->current->next; + } + else + { + new_current = NULL; + } + + /* now delete the entry :-) */ + if (this->current->previous == NULL) + { + if (this->current->next == NULL) + { + this->list->first = NULL; + this->list->last = NULL; + } + else + { + this->current->next->previous = NULL; + this->list->first = this->current->next; + } + } + else if (this->current->next == NULL) + { + this->current->previous->next = NULL; + this->list->last = this->current->previous; + } + else + { + this->current->previous->next = this->current->next; + this->current->next->previous = this->current->previous; + } + + this->list->count--; + this->current->destroy(this->current); + /* set the new iterator position */ + this->current = new_current; + return SUCCESS; +} + +/** + * Implementation of iterator_t.insert_before. + */ +static void insert_before(private_iterator_t * iterator, void *item) +{ + if (iterator->current == NULL) + { + iterator->list->public.insert_first(&(iterator->list->public), item); + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + if (iterator->current->previous == NULL) + { + iterator->current->previous = element; + element->next = iterator->current; + iterator->list->first = element; + } + else + { + iterator->current->previous->next = element; + element->previous = iterator->current->previous; + iterator->current->previous = element; + element->next = iterator->current; + } + + iterator->list->count++; +} + +/** + * Implementation of iterator_t.replace. + */ +static status_t replace (private_iterator_t *this, void **old_item, void *new_item) +{ + if (this->current == NULL) + { + return NOT_FOUND; + } + if (old_item != NULL) + { + *old_item = this->current->value; + } + this->current->value = new_item; + + return SUCCESS; +} + +/** + * Implementation of iterator_t.insert_after. + */ +static void insert_after(private_iterator_t * iterator, void *item) +{ + if (iterator->current == NULL) + { + iterator->list->public.insert_first(&(iterator->list->public),item); + return; + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + if (iterator->current->next == NULL) + { + iterator->current->next = element; + element->previous = iterator->current; + iterator->list->last = element; + } + else + { + iterator->current->next->previous = element; + element->next = iterator->current->next; + iterator->current->next = element; + element->previous = iterator->current; + } + iterator->list->count++; +} + +/** + * Implementation of iterator_t.destroy. + */ +static void iterator_destroy(private_iterator_t *this) +{ + allocator_free(this); +} + +/** + * Implementation of linked_list_t.get_count. + */ +static int get_count(private_linked_list_t *this) +{ + return this->count; +} + +/** + * Implementation of linked_list_t.call_on_items. + */ +static void call_on_items(private_linked_list_t *this, void(*func)(void*)) +{ + iterator_t *iterator; + void *item; + + iterator = this->public.create_iterator(&(this->public),TRUE); + + while (iterator->has_next(iterator)) + { + iterator->current(iterator, &item); + (*func)(item); + } + iterator->destroy(iterator); +} + +/** + * Implementation of linked_list_t.insert_first. + */ +static void insert_first(private_linked_list_t *this, void *item) +{ + linked_list_element_t *element; + + element =(linked_list_element_t *) linked_list_element_create(item); + + if (this->count == 0) + { + /* first entry in list */ + this->first = element; + this->last = element; + element->previous = NULL; + element->next = NULL; + } + else + { + linked_list_element_t *old_first_element = this->first; + element->next = old_first_element; + element->previous = NULL; + old_first_element->previous = element; + this->first = element; + } + + this->count++; +} + +/** + * Implementation of linked_list_t.remove_first. + */ +static status_t remove_first(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + linked_list_element_t *element = this->first; + + if (element->next != NULL) + { + element->next->previous = NULL; + } + this->first = element->next; + + if (item != NULL) + { + *item = element->value; + } + + this->count--; + + element->destroy(element); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.get_first. + */ +static status_t get_first(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + *item = this->first->value; + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.insert_last. + */ +static void insert_last(private_linked_list_t *this, void *item) +{ + linked_list_element_t *element = (linked_list_element_t *) linked_list_element_create(item); + + if (this->count == 0) + { + /* first entry in list */ + this->first = element; + this->last = element; + element->previous = NULL; + element->next = NULL; + } + else + { + + linked_list_element_t *old_last_element = this->last; + element->previous = old_last_element; + element->next = NULL; + old_last_element->next = element; + this->last = element; + } + + this->count++; +} + +/** + * Implementation of linked_list_t.remove_last. + */ +static status_t remove_last(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + linked_list_element_t *element = this->last; + + if (element->previous != NULL) + { + element->previous->next = NULL; + } + this->last = element->previous; + + if (item != NULL) + { + *item = element->value; + } + + this->count--; + + element->destroy(element); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.insert_at_position. + */ +static status_t insert_at_position (private_linked_list_t *this,size_t position, void *item) +{ + linked_list_element_t *current_element; + int i; + + if (this->count <= position) + { + return INVALID_ARG; + } + + current_element = this->first; + + for (i = 0; i < position;i++) + { + current_element = current_element->next; + } + + if (current_element == NULL) + { + this->public.insert_last(&(this->public),item); + return SUCCESS; + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + + if (current_element->previous == NULL) + { + current_element->previous = element; + element->next = current_element; + this->first = element; + } + else + { + current_element->previous->next = element; + element->previous = current_element->previous; + current_element->previous = element; + element->next = current_element; + } + + + this->count++; + return SUCCESS; +} + +/** + * Implementation of linked_list_t.remove_at_position. + */ +static status_t remove_at_position (private_linked_list_t *this,size_t position, void **item) +{ + iterator_t *iterator; + int i; + + if (this->count <= position) + { + return INVALID_ARG; + } + + iterator = this->public.create_iterator(&(this->public),TRUE); + + iterator->has_next(iterator); + for (i = 0; i < position;i++) + { + iterator->has_next(iterator); + } + iterator->current(iterator,item); + iterator->remove(iterator); + iterator->destroy(iterator); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.get_at_position. + */ +static status_t get_at_position (private_linked_list_t *this,size_t position, void **item) +{ + int i; + iterator_t *iterator; + status_t status; + if (this->count <= position) + { + return INVALID_ARG; + } + + iterator = this->public.create_iterator(&(this->public),TRUE); + + iterator->has_next(iterator); + for (i = 0; i < position;i++) + { + iterator->has_next(iterator); + } + status = iterator->current(iterator,item); + iterator->destroy(iterator); + return status; +} + +/** + * Implementation of linked_list_t.get_last. + */ +static status_t get_last(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + *item = this->last->value; + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.create_iterator. + */ +static iterator_t *create_iterator (private_linked_list_t *linked_list,bool forward) +{ + private_iterator_t *this = allocator_alloc_thing(private_iterator_t); + + this->public.iterate = (bool (*) (iterator_t *this, void **value)) iterate; + this->public.has_next = (bool (*) (iterator_t *this)) iterator_has_next; + this->public.current = (status_t (*) (iterator_t *this, void **value)) iterator_current; + this->public.insert_before = (void (*) (iterator_t *this, void *item)) insert_before; + this->public.insert_after = (void (*) (iterator_t *this, void *item)) insert_after; + this->public.replace = (status_t (*) (iterator_t *, void **, void *)) replace; + this->public.remove = (status_t (*) (iterator_t *this)) remove; + this->public.reset = (void (*) (iterator_t *this)) iterator_reset; + this->public.destroy = (void (*) (iterator_t *this)) iterator_destroy; + + this->forward = forward; + this->current = NULL; + this->list = linked_list; + + return &(this->public); +} + +/** + * Implementation of linked_list_t.destroy. + */ +static void linked_list_destroy(private_linked_list_t *this) +{ + void * value; + /* Remove all list items before destroying list */ + while (this->public.remove_first(&(this->public),&value) != NOT_FOUND) + { + /* values are not destroyed so memory leaks are possible + * if list is not empty when deleting */ + } + allocator_free(this); +} + +/* + * Described in header. + */ +linked_list_t *linked_list_create() +{ + private_linked_list_t *this = allocator_alloc_thing(private_linked_list_t); + + this->public.get_count = (int (*) (linked_list_t *)) get_count; + this->public.create_iterator = (iterator_t * (*) (linked_list_t *,bool )) create_iterator; + this->public.call_on_items = (void (*) (linked_list_t *, void(*func)(void*)))call_on_items; + this->public.get_first = (status_t (*) (linked_list_t *, void **item)) get_first; + this->public.get_last = (status_t (*) (linked_list_t *, void **item)) get_last; + this->public.insert_first = (void (*) (linked_list_t *, void *item)) insert_first; + this->public.insert_last = (void (*) (linked_list_t *, void *item)) insert_last; + this->public.remove_first = (status_t (*) (linked_list_t *, void **item)) remove_first; + this->public.remove_last = (status_t (*) (linked_list_t *, void **item)) remove_last; + this->public.insert_at_position =(status_t (*) (linked_list_t *,size_t, void *)) insert_at_position; + this->public.remove_at_position =(status_t (*) (linked_list_t *,size_t, void **)) remove_at_position; + this->public.get_at_position =(status_t (*) (linked_list_t *,size_t, void **)) get_at_position; + + this->public.destroy = (void (*) (linked_list_t *)) linked_list_destroy; + + this->count = 0; + this->first = NULL; + this->last = NULL; + + return (&(this->public)); +} diff --git a/Source/lib/utils/linked_list.h b/Source/lib/utils/linked_list.h new file mode 100644 index 000000000..8647f064d --- /dev/null +++ b/Source/lib/utils/linked_list.h @@ -0,0 +1,203 @@ +/** + * @file linked_list.h + * + * @brief Interface of linked_list_t. + * + */ + +/* + * 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 LINKED_LIST_H_ +#define LINKED_LIST_H_ + +#include <types.h> +#include <utils/iterator.h> + + +typedef struct linked_list_t linked_list_t; + +/** + * @brief Class implementing a double linked list (named only as linked list). + * + * @warning Access to an object of this type is not thread-save. + * + * @b Costructors: + * - linked_list_create() + * + * @see + * - job_queue_t + * - event_queue_t + * - send_queue_t + * + * @ingroup utils + */ +struct linked_list_t { + + /** + * @brief Gets the count of items in the list. + * + * @param linked_list calling object + * @return number of items in list + */ + int (*get_count) (linked_list_t *linked_list); + + /** + * @brief Creates a iterator for the given list. + * + * @warning Created iterator_t object has to get destroyed by the caller. + * + * @param linked_list calling object + * @param forward iterator direction (TRUE: front to end) + * @return new iterator_t object + */ + iterator_t * (*create_iterator) (linked_list_t *linked_list, bool forward); + + /** + * @brief Call a function with list element as argument. + * + * This method accepts a function, which will be called for + * each list element once. The function must accept the list + * element as the first argument. Handy for destruction of + * list elements. + * + * @todo Additional vararg which are passed to the + * function would be nice... + * + * @param linked_list calling object + * @param func function to call + */ + void (*call_on_items) (linked_list_t *linked_list, void(*func)(void*)); + + /** + * @brief Inserts a new item at the beginning of the list. + * + * @param linked_list calling object + * @param[in] item item value to insert in list + */ + void (*insert_first) (linked_list_t *linked_list, void *item); + + /** + * @brief Removes the first item in the list and returns its value. + * + * @param linked_list calling object + * @param[out] item returned value of first item, or NULL + * @return + * - SUCCESS + * - NOT_FOUND, if list is empty + */ + status_t (*remove_first) (linked_list_t *linked_list, void **item); + + /** + * @brief Returns the value of the first list item without removing it. + * + * @param linked_list calling object + * @param[out] item item returned value of first item + * @return + * - SUCCESS + * - NOT_FOUND, if list is empty + */ + status_t (*get_first) (linked_list_t *linked_list, void **item); + + /** + * @brief Inserts a new item at the end of the list. + * + * @param linked_list calling object + * @param[in] item item value to insert into list + */ + void (*insert_last) (linked_list_t *linked_list, void *item); + + /** + * @brief Inserts a new item at a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to insert new entry + * @param[in] item item value to insert into list + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*insert_at_position) (linked_list_t *linked_list,size_t position, void *item); + + /** + * @brief Removes an item from a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to remove entry from + * @param[out] item removed item will be stored at this location + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*remove_at_position) (linked_list_t *linked_list,size_t position, void **item); + + /** + * @brief Get an item from a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to get entry from + * @param[out] item item will be stored at this location + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*get_at_position) (linked_list_t *linked_list,size_t position, void **item); + + /** + * @brief Removes the last item in the list and returns its value. + * + * @param linked_list calling object + * @param[out] item returned value of last item, or NULL + * @return + * - SUCCESS + * - NOT_FOUND if list is empty + */ + status_t (*remove_last) (linked_list_t *linked_list, void **item); + + /** + * @brief Returns the value of the last list item without removing it. + * + * @param linked_list calling object + * @param[out] item returned value of last item + * @return + * - SUCCESS + * - NOT_FOUND if list is empty + */ + status_t (*get_last) (linked_list_t *linked_list, void **item); + + /** + * @brief Destroys a linked_list object. + * + * @warning All items are removed before deleting the list. The + * associated values are NOT destroyed. + * Destroying an list which is not empty may cause + * memory leaks! + * + * @param linked_list calling object + */ + void (*destroy) (linked_list_t *linked_list); +}; + +/** + * @brief Creates an empty linked list object. + * + * @return linked_list_t object. + * + * @ingroup utils + */ +linked_list_t *linked_list_create(); + + +#endif /*LINKED_LIST_H_*/ diff --git a/Source/lib/utils/logger.c b/Source/lib/utils/logger.c new file mode 100644 index 000000000..c66de481e --- /dev/null +++ b/Source/lib/utils/logger.c @@ -0,0 +1,360 @@ +/** + * @file logger.c + * + * @brief Implementation of logger_t. + * + */ + +/* + * 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 <pthread.h> + +#include "logger.h" + +#include <daemon.h> +#include <utils/allocator.h> + +/** + * Maximum length of a log entry (only used for logger_s.log). + */ +#define MAX_LOG 8192 + + +typedef struct private_logger_t private_logger_t; + +/** + * @brief Private data of a logger_t object. + */ +struct private_logger_t { + /** + * Public data. + */ + logger_t public; + /** + * Detail-level of logger. + */ + log_level_t level; + /** + * Name of logger. + */ + char *name; + /** + * File to write log output to. + * NULL for syslog. + */ + FILE *output; + + /** + * Should a thread_id be included in the log? + */ + bool log_thread_id; + + /** + * Applies a prefix to string and stores it in buffer. + * + * @warning: buffer must be at least have MAX_LOG size. + */ + void (*prepend_prefix) (private_logger_t *this, log_level_t loglevel, char *string, char *buffer); +}; + +/** + * Implementation of private_logger_t.prepend_prefix. + */ +static void prepend_prefix(private_logger_t *this, log_level_t loglevel, char *string, char *buffer) +{ + char log_type, log_details; + if (loglevel & CONTROL) + { + log_type = '~'; + } + else if (loglevel & ERROR) + { + log_type = '!'; + } + else if (loglevel & RAW) + { + log_type = '#'; + } + else if (loglevel & PRIVATE) + { + log_type = '?'; + } + else if (loglevel & AUDIT) + { + log_type = '>'; + } + else + { + log_type = '-'; + } + + if (loglevel & (LEVEL3 - LEVEL2)) + { + log_details = '3'; + } + else if (loglevel & (LEVEL2 - LEVEL1)) + { + log_details = '2'; + } + else if (loglevel & LEVEL1) + { + log_details = '1'; + } + else + { + log_details = '0'; + } + + if (this->log_thread_id) + { + snprintf(buffer, MAX_LOG, "[%c%c] [%s] @%u %s", log_type, log_details, this->name, (int)pthread_self(), string); + } + else + { + snprintf(buffer, MAX_LOG, "[%c%c] [%s] %s", log_type, log_details, this->name, string); + } +} + +/** + * Implementation of logger_t.log. + * + * Yes, logg is wrong written :-). + */ +static void logg(private_logger_t *this, log_level_t loglevel, char *format, ...) +{ + if ((this->level & loglevel) == loglevel) + { + char buffer[MAX_LOG]; + va_list args; + + + if (this->output == NULL) + { + /* syslog */ + this->prepend_prefix(this, loglevel, format, buffer); + va_start(args, format); + vsyslog(LOG_INFO, buffer, args); + va_end(args); + } + else + { + /* File output */ + this->prepend_prefix(this, loglevel, format, buffer); + va_start(args, format); + vfprintf(this->output, buffer, args); + va_end(args); + fprintf(this->output, "\n"); + } + + } +} + +/** + * Implementation of logger_t.log_bytes. + */ +static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label, char *bytes, size_t len) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + + if ((this->level & loglevel) == loglevel) + { + char buffer[MAX_LOG]; + char ascii_buffer[17]; + char *format; + char *buffer_pos; + char *bytes_pos, *bytes_roof; + int i; + int line_start = 0; + + /* since me can't do multi-line output to syslog, + * we must do multiple syslogs. To avoid + * problems in output order, lock this by a mutex. + */ + pthread_mutex_lock(&mutex); + + + format = "%s (%d bytes @%p)"; + this->prepend_prefix(this, loglevel, format, buffer); + + if (this->output == NULL) + { + syslog(LOG_INFO, buffer, label, len); + } + else + { + fprintf(this->output, buffer, label, len, bytes); + fprintf(this->output, "\n"); + } + + bytes_pos = bytes; + bytes_roof = bytes + len; + buffer_pos = buffer; + memset(ascii_buffer, 0, 17); + + for (i = 1; bytes_pos < bytes_roof; i++) + { + static 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, "[=>] [%5d ] %s %s", line_start, buffer, ascii_buffer); + } + else + { + fprintf(this->output, "[=>] [%5d ] %s %s\n", line_start, buffer, ascii_buffer); + } + memset(ascii_buffer, 0, 16); + line_start += 16; + } + else if ((i % 4) == 0) + { + *buffer_pos++ = ' '; + // *buffer_pos++ = ' '; + } + else + { + *buffer_pos++ = ' '; + } + + if (*bytes_pos > 31 && *bytes_pos < 127) + { + ascii_buffer[(i % 16)] = *bytes_pos; + } + else + { + ascii_buffer[(i % 16)] = '*'; + } + + bytes_pos++; + } + + *buffer_pos++ = '\0'; + if (buffer_pos > buffer + 1) + { + buffer_pos = buffer; + if (this->output == NULL) + { + syslog(LOG_INFO, "[=>] [%5d ] %s %16s", line_start, buffer, ascii_buffer); + } + else + { + fprintf(this->output, "[=>] [%5d ] %s %16s\n", line_start, buffer, ascii_buffer); + } + } + pthread_mutex_unlock(&mutex); + } +} + +/** + * Implementation of logger_t.log_chunk. + */ +static void log_chunk(logger_t *this, log_level_t loglevel, char *label, chunk_t chunk) +{ + this->log_bytes(this, loglevel, label, chunk.ptr, chunk.len); +} + +/** + * Implementation of logger_t.enable_level. + */ +static void enable_level(private_logger_t *this, log_level_t log_level) +{ + this->level |= log_level; +} + +/** + * Implementation of logger_t.disable_level. + */ +static void disable_level(private_logger_t *this, log_level_t log_level) +{ + this->level &= ~log_level; +} + +/** + * Implementation of logger_t.set_output. + */ +static void set_output(private_logger_t *this, FILE * output) +{ + this->output = output; +} + +/** + * Implementation of logger_t.get_level. + */ +static log_level_t get_level(private_logger_t *this) +{ + return this->level; +} + +/** + * Implementation of logger_t.destroy. + */ +static void destroy(private_logger_t *this) +{ + allocator_free(this->name); + allocator_free(this); +} + +/* + * Described in header. + */ +logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output) +{ + private_logger_t *this = allocator_alloc_thing(private_logger_t); + + /* public functions */ + this->public.log = (void(*)(logger_t*,log_level_t,char*,...))logg; + this->public.log_bytes = (void(*)(logger_t*, log_level_t, char*,char*,size_t))log_bytes; + this->public.log_chunk = log_chunk; + this->public.enable_level = (void(*)(logger_t*,log_level_t))enable_level; + this->public.disable_level = (void(*)(logger_t*,log_level_t))disable_level; + this->public.get_level = (log_level_t(*)(logger_t*))get_level; + this->public.set_output = (void(*)(logger_t*,FILE*))set_output; + this->public.destroy = (void(*)(logger_t*))destroy; + + /* private functions */ + this->prepend_prefix = prepend_prefix; + + if (logger_name == NULL) + { + logger_name = ""; + } + + /* private variables */ + this->level = log_level; + this->log_thread_id = log_thread_id; + this->name = allocator_alloc(strlen(logger_name) + 1); + + strcpy(this->name,logger_name); + this->output = output; + + if (output == NULL) + { + openlog(DAEMON_NAME, 0, LOG_DAEMON); + } + + return (logger_t*)this; +} diff --git a/Source/lib/utils/logger.h b/Source/lib/utils/logger.h new file mode 100644 index 000000000..637915e8b --- /dev/null +++ b/Source/lib/utils/logger.h @@ -0,0 +1,199 @@ +/** + * @file logger.h + * + * @brief Interface of logger_t. + * + */ + +/* + * 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> + + +typedef enum log_level_t log_level_t; + +/** + * @brief Log Levels supported by the logger object. + * + * Logleves are devided in two different kinds: + * - levels to specify the type of the log + * - levels to specify the detail-level of the log + * + * Use combinations of these to build detailed loglevels, such + * as CONTROL|MORE fore a detailed cotrol level, or + * use RAW to see all raw data dumps (except private). + * + * @ingroup utils + */ +enum log_level_t { + /** + * Control flow. + */ + CONTROL = 1, + /** + * Error reporting. + */ + ERROR = 2, + /** + * Logs important for the sysadmin. + */ + AUDIT = 4, + /** + * Raw data dumps. + */ + RAW = 8, + /** + * Private data dumps. + */ + PRIVATE = 16, + + /** + * Log most important output, can be omitted. + */ + LEVEL0 = 0, + /** + * Log more detailed output. + */ + LEVEL1 = 32, + /** + * Log even more detailed output. + */ + LEVEL2 = LEVEL1 + 64, + /** + * Use maximum detailed output. + */ + LEVEL3 = LEVEL2 + 128, + + /** + * Summary for all types with all detail-levels. + */ + FULL = LEVEL3 + CONTROL + ERROR + RAW + PRIVATE + AUDIT +}; + +typedef struct logger_t logger_t; + +/** + * @brief Class to simplify logging. + * + * @b Constructors: + * - logger_create() + * + * @ingroup utils + */ +struct logger_t { + + /** + * @brief Log an entry, using printf()-like params. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param format printf like format string + * @param ... printf like parameters + */ + void (*log) (logger_t *this, log_level_t log_level, char *format, ...); + + /** + * @brief Log some bytes, useful for debugging. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param label a labeling name, logged with the bytes + * @param bytes pointer to the bytes to dump + * @param len number of bytes to dump + */ + void (*log_bytes) (logger_t *this, log_level_t loglevel, char *label, char *bytes, size_t len); + + /** + * @brief Log a chunk, useful for debugging. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param label a labeling name, logged with the bytes + * @param chunk chunk to log + */ + void (*log_chunk) (logger_t *this, log_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 + */ + void (*enable_level) (logger_t *this, log_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 + */ + void (*disable_level) (logger_t *this, log_level_t log_level); + + /** + * @brief Set the output of the logger. + * + * Use NULL for syslog. + * + * @param this logger_t object + * @param output file, where log output should be written + */ + void (*set_output) (logger_t *this, FILE *output); + + /** + * @brief Get the currently used loglevel. + * + * @param this logger_t object + * @return currently used loglevel + */ + log_level_t (*get_level) (logger_t *this); + + /** + * @brief Destroys a logger_t object. + * + * @param this logger_t object + */ + void (*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 log_thread_id TRUE if thread id should also be logged + * @param output FILE * if log has to go on a file output, NULL for syslog + * @return logger_t object + * + * @ingroup utils + */ +logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output); + + +#endif /*LOGGER_H_*/ diff --git a/Source/lib/utils/logger_manager.c b/Source/lib/utils/logger_manager.c new file mode 100644 index 000000000..8270191a9 --- /dev/null +++ b/Source/lib/utils/logger_manager.c @@ -0,0 +1,212 @@ +/** + * @file logger_manager.c + * + * @brief Implementation of logger_manager_t. + * + */ + +/* + * 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 <daemon.h> +#include <definitions.h> +#include <utils/allocator.h> +#include <utils/linked_list.h> + +/** + * String mappings for logger_context_t + */ +mapping_t logger_context_t_mappings[] = { + {PARSER, "PARSER"}, + {GENERATOR, "GENERATOR"}, + {IKE_SA, "IKE_SA"}, + {IKE_SA_MANAGER, "IKE_SA_MANAGER"}, + {CHILD_SA, "CHILD_SA"}, + {MESSAGE, "MESSAGE"}, + {THREAD_POOL, "THREAD_POOL"}, + {WORKER, "WORKER"}, + {SCHEDULER, "SCHEDULER"}, + {SENDER, "SENDER"}, + {RECEIVER, "RECEIVER"}, + {SOCKET, "SOCKET"}, + {TESTER, "TESTER"}, + {DAEMON, "DAEMON"}, + {CONFIG, "CONFIG"}, + {ENCRYPTION_PAYLOAD, "ENCRYPTION_PAYLOAD"}, + {PAYLOAD, "PAYLOAD"}, + {DER_DECODER, "DER_DECODER"}, + {DER_ENCODER, "DER_ENCODER"}, + {MAPPING_END, NULL}, +}; + +#define DEFAULT_OUTPUT NULL + +struct { + char *name; + log_level_t level; + bool log_thread_ids; + FILE *output; +} logger_defaults[] = { + { "PARSR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* PARSER */ + { "GNRAT", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* GENERATOR */ + { "IKESA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* IKE_SA */ + { "SAMGR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* IKE_SA_MANAGER */ + { "CHDSA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* CHILD_SA */ + { "MESSG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* MESSAGE */ + { "TPOOL", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* THREAD_POOL */ + { "WORKR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* WORKER */ + { "SCHED", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SCHEDULER */ + { "SENDR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SENDER */ + { "RECVR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* RECEIVER */ + { "SOCKT", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* SOCKET */ + { "TESTR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* TESTER */ + { "DAEMN", ERROR|CONTROL|AUDIT|LEVEL0, FALSE, DEFAULT_OUTPUT}, /* DAEMON */ + { "CONFG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* CONFIG */ + { "ENCPL", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* ENCRYPTION_PAYLOAD */ + { "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* PAYLOAD */ + { "DERDC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* DER_DECODER */ + { "DEREC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE, DEFAULT_OUTPUT}, /* DER_ENCODER */ +}; + + +typedef struct private_logger_manager_t private_logger_manager_t; + +/** + * Private data of logger_manager_t object. + */ +struct private_logger_manager_t { + /** + * Public data. + */ + logger_manager_t public; + + /** + * Array of loggers, one for each context + */ + logger_t *loggers[LOGGER_CONTEXT_ROOF]; + +}; + +/** + * Implementation of logger_manager_t.get_logger. + */ +static logger_t *get_logger(private_logger_manager_t *this, logger_context_t context) +{ + return this->loggers[context]; +} + +/** + * Implementation of logger_manager_t.get_log_level. + */ +static log_level_t get_log_level (private_logger_manager_t *this, logger_context_t context) +{ + return this->loggers[context]->get_level(this->loggers[context]); +} + +/** + * Implementation of private_logger_manager_t.enable_log_level. + */ +static void enable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->enable_level(this->loggers[context], level); + } + } + else + { + this->loggers[context]->enable_level(this->loggers[context], level); + } +} + +/** + * Implementation of private_logger_manager_t.disable_log_level. + */ +static void disable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->disable_level(this->loggers[context], level); + } + } + else + { + this->loggers[context]->disable_level(this->loggers[context], level); + } +} + +/** + * Implementation of private_logger_manager_t.set_output. + */ +static void set_output(private_logger_manager_t *this, logger_context_t context, FILE *output) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->set_output(this->loggers[context], output); + } + } + else + { + this->loggers[context]->set_output(this->loggers[context], output); + } +} + + +/** + * Implementation of logger_manager_t.destroy. + */ +static void destroy(private_logger_manager_t *this) +{ + int i; + for (i = 0; i < LOGGER_CONTEXT_ROOF; i++) + { + this->loggers[i]->destroy(this->loggers[i]); + } + allocator_free(this); +} + +/* + * Described in header. + */ +logger_manager_t *logger_manager_create(log_level_t default_log_level) +{ + private_logger_manager_t *this = allocator_alloc_thing(private_logger_manager_t); + int i; + + this->public.get_logger = (logger_t *(*)(logger_manager_t*,logger_context_t context))get_logger; + this->public.get_log_level = (log_level_t (*)(logger_manager_t *, logger_context_t)) get_log_level; + this->public.enable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) enable_log_level; + this->public.disable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) disable_log_level; + this->public.set_output = (void (*)(logger_manager_t *, logger_context_t, FILE*)) set_output; + this->public.destroy = (void(*)(logger_manager_t*))destroy; + + for (i = 0; i < LOGGER_CONTEXT_ROOF; i++) + { + this->loggers[i] = logger_create(logger_defaults[i].name, logger_defaults[i].level, + logger_defaults[i].log_thread_ids, stdout);//logger_defaults[i].output); + } + + return &this->public; +} + diff --git a/Source/lib/utils/logger_manager.h b/Source/lib/utils/logger_manager.h new file mode 100644 index 000000000..bc8f0e62f --- /dev/null +++ b/Source/lib/utils/logger_manager.h @@ -0,0 +1,155 @@ +/** + * @file logger_manager.h + * + * @brief Interface of logger_manager_t. + * + */ + +/* + * 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 <utils/logger.h> + + +typedef enum logger_context_t logger_context_t; + +/** + * @brief Context of a specific logger. + * + * @ingroup utils + */ +enum logger_context_t { + ALL_LOGGERS = -1, + PARSER = 0, + GENERATOR, + IKE_SA, + IKE_SA_MANAGER, + CHILD_SA, + MESSAGE, + THREAD_POOL, + WORKER, + SCHEDULER, + SENDER, + RECEIVER, + SOCKET, + TESTER, + DAEMON, + CONFIG, + ENCRYPTION_PAYLOAD, + PAYLOAD, + DER_DECODER, + DER_ENCODER, + LOGGER_CONTEXT_ROOF, +}; + + +typedef struct logger_manager_t logger_manager_t; + +/** + * @brief Class to manage logger_t objects. + * + * The logger manager manages all logger_t object in a list and + * allows their manipulation. Via a logger_context_t, the loglevel + * of a specific logging type can be adjusted at runtime. + * + * @b Constructors: + * - logger_manager_create() + * + * @see logger_t + * + * @ingroup utils + */ +struct logger_manager_t { + + /** + * @brief Gets a logger_t object for a specific logger context. + * + * @param this logger_manager_t object + * @param context logger_context to use the logger for + * @param name name for the new logger. Context name is already included + * and has not to be specified (so NULL is allowed) + * @return logger_t object + */ + logger_t *(*get_logger) (logger_manager_t *this, logger_context_t context); + + /** + * @brief Returns the set log_level of a specific context. + * + * @param this calling object + * @param context context to check level + * @return log_level for the given logger_context + */ + log_level_t (*get_log_level) (logger_manager_t *this, logger_context_t context); + + /** + * @brief Enables a logger level of a specific context. + * + * Use context ALL_LOGGERS to manipulate all loggers. + * + * @param this calling object + * @param context context to set level + * @param log_level logger level to eanble + */ + void (*enable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level); + + /** + * @brief Disables a logger level of a specific context. + * + * Use context ALL_LOGGERS to manipulate all loggers. + * + * @param this calling object + * @param context context to set level + * @param log_level logger level to disable + */ + void (*disable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level); + + /** + * @brief Sets the output of a logger. + * + * Use context ALL_LOGGERS to redirect all loggers. + * + * @param this calling object + * @param context context to set output + * @param log_level logger level to disable + */ + void (*set_output) (logger_manager_t *this, logger_context_t context, FILE *output); + + /** + * @brief Destroys a logger_manager_t object. + * + * All managed logger_t objects are also destroyed. + * + * @param this logger_manager_t object + */ + void (*destroy) (logger_manager_t *this); +}; + +/** + * @brief Constructor to create a logger_manager_t object. + * + * @param default_log_level default log level for all context + * @return logger_manager_t object + * + * @ingroup utils + */ +logger_manager_t *logger_manager_create(log_level_t default_log_level); + + +#endif /*LOGGER_MANAGER_H_*/ diff --git a/Source/lib/utils/randomizer.c b/Source/lib/utils/randomizer.c new file mode 100644 index 000000000..efe51af71 --- /dev/null +++ b/Source/lib/utils/randomizer.c @@ -0,0 +1,165 @@ +/** + * @file randomizer.c + * + * @brief Implementation of randomizer_t. + * + */ + +/* + * 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 <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "randomizer.h" + +#include <utils/allocator.h> + +typedef struct private_randomizer_t private_randomizer_t; + +/** + * Private data of an randomizer_t object. + */ +struct private_randomizer_t { + + /** + * Public randomizer_t interface. + */ + randomizer_t public; + + /** + * @brief Reads a specific number of bytes from random or pseudo random device. + * + * @param this calling object + * @param pseudo_random TRUE, if from pseudo random bytes should be read, + * FALSE for true random bytes + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * Size of buffer has to be at least bytes. + */ + status_t (*get_bytes_from_device) (private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer); +}; + + +/** + * Implementation of private_randomizer_t.get_bytes_from_device. + */ +static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer) +{ + size_t ndone; + int device; + size_t got; + char * device_name; + + device_name = pseudo_random ? RANDOM_DEVICE : PSEUDO_RANDOM_DEVICE; + + device = open(device_name, 0); + if (device < 0) { + return FAILED; + } + ndone = 0; + + /* read until nbytes are read */ + while (ndone < bytes) + { + got = read(device, buffer + ndone, bytes - ndone); + if (got <= 0) { + close(device); + return FAILED; + } + ndone += got; + } + close(device); + return SUCCESS; +} + +/** + * Implementation of randomizer_t.get_random_bytes. + */ +static status_t get_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +{ + return this->get_bytes_from_device(this, FALSE, bytes, buffer); +} + +/** + * Implementation of randomizer_t.allocate_random_bytes. + */ +static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +{ + status_t status; + chunk->len = bytes; + chunk->ptr = allocator_alloc(bytes); + status = this->get_bytes_from_device(this, FALSE, bytes, chunk->ptr); + if (status != SUCCESS) + { + allocator_free(chunk->ptr); + } + return status; +} + +/** + * Implementation of randomizer_t.get_pseudo_random_bytes. + */ +static status_t get_pseudo_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +{ + return (this->get_bytes_from_device(this, TRUE, bytes, buffer)); +} + +/** + * Implementation of randomizer_t.allocate_pseudo_random_bytes. + */ +static status_t allocate_pseudo_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +{ + status_t status; + chunk->len = bytes; + chunk->ptr = allocator_alloc(bytes); + status = this->get_bytes_from_device(this, TRUE, bytes, chunk->ptr); + if (status != SUCCESS) + { + allocator_free(chunk->ptr); + } + return status; +} + +/** + * Implementation of randomizer_t.destroy. + */ +static void destroy(private_randomizer_t *this) +{ + allocator_free(this); +} + +/* + * Described in header. + */ +randomizer_t *randomizer_create(void) +{ + private_randomizer_t *this = allocator_alloc_thing(private_randomizer_t); + + /* public functions */ + this->public.get_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_random_bytes; + this->public.allocate_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_random_bytes; + this->public.get_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_pseudo_random_bytes; + this->public.allocate_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_pseudo_random_bytes; + this->public.destroy = (void (*) (randomizer_t *))destroy; + + /* private functions */ + this->get_bytes_from_device = get_bytes_from_device; + + return &(this->public); +} diff --git a/Source/lib/utils/randomizer.h b/Source/lib/utils/randomizer.h new file mode 100644 index 000000000..55519550e --- /dev/null +++ b/Source/lib/utils/randomizer.h @@ -0,0 +1,110 @@ +/** + * @file randomizer.h + * + * @brief Interface of randomizer_t. + * + */ + +/* + * 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 RANDOMIZER_H_ +#define RANDOMIZER_H_ + +#include <types.h> + + +/** + * Device to read real random bytes + */ +#define RANDOM_DEVICE "/dev/random" + +/** + * Device to read pseudo random bytes + */ +#define PSEUDO_RANDOM_DEVICE "/dev/urandom" + +typedef struct randomizer_t randomizer_t; + +/** + * @brief Class used to get random and pseudo random values. + * + * @b Constructors: + * - randomizer_create() + * + * @ingroup utils + */ +struct randomizer_t { + + /** + * @brief Reads a specific number of bytes from random device. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * Size of buffer has to be at least bytes. + * @return SUCCESS, or FAILED + */ + status_t (*get_random_bytes) (randomizer_t *this, size_t bytes, u_int8_t *buffer); + + /** + * @brief Allocates space and writes in random bytes. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to allocate + * @param[out] chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED + */ + status_t (*allocate_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); + + /** + * @brief Reads a specific number of bytes from pseudo random device. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * size of buffer has to be at least bytes. + * @return SUCCESS, or FAILED + */ + status_t (*get_pseudo_random_bytes) (randomizer_t *this,size_t bytes, u_int8_t *buffer); + + /** + * @brief Allocates space and writes in pseudo random bytes. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to allocate + * @param[out] chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED + */ + status_t (*allocate_pseudo_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); + + /** + * @brief Destroys a randomizer_t object. + * + * @param this randomizer_t object to destroy + */ + void (*destroy) (randomizer_t *this); +}; + +/** + * @brief Creates a randomizer_t object. + * + * @return created randomizer_t, or + * + * @ingroup utils + */ +randomizer_t *randomizer_create(); + +#endif /*RANDOMIZER_H_*/ diff --git a/Source/lib/utils/tester.c b/Source/lib/utils/tester.c new file mode 100644 index 000000000..20dea2e82 --- /dev/null +++ b/Source/lib/utils/tester.c @@ -0,0 +1,257 @@ +/** + * @file tester.c + * + * @brief Implementation of tester_t. + * + */ + +/* + * 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 <utils/allocator.h> +#include <utils/linked_list.h> +#include <queues/job_queue.h> + + +typedef struct private_tester_t private_tester_t; + +/** + * @brief Private Data of tester_t class. + * + */ +struct private_tester_t { + + /** + * Protected interface of tester_t. + */ + protected_tester_t protected; + + /** + * Runs a specific test. + * + * @param tester associated tester object + * @param test_function test function to perform + * @param test_name name for the given test + */ + void (*run_test) (private_tester_t *tester, void (*test_function) (protected_tester_t * tester), char * test_name); + + /** + * Returns the difference of to timeval structs in microseconds. + * + * @warning this function is also defined in the event queue + * in later improvements, this function can be added to a general + * class type! + * + * @param end_time end time + * @param start_time start time + * + * @TODO make object function or move to utils! + * + * @return difference in microseconds + */ + long (*time_difference) (private_tester_t *tester,struct timeval *end_time, struct timeval *start_time); + + /** + * Output is written into this file. + */ + FILE* output; + + /** + * Number of already performed tests. + */ + int tests_count; + + /** + * Number of failed tests. + */ + int failed_tests_count; + + /** + * Number of failed asserts in current test. + */ + int failed_asserts_count; + + /** + * TRUE if also succeeded asserts should be written to output. + */ + bool display_succeeded_asserts; + + /** + * Mutex to make this class thread-save. + */ + pthread_mutex_t mutex; +}; + +/** + * Implementation of tester_t.perform_tests. + */ +static void perform_tests(private_tester_t *this,test_t **tests) +{ + 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(this,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"); +} + +/** + * Implementation of tester_t.perform_test. + */ +static void perform_test(private_tester_t *this, test_t *test) +{ + test_t *tests[] = {test, NULL}; + return (perform_tests(this,tests)); +} + +/** + * Returns the difference of to timeval structs in microseconds. + * + * @warning this function is also defined in the event queue + * in later improvements, this function can be added to a general + * class type! + * + * @param end_time end time + * @param start_time start time + * + * @TODO make object function or move to utils! + * + * @return difference in microseconds + */ +static long time_difference(private_tester_t *this,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 private_tester_t.run_test. + */ +static void run_test(private_tester_t *this, void (*test_function) (protected_tester_t * tester), char * test_name) +{ + struct timeval start_time, end_time; + long timediff; + this->tests_count++; + this->failed_asserts_count = 0; + fprintf(this->output,"%-55s\n", test_name); + gettimeofday(&start_time,NULL); + test_function(&(this->protected)); + gettimeofday(&end_time,NULL); + timediff = this->time_difference(this,&end_time, &start_time); + + if (this->failed_asserts_count > 0) + { + fprintf(this->output," => Test failed: %-37s|%10ld us\n",test_name,timediff); + }else + { + fprintf(this->output,"\033[1A\033[55C|%10ld us\033[1B\033[80D",timediff); + } + if (this->failed_asserts_count > 0) + { + this->failed_tests_count++; + } +} + + +/** + * Implementation of tester_t.assert_true. + */ +static void assert_true(private_tester_t *this, bool to_be_true,char * assert_name) +{ + 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 tester_t.assert_false. + */ +static void assert_false(private_tester_t *this, bool to_be_false,char * assert_name) +{ + this->protected.assert_true(&(this->protected),(!to_be_false),assert_name); +} + +/** + * Implementation of tester_t.destroy. + */ +static void destroy(private_tester_t *tester) +{ + private_tester_t *this = (private_tester_t*) tester; + pthread_mutex_destroy(&(this->mutex)); + allocator_free(this); +} + +/* + * Described in header. + */ +tester_t *tester_create(FILE *output, bool display_succeeded_asserts) +{ + private_tester_t *this = allocator_alloc_thing(private_tester_t); + + /* public functions */ + this->protected.public.destroy = (void (*) (tester_t *))destroy; + this->protected.public.perform_tests = (void (*) (tester_t *, test_t**)) perform_tests; + this->protected.public.perform_test = (void (*) (tester_t *, test_t*))perform_test; + this->protected.assert_true = (void (*) (protected_tester_t *, bool, char*)) assert_true; + this->protected.assert_false = (void (*) (protected_tester_t *, bool, char*)) assert_false; + + /* private functions */ + this->run_test = run_test; + this->time_difference = time_difference; + + /* private data */ + 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->protected.public); +} diff --git a/Source/lib/utils/tester.h b/Source/lib/utils/tester.h new file mode 100644 index 000000000..3decb2039 --- /dev/null +++ b/Source/lib/utils/tester.h @@ -0,0 +1,148 @@ +/** + * @file tester.h + * + * @brief Interface of tester_t. + * + */ + +/* + * 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> + + +/* must be defined here cause it is used in test_t */ +typedef struct protected_tester_t protected_tester_t; + +typedef struct test_t test_t; + +/** + * @brief Representing a specified test. + * + * @ingroup utils + */ +struct test_t { + /** + * Testfunction called for this test. + * + * @param tester associated tester_t object + */ + void (*test_function) (protected_tester_t * tester); + + /** + * Name of the test. + */ + char * test_name; +}; + + +typedef struct tester_t tester_t; + +/** + * @brief A class to perform tests. + * + * @b Constructors: + * - tester_create() + * + * @ingroup utils + */ +struct tester_t { + /** + * @brief Test all testcases in array tests with specific tester_t object. + * + * @param tester tester_t object + * @param tests pointer to an array of test_t-pointers. + * The last item has to be NULL to mark end of array. + */ + void (*perform_tests) (tester_t *tester,test_t **tests); + + /** + * @brief Run a specific test case. + * + * @param this tester_t object + * @param test pointer to a test_t object which will be performed + */ + void (*perform_test) (tester_t *tester, test_t *test); + + /** + * @brief Destroys a tester_t object. + * + * @param tester tester_t object + */ + void (*destroy) (tester_t *tester); +}; + + +/** + * @brief A class used in a specific testcase. + * + * For each testcase an object of this type is passed to the testfunction. The testfunction uses this + * object to check specific asserts with protected_tester_t.assert_true and protected_tester_t.assert_false. + * + * @b Constructors: + * - tester_create() + * + * @ingroup utils + */ +struct protected_tester_t { + + /** + * Public functions of a tester_t object + */ + tester_t public; + + /** + * @brief Is called in a testcase to check a specific situation for TRUE. + * + * Log-Values to the tester output are protected from multiple access. + * + * @param this tester_t object + * @param to_be_true assert which has to be TRUE + * @param assert_name name of the assertion + */ + void (*assert_true) (protected_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. + * + * @param this tester_t object + * @param to_be_false assert which has to be FALSE + * @param assert_name name of the assertion + */ + void (*assert_false) (protected_tester_t *tester, bool to_be_false, char *assert_name); +}; + + +/** + * @brief Creates a tester_t object used to perform tests with. + * + * @param output test output is written to this output. + * @param display_succeeded_asserts has to be TRUE, if all asserts should be displayed, + * FALSE otherwise + * + * @return tester_t object + * + * @ingroup utils + */ +tester_t *tester_create(FILE *output, bool display_succeeded_asserts); + +#endif /*TESTER_H_*/ |