aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/bus
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/bus')
-rw-r--r--src/charon/bus/bus.c274
-rw-r--r--src/charon/bus/bus.h294
-rw-r--r--src/charon/bus/listeners/file_logger.c125
-rw-r--r--src/charon/bus/listeners/file_logger.h2
-rw-r--r--src/charon/bus/listeners/stream_logger.c141
-rw-r--r--src/charon/bus/listeners/stream_logger.h75
-rw-r--r--src/charon/bus/listeners/sys_logger.c126
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**)&current))
+ {
+ 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;
}