diff options
Diffstat (limited to 'src/charon/bus')
-rw-r--r-- | src/charon/bus/bus.c | 274 | ||||
-rw-r--r-- | src/charon/bus/bus.h | 294 | ||||
-rw-r--r-- | src/charon/bus/listeners/file_logger.c | 125 | ||||
-rw-r--r-- | src/charon/bus/listeners/file_logger.h | 2 | ||||
-rw-r--r-- | src/charon/bus/listeners/stream_logger.c | 141 | ||||
-rw-r--r-- | src/charon/bus/listeners/stream_logger.h | 75 | ||||
-rw-r--r-- | src/charon/bus/listeners/sys_logger.c | 126 |
7 files changed, 561 insertions, 476 deletions
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index 1e5ff9857..028fd37c9 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -22,6 +22,102 @@ #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", + /** 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; /** @@ -39,6 +135,16 @@ struct private_bus_t { 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; @@ -76,10 +182,96 @@ static int get_thread_number(private_bus_t *this) */ static void add_listener(private_bus_t *this, bus_listener_t *listener) { + pthread_mutex_lock(&this->mutex); this->listeners->insert_last(this->listeners, (void*)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; + *args = 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 omitter; 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) @@ -88,28 +280,83 @@ static void set_sa(private_bus_t *this, ike_sa_t *ike_sa) } /** - * Implementation of bus_t.signal. + * Implementation of bus_t.vsignal. */ -static void signal_(private_bus_t *this, signal_t signal, level_t condition, - char* format, ...) +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; - va_list args; + active_listener_t *active_listener; ike_sa_t *ike_sa; int thread; ike_sa = pthread_getspecific(this->thread_sa); thread = get_thread_number(this); - va_start(args, format); + 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)) { - listener->signal(listener, thread, ike_sa, - signal, condition, format, args); + va_list args_copy; + + va_copy(args_copy, args); + listener->signal(listener, signal, level, thread, ike_sa, format, args_copy); + 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); + } + va_end(active_listener->args); + } + 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); } @@ -118,6 +365,14 @@ static void signal_(private_bus_t *this, signal_t signal, level_t condition, */ static void destroy(private_bus_t *this) { + active_listener_t *listener; + while (this->active_listeners->remove_last(this->active_listeners, + (void**)&listener) == SUCCESS) + { + free(listener); + } + + this->active_listeners->destroy(this->active_listeners); this->listeners->destroy(this->listeners); free(this); } @@ -130,11 +385,16 @@ 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); diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index cce1f4217..d04ce4c4c 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -29,60 +29,81 @@ #include <sa/child_sa.h> -/** - * @brief Raise a signal for an occured event. - * - * @param sig signal_t signal description - * @param level level for the signal - * @param format printf() style format string - * @param ... printf() style agument list - */ -#define SIG(sig, level, format, ...) charon->bus->signal(charon->bus, sig, level, format, ##__VA_ARGS__) +typedef enum signal_t signal_t; /** - * @brief Set the IKE_SA the calling thread is using. + * @brief signals ommited by the daemon. * - * @param ike_sa ike_sa to register, or NULL to unregister - */ -#define SIG_SA(ike_sa) charon->bus->set_sa(charon->bus, ike_sa) + * 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 a multiple messages 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 whole daemon ommits to the bus. + * + * @par Schema 1: Signals involved in IKE_SA/CHILD_SA initiation + * + * In the initiation of a IKE- or CHILD_SA is triggered by three possible + * sources: User request, a request from the other peer, or a request + * triggered by the kernel. + * Once the user requests initiation, the SIG_INITIATE signal is ommited. + * This signal contains the IKE_SA that got created. Any further signals + * have the same IKE_SA and are therefore easy to trace. + * If the kernel initiates, a SIG_ACQUIRE is sent over the bus. + * If a new IKE_SA is needed, it is set up. If it succeeds, a + * SIG_IKE_ESTABLISHED is ommitted. If the peer didn't accept our DH + * group, the initiation fails. A SIG_DH_INVALID is sent over the bus. It still + * contains the the old IKE_SA. Shortly afterwards, a SIG_DH_RETRY is ommited. + * It contains the NEW IKE_SA. This mechanism allows us to trace the setup even + * beyond a INVALID_KE_PAYLOUD error. + * If the setup fails, SIG_IKE_ESTABLISH_FAILED is sent. + * After a successful establishment of the IKE_SA, or if an already established + * IKE_SA is reused, the child establishment begins. If it is set up with + * the ike_auth transaction, the SIG_CHILD_ESTABLISHED signal is ommited + * directly after the SIG_IKE_ESTABLISHED signal, as both are set up + * simultaneously. The child setup may fail (in a ike_auth, or in a + * create_child_sa exchange), if so, the SIG_CHID_ESTABLISH_FAILED signal + * is raised. + * + * @verbatim -/** - * @brief Log a debug message via the signal bus. + "ipsec up" "peer msg" "kernel acquire" + | | | + V | V + SIG_INITIATE | SIG_ACQUIRE + \ | / + \ |/______________________________________________ + \/________________________________ \ + /\ \ \ | + | | | | | + V V | V | + SIG_IKE_ESTABLISHED SIG_IKE_ESTABLISH_FALIED | SIG_DH_INVALID | + \ | | | | + \ X | V | + \___________________________/ SIG_DH_RETRY | + /\ \______________/ + | | + V V + SIG_CHILD_ESTABLISHED SIG_CHILD_ESTABLISH_FAILED + | + X + @endverbatim + * Other scenarios are much simpler. Termination is just indicated with + * a simple SIG_CHILD_TERMINATED and/or SIG_IKE_TERMINATED signal. There + * are other signals as SIG_CHILD_ROUTED or SIG_CHILD_UNROUTED. Rekeying is + * also trivial (SIG_IKE_REKEYED/SIG_CHILD_REKEYED), but may contain + * SIG_DH_INVALID... * - * @param signal signal_t signal description - * @param format printf() style format string - * @param ... printf() style agument list + * @ingroup bus */ -#define DBG1(sig, format, ...) charon->bus->signal(charon->bus, sig, LEV_DBG1, format, ##__VA_ARGS__) -#define DBG2(sig, format, ...) charon->bus->signal(charon->bus, sig, LEV_DBG2, format, ##__VA_ARGS__) -#define DBG3(sig, format, ...) charon->bus->signal(charon->bus, sig, LEV_DBG3, format, ##__VA_ARGS__) -#define DBG4(sig, format, ...) charon->bus->signal(charon->bus, sig, LEV_DBG4, format, ##__VA_ARGS__) - - -typedef enum signal_t signal_t; - enum signal_t { - /** an IKE_SA has been established */ - SIG_IKE_UP, - /** an IKE_SA has been closed */ - SIG_IKE_DOWN, - /** an IKE_SA has been rekeyed */ - SIG_IKE_REKEY, - /** a CHILD_SA has been installed */ - SIG_CHILD_UP, - /** a CHILD_SA has been closed */ - SIG_CHILD_DOWN, - /** a CHILD_SA has been rekeyed */ - SIG_CHILD_REKEY, - /** a CHILD_SA has been routed */ - SIG_CHILD_ROUTE, - /** a CHILD_SA has been unrouted */ - SIG_CHILD_UNROUTE, - /** a remote peer has been authenticated using RSA digital signature */ - SIG_AUTH_RSA, - /** a remote peer has been authenticated using preshared keys */ - SIG_AUTH_PSK, + /** pseudo signal, representing any other signal */ + SIG_ANY, + /** debugging messages printed from daemon main loop */ + SIG_DBG_DMN, + /** debugging message printed from IKE_SA_MANAGER */ + SIG_DBG_MGR, /** debugging message printed from an IKE_SA */ SIG_DBG_IKE, /** debugging message printed from a CHILD_SA */ @@ -97,27 +118,103 @@ enum signal_t { SIG_DBG_NET, /** debugging message printed from message encoding/decoding */ SIG_DBG_ENC, + /** debugging message printed from libstrongswan via logging hook */ + SIG_DBG_LIB, + + /** number of debug signals */ + SIG_DBG_MAX, + + /** initiation started on user request */ + SIG_INITIATE, + /** acquiring on kernel request */ + SIG_ACQUIRE, + + /** an IKE_SA has been established */ + SIG_IKE_UP, + /** an IKE_SA has been closed as requested */ + SIG_IKE_DOWN, + /** an IKE_SA got deleted due an error */ + SIG_IKE_FAILED, + /** an IKE_SA has been rekeyed */ + SIG_IKE_REKEY, + + /** a CHILD_SA has been established */ + SIG_CHILD_UP, + /** a CHILD_SA has been closed as requested */ + SIG_CHILD_DOWN, + /** a CHILD_SA got deleted due an error */ + SIG_CHILD_FAILED, + /** a CHILD_SA has been rekeyed */ + SIG_CHILD_REKEY, + /** a CHILD_SA has been routed */ + SIG_CHILD_ROUTE, + /** a CHILD_SA has been unrouted */ + SIG_CHILD_UNROUTE, - SIG_MAX, + SIG_MAX }; +/** + * short names of signals using 3 chars + */ +extern enum_name_t *signal_names; + typedef enum level_t level_t; +/** + * Signal levels used to control output verbosity. + */ enum level_t { - /** Signal indicates something has failed */ - LEV_FAILED, - /** Signal indicates something was successful */ - LEV_SUCCESS, - /** Debug level 1, control flow messages */ - LEV_DBG1, - /** Debug level 2, more detail informational messages */ - LEV_DBG2, - /** Debug level 3, RAW data output */ - LEV_DBG3, - /** Debug level 4, RAW data with sensitive (private) data */ - LEV_DBG4, + /** 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 ommited 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, }; +/** + * @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 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__) +#define DBG2(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_2, format, ##__VA_ARGS__) +#define DBG3(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_3, format, ##__VA_ARGS__) +#define DBG4(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_4, 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..(SIG_DBG_MAX-1) + */ +#define SIG_TYPE(sig) (sig > SIG_DBG_MAX ? SIG_ANY : sig) + + typedef struct bus_listener_t bus_listener_t; /** @@ -135,21 +232,21 @@ struct bus_listener_t { * * A numerical identification for the thread is included, as the * associated IKE_SA, if any. Signal specifies the type of - * the event occured, with a verbosity level. The format string specifies + * 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. * * @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 singal kind of the signal (up, down, rekeyed, ...) - * @param level level for signal * @param format printf() style format string * @param args vprintf() style va_list argument list */ - void (*signal) (bus_listener_t *this, int thread, ike_sa_t *ike_sa, - signal_t signal, level_t level, char* format, va_list args); + void (*signal) (bus_listener_t *this, signal_t signal, level_t level, + int thread, ike_sa_t *ike_sa, char* format, va_list args); }; @@ -161,7 +258,8 @@ typedef struct bus_t bus_t; * 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 */ @@ -171,6 +269,8 @@ 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 ommited the signal + * processes the listener routine. * * @param this bus * @param listener listener to register. @@ -178,6 +278,43 @@ struct bus_t { 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 ommited 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 ommited 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 ommited 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 ommiter 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 omitting 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 @@ -185,8 +322,6 @@ struct bus_t { * 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). - * There is a macro to simplify the call. - * @see SIG_SA() * * @param this bus * @param ike_sa ike_sa to register, or NULL to unregister @@ -196,23 +331,34 @@ struct bus_t { /** * @brief Send a signal to the bus. * - * A signal may belong to an IKE_SA and a CHILD_SA. If so, these - * are supplied to the signal function. 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 may be available to shorten this call. + * 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 status level of the signal to send + * @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 diff --git a/src/charon/bus/listeners/file_logger.c b/src/charon/bus/listeners/file_logger.c index 4a2fe4b9e..794548b0e 100644 --- a/src/charon/bus/listeners/file_logger.c +++ b/src/charon/bus/listeners/file_logger.c @@ -20,15 +20,11 @@ * for more details. */ -/* for fmemopen() */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include "file_logger.h" -#include <bus/listeners/stream_logger.h> - typedef struct private_file_logger_t private_file_logger_t; @@ -48,99 +44,58 @@ struct private_file_logger_t { FILE *out; /** - * Internal used stream logger that does the dirty work - */ - stream_logger_t *logger; - - /** - * Memory stream used for stream_logger - */ - FILE *stream; - - /** - * Underlying buffer for stream + * Maximum level to log */ - char buffer[4096]; + level_t levels[SIG_DBG_MAX]; }; /** * Implementation of bus_listener_t.signal. */ -static void signal_(private_file_logger_t *this, int thread, ike_sa_t* ike_sa, - signal_t signal, level_t level, - char *format, va_list args) +static void signal_(private_file_logger_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) { - char line[512]; - char *prefix; - FILE *reader; - - switch (signal) + if (level <= this->levels[SIG_TYPE(signal)]) { - case SIG_IKE_UP: - case SIG_IKE_DOWN: - case SIG_IKE_REKEY: - case SIG_DBG_IKE: - prefix = "IKE"; - break; - case SIG_DBG_CHD: - prefix = "CHD"; - break; - case SIG_DBG_JOB: - prefix = "JOG"; - break; - case SIG_DBG_CFG: - prefix = "CFG"; - break; - case SIG_DBG_KNL: - prefix = "KNL"; - break; - case SIG_DBG_NET: - prefix = "NET"; - break; - case SIG_DBG_ENC: - prefix = "ENC"; - break; - default: - prefix = "???"; - break; - } - - flockfile(this->stream); - /* reset memory stream */ - rewind(this->stream); - memset(this->buffer, '\0', sizeof(this->buffer)); - /* log to memstream */ - this->logger->listener.signal(&this->logger->listener, thread, ike_sa, - signal, level, format, args); - /* flush is needed to append a '\0' */ - fflush(this->stream); - - /* create a reader stream that reads out line by line */ - reader = fmemopen(this->buffer, sizeof(this->buffer), "r"); - - while (fgets(line, sizeof(line), reader)) - { - if (line[0] == '\0') - { - /* abort on EOF */ - break; - } - else if (line[0] != '\n') + 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) { - fprintf(this->out, "%.2d[%s] %s", thread, prefix, line); + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + fprintf(this->out, "%.2d[%N] %s\n", thread, signal_names, signal, current); + current = next; } } - fclose(reader); - funlockfile(this->stream); } /** * Implementation of file_logger_t.set_level. */ -static void set_level(private_file_logger_t *this, signal_t signal, level_t max) +static void set_level(private_file_logger_t *this, signal_t signal, level_t level) { - this->logger->set_level(this->logger, signal, max); + if (signal == SIG_ANY) + { + int i; + for (i = 0; i < SIG_DBG_MAX; i++) + { + this->levels[i] = level; + } + } + else + { + + this->levels[SIG_TYPE(signal)] = level; + } } /** @@ -148,8 +103,6 @@ static void set_level(private_file_logger_t *this, signal_t signal, level_t max) */ static void destroy(private_file_logger_t *this) { - fclose(this->stream); - this->logger->destroy(this->logger); free(this); } @@ -161,19 +114,13 @@ 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 = (void(*)(bus_listener_t*,int,ike_sa_t*,signal_t,level_t,char*,va_list))signal_; + this->public.listener.signal = (void(*)(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; - this->stream = fmemopen(this->buffer, sizeof(this->buffer), "w"); - if (this->stream == NULL) - { - /* fallback to stderr */ - this->stream = stderr; - } - this->logger = stream_logger_create(this->stream); + 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 index 2ca028be3..919c8f0de 100644 --- a/src/charon/bus/listeners/file_logger.h +++ b/src/charon/bus/listeners/file_logger.h @@ -48,7 +48,7 @@ struct file_logger_t { * * @param this stream_logger_t object * @param singal type of signal - * @param level max level to log + * @param level max level to log (0..4) */ void (*set_level) (file_logger_t *this, signal_t signal, level_t level); diff --git a/src/charon/bus/listeners/stream_logger.c b/src/charon/bus/listeners/stream_logger.c deleted file mode 100644 index 70218728f..000000000 --- a/src/charon/bus/listeners/stream_logger.c +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @file stream_logger.c - * - * @brief Implementation of stream_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 <string.h> -#include <stdio.h> -#include <pthread.h> - -#include "stream_logger.h" - - -typedef struct private_stream_logger_t private_stream_logger_t; - -/** - * @brief Private data of a stream_logger_t object. - */ -struct private_stream_logger_t { - - /** - * Public data - */ - stream_logger_t public; - - /** - * Maximum level to log - */ - level_t max; - - /** - * stream to write log output to - */ - FILE *out; -}; - -/** - * Implementation of bus_listener_t.signal. - */ -static void signal_(private_stream_logger_t *this, int thread, - ike_sa_t* ike_sa, signal_t signal, level_t level, - char *format, va_list args) -{ - FILE *o = this->out; - - flockfile(o); - - if (level <= this->max) - { - /* then print the info */ - switch (signal) - { - case SIG_IKE_UP: - { - if (level == LEV_SUCCESS) - { - fprintf(o, "established: %H[%D]...%H[%D]\n", - ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa), - ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa)); - } - else - { - fprintf(o, "establishing failed: %H[%D]...%H[%D]:\n", - ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa), - ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa)); - fprintf(o, " "); - vfprintf(o, format, args); - fprintf(o, "\n"); - } - break; - } - case SIG_DBG_IKE: - case SIG_DBG_CHD: - case SIG_DBG_JOB: - case SIG_DBG_CFG: - case SIG_DBG_KNL: - case SIG_DBG_NET: - case SIG_DBG_ENC: - { - vfprintf(o, format, args); - fprintf(o, "\n"); - break; - } - default: - break; - } - } - - funlockfile(o); -} - -/** - * Implementation of stream_logger_t.set_level. - */ -static void set_level(private_stream_logger_t *this, signal_t signal, level_t max) -{ - this->max = max; -} - -/** - * Implementation of stream_logger_t.destroy. - */ -static void destroy(private_stream_logger_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -stream_logger_t *stream_logger_create(FILE *out) -{ - private_stream_logger_t *this = malloc_thing(private_stream_logger_t); - - /* public functions */ - this->public.listener.signal = (void(*)(bus_listener_t*,int,ike_sa_t*,signal_t,level_t,char*,va_list))signal_; - this->public.set_level = (void(*)(stream_logger_t*,signal_t,level_t))set_level; - this->public.destroy = (void(*)(stream_logger_t*))destroy; - - /* private variables */ - this->max = LEV_DBG4; - this->out = out; - - return &this->public; -} diff --git a/src/charon/bus/listeners/stream_logger.h b/src/charon/bus/listeners/stream_logger.h deleted file mode 100644 index 62d6c5aca..000000000 --- a/src/charon/bus/listeners/stream_logger.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file stream_logger.h - * - * @brief Interface of stream_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 STREAM_LOGGER_H_ -#define STREAM_LOGGER_H_ - -#include <stdio.h> - -#include <types.h> -#include <bus/bus.h> - -typedef struct stream_logger_t stream_logger_t; - -/** - * @brief Logger for a file stream which implements bus_listener_t. - * - * @b Constructors: - * - stream_logger_create() - * - * @ingroup listeners - */ -struct stream_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) (stream_logger_t *this, signal_t signal, level_t level); - - /** - * @brief Destroys a stream_logger_t object. - * - * @param this stream_logger_t object - */ - void (*destroy) (stream_logger_t *this); -}; - -/** - * @brief Constructor to create a stream_logger_t object. - * - * @param out output stream to log to - * @return stream_logger_t object - * - * @ingroup utils - */ -stream_logger_t *stream_logger_create(FILE *out); - -#endif /* STREAM_LOGGER_H_ */ diff --git a/src/charon/bus/listeners/sys_logger.c b/src/charon/bus/listeners/sys_logger.c index 357737610..0e3c9dca4 100644 --- a/src/charon/bus/listeners/sys_logger.c +++ b/src/charon/bus/listeners/sys_logger.c @@ -20,16 +20,12 @@ * for more details. */ -/* for open_memstream() */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <pthread.h> #include "sys_logger.h" -#include <bus/listeners/stream_logger.h> - typedef struct private_sys_logger_t private_sys_logger_t; @@ -49,99 +45,59 @@ struct private_sys_logger_t { int facility; /** - * Internal used stream logger that does the dirty work - */ - stream_logger_t *logger; - - /** - * Memory stream used for stream_logger - */ - FILE *stream; - - /** - * Underlying buffer for stream + * Maximum level to log */ - char buffer[4096]; + level_t levels[SIG_DBG_MAX]; }; /** * Implementation of bus_listener_t.signal. */ -static void signal_(private_sys_logger_t *this, int thread, ike_sa_t* ike_sa, - signal_t signal, level_t level, - char *format, va_list args) +static void signal_(private_sys_logger_t *this, signal_t signal, level_t level, + int thread, ike_sa_t* ike_sa, char *format, va_list args) { - char line[512]; - char *prefix; - FILE *reader; - - switch (signal) + if (level <= this->levels[SIG_TYPE(signal)]) { - case SIG_IKE_UP: - case SIG_IKE_DOWN: - case SIG_IKE_REKEY: - case SIG_DBG_IKE: - prefix = "IKE"; - break; - case SIG_DBG_CHD: - prefix = "CHD"; - break; - case SIG_DBG_JOB: - prefix = "JOG"; - break; - case SIG_DBG_CFG: - prefix = "CFG"; - break; - case SIG_DBG_KNL: - prefix = "KNL"; - break; - case SIG_DBG_NET: - prefix = "NET"; - break; - case SIG_DBG_ENC: - prefix = "ENC"; - break; - default: - prefix = "???"; - break; - } - - flockfile(this->stream); - /* reset memory stream */ - rewind(this->stream); - memset(this->buffer, '\0', sizeof(this->buffer)); - /* log to memstream */ - this->logger->listener.signal(&this->logger->listener, thread, ike_sa, - signal, level, format, args); - /* flush is needed to append a '\0' */ - fflush(this->stream); - - /* create a reader stream that reads out line by line */ - reader = fmemopen(this->buffer, sizeof(this->buffer), "r"); - - while (fgets(line, sizeof(line), reader)) - { - if (line[0] == '\0') - { - /* abort on EOF */ - break; - } - else if (line[0] != '\n') + 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) { - syslog(this->facility|LOG_INFO, "%.2d[%s] %s", thread, prefix, line); + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(this->facility|LOG_INFO, "%.2d[%N] %s\n", + thread, signal_names, signal, current); + current = next; } } - fclose(reader); - funlockfile(this->stream); } /** * Implementation of sys_logger_t.set_level. */ -static void set_level(private_sys_logger_t *this, signal_t signal, level_t max) +static void set_level(private_sys_logger_t *this, signal_t signal, level_t level) { - this->logger->set_level(this->logger, signal, max); + if (signal == SIG_ANY) + { + int i; + for (i = 0; i < SIG_DBG_MAX; i++) + { + this->levels[i] = level; + } + } + else + { + + this->levels[SIG_TYPE(signal)] = level; + } } /** @@ -150,8 +106,6 @@ static void set_level(private_sys_logger_t *this, signal_t signal, level_t max) static void destroy(private_sys_logger_t *this) { closelog(); - fclose(this->stream); - this->logger->destroy(this->logger); free(this); } @@ -163,19 +117,13 @@ 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 = (void(*)(bus_listener_t*,int,ike_sa_t*,signal_t,level_t,char*,va_list))signal_; + this->public.listener.signal = (void(*)(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; - this->stream = fmemopen(this->buffer, sizeof(this->buffer), "w"); - if (this->stream == NULL) - { - /* fallback to stderr */ - this->stream = stderr; - } - this->logger = stream_logger_create(this->stream); + set_level(this, SIG_ANY, LEVEL_SILENT); return &this->public; } |