diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
commit | c1343b3278cdf99533b7902744d15969f9d6fdc1 (patch) | |
tree | d5ed3dc5677a59260ec41cd39bb284d3e94c91b3 /src/libcharon/bus | |
parent | b34738ed08c2227300d554b139e2495ca5da97d6 (diff) | |
download | vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.tar.gz vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.zip |
Imported Upstream version 5.0.1
Diffstat (limited to 'src/libcharon/bus')
-rw-r--r-- | src/libcharon/bus/bus.c | 380 | ||||
-rw-r--r-- | src/libcharon/bus/bus.h | 75 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/file_logger.c | 116 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/file_logger.h | 6 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/listener.h | 44 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/logger.h | 63 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/sys_logger.c | 85 | ||||
-rw-r--r-- | src/libcharon/bus/listeners/sys_logger.h | 6 |
8 files changed, 485 insertions, 290 deletions
diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index bf0ab2286..1f9592e6e 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,8 +20,8 @@ #include <threading/thread.h> #include <threading/thread_value.h> -#include <threading/condvar.h> #include <threading/mutex.h> +#include <threading/rwlock.h> typedef struct private_bus_t private_bus_t; @@ -34,16 +35,34 @@ struct private_bus_t { bus_t public; /** - * List of registered listeners as entry_t's + * List of registered listeners as entry_t. */ linked_list_t *listeners; /** - * mutex to synchronize active listeners, recursively + * List of registered loggers for each log group as log_entry_t. + * Loggers are ordered by descending log level. + * The extra list stores all loggers so we can properly unregister them. + */ + linked_list_t *loggers[DBG_MAX + 1]; + + /** + * Maximum log level of any registered logger for each log group. + * This allows to check quickly if a log message has to be logged at all. + */ + level_t max_level[DBG_MAX + 1]; + + /** + * Mutex for the list of listeners, recursively. */ mutex_t *mutex; /** + * Read-write lock for the list of loggers. + */ + rwlock_t *log_lock; + + /** * Thread local storage the threads IKE_SA */ thread_value_t *thread_sa; @@ -52,7 +71,7 @@ struct private_bus_t { typedef struct entry_t entry_t; /** - * a listener entry, either active or passive + * a listener entry */ struct entry_t { @@ -62,50 +81,42 @@ struct entry_t { listener_t *listener; /** - * is this a active listen() call with a blocking thread - */ - bool blocker; - - /** * are we currently calling this listener */ int calling; - /** - * condvar where active listeners wait - */ - condvar_t *condvar; }; +typedef struct log_entry_t log_entry_t; + /** - * create a listener entry + * a logger entry */ -static entry_t *entry_create(listener_t *listener, bool blocker) -{ - entry_t *this = malloc_thing(entry_t); +struct log_entry_t { - this->listener = listener; - this->blocker = blocker; - this->calling = 0; - this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); + /** + * registered logger interface + */ + logger_t *logger; - return this; -} + /** + * registered log levels per group + */ + level_t levels[DBG_MAX]; -/** - * destroy an entry_t - */ -static void entry_destroy(entry_t *entry) -{ - entry->condvar->destroy(entry->condvar); - free(entry); -} +}; METHOD(bus_t, add_listener, void, private_bus_t *this, listener_t *listener) { + entry_t *entry; + + INIT(entry, + .listener = listener, + ); + this->mutex->lock(this->mutex); - this->listeners->insert_last(this->listeners, entry_create(listener, FALSE)); + this->listeners->insert_last(this->listeners, entry); this->mutex->unlock(this->mutex); } @@ -122,7 +133,7 @@ METHOD(bus_t, remove_listener, void, if (entry->listener == listener) { this->listeners->remove_at(this->listeners, enumerator); - entry_destroy(entry); + free(entry); break; } } @@ -130,74 +141,107 @@ METHOD(bus_t, remove_listener, void, this->mutex->unlock(this->mutex); } -typedef struct cleanup_data_t cleanup_data_t; - /** - * data to remove a listener using thread_cleanup_t handler + * Register a logger on the given log group according to the requested level */ -struct cleanup_data_t { - /** bus instance */ - private_bus_t *this; - /** listener entry */ - entry_t *entry; -}; - -/** - * thread_cleanup_t handler to remove a listener - */ -static void listener_cleanup(cleanup_data_t *data) +static inline void register_logger(private_bus_t *this, debug_t group, + log_entry_t *entry) { - data->this->listeners->remove(data->this->listeners, data->entry, NULL); - entry_destroy(data->entry); + enumerator_t *enumerator; + linked_list_t *loggers; + log_entry_t *current; + level_t level; + + loggers = this->loggers[group]; + level = entry->levels[group]; + + enumerator = loggers->create_enumerator(loggers); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->levels[group] <= level) + { + break; + } + } + loggers->insert_before(loggers, enumerator, entry); + enumerator->destroy(enumerator); + + this->max_level[group] = max(this->max_level[group], level); } -METHOD(bus_t, listen_, bool, - private_bus_t *this, listener_t *listener, job_t *job, u_int timeout) +/** + * Unregister a logger from all log groups (destroys the log_entry_t) + */ +static inline void unregister_logger(private_bus_t *this, logger_t *logger) { - bool old, timed_out = FALSE; - cleanup_data_t data; - timeval_t tv, add; + enumerator_t *enumerator; + linked_list_t *loggers; + log_entry_t *entry, *found = NULL; - if (timeout) + loggers = this->loggers[DBG_MAX]; + enumerator = loggers->create_enumerator(loggers); + while (enumerator->enumerate(enumerator, &entry)) { - add.tv_sec = timeout / 1000; - add.tv_usec = (timeout - (add.tv_sec * 1000)) * 1000; - time_monotonic(&tv); - timeradd(&tv, &add, &tv); + if (entry->logger == logger) + { + loggers->remove_at(loggers, enumerator); + found = entry; + break; + } } + enumerator->destroy(enumerator); - data.this = this; - data.entry = entry_create(listener, TRUE); - - this->mutex->lock(this->mutex); - this->listeners->insert_last(this->listeners, data.entry); - lib->processor->queue_job(lib->processor, job); - thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); - thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data); - old = thread_cancelability(TRUE); - while (data.entry->blocker) + if (found) { - if (timeout) + debug_t group; + for (group = 0; group < DBG_MAX; group++) { - if (data.entry->condvar->timed_wait_abs(data.entry->condvar, - this->mutex, tv)) + if (found->levels[group] > LEVEL_SILENT) { - this->listeners->remove(this->listeners, data.entry, NULL); - timed_out = TRUE; - break; + loggers = this->loggers[group]; + loggers->remove(loggers, found, NULL); + + this->max_level[group] = LEVEL_SILENT; + if (loggers->get_first(loggers, (void**)&entry) == SUCCESS) + { + this->max_level[group] = entry->levels[group]; + } } } - else + free(found); + } +} + +METHOD(bus_t, add_logger, void, + private_bus_t *this, logger_t *logger) +{ + log_entry_t *entry; + debug_t group; + + INIT(entry, + .logger = logger, + ); + + this->log_lock->write_lock(this->log_lock); + unregister_logger(this, logger); + for (group = 0; group < DBG_MAX; group++) + { + entry->levels[group] = logger->get_level(logger, group); + if (entry->levels[group] > LEVEL_SILENT) { - data.entry->condvar->wait(data.entry->condvar, this->mutex); + register_logger(this, group, entry); } } - thread_cancelability(old); - thread_cleanup_pop(FALSE); - /* unlock mutex */ - thread_cleanup_pop(TRUE); - entry_destroy(data.entry); - return timed_out; + this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry); + this->log_lock->unlock(this->log_lock); +} + +METHOD(bus_t, remove_logger, void, + private_bus_t *this, logger_t *logger) +{ + this->log_lock->write_lock(this->log_lock); + unregister_logger(this, logger); + this->log_lock->unlock(this->log_lock); } METHOD(bus_t, set_sa, void, @@ -224,66 +268,61 @@ typedef struct { debug_t group; /** debug level */ level_t level; - /** format string */ - char *format; - /** argument list */ - va_list args; + /** message */ + char *message; } log_data_t; /** - * listener->log() invocation as a list remove callback + * logger->log() invocation as a invoke_function callback */ -static bool log_cb(entry_t *entry, log_data_t *data) +static void log_cb(log_entry_t *entry, log_data_t *data) { - va_list args; - - if (entry->calling || !entry->listener->log) - { /* avoid recursive calls */ - return FALSE; - } - entry->calling++; - va_copy(args, data->args); - if (!entry->listener->log(entry->listener, data->group, data->level, - data->thread, data->ike_sa, data->format, args)) + if (entry->levels[data->group] < data->level) { - if (entry->blocker) - { - entry->blocker = FALSE; - entry->condvar->signal(entry->condvar); - entry->calling--; - } - else - { - entry_destroy(entry); - } - va_end(args); - return TRUE; + return; } - va_end(args); - entry->calling--; - return FALSE; + entry->logger->log(entry->logger, data->group, data->level, + data->thread, data->ike_sa, data->message); } METHOD(bus_t, vlog, void, private_bus_t *this, debug_t group, level_t level, char* format, va_list args) { - log_data_t data; - - data.ike_sa = this->thread_sa->get(this->thread_sa); - data.thread = thread_current_id(); - data.group = group; - data.level = level; - data.format = format; - va_copy(data.args, args); - - this->mutex->lock(this->mutex); - /* We use the remove() method to invoke all listeners. This is cheap and - * does not require an allocation for this performance critical function. */ - this->listeners->remove(this->listeners, &data, (void*)log_cb); - this->mutex->unlock(this->mutex); - - va_end(data.args); + this->log_lock->read_lock(this->log_lock); + if (this->max_level[group] >= level) + { + linked_list_t *loggers = this->loggers[group]; + log_data_t data; + va_list copy; + char buf[1024]; + ssize_t len; + + data.ike_sa = this->thread_sa->get(this->thread_sa); + data.thread = thread_current_id(); + data.group = group; + data.level = level; + data.message = buf; + + va_copy(copy, args); + len = vsnprintf(data.message, sizeof(buf), format, copy); + va_end(copy); + if (len >= sizeof(buf)) + { + data.message = malloc(len); + len = vsnprintf(data.message, len, format, args); + } + if (len > 0) + { + loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb, + &data); + } + if (data.message != buf) + { + free(data.message); + } + } + this->log_lock->unlock(this->log_lock); } METHOD(bus_t, log_, void, @@ -299,19 +338,11 @@ METHOD(bus_t, log_, void, /** * unregister a listener */ -static void unregister_listener(private_bus_t *this, entry_t *entry, - enumerator_t *enumerator) +static inline void unregister_listener(private_bus_t *this, entry_t *entry, + enumerator_t *enumerator) { - if (entry->blocker) - { - entry->blocker = FALSE; - entry->condvar->signal(entry->condvar); - } - else - { - entry_destroy(entry); - } this->listeners->remove_at(this->listeners, enumerator); + free(entry); } METHOD(bus_t, alert, void, @@ -406,7 +437,7 @@ METHOD(bus_t, child_state_change, void, } METHOD(bus_t, message, void, - private_bus_t *this, message_t *message, bool incoming) + private_bus_t *this, message_t *message, bool incoming, bool plain) { enumerator_t *enumerator; ike_sa_t *ike_sa; @@ -425,7 +456,7 @@ METHOD(bus_t, message, void, } entry->calling++; keep = entry->listener->message(entry->listener, ike_sa, - message, incoming); + message, incoming, plain); entry->calling--; if (!keep) { @@ -438,7 +469,8 @@ METHOD(bus_t, message, void, METHOD(bus_t, ike_keys, void, private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey) + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared) { enumerator_t *enumerator; entry_t *entry; @@ -453,8 +485,8 @@ METHOD(bus_t, ike_keys, void, continue; } entry->calling++; - keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, - nonce_i, nonce_r, rekey); + keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other, + nonce_i, nonce_r, rekey, shared); entry->calling--; if (!keep) { @@ -485,8 +517,8 @@ METHOD(bus_t, child_keys, void, continue; } entry->calling++; - keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa, - initiator, dh, nonce_i, nonce_r); + keep = entry->listener->child_keys(entry->listener, ike_sa, + child_sa, initiator, dh, nonce_i, nonce_r); entry->calling--; if (!keep) { @@ -547,7 +579,8 @@ METHOD(bus_t, child_rekey, void, continue; } entry->calling++; - keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new); + keep = entry->listener->child_rekey(entry->listener, ike_sa, + old, new); entry->calling--; if (!keep) { @@ -626,6 +659,33 @@ METHOD(bus_t, ike_rekey, void, this->mutex->unlock(this->mutex); } +METHOD(bus_t, ike_reestablish, void, + private_bus_t *this, ike_sa_t *old, ike_sa_t *new) +{ + enumerator_t *enumerator; + entry_t *entry; + bool keep; + + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->calling || !entry->listener->ike_reestablish) + { + continue; + } + entry->calling++; + keep = entry->listener->ike_reestablish(entry->listener, old, new); + entry->calling--; + if (!keep) + { + unregister_listener(this, entry, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + METHOD(bus_t, authorize, bool, private_bus_t *this, bool final) { @@ -697,9 +757,17 @@ METHOD(bus_t, narrow, void, METHOD(bus_t, destroy, void, private_bus_t *this) { + debug_t group; + for (group = 0; group < DBG_MAX; group++) + { + this->loggers[group]->destroy(this->loggers[group]); + } + this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX], + (void*)free); + this->listeners->destroy_function(this->listeners, (void*)free); this->thread_sa->destroy(this->thread_sa); + this->log_lock->destroy(this->log_lock); this->mutex->destroy(this->mutex); - this->listeners->destroy_function(this->listeners, (void*)entry_destroy); free(this); } @@ -709,12 +777,14 @@ METHOD(bus_t, destroy, void, bus_t *bus_create() { private_bus_t *this; + debug_t group; INIT(this, .public = { .add_listener = _add_listener, .remove_listener = _remove_listener, - .listen = _listen_, + .add_logger = _add_logger, + .remove_logger = _remove_logger, .set_sa = _set_sa, .get_sa = _get_sa, .log = _log_, @@ -727,6 +797,7 @@ bus_t *bus_create() .child_keys = _child_keys, .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, + .ike_reestablish = _ike_reestablish, .child_updown = _child_updown, .child_rekey = _child_rekey, .authorize = _authorize, @@ -735,9 +806,16 @@ bus_t *bus_create() }, .listeners = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), + .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .thread_sa = thread_value_create(NULL), ); + for (group = 0; group <= DBG_MAX; group++) + { + this->loggers[group] = linked_list_create(); + this->max_level[group] = LEVEL_SILENT; + } + return &this->public; } diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h index 69060d383..aba8acdbd 100644 --- a/src/libcharon/bus/bus.h +++ b/src/libcharon/bus/bus.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -31,6 +32,7 @@ typedef struct bus_t bus_t; #include <sa/ike_sa.h> #include <sa/child_sa.h> #include <processing/jobs/job.h> +#include <bus/listeners/logger.h> #include <bus/listeners/listener.h> /* undefine the definitions from libstrongswan */ @@ -109,6 +111,8 @@ enum narrow_hook_t { NARROW_INITIATOR_PRE_AUTH, /** invoked as responder during exchange, peer is authenticated */ NARROW_RESPONDER, + /** invoked as responder after exchange, peer is authenticated */ + NARROW_RESPONDER_POST, /** invoked as initiator after exchange, follows a INITIATOR_PRE_NOAUTH */ NARROW_INITIATOR_POST_NOAUTH, /** invoked as initiator after exchange, follows a INITIATOR_PRE_AUTH */ @@ -118,8 +122,7 @@ enum narrow_hook_t { /** * The bus receives events and sends them to all registered listeners. * - * Any events sent to are delivered to all registered listeners. Threads - * may wait actively to events using the blocking listen() call. + * Loggers are handled separately. */ struct bus_t { @@ -142,26 +145,37 @@ struct bus_t { void (*remove_listener) (bus_t *this, listener_t *listener); /** - * Register a listener and block the calling thread. + * Register a logger with the bus. * - * This call registers a listener and blocks the calling thread until - * its listeners function returns FALSE. This allows to wait for certain - * events. The associated job is executed after the listener has been - * registered: This allows to listen on events we initiate with the job, - * without missing any events to job may fire. + * The logger is passive; the thread which emitted the event + * processes the logger routine. This routine may be called concurrently + * by multiple threads. Recursive calls are not prevented, so logger that + * may cause recursive calls are responsible to avoid infinite loops. * - * @param listener listener to register - * @param job job to execute asynchronously when registered, or NULL - * @param timeout max timeout in ms to listen for events, 0 to disable - * @return TRUE if timed out + * During registration get_level() is called for all log groups and the + * logger is registered to receive log messages for groups for which + * the requested log level is > LEVEL_SILENT and whose level is lower + * or equal than the requested level. + * + * To update the registered log levels call add_logger again with the + * same logger and return the new levels from get_level(). + * + * @param logger logger to register. */ - bool (*listen)(bus_t *this, listener_t *listener, job_t *job, u_int timeout); + void (*add_logger) (bus_t *this, logger_t *logger); + + /** + * Unregister a logger from the bus. + * + * @param logger logger to unregister. + */ + void (*remove_logger) (bus_t *this, logger_t *logger); /** * Set the IKE_SA the calling thread is using. * - * To associate an received log message to an IKE_SA without passing it as - * parameter each time, the thread registers the currenlty used IKE_SA + * To associate a received log message with an IKE_SA without passing it as + * parameter each time, the thread registers the currently used IKE_SA * during check-out. Before check-in, the thread unregisters the IKE_SA. * This IKE_SA is stored per-thread, so each thread has its own IKE_SA * registered. @@ -183,9 +197,8 @@ struct bus_t { /** * Send a log message to the bus. * - * The signal specifies the type of the event occurred. The format string - * specifies an additional informational or error message with a - * printf() like variable argument list. + * The format string specifies an additional informational or error + * message with a printf() like variable argument list. * Use the DBG() macros. * * @param group debugging group @@ -198,7 +211,7 @@ struct bus_t { /** * Send a log message to the bus using va_list arguments. * - * Same as bus_t.signal(), but uses va_list argument list. + * Same as bus_t.log(), but uses va_list argument list. * * @param group kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal @@ -212,7 +225,7 @@ struct bus_t { * Raise an alert over the bus. * * @param alert kind of alert - * @param ... alert specific attributes + * @param ... alert specific arguments */ void (*alert)(bus_t *this, alert_t alert, ...); @@ -235,10 +248,14 @@ struct bus_t { /** * Message send/receive hook. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param message message to send/receive * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not */ - void (*message)(bus_t *this, message_t *message, bool incoming); + void (*message)(bus_t *this, message_t *message, bool incoming, bool plain); /** * IKE_SA authorization hook. @@ -264,12 +281,16 @@ struct bus_t { * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) */ void (*ike_keys)(bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); + /** * CHILD_SA keymat hook. * @@ -299,6 +320,14 @@ struct bus_t { void (*ike_rekey)(bus_t *this, ike_sa_t *old, ike_sa_t *new); /** + * IKE_SA reestablishing hook. + * + * @param old reestablished and obsolete IKE_SA + * @param new new IKE_SA replacing old + */ + void (*ike_reestablish)(bus_t *this, ike_sa_t *old, ike_sa_t *new); + + /** * CHILD_SA up/down hook. * * @param child_sa CHILD_SA coming up/going down diff --git a/src/libcharon/bus/listeners/file_logger.c b/src/libcharon/bus/listeners/file_logger.c index 36d18619a..9c8458eb5 100644 --- a/src/libcharon/bus/listeners/file_logger.c +++ b/src/libcharon/bus/listeners/file_logger.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,6 +20,7 @@ #include "file_logger.h" +#include <threading/mutex.h> typedef struct private_file_logger_t private_file_logger_t; @@ -51,73 +53,80 @@ struct private_file_logger_t { * Print the name/# of the IKE_SA? */ bool ike_name; + + /** + * Mutex to ensure multi-line log messages are not torn apart + */ + mutex_t *mutex; }; -METHOD(listener_t, log_, bool, - private_file_logger_t *this, debug_t group, level_t level, int thread, - ike_sa_t* ike_sa, char *format, va_list args) +METHOD(logger_t, log_, void, + private_file_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *message) { - if (level <= this->levels[group]) - { - char buffer[8192], timestr[128], namestr[128] = ""; - char *current = buffer, *next; - struct tm tm; - time_t t; + char timestr[128], namestr[128] = ""; + const char *current = message, *next; + struct tm tm; + time_t t; - if (this->time_format) + if (this->time_format) + { + t = time(NULL); + localtime_r(&t, &tm); + strftime(timestr, sizeof(timestr), this->time_format, &tm); + } + if (this->ike_name && ike_sa) + { + if (ike_sa->get_peer_cfg(ike_sa)) { - t = time(NULL); - localtime_r(&t, &tm); - strftime(timestr, sizeof(timestr), this->time_format, &tm); + snprintf(namestr, sizeof(namestr), " <%s|%d>", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); } - if (this->ike_name && ike_sa) + else { - if (ike_sa->get_peer_cfg(ike_sa)) - { - snprintf(namestr, sizeof(namestr), " <%s|%d>", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - } - else - { - snprintf(namestr, sizeof(namestr), " <%d>", - ike_sa->get_unique_id(ike_sa)); - } + snprintf(namestr, sizeof(namestr), " <%d>", + ike_sa->get_unique_id(ike_sa)); + } + } + else + { + namestr[0] = '\0'; + } + + /* prepend a prefix in front of every line */ + this->mutex->lock(this->mutex); + while (TRUE) + { + next = strchr(current, '\n'); + if (this->time_format) + { + fprintf(this->out, "%s %.2d[%N]%s ", + timestr, thread, debug_names, group, namestr); } else { - namestr[0] = '\0'; + fprintf(this->out, "%.2d[%N]%s ", + thread, debug_names, group, namestr); } - - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), format, args); - - /* prepend a prefix in front of every line */ - while (current) + if (next == NULL) { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - if (this->time_format) - { - fprintf(this->out, "%s %.2d[%N]%s %s\n", - timestr, thread, debug_names, group, namestr, current); - } - else - { - fprintf(this->out, "%.2d[%N]%s %s\n", - thread, debug_names, group, namestr, current); - } - current = next; + fprintf(this->out, "%s\n", current); + break; } + fprintf(this->out, "%.*s\n", (int)(next - current), current); + current = next + 1; } - /* always stay registered */ - return TRUE; + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_file_logger_t *this, debug_t group) +{ + return this->levels[group]; } METHOD(file_logger_t, set_level, void, - private_file_logger_t *this, debug_t group, level_t level) + private_file_logger_t *this, debug_t group, level_t level) { if (group < DBG_ANY) { @@ -133,12 +142,13 @@ METHOD(file_logger_t, set_level, void, } METHOD(file_logger_t, destroy, void, - private_file_logger_t *this) + private_file_logger_t *this) { if (this->out != stdout && this->out != stderr) { fclose(this->out); } + this->mutex->destroy(this->mutex); free(this); } @@ -151,8 +161,9 @@ file_logger_t *file_logger_create(FILE *out, char *time_format, bool ike_name) INIT(this, .public = { - .listener = { + .logger = { .log = _log_, + .get_level = _get_level, }, .set_level = _set_level, .destroy = _destroy, @@ -160,6 +171,7 @@ file_logger_t *file_logger_create(FILE *out, char *time_format, bool ike_name) .out = out, .time_format = time_format, .ike_name = ike_name, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); set_level(this, DBG_ANY, LEVEL_SILENT); diff --git a/src/libcharon/bus/listeners/file_logger.h b/src/libcharon/bus/listeners/file_logger.h index d02f1701d..85a2690a2 100644 --- a/src/libcharon/bus/listeners/file_logger.h +++ b/src/libcharon/bus/listeners/file_logger.h @@ -21,7 +21,7 @@ #ifndef FILE_LOGGER_H_ #define FILE_LOGGER_H_ -#include <bus/listeners/listener.h> +#include <bus/listeners/logger.h> typedef struct file_logger_t file_logger_t; @@ -31,9 +31,9 @@ typedef struct file_logger_t file_logger_t; struct file_logger_t { /** - * Implements the listener_t interface. + * Implements the logger_t interface. */ - listener_t listener; + logger_t logger; /** * Set the loglevel for a debug group. diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h index 21caed064..782289302 100644 --- a/src/libcharon/bus/listeners/listener.h +++ b/src/libcharon/bus/listeners/listener.h @@ -31,25 +31,6 @@ typedef struct listener_t listener_t; struct listener_t { /** - * Log a debugging message. - * - * The implementing signal function returns TRUE to stay registered - * to the bus, or FALSE to unregister itself. - * Calling bus_t.log() inside of a registered listener is possible, - * but the bus does not invoke listeners recursively. - * - * @param group 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 (*log)(listener_t *this, debug_t group, level_t level, int thread, - ike_sa_t *ike_sa, char* format, va_list args); - - /** * Hook called if a critical alert is risen. * * @param ike_sa IKE_SA associated to the alert, if any @@ -84,26 +65,33 @@ struct listener_t { /** * Hook called for received/sent messages of an IKE_SA. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param ike_sa IKE_SA sending/receiving a message * @param message message object * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not * @return TRUE to stay registered, FALSE to unregister */ bool (*message)(listener_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming); + bool incoming, bool plain); /** * Hook called with IKE_SA key material. * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) * @return TRUE to stay registered, FALSE to unregister */ bool (*ike_keys)(listener_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); /** * Hook called with CHILD_SA key material. @@ -139,6 +127,18 @@ struct listener_t { bool (*ike_rekey)(listener_t *this, ike_sa_t *old, ike_sa_t *new); /** + * Hook called when an initiator reestablishes an IKE_SA. + * + * This is invoked right before the new IKE_SA is checked in after + * initiating it. It is not invoked on the responder. + * + * @param old IKE_SA getting reestablished (is destroyed) + * @param new new IKE_SA replacing old (gets established) + * @return TRUE to stay registered, FALSE to unregister + */ + bool (*ike_reestablish)(listener_t *this, ike_sa_t *old, ike_sa_t *new); + + /** * Hook called when a CHILD_SA gets up or down. * * @param ike_sa IKE_SA containing the handled CHILD_SA diff --git a/src/libcharon/bus/listeners/logger.h b/src/libcharon/bus/listeners/logger.h new file mode 100644 index 000000000..3b99e7dc1 --- /dev/null +++ b/src/libcharon/bus/listeners/logger.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * 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. + */ + +/** + * @defgroup logger logger + * @{ @ingroup listeners + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +typedef struct logger_t logger_t; + +#include <bus/bus.h> + +/** + * Logger interface, listens for log events on the bus. + */ +struct logger_t { + + /** + * Log a debugging message. + * + * @note Calls to bus_t.log() are handled separately from calls to + * other functions. This callback may be called concurrently by + * multiple threads. Also recursive calls are not prevented, loggers that + * may cause recursive log messages are responsible to avoid infinite loops. + * + * @param group 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 message log message + */ + void (*log)(logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t *ike_sa, const char *message); + + /** + * Get the desired log level for a debug group. This is called during + * registration. + * + * If the desired log levels have changed, re-register the logger with + * the bus. + * + * @param group debug group + * @return max level to log (0..4) or -1 for none (see debug.h) + */ + level_t (*get_level)(logger_t *this, debug_t group); +}; + +#endif /** LOGGER_H_ @}*/ diff --git a/src/libcharon/bus/listeners/sys_logger.c b/src/libcharon/bus/listeners/sys_logger.c index c29c9f2e4..53fdefe89 100644 --- a/src/libcharon/bus/listeners/sys_logger.c +++ b/src/libcharon/bus/listeners/sys_logger.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,6 +20,7 @@ #include "sys_logger.h" +#include <threading/mutex.h> typedef struct private_sys_logger_t private_sys_logger_t; @@ -46,55 +48,63 @@ struct private_sys_logger_t { * Print the name/# of the IKE_SA? */ bool ike_name; + + /** + * Mutex to ensure multi-line log messages are not torn apart + */ + mutex_t *mutex; }; -METHOD(listener_t, log_, bool, - private_sys_logger_t *this, debug_t group, level_t level, int thread, - ike_sa_t* ike_sa, char *format, va_list args) +METHOD(logger_t, log_, void, + private_sys_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *message) { - if (level <= this->levels[group]) - { - char buffer[8192], groupstr[4], namestr[128] = ""; - char *current = buffer, *next; + char groupstr[4], namestr[128] = ""; + const char *current = message, *next; - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), format, args); - /* cache group name */ - snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group); + /* cache group name and optional name string */ + snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group); - if (this->ike_name && ike_sa) + if (this->ike_name && ike_sa) + { + if (ike_sa->get_peer_cfg(ike_sa)) + { + snprintf(namestr, sizeof(namestr), " <%s|%d>", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + } + else { - if (ike_sa->get_peer_cfg(ike_sa)) - { - snprintf(namestr, sizeof(namestr), " <%s|%d>", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - } - else - { - snprintf(namestr, sizeof(namestr), " <%d>", - ike_sa->get_unique_id(ike_sa)); - } + snprintf(namestr, sizeof(namestr), " <%d>", + ike_sa->get_unique_id(ike_sa)); } + } - /* do a syslog with every line */ - while (current) + /* do a syslog for every line */ + this->mutex->lock(this->mutex); + while (TRUE) + { + next = strchr(current, '\n'); + if (next == NULL) { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - syslog(this->facility|LOG_INFO, "%.2d[%s]%s %s\n", + syslog(this->facility | LOG_INFO, "%.2d[%s]%s %s\n", thread, groupstr, namestr, current); - current = next; + break; } + syslog(this->facility | LOG_INFO, "%.2d[%s]%s %.*s\n", + thread, groupstr, namestr, (int)(next - current), current); + current = next + 1; } - /* always stay registered */ - return TRUE; + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_sys_logger_t *this, debug_t group) +{ + return this->levels[group]; } METHOD(sys_logger_t, set_level, void, - private_sys_logger_t *this, debug_t group, level_t level) + private_sys_logger_t *this, debug_t group, level_t level) { if (group < DBG_ANY) { @@ -110,9 +120,10 @@ METHOD(sys_logger_t, set_level, void, } METHOD(sys_logger_t, destroy, void, - private_sys_logger_t *this) + private_sys_logger_t *this) { closelog(); + this->mutex->destroy(this->mutex); free(this); } @@ -125,14 +136,16 @@ sys_logger_t *sys_logger_create(int facility, bool ike_name) INIT(this, .public = { - .listener = { + .logger = { .log = _log_, + .get_level = _get_level, }, .set_level = _set_level, .destroy = _destroy, }, .facility = facility, .ike_name = ike_name, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); set_level(this, DBG_ANY, LEVEL_SILENT); diff --git a/src/libcharon/bus/listeners/sys_logger.h b/src/libcharon/bus/listeners/sys_logger.h index d83715a6a..fcb6655ca 100644 --- a/src/libcharon/bus/listeners/sys_logger.h +++ b/src/libcharon/bus/listeners/sys_logger.h @@ -21,7 +21,7 @@ #ifndef SYS_LOGGER_H_ #define SYS_LOGGER_H_ -#include <bus/listeners/listener.h> +#include <bus/listeners/logger.h> typedef struct sys_logger_t sys_logger_t; @@ -31,9 +31,9 @@ typedef struct sys_logger_t sys_logger_t; struct sys_logger_t { /** - * Implements the listener_t interface. + * Implements the logger_t interface. */ - listener_t listener; + logger_t logger; /** * Set the loglevel for a debug group. |