diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-04-12 20:41:31 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-04-12 20:41:31 +0000 |
commit | 774a362e87feab25f1be16fbca08269ddc7121a4 (patch) | |
tree | cf71f4e7466468ac3edc2127125f333224a9acfb /src/charon/bus | |
parent | c54a140a445bfe7aa66721f68bb0781f26add91c (diff) | |
download | vyos-strongswan-774a362e87feab25f1be16fbca08269ddc7121a4.tar.gz vyos-strongswan-774a362e87feab25f1be16fbca08269ddc7121a4.zip |
Major new upstream release, just ran svn-upgrade for now (and wrote some
debian/changelong entries).
Diffstat (limited to 'src/charon/bus')
-rw-r--r-- | src/charon/bus/bus.c | 397 | ||||
-rw-r--r-- | src/charon/bus/bus.h | 366 | ||||
-rw-r--r-- | src/charon/bus/listeners/file_logger.c | 128 | ||||
-rw-r--r-- | src/charon/bus/listeners/file_logger.h | 73 | ||||
-rw-r--r-- | src/charon/bus/listeners/sys_logger.c | 131 | ||||
-rw-r--r-- | src/charon/bus/listeners/sys_logger.h | 75 |
6 files changed, 1170 insertions, 0 deletions
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c new file mode 100644 index 000000000..740663d5c --- /dev/null +++ b/src/charon/bus/bus.c @@ -0,0 +1,397 @@ +/** + * @file bus.c + * + * @brief Implementation of bus_t. + * + */ + +/* + * Copyright (C) 2006 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 "bus.h" + +#include <pthread.h> + +ENUM(signal_names, SIG_ANY, SIG_MAX, + /** should not get printed */ + "SIG_ANY", + /** debugging message types */ + "DMN", + "MGR", + "IKE", + "CHD", + "JOB", + "CFG", + "KNL", + "NET", + "ENC", + "LIB", + /** should not get printed */ + "SIG_DBG_MAX", + /** all level0 signals are AUDIT signals */ + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + "AUD", "AUD", "AUD", + /** should not get printed */ + "SIG_MAX", +); + +typedef struct active_listener_t active_listener_t; + +/** + * information for a active listener + */ +struct active_listener_t { + + /** + * associated thread + */ + pthread_t id; + + /** + * condvar to wait for a signal + */ + pthread_cond_t cond; + + /** + * state of the thread + */ + enum { + /** not registered, do not wait for thread */ + UNREGISTERED, + /** registered, if a signal occurs, wait until it is LISTENING */ + REGISTERED, + /** listening, deliver signal */ + LISTENING, + } state; + + /** + * currently processed signals type + */ + signal_t signal; + + /** + * verbosity level of the signal + */ + level_t level; + + /** + * current processed signals thread number + */ + int thread; + + /** + * currently processed signals ike_sa + */ + ike_sa_t *ike_sa; + + /** + * currently processed signals format string + */ + char *format; + + /** + * currently processed signals format varargs + */ + va_list args; + +}; + +typedef struct private_bus_t private_bus_t; + +/** + * Private data of a bus_t object. + */ +struct private_bus_t { + /** + * Public part of a bus_t object. + */ + bus_t public; + + /** + * List of registered listeners implementing the bus_t interface + */ + linked_list_t *listeners; + + /** + * List of active listeners with listener_state TRUE + */ + linked_list_t *active_listeners; + + /** + * mutex to synchronize active listeners + */ + pthread_mutex_t mutex; + + /** + * Thread local storage for a unique, simple thread ID + */ + pthread_key_t thread_id; + + /** + * Thread local storage the threads IKE_SA + */ + pthread_key_t thread_sa; + +}; + +/** + * Get a unique thread number for a calling thread. Since + * pthread_self returns large and ugly numbers, use this function + * for logging; these numbers are incremental starting at 1 + */ +static int get_thread_number(private_bus_t *this) +{ + static long current_num = 0; + static long stored_num; + + stored_num = (long)pthread_getspecific(this->thread_id); + if (stored_num == 0) + { /* first call of current thread */ + pthread_setspecific(this->thread_id, (void*)++current_num); + return current_num; + } + else + { + return stored_num; + } +} + +/** + * Implementation of bus_t.add_listener. + */ +static void add_listener(private_bus_t *this, bus_listener_t *listener) +{ + pthread_mutex_lock(&this->mutex); + this->listeners->insert_last(this->listeners, listener); + pthread_mutex_unlock(&this->mutex); +} + +/** + * Get the listener object for the calling thread + */ +static active_listener_t *get_active_listener(private_bus_t *this) +{ + active_listener_t *current, *found = NULL; + iterator_t *iterator; + + /* if the thread was here once before, we have a active_listener record */ + iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (current->id == pthread_self()) + { + found = current; + break; + } + } + iterator->destroy(iterator); + + if (found == NULL) + { + /* create a new object for a never-seen thread */ + found = malloc_thing(active_listener_t); + found->id = pthread_self(); + pthread_cond_init(&found->cond, NULL); + this->active_listeners->insert_last(this->active_listeners, found); + } + + return found; +} + +/** + * Implementation of bus_t.listen. + */ +static signal_t listen_(private_bus_t *this, level_t *level, int *thread, + ike_sa_t **ike_sa, char** format, va_list* args) +{ + active_listener_t *listener; + + pthread_mutex_lock(&this->mutex); + listener = get_active_listener(this); + /* go "listening", say hello to a thread which have a signal for us */ + listener->state = LISTENING; + pthread_cond_broadcast(&listener->cond); + /* wait until it has us delivered a signal, and go back to "registered" */ + pthread_cond_wait(&listener->cond, &this->mutex); + pthread_mutex_unlock(&this->mutex); + + /* return signal values */ + *level = listener->level; + *thread = listener->thread; + *ike_sa = listener->ike_sa; + *format = listener->format; + va_copy(*args, listener->args); + va_end(listener->args); + + return listener->signal; +} + +/** + * Implementation of bus_t.set_listen_state. + */ +static void set_listen_state(private_bus_t *this, bool active) +{ + active_listener_t *listener; + + pthread_mutex_lock(&this->mutex); + + listener = get_active_listener(this); + if (active) + { + listener->state = REGISTERED; + } + else + { + listener->state = UNREGISTERED; + /* say hello to signal emitter; we are finished processing the signal */ + pthread_cond_signal(&listener->cond); + } + + pthread_mutex_unlock(&this->mutex); +} + + +/** + * Implementation of bus_t.set_sa. + */ +static void set_sa(private_bus_t *this, ike_sa_t *ike_sa) +{ + pthread_setspecific(this->thread_sa, ike_sa); +} + +/** + * Implementation of bus_t.vsignal. + */ +static void vsignal(private_bus_t *this, signal_t signal, level_t level, + char* format, va_list args) +{ + iterator_t *iterator; + bus_listener_t *listener; + active_listener_t *active_listener; + ike_sa_t *ike_sa; + long thread; + + ike_sa = pthread_getspecific(this->thread_sa); + thread = get_thread_number(this); + + pthread_mutex_lock(&this->mutex); + + /* do the job for all passive bus_listeners */ + iterator = this->listeners->create_iterator(this->listeners, TRUE); + while (iterator->iterate(iterator, (void**)&listener)) + { + va_list args_copy; + + va_copy(args_copy, args); + if (!listener->signal(listener, signal, level, thread, + ike_sa, format, args_copy)) + { + /* unregister listener if requested */ + iterator->remove(iterator); + } + va_end(args_copy); + } + iterator->destroy(iterator); + + /* wake up all active listeners */ + iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE); + while (iterator->iterate(iterator, (void**)&active_listener)) + { + /* wait until it is back */ + while (active_listener->state == REGISTERED) + { + pthread_cond_wait(&active_listener->cond, &this->mutex); + } + /* if thread is listening now, give it the signal to process */ + if (active_listener->state == LISTENING) + { + active_listener->level = level; + active_listener->thread = thread; + active_listener->ike_sa = ike_sa; + active_listener->signal = signal; + active_listener->format = format; + va_copy(active_listener->args, args); + active_listener->state = REGISTERED; + pthread_cond_signal(&active_listener->cond); + } + } + + /* we must wait now until all are not in state REGISTERED, + * as they may still use our arguments */ + iterator->reset(iterator); + while (iterator->iterate(iterator, (void**)&active_listener)) + { + while (active_listener->state == REGISTERED) + { + pthread_cond_wait(&active_listener->cond, &this->mutex); + } + } + iterator->destroy(iterator); + + pthread_mutex_unlock(&this->mutex); +} + +/** + * Implementation of bus_t.signal. + */ +static void signal_(private_bus_t *this, signal_t signal, level_t level, + char* format, ...) +{ + va_list args; + + va_start(args, format); + vsignal(this, signal, level, format, args); + va_end(args); +} + +/** + * Implementation of bus_t.destroy. + */ +static void destroy(private_bus_t *this) +{ + this->active_listeners->destroy_function(this->active_listeners, free); + this->listeners->destroy(this->listeners); + free(this); +} + +/* + * Described in header. + */ +bus_t *bus_create() +{ + private_bus_t *this = malloc_thing(private_bus_t); + + this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener; + this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_; + this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state; + this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa; + this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_; + this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal; + this->public.destroy = (void(*)(bus_t*)) destroy; + + this->listeners = linked_list_create(); + this->active_listeners = linked_list_create(); + pthread_mutex_init(&this->mutex, NULL); + pthread_key_create(&this->thread_id, NULL); + pthread_key_create(&this->thread_sa, NULL); + + return &(this->public); +} diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h new file mode 100644 index 000000000..200525fb7 --- /dev/null +++ b/src/charon/bus/bus.h @@ -0,0 +1,366 @@ +/** + * @file bus.h + * + * @brief Interface of bus_t. + * + */ + +/* + * Copyright (C) 2006 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 BUS_H_ +#define BUS_H_ + +typedef enum signal_t signal_t; +typedef enum level_t level_t; +typedef struct bus_listener_t bus_listener_t; +typedef struct bus_t bus_t; + +#include <stdarg.h> + +#include <sa/ike_sa.h> +#include <sa/child_sa.h> + + +/** + * @brief signals emitted by the daemon. + * + * Signaling is for different purporses. First, it allows debugging via + * "debugging signal messages", sencondly, it allows to follow certain + * mechanisms currently going on in the daemon. As we are multithreaded, + * and of multiple transactions are involved, it's not possible to follow + * one connection setup without further infrastructure. These infrastructure + * is provided by the bus and the signals the daemon emits to the bus. + * + * There are different scenarios to follow these signals, but all have + * the same scheme. First, a START signal is emitted to indicate the daemon + * has started to + * + * @ingroup bus + */ +enum signal_t { + /** pseudo signal, representing any other signal */ + SIG_ANY, + + /** debugging message from daemon main loop */ + DBG_DMN, + /** debugging message from IKE_SA_MANAGER */ + DBG_MGR, + /** debugging message from an IKE_SA */ + DBG_IKE, + /** debugging message from a CHILD_SA */ + DBG_CHD, + /** debugging message from job processing */ + DBG_JOB, + /** debugging message from configuration backends */ + DBG_CFG, + /** debugging message from kernel interface */ + DBG_KNL, + /** debugging message from networking */ + DBG_NET, + /** debugging message from message encoding/decoding */ + DBG_ENC, + /** debugging message from libstrongswan via logging hook */ + DBG_LIB, + + /** number of debug signals */ + DBG_MAX, + + /** signals for IKE_SA establishment */ + IKE_UP_START, + IKE_UP_SUCCESS, + IKE_UP_FAILED, + + /** signals for IKE_SA delete */ + IKE_DOWN_START, + IKE_DOWN_SUCCESS, + IKE_DOWN_FAILED, + + /** signals for IKE_SA rekeying */ + IKE_REKEY_START, + IKE_REKEY_SUCCESS, + IKE_REKEY_FAILED, + + /** signals for CHILD_SA establishment */ + CHILD_UP_START, + CHILD_UP_SUCCESS, + CHILD_UP_FAILED, + + /** signals for CHILD_SA delete */ + CHILD_DOWN_START, + CHILD_DOWN_SUCCESS, + CHILD_DOWN_FAILED, + + /** signals for CHILD_SA rekeying */ + CHILD_REKEY_START, + CHILD_REKEY_SUCCESS, + CHILD_REKEY_FAILED, + + /** signals for CHILD_SA routing */ + CHILD_ROUTE_START, + CHILD_ROUTE_SUCCESS, + CHILD_ROUTE_FAILED, + + /** signals for CHILD_SA routing */ + CHILD_UNROUTE_START, + CHILD_UNROUTE_SUCCESS, + CHILD_UNROUTE_FAILED, + + SIG_MAX +}; + +/** + * short names of signals using 3 chars + */ +extern enum_name_t *signal_names; + +/** + * Signal levels used to control output verbosity. + */ +enum level_t { + /** numerical levels from 0 to 4 */ + LEVEL_0 = 0, + LEVEL_1 = 1, + LEVEL_2 = 2, + LEVEL_3 = 3, + LEVEL_4 = 4, + /** absolutely silent, no signal is emitted with this level */ + LEVEL_SILENT = -1, + /** alias for numberical levels */ + LEVEL_AUDIT = LEVEL_0, + LEVEL_CTRL = LEVEL_1, + LEVEL_CTRLMORE = LEVEL_2, + LEVEL_RAW = LEVEL_3, + LEVEL_PRIVATE = LEVEL_4, +}; + +#ifndef DEBUG_LEVEL +# define DEBUG_LEVEL 4 +#endif /* DEBUG_LEVEL */ + +#if DEBUG_LEVEL >= 1 +/** + * @brief Log a debug message via the signal bus. + * + * @param signal signal_t signal description + * @param format printf() style format string + * @param ... printf() style agument list + */ +# define DBG1(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_1, format, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 2 +#define DBG2(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_2, format, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 3 +#define DBG3(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_3, format, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ +#if DEBUG_LEVEL >= 4 +#define DBG4(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_4, format, ##__VA_ARGS__) +#endif /* DEBUG_LEVEL */ + +#ifndef DBG1 +# define DBG1(...) {} +#endif /* DBG1 */ +#ifndef DBG2 +# define DBG2(...) {} +#endif /* DBG2 */ +#ifndef DBG3 +# define DBG3(...) {} +#endif /* DBG3 */ +#ifndef DBG4 +# define DBG4(...) {} +#endif /* DBG4 */ + +/** + * @brief Raise a signal for an occured event. + * + * @param sig signal_t signal description + * @param format printf() style format string + * @param ... printf() style agument list + */ +#define SIG(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_0, format, ##__VA_ARGS__) + +/** + * @brief Get the type of a signal. + * + * A signal may be a debugging signal with a specific context. They have + * a level specific for their context > 0. All audit signals use the + * type 0. This allows filtering of singals by their type. + * + * @param signal signal to get the type from + * @return type of the signal, between 0..(DBG_MAX-1) + */ +#define SIG_TYPE(sig) (sig > DBG_MAX ? SIG_ANY : sig) + + +/** + * @brief Interface for registering at the signal bus. + * + * To receive signals from the bus, the client implementing the + * bus_listener_t interface registers itself at the signal bus. + * + * @ingroup bus + */ +struct bus_listener_t { + + /** + * @brief Send a signal to a bus listener. + * + * A numerical identification for the thread is included, as the + * associated IKE_SA, if any. Signal specifies the type of + * the event occured. The format string specifies + * an additional informational or error message with a printf() like + * variable argument list. This is in the va_list form, as forwarding + * a "..." parameters to functions is not (cleanly) possible. + * The implementing signal function returns TRUE to stay registered + * to the bus, or FALSE to unregister itself. + * + * @param this listener + * @param singal kind of the signal (up, down, rekeyed, ...) + * @param level verbosity level of the signal + * @param thread ID of the thread raised this signal + * @param ike_sa IKE_SA associated to the event + * @param format printf() style format string + * @param args vprintf() style va_list argument list + " @return TRUE to stay registered, FALSE to unregister + */ + bool (*signal) (bus_listener_t *this, signal_t signal, level_t level, + int thread, ike_sa_t *ike_sa, char* format, va_list args); +}; + +/** + * @brief Signal bus which sends signals to registered listeners. + * + * The signal bus is not much more than a multiplexer. A listener interested + * in receiving event signals registers at the bus. Any signals sent to + * are delivered to all registered listeners. + * To deliver signals to threads, the blocking listen() call may be used + * to wait for a signal. + * + * @ingroup bus + */ +struct bus_t { + + /** + * @brief Register a listener to the bus. + * + * A registered listener receives all signals which are sent to the bus. + * The listener is passive; the thread which emitted the signal + * processes the listener routine. + * + * @param this bus + * @param listener listener to register. + */ + void (*add_listener) (bus_t *this, bus_listener_t *listener); + + /** + * @brief Listen actively on the bus. + * + * As we are fully multithreaded, we must provide a mechanism + * for active threads to listen to the bus. With the listen() method, + * a thread waits until a signal occurs, and then processes it. + * To prevent the listen() calling thread to miss signals emitted while + * it processes a signal, registration is required. This is done through + * the set_listen_state() method, see below. + * + * @param this bus + * @param level verbosity level of the signal + * @param thread receives thread number emitted the signal + * @param ike_sa receives the IKE_SA involved in the signal, or NULL + * @param format receives the format string supplied with the signal + * @param va_list receives the variable argument list for format + * @return the emitted signal type + */ + signal_t (*listen) (bus_t *this, level_t* level, int *thread, + ike_sa_t **ike_sa, char** format, va_list* args); + + /** + * @brief Set the listening state of the calling thread. + * + * To prevent message loss for active listeners using listen(), threads + * must register themself to the bus before starting to listen(). When + * a signal occurs, the emitter waits until all threads with listen_state + * TRUE are waiting in the listen() method to process the signal. + * It is important that a thread with liste_state TRUE calls listen() + * periodically, or sets it's listening state to FALSE; otherwise + * all signal emitting threads get blocked on the bus. + * + * @param this bus + * @param active TRUE to set to listening + */ + void (*set_listen_state) (bus_t *this, bool active); + + /** + * @brief Set the IKE_SA the calling thread is using. + * + * To associate an received signal to an IKE_SA without passing it as + * parameter each time, the thread registers it's used IKE_SA each + * time it checked it out. Before checking it in, the thread unregisters + * the IKE_SA (by passing NULL). This IKE_SA is stored per-thread, so each + * thread has one IKE_SA registered (or not). + * + * @param this bus + * @param ike_sa ike_sa to register, or NULL to unregister + */ + void (*set_sa) (bus_t *this, ike_sa_t *ike_sa); + + /** + * @brief Send a signal to the bus. + * + * The signal specifies the type of the event occured. The format string + * specifies an additional informational or error message with a + * printf() like variable argument list. + * Some useful macros are available to shorten this call. + * @see SIG(), DBG1() + * + * @param this bus + * @param singal kind of the signal (up, down, rekeyed, ...) + * @param level verbosity level of the signal + * @param format printf() style format string + * @param ... printf() style argument list + */ + void (*signal) (bus_t *this, signal_t signal, level_t level, char* format, ...); + + /** + * @brief Send a signal to the bus using va_list arguments. + * + * Same as bus_t.signal(), but uses va_list argument list. + * + * @param this bus + * @param singal kind of the signal (up, down, rekeyed, ...) + * @param level verbosity level of the signal + * @param format printf() style format string + * @param args va_list arguments + */ + void (*vsignal) (bus_t *this, signal_t signal, level_t level, char* format, va_list args); + + /** + * @brief Destroy the signal bus. + * + * @param this bus to destroy + */ + void (*destroy) (bus_t *this); +}; + +/** + * @brief Create the signal bus which multiplexes signals to its listeners. + * + * @return signal bus instance + * + * @ingroup bus + */ +bus_t *bus_create(); + +#endif /* BUS_H_ */ diff --git a/src/charon/bus/listeners/file_logger.c b/src/charon/bus/listeners/file_logger.c new file mode 100644 index 000000000..14f9f72cf --- /dev/null +++ b/src/charon/bus/listeners/file_logger.c @@ -0,0 +1,128 @@ +/** + * @file file_logger.c + * + * @brief Implementation of file_logger_t. + * + */ + +/* + * Copyright (C) 2006 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 <stdio.h> +#include <string.h> + +#include "file_logger.h" + + +typedef struct private_file_logger_t private_file_logger_t; + +/** + * Private data of a file_logger_t object + */ +struct private_file_logger_t { + + /** + * Public data. + */ + file_logger_t public; + + /** + * output file + */ + FILE *out; + + /** + * Maximum level to log + */ + level_t levels[DBG_MAX]; +}; + + +/** + * Implementation of bus_listener_t.signal. + */ +static bool signal_(private_file_logger_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) +{ + if (level <= this->levels[SIG_TYPE(signal)]) + { + char buffer[8192]; + char *current = buffer, *next; + + /* write in memory buffer first */ + vsnprintf(buffer, sizeof(buffer), format, args); + + /* prepend a prefix in front of every line */ + while (current) + { + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + fprintf(this->out, "%.2d[%N] %s\n", thread, signal_names, signal, current); + current = next; + } + } + /* always stay registered */ + return TRUE; +} + +/** + * Implementation of file_logger_t.set_level. + */ +static void set_level(private_file_logger_t *this, signal_t signal, level_t level) +{ + if (signal == SIG_ANY) + { + int i; + for (i = 0; i < DBG_MAX; i++) + { + this->levels[i] = level; + } + } + else + { + + this->levels[SIG_TYPE(signal)] = level; + } +} + +/** + * Implementation of file_logger_t.destroy. + */ +static void destroy(private_file_logger_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +file_logger_t *file_logger_create(FILE *out) +{ + private_file_logger_t *this = malloc_thing(private_file_logger_t); + + /* public functions */ + this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_; + this->public.set_level = (void(*)(file_logger_t*,signal_t,level_t))set_level; + this->public.destroy = (void(*)(file_logger_t*))destroy; + + /* private variables */ + this->out = out; + set_level(this, SIG_ANY, LEVEL_SILENT); + + return &this->public; +} diff --git a/src/charon/bus/listeners/file_logger.h b/src/charon/bus/listeners/file_logger.h new file mode 100644 index 000000000..d67daba25 --- /dev/null +++ b/src/charon/bus/listeners/file_logger.h @@ -0,0 +1,73 @@ +/** + * @file file_logger.h + * + * @brief Interface of file_logger_t. + * + */ + +/* + * Copyright (C) 2006 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 FILE_LOGGER_H_ +#define FILE_LOGGER_H_ + +typedef struct file_logger_t file_logger_t; + +#include <bus/bus.h> + +/** + * @brief Logger to files which implements bus_listener_t. + * + * @b Constructors: + * - file_logger_create() + * + * @ingroup listeners + */ +struct file_logger_t { + + /** + * Implements the bus_listener_t interface. + */ + bus_listener_t listener; + + /** + * @brief Set the loglevel for a signal type. + * + * @param this stream_logger_t object + * @param singal type of signal + * @param level max level to log (0..4) + */ + void (*set_level) (file_logger_t *this, signal_t signal, level_t level); + + /** + * @brief Destroys a file_logger_t object. + * + * @param this file_logger_t object + */ + void (*destroy) (file_logger_t *this); +}; + +/** + * @brief Constructor to create a file_logger_t object. + * + * @param out FILE to write to + * @return file_logger_t object + * + * @ingroup listeners + */ +file_logger_t *file_logger_create(FILE *out); + + +#endif /* FILE_LOGGER_H_ */ diff --git a/src/charon/bus/listeners/sys_logger.c b/src/charon/bus/listeners/sys_logger.c new file mode 100644 index 000000000..d26d14dc0 --- /dev/null +++ b/src/charon/bus/listeners/sys_logger.c @@ -0,0 +1,131 @@ +/** + * @file sys_logger.c + * + * @brief Implementation of sys_logger_t. + * + */ + +/* + * Copyright (C) 2006 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 <stdio.h> +#include <string.h> +#include <pthread.h> + +#include "sys_logger.h" + + +typedef struct private_sys_logger_t private_sys_logger_t; + +/** + * Private data of a sys_logger_t object + */ +struct private_sys_logger_t { + + /** + * Public data. + */ + sys_logger_t public; + + /** + * syslog facility to use + */ + int facility; + + /** + * Maximum level to log + */ + level_t levels[DBG_MAX]; +}; + + +/** + * Implementation of bus_listener_t.signal. + */ +static bool signal_(private_sys_logger_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) +{ + if (level <= this->levels[SIG_TYPE(signal)]) + { + char buffer[8192]; + char *current = buffer, *next; + + /* write in memory buffer first */ + vsnprintf(buffer, sizeof(buffer), format, args); + + /* do a syslog with every line */ + while (current) + { + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(this->facility|LOG_INFO, "%.2d[%N] %s\n", + thread, signal_names, signal, current); + current = next; + } + } + /* always stay registered */ + return TRUE; +} + +/** + * Implementation of sys_logger_t.set_level. + */ +static void set_level(private_sys_logger_t *this, signal_t signal, level_t level) +{ + if (signal == SIG_ANY) + { + int i; + for (i = 0; i < DBG_MAX; i++) + { + this->levels[i] = level; + } + } + else + { + + this->levels[SIG_TYPE(signal)] = level; + } +} + +/** + * Implementation of sys_logger_t.destroy. + */ +static void destroy(private_sys_logger_t *this) +{ + closelog(); + free(this); +} + +/* + * Described in header. + */ +sys_logger_t *sys_logger_create(int facility) +{ + private_sys_logger_t *this = malloc_thing(private_sys_logger_t); + + /* public functions */ + this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_; + this->public.set_level = (void(*)(sys_logger_t*,signal_t,level_t))set_level; + this->public.destroy = (void(*)(sys_logger_t*))destroy; + + /* private variables */ + this->facility = facility; + set_level(this, SIG_ANY, LEVEL_SILENT); + + return &this->public; +} diff --git a/src/charon/bus/listeners/sys_logger.h b/src/charon/bus/listeners/sys_logger.h new file mode 100644 index 000000000..091217313 --- /dev/null +++ b/src/charon/bus/listeners/sys_logger.h @@ -0,0 +1,75 @@ +/** + * @file sys_logger.h + * + * @brief Interface of sys_logger_t. + * + */ + +/* + * Copyright (C) 2006 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 SYS_LOGGER_H_ +#define SYS_LOGGER_H_ + +typedef struct sys_logger_t sys_logger_t; + +#include <syslog.h> + +#include <bus/bus.h> + +/** + * @brief Logger for syslog which implements bus_listener_t. + * + * @b Constructors: + * - sys_logger_create() + * + * @ingroup listeners + */ +struct sys_logger_t { + + /** + * Implements the bus_listener_t interface. + */ + bus_listener_t listener; + + /** + * @brief Set the loglevel for a signal type. + * + * @param this stream_logger_t object + * @param singal type of signal + * @param level max level to log + */ + void (*set_level) (sys_logger_t *this, signal_t signal, level_t level); + + /** + * @brief Destroys a sys_logger_t object. + * + * @param this sys_logger_t object + */ + void (*destroy) (sys_logger_t *this); +}; + +/** + * @brief Constructor to create a sys_logger_t object. + * + * @param facility syslog facility to use + * @return sys_logger_t object + * + * @ingroup listeners + */ +sys_logger_t *sys_logger_create(int facility); + + +#endif /* SYS_LOGGER_H_ */ |