diff options
author | Martin Willi <martin@strongswan.org> | 2007-11-15 18:35:54 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-11-15 18:35:54 +0000 |
commit | e101f162abba82d4713d68721d911d5cbd772201 (patch) | |
tree | 361117270a6b376c042c6a0c35ca42458ded8c4e /src/charon | |
parent | 1871cffdc4fe5e6c762a84fc012906abc84807f6 (diff) | |
download | strongswan-e101f162abba82d4713d68721d911d5cbd772201.tar.bz2 strongswan-e101f162abba82d4713d68721d911d5cbd772201.tar.xz |
refactored bus and interface to resolve threading issues (WIP)
Diffstat (limited to 'src/charon')
-rw-r--r-- | src/charon/bus/bus.c | 293 | ||||
-rw-r--r-- | src/charon/bus/bus.h | 48 | ||||
-rw-r--r-- | src/charon/control/interface_manager.c | 656 | ||||
-rwxr-xr-x | src/charon/control/interfaces/stroke_interface.c | 1 | ||||
-rw-r--r-- | src/charon/processing/jobs/callback_job.c | 1 |
5 files changed, 391 insertions, 608 deletions
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c index 5fda36925..62e57ae3b 100644 --- a/src/charon/bus/bus.c +++ b/src/charon/bus/bus.c @@ -24,6 +24,8 @@ #include <pthread.h> +#include <daemon.h> + ENUM(signal_names, SIG_ANY, SIG_MAX, /** should not get printed */ "SIG_ANY", @@ -53,104 +55,74 @@ ENUM(signal_names, SIG_ANY, SIG_MAX, "SIG_MAX", ); -typedef struct active_listener_t active_listener_t; +typedef struct private_bus_t private_bus_t; /** - * information for a active listener + * Private data of a bus_t object. */ -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; - +struct private_bus_t { /** - * verbosity level of the signal + * Public part of a bus_t object. */ - level_t level; + bus_t public; /** - * current processed signals thread number + * List of registered listeners as entry_t's */ - int thread; + linked_list_t *listeners; /** - * currently processed signals ike_sa + * mutex to synchronize active listeners */ - ike_sa_t *ike_sa; + pthread_mutex_t mutex; /** - * currently processed signals format string + * Thread local storage for a unique, simple thread ID */ - char *format; + pthread_key_t thread_id; /** - * currently processed signals format varargs + * Thread local storage the threads IKE_SA */ - va_list args; - + pthread_key_t thread_sa; }; -typedef struct private_bus_t private_bus_t; +typedef struct entry_t entry_t; /** - * Private data of a bus_t object. + * a listener entry, either active or passive */ -struct private_bus_t { - /** - * Public part of a bus_t object. - */ - bus_t public; - - /** - * List of registered listeners implementing the bus_t interface - */ - linked_list_t *listeners; - +struct entry_t { + /** - * List of active listeners with listener_state TRUE + * registered listener interface */ - linked_list_t *active_listeners; + bus_listener_t *listener; /** - * mutex to synchronize active listeners + * is this a active listen() call with a blocking thread */ - pthread_mutex_t mutex; + bool blocker; /** - * Thread local storage for a unique, simple thread ID + * condvar where active listeners wait */ - pthread_key_t thread_id; + pthread_cond_t cond; +}; + +/** + * create a listener entry + */ +static entry_t *entry_create(bus_listener_t *listener, bool blocker) +{ + entry_t *this = malloc_thing(entry_t); - /** - * Thread local storage the threads IKE_SA - */ - pthread_key_t thread_sa; + this->listener = listener; + this->blocker = blocker; + pthread_cond_init(&this->cond, NULL); -}; + return this; +} /** * Get a unique thread number for a calling thread. Since @@ -160,7 +132,7 @@ struct private_bus_t { static int get_thread_number(private_bus_t *this) { static long current_num = 0; - static long stored_num; + long stored_num; stored_num = (long)pthread_getspecific(this->thread_id); if (stored_num == 0) @@ -180,7 +152,7 @@ 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, listener); + this->listeners->insert_last(this->listeners, entry_create(listener, FALSE)); pthread_mutex_unlock(&this->mutex); } @@ -190,15 +162,16 @@ static void add_listener(private_bus_t *this, bus_listener_t *listener) static void remove_listener(private_bus_t *this, bus_listener_t *listener) { iterator_t *iterator; - bus_listener_t *current; + entry_t *entry; pthread_mutex_lock(&this->mutex); iterator = this->listeners->create_iterator(this->listeners, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + while (iterator->iterate(iterator, (void**)&entry)) { - if (current == listener) + if (entry->listener == listener) { iterator->remove(iterator); + free(entry); break; } } @@ -207,108 +180,29 @@ static void remove_listener(private_bus_t *this, bus_listener_t *listener) } /** - * 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; -} - -/** - * disable a listener to cleanly clean up - */ -static void unregister(active_listener_t *listener) -{ - listener->state = UNREGISTERED; - pthread_cond_broadcast(&listener->cond); -} - -/** * 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) +static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job) { - active_listener_t *listener; - int oldstate; + entry_t *entry; + int old; - 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". - * we allow cancellation here, but must cleanly disable the listener. */ - pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); - pthread_cleanup_push((void*)unregister, listener); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); - pthread_cond_wait(&listener->cond, &this->mutex); - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - pthread_cleanup_pop(0); - - pthread_mutex_unlock(&this->mutex); - - /* return signal values */ - *level = listener->level; - *thread = listener->thread; - *ike_sa = listener->ike_sa; - *format = listener->format; - va_copy(*args, listener->args); - va_end(listener->args); - - return listener->signal; -} + entry = entry_create(listener, TRUE); -/** - * 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 + this->listeners->insert_last(this->listeners, entry); + charon->processor->queue_job(charon->processor, job); + pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old); + while (entry->blocker) { - listener->state = UNREGISTERED; - /* say hello to signal emitter; we are finished processing the signal */ - pthread_cond_broadcast(&listener->cond); + pthread_cond_wait(&entry->cond, &this->mutex); } - - pthread_mutex_unlock(&this->mutex); + pthread_setcancelstate(old, NULL); + pthread_cleanup_pop(TRUE); + free(entry); } - /** * Implementation of bus_t.set_sa. */ @@ -324,72 +218,37 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level, char* format, va_list args) { iterator_t *iterator; - bus_listener_t *listener; - active_listener_t *active_listener; + entry_t *entry; ike_sa_t *ike_sa; long thread; + pthread_mutex_lock(&this->mutex); ike_sa = pthread_getspecific(this->thread_sa); thread = get_thread_number(this); - pthread_mutex_lock(&this->mutex); - - /* do the job for all passive bus_listeners */ iterator = this->listeners->create_iterator(this->listeners, TRUE); - while (iterator->iterate(iterator, (void**)&listener)) + while (iterator->iterate(iterator, (void**)&entry)) { va_list args_copy; va_copy(args_copy, args); - if (!listener->signal(listener, signal, level, thread, - ike_sa, format, args_copy)) + if (!entry->listener->signal(entry->listener, signal, level, thread, + ike_sa, format, args_copy)) { - /* unregister listener if requested */ iterator->remove(iterator); + if (entry->blocker) + { + entry->blocker = FALSE; + pthread_cond_signal(&entry->cond); + } + else + { + free(entry); + } } 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 all threads are registered. But if the thread raising - * the signal is the same as the one that listens, we skip it. - * Otherwise we would deadlock. */ - while (active_listener->id != pthread_self() && - 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_broadcast(&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)) - { - /* do not wait for ourself, it won't happen (see above) */ - while (active_listener->id != pthread_self() && - active_listener->state == REGISTERED) - { - pthread_cond_wait(&active_listener->cond, &this->mutex); - } - } - iterator->destroy(iterator); - pthread_mutex_unlock(&this->mutex); } @@ -411,8 +270,7 @@ static void signal_(private_bus_t *this, signal_t signal, level_t level, */ static void destroy(private_bus_t *this) { - this->active_listeners->destroy_function(this->active_listeners, free); - this->listeners->destroy(this->listeners); + this->listeners->destroy_function(this->listeners, free); free(this); } @@ -425,18 +283,17 @@ bus_t *bus_create() this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener; this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_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.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))listen_; this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa; this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_; this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal; this->public.destroy = (void(*)(bus_t*)) destroy; this->listeners = linked_list_create(); - this->active_listeners = linked_list_create(); pthread_mutex_init(&this->mutex, NULL); pthread_key_create(&this->thread_id, NULL); pthread_key_create(&this->thread_sa, NULL); - return &(this->public); + return &this->public; } + diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h index 6138c2538..f71018444 100644 --- a/src/charon/bus/bus.h +++ b/src/charon/bus/bus.h @@ -32,6 +32,7 @@ typedef struct bus_t bus_t; #include <sa/ike_sa.h> #include <sa/child_sa.h> +#include <processing/jobs/job.h> /** @@ -251,9 +252,7 @@ struct bus_listener_t { * 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. However, passive listeners should be preferred, - * as listening actively requires some synchronization overhead as data - * must be passed from the raising thread to the listening thread. + * to wait for a signal. * * @ingroup bus */ @@ -280,44 +279,19 @@ struct bus_t { void (*remove_listener) (bus_t *this, bus_listener_t *listener); /** - * @brief Listen actively on the bus. + * @brief Register a listener and block the calling thread. * - * As we are fully multithreaded, we must provide a mechanism - * for active threads to listen to the bus. With the listen() method, - * a thread waits until a signal occurs, and then processes it. - * To prevent the listen() calling thread to miss signals emitted while - * it processes a signal, registration is required. This is done through - * the set_listen_state() method, see below. - * - * The listen() function is (has) a thread cancellation point, so you might - * want to register cleanup handlers. - * - * @param this bus - * @param level verbosity level of the signal - * @param thread receives thread number emitted the signal - * @param ike_sa receives the IKE_SA involved in the signal, or NULL - * @param format receives the format string supplied with the signal - * @param va_list receives the variable argument list for format - * @return the emitted signal type - */ - signal_t (*listen) (bus_t *this, level_t* level, int *thread, - ike_sa_t **ike_sa, char** format, va_list* args); - - /** - * @brief Set the listening state of the calling thread. - * - * To prevent message loss for active listeners using listen(), threads - * must register themself to the bus before starting to listen(). When - * a signal occurs, the emitter waits until all threads with listen_state - * TRUE are waiting in the listen() method to process the signal. - * It is important that a thread with listen_state TRUE calls listen() - * periodically, or sets it's listening state to FALSE; otherwise - * all signal emitting threads get blocked on 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 signals. * * @param this bus - * @param active TRUE to set to listening + * @param listener listener to register + * @param job job to execute asynchronously when registered, or NULL */ - void (*set_listen_state) (bus_t *this, bool active); + void (*listen)(bus_t *this, bus_listener_t *listener, job_t *job); /** * @brief Set the IKE_SA the calling thread is using. diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c index c71036567..c14903c7d 100644 --- a/src/charon/control/interface_manager.c +++ b/src/charon/control/interface_manager.c @@ -56,18 +56,24 @@ struct private_interface_manager_t { linked_list_t *handles; }; + /** * helper struct to map bus listener callbacks to interface callbacks */ struct interface_bus_listener_t { /** - * bus listener callback function (called) + * public bus listener interface */ - bus_listener_t listener; + bus_listener_t public; + + /** + * status of the operation, return to method callers + */ + status_t status; /** - * IKE_SA to use for message filtering + * IKE SA to filter log output */ ike_sa_t *ike_sa; @@ -82,12 +88,48 @@ struct interface_bus_listener_t { void *param; /** - * caller has cancelled its listening subscription + * child configuration, used for initiate + */ + child_cfg_t *child_cfg; + + /** + * peer configuration, used for initiate + */ + peer_cfg_t *peer_cfg; + + /** + * unique ID, used for various methods + */ + u_int32_t id; +}; + + +typedef struct interface_job_t interface_job_t; + +/** + * job for asynchronous listen operations + */ +struct interface_job_t { + /** + * job interface + */ + job_t public; + + /** + * associated listener */ - bool cancelled; + interface_bus_listener_t listener; }; /** + * Implements the famous nop operation + */ +static void nop(job_t *job) +{ + /* NOP */ +} + +/** * Implementation of interface_manager_t.create_ike_sa_iterator. */ static iterator_t* create_ike_sa_iterator(interface_manager_t *this) @@ -106,17 +148,16 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { + case CHILD_UP_SUCCESS: + this->status = SUCCESS; + return FALSE; case IKE_UP_FAILED: case CHILD_UP_FAILED: - case CHILD_UP_SUCCESS: - { return FALSE; - } default: break; } @@ -125,112 +166,82 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, } /** - * listener function for terminate_ike + * execute function for initiate */ -static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate_execute(interface_job_t *job) { - if (this->ike_sa == ike_sa) + ike_sa_t *ike_sa; + ike_cfg_t *ike_cfg; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, + ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), + peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; + + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - return TRUE; -} - -/** - * listener function for terminate_child - */ -static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) + peer_cfg->destroy(peer_cfg); + + if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - return TRUE; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** - * listener function for route + * Implementation of interface_manager_t.initiate. */ -static bool route_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate(private_interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) { - if (this->ike_sa == ike_sa) + interface_job_t job; + + job.listener.public.signal = (void*)initiate_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.child_cfg = child_cfg; + job.listener.peer_cfg = peer_cfg; + job.public.execute = (void*)initiate_execute; + job.public.destroy = nop; + + if (callback == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case CHILD_ROUTE_SUCCESS: - case CHILD_ROUTE_FAILED: - { - return FALSE; - } - default: - break; - } + return initiate_execute(&job); } - return TRUE; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * listener function for unroute + * listener function for terminate_ike */ -static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) { if (this->ike_sa == ike_sa) { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { - case CHILD_UNROUTE_SUCCESS: - case CHILD_UNROUTE_FAILED: - { + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: return FALSE; - } default: break; } @@ -239,102 +250,29 @@ static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, } /** - * remove a previously registered listener from the bus + * execute function for terminate_ike */ -static void remove_listener(interface_bus_listener_t *listener) -{ - charon->bus->remove_listener(charon->bus, &listener->listener); -} - -/** - * Implementation of interface_manager_t.initiate. - */ -static status_t initiate(private_interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t terminate_ike_execute(interface_job_t *job) { ike_sa_t *ike_sa; - ike_cfg_t *ike_cfg; - status_t retval = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, - ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), - peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); - - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - peer_cfg->destroy(peer_cfg); - - listener.listener.signal = (void*)initiate_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS) - { - charon->bus->set_listen_state(charon->bus, FALSE); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - return FAILED; - } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - if (callback == NULL) + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, FALSE); + if (ike_sa == NULL) { - /* don't wait for a result if no callback is specified */ - charon->bus->set_listen_state(charon->bus, FALSE); - return NEED_MORE; - } + SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; - /* wait until we get a result */ - while (TRUE) + if (ike_sa->delete(ike_sa) == DESTROY_ME) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - retval = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* ike_sa is a valid pointer until we get one of the signals */ - if (ike_sa == current) - { - switch (signal) - { - case CHILD_UP_SUCCESS: - retval = SUCCESS; - case CHILD_UP_FAILED: - case IKE_UP_FAILED: - break; - default: - continue; - } - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, FALSE); - return retval; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** @@ -343,107 +281,78 @@ static status_t initiate(private_interface_manager_t *this, static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id, interface_manager_cb_t callback, void *param) { - ike_sa_t *ike_sa; - status_t status = FAILED;; - interface_bus_listener_t listener; + interface_job_t job; - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - unique_id, FALSE); - if (ike_sa == NULL) - { - return NOT_FOUND; - } - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - listener.listener.signal = (void*)terminate_ike_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete(ike_sa); - if (status == DESTROY_ME) + job.listener.public.signal = (void*)terminate_ike_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = unique_id; + job.public.execute = (void*)terminate_ike_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_ike_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} +/** + * listener function for terminate_child + */ +static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until IKE_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_DOWN_SUCCESS: + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: + case CHILD_DOWN_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.terminate_child. + * execute function for terminate_child */ -static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static status_t terminate_child_execute(interface_job_t *job) { ike_sa_t *ike_sa; child_sa_t *child_sa; iterator_t *iterator; - status_t status = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } + listener->ike_sa = ike_sa; iterator = ike_sa->create_child_sa_iterator(ike_sa); while (iterator->iterate(iterator, (void**)&child_sa)) { if (child_sa->get_state(child_sa) != CHILD_ROUTED && - child_sa->get_reqid(child_sa) == reqid) + child_sa->get_reqid(child_sa) == listener->id) { break; } @@ -453,160 +362,203 @@ static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, if (child_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with " + "ID %d not found", listener->id); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); return NOT_FOUND; } - listener.listener.signal = (void*)terminate_child_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising */ - if (callback) + if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) { - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - if (status == DESTROY_ME) + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.terminate_child. + */ +static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)terminate_child_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)terminate_child_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_child_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for route + */ +static bool route_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until CHILD_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_ROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_ROUTE_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.route. + * execute function for route */ -static status_t route(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t route_execute(interface_job_t *job) { ike_sa_t *ike_sa; ike_cfg_t *ike_cfg; - status_t status = SUCCESS; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; if (ike_sa->get_peer_cfg(ike_sa) == NULL) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)route_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.route. + */ +static status_t route(interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; - if (ike_sa->route(ike_sa, child_cfg) != SUCCESS) + job.listener.public.signal = (void*)route_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.peer_cfg = peer_cfg; + job.listener.child_cfg = child_cfg; + job.public.execute = (void*)route_execute; + job.public.destroy = nop; + + if (callback == NULL) { - status = FAILED; + return route_execute(&job); } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * Implementation of interface_manager_t.unroute. + * listener function for unroute */ -static status_t unroute(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_UNROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_UNROUTE_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} +/** + * execute function for unroute + */ +static status_t unroute_execute(interface_job_t *job) { ike_sa_t *ike_sa; - status_t status; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + listener->ike_sa = ike_sa; + if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)unroute_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - status = ike_sa->unroute(ike_sa, reqid); - if (status == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - status = SUCCESS; - } - else + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.unroute. + */ +static status_t unroute(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)unroute_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)unroute_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return unroute_execute(&job); } - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 66ed423ae..34622f9c1 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -1692,7 +1692,6 @@ static job_requeue_t stroke_process(int *fdp) return JOB_REQUEUE_NONE; } - /** * Implementation of private_stroke_interface_t.stroke_receive. */ diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c index 2cba60629..924af900c 100644 --- a/src/charon/processing/jobs/callback_job.c +++ b/src/charon/processing/jobs/callback_job.c @@ -170,6 +170,7 @@ static void execute(private_callback_job_t *this) } break; } + this->thread = 0; unregister(this); pthread_cleanup_pop(cleanup); } |