refactored bus and interface to resolve threading issues (WIP)
This commit is contained in:
+77
-220
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <daemon.h>
|
||||||
|
|
||||||
ENUM(signal_names, SIG_ANY, SIG_MAX,
|
ENUM(signal_names, SIG_ANY, SIG_MAX,
|
||||||
/** should not get printed */
|
/** should not get printed */
|
||||||
"SIG_ANY",
|
"SIG_ANY",
|
||||||
@@ -53,67 +55,6 @@ ENUM(signal_names, SIG_ANY, SIG_MAX,
|
|||||||
"SIG_MAX",
|
"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;
|
typedef struct private_bus_t private_bus_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,15 +67,10 @@ struct private_bus_t {
|
|||||||
bus_t public;
|
bus_t public;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of registered listeners implementing the bus_t interface
|
* List of registered listeners as entry_t's
|
||||||
*/
|
*/
|
||||||
linked_list_t *listeners;
|
linked_list_t *listeners;
|
||||||
|
|
||||||
/**
|
|
||||||
* List of active listeners with listener_state TRUE
|
|
||||||
*/
|
|
||||||
linked_list_t *active_listeners;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mutex to synchronize active listeners
|
* mutex to synchronize active listeners
|
||||||
*/
|
*/
|
||||||
@@ -149,9 +85,45 @@ struct private_bus_t {
|
|||||||
* Thread local storage the threads IKE_SA
|
* Thread local storage the threads IKE_SA
|
||||||
*/
|
*/
|
||||||
pthread_key_t thread_sa;
|
pthread_key_t thread_sa;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct entry_t entry_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a listener entry, either active or passive
|
||||||
|
*/
|
||||||
|
struct entry_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registered listener interface
|
||||||
|
*/
|
||||||
|
bus_listener_t *listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this a active listen() call with a blocking thread
|
||||||
|
*/
|
||||||
|
bool blocker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* condvar where active listeners wait
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
this->listener = listener;
|
||||||
|
this->blocker = blocker;
|
||||||
|
pthread_cond_init(&this->cond, NULL);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a unique thread number for a calling thread. Since
|
* Get a unique thread number for a calling thread. Since
|
||||||
* pthread_self returns large and ugly numbers, use this function
|
* pthread_self returns large and ugly numbers, use this function
|
||||||
@@ -160,7 +132,7 @@ struct private_bus_t {
|
|||||||
static int get_thread_number(private_bus_t *this)
|
static int get_thread_number(private_bus_t *this)
|
||||||
{
|
{
|
||||||
static long current_num = 0;
|
static long current_num = 0;
|
||||||
static long stored_num;
|
long stored_num;
|
||||||
|
|
||||||
stored_num = (long)pthread_getspecific(this->thread_id);
|
stored_num = (long)pthread_getspecific(this->thread_id);
|
||||||
if (stored_num == 0)
|
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)
|
static void add_listener(private_bus_t *this, bus_listener_t *listener)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&this->mutex);
|
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);
|
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)
|
static void remove_listener(private_bus_t *this, bus_listener_t *listener)
|
||||||
{
|
{
|
||||||
iterator_t *iterator;
|
iterator_t *iterator;
|
||||||
bus_listener_t *current;
|
entry_t *entry;
|
||||||
|
|
||||||
pthread_mutex_lock(&this->mutex);
|
pthread_mutex_lock(&this->mutex);
|
||||||
iterator = this->listeners->create_iterator(this->listeners, TRUE);
|
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);
|
iterator->remove(iterator);
|
||||||
|
free(entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,109 +179,30 @@ static void remove_listener(private_bus_t *this, bus_listener_t *listener)
|
|||||||
pthread_mutex_unlock(&this->mutex);
|
pthread_mutex_unlock(&this->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the listener object for the calling thread
|
|
||||||
*/
|
|
||||||
static active_listener_t *get_active_listener(private_bus_t *this)
|
|
||||||
{
|
|
||||||
active_listener_t *current, *found = NULL;
|
|
||||||
iterator_t *iterator;
|
|
||||||
|
|
||||||
/* if the thread was here once before, we have a active_listener record */
|
|
||||||
iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
|
|
||||||
while (iterator->iterate(iterator, (void**)¤t))
|
|
||||||
{
|
|
||||||
if (current->id == pthread_self())
|
|
||||||
{
|
|
||||||
found = current;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iterator->destroy(iterator);
|
|
||||||
|
|
||||||
if (found == NULL)
|
|
||||||
{
|
|
||||||
/* create a new object for a never-seen thread */
|
|
||||||
found = malloc_thing(active_listener_t);
|
|
||||||
found->id = pthread_self();
|
|
||||||
pthread_cond_init(&found->cond, NULL);
|
|
||||||
this->active_listeners->insert_last(this->active_listeners, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Implementation of bus_t.listen.
|
||||||
*/
|
*/
|
||||||
static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
|
static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job)
|
||||||
ike_sa_t **ike_sa, char** format, va_list* args)
|
|
||||||
{
|
{
|
||||||
active_listener_t *listener;
|
entry_t *entry;
|
||||||
int oldstate;
|
int old;
|
||||||
|
|
||||||
|
entry = entry_create(listener, TRUE);
|
||||||
|
|
||||||
pthread_mutex_lock(&this->mutex);
|
pthread_mutex_lock(&this->mutex);
|
||||||
listener = get_active_listener(this);
|
this->listeners->insert_last(this->listeners, entry);
|
||||||
/* go "listening", say hello to a thread which have a signal for us */
|
charon->processor->queue_job(charon->processor, job);
|
||||||
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*)pthread_mutex_unlock, &this->mutex);
|
||||||
pthread_cleanup_push((void*)unregister, listener);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
while (entry->blocker)
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
pthread_cond_wait(&entry->cond, &this->mutex);
|
||||||
}
|
}
|
||||||
else
|
pthread_setcancelstate(old, NULL);
|
||||||
{
|
pthread_cleanup_pop(TRUE);
|
||||||
listener->state = UNREGISTERED;
|
free(entry);
|
||||||
/* say hello to signal emitter; we are finished processing the signal */
|
|
||||||
pthread_cond_broadcast(&listener->cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&this->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of bus_t.set_sa.
|
* 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)
|
char* format, va_list args)
|
||||||
{
|
{
|
||||||
iterator_t *iterator;
|
iterator_t *iterator;
|
||||||
bus_listener_t *listener;
|
entry_t *entry;
|
||||||
active_listener_t *active_listener;
|
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
long thread;
|
long thread;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&this->mutex);
|
||||||
ike_sa = pthread_getspecific(this->thread_sa);
|
ike_sa = pthread_getspecific(this->thread_sa);
|
||||||
thread = get_thread_number(this);
|
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);
|
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_list args_copy;
|
||||||
va_copy(args_copy, args);
|
va_copy(args_copy, args);
|
||||||
if (!listener->signal(listener, signal, level, thread,
|
if (!entry->listener->signal(entry->listener, signal, level, thread,
|
||||||
ike_sa, format, args_copy))
|
ike_sa, format, args_copy))
|
||||||
{
|
{
|
||||||
/* unregister listener if requested */
|
|
||||||
iterator->remove(iterator);
|
iterator->remove(iterator);
|
||||||
|
if (entry->blocker)
|
||||||
|
{
|
||||||
|
entry->blocker = FALSE;
|
||||||
|
pthread_cond_signal(&entry->cond);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
va_end(args_copy);
|
va_end(args_copy);
|
||||||
}
|
}
|
||||||
iterator->destroy(iterator);
|
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);
|
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)
|
static void destroy(private_bus_t *this)
|
||||||
{
|
{
|
||||||
this->active_listeners->destroy_function(this->active_listeners, free);
|
this->listeners->destroy_function(this->listeners, free);
|
||||||
this->listeners->destroy(this->listeners);
|
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,18 +283,17 @@ bus_t *bus_create()
|
|||||||
|
|
||||||
this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
|
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.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.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))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.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
|
||||||
this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
|
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.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
|
||||||
this->public.destroy = (void(*)(bus_t*)) destroy;
|
this->public.destroy = (void(*)(bus_t*)) destroy;
|
||||||
|
|
||||||
this->listeners = linked_list_create();
|
this->listeners = linked_list_create();
|
||||||
this->active_listeners = linked_list_create();
|
|
||||||
pthread_mutex_init(&this->mutex, NULL);
|
pthread_mutex_init(&this->mutex, NULL);
|
||||||
pthread_key_create(&this->thread_id, NULL);
|
pthread_key_create(&this->thread_id, NULL);
|
||||||
pthread_key_create(&this->thread_sa, NULL);
|
pthread_key_create(&this->thread_sa, NULL);
|
||||||
|
|
||||||
return &(this->public);
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-37
@@ -32,6 +32,7 @@ typedef struct bus_t bus_t;
|
|||||||
|
|
||||||
#include <sa/ike_sa.h>
|
#include <sa/ike_sa.h>
|
||||||
#include <sa/child_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
|
* in receiving event signals registers at the bus. Any signals sent to
|
||||||
* are delivered to all registered listeners.
|
* are delivered to all registered listeners.
|
||||||
* To deliver signals to threads, the blocking listen() call may be used
|
* To deliver signals to threads, the blocking listen() call may be used
|
||||||
* to wait for a signal. However, passive listeners should be preferred,
|
* to wait for a signal.
|
||||||
* as listening actively requires some synchronization overhead as data
|
|
||||||
* must be passed from the raising thread to the listening thread.
|
|
||||||
*
|
*
|
||||||
* @ingroup bus
|
* @ingroup bus
|
||||||
*/
|
*/
|
||||||
@@ -280,44 +279,19 @@ struct bus_t {
|
|||||||
void (*remove_listener) (bus_t *this, bus_listener_t *listener);
|
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
|
* This call registers a listener and blocks the calling thread until
|
||||||
* for active threads to listen to the bus. With the listen() method,
|
* its listeners function returns FALSE. This allows to wait for certain
|
||||||
* a thread waits until a signal occurs, and then processes it.
|
* events. The associated job is executed after the listener has been
|
||||||
* To prevent the listen() calling thread to miss signals emitted while
|
* registered, this allows to listen on events we initiate with the job
|
||||||
* it processes a signal, registration is required. This is done through
|
* without missing any signals.
|
||||||
* 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 this bus
|
||||||
* @param level verbosity level of the signal
|
* @param listener listener to register
|
||||||
* @param thread receives thread number emitted the signal
|
* @param job job to execute asynchronously when registered, or NULL
|
||||||
* @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,
|
void (*listen)(bus_t *this, bus_listener_t *listener, job_t *job);
|
||||||
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.
|
|
||||||
*
|
|
||||||
* @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.
|
* @brief Set the IKE_SA the calling thread is using.
|
||||||
|
|||||||
@@ -56,18 +56,24 @@ struct private_interface_manager_t {
|
|||||||
linked_list_t *handles;
|
linked_list_t *handles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* helper struct to map bus listener callbacks to interface callbacks
|
* helper struct to map bus listener callbacks to interface callbacks
|
||||||
*/
|
*/
|
||||||
struct interface_bus_listener_t {
|
struct interface_bus_listener_t {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bus listener callback function (called)
|
* public bus listener interface
|
||||||
*/
|
*/
|
||||||
bus_listener_t listener;
|
bus_listener_t public;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IKE_SA to use for message filtering
|
* status of the operation, return to method callers
|
||||||
|
*/
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IKE SA to filter log output
|
||||||
*/
|
*/
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
|
|
||||||
@@ -82,11 +88,47 @@ struct interface_bus_listener_t {
|
|||||||
void *param;
|
void *param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* caller has cancelled its listening subscription
|
* child configuration, used for initiate
|
||||||
*/
|
*/
|
||||||
bool cancelled;
|
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
|
||||||
|
*/
|
||||||
|
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.
|
* Implementation of interface_manager_t.create_ike_sa_iterator.
|
||||||
*/
|
*/
|
||||||
@@ -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))
|
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
||||||
{
|
{
|
||||||
this->cancelled = TRUE;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
|
case CHILD_UP_SUCCESS:
|
||||||
|
this->status = SUCCESS;
|
||||||
|
return FALSE;
|
||||||
case IKE_UP_FAILED:
|
case IKE_UP_FAILED:
|
||||||
case CHILD_UP_FAILED:
|
case CHILD_UP_FAILED:
|
||||||
case CHILD_UP_SUCCESS:
|
|
||||||
{
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -124,6 +165,63 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute function for initiate
|
||||||
|
*/
|
||||||
|
static status_t initiate_execute(interface_job_t *job)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ike_sa->set_peer_cfg(ike_sa, peer_cfg);
|
||||||
|
}
|
||||||
|
peer_cfg->destroy(peer_cfg);
|
||||||
|
|
||||||
|
if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS)
|
||||||
|
{
|
||||||
|
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.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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return initiate_execute(&job);
|
||||||
|
}
|
||||||
|
charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
|
||||||
|
return job.listener.status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listener function for terminate_ike
|
* listener function for terminate_ike
|
||||||
*/
|
*/
|
||||||
@@ -135,16 +233,15 @@ static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t sign
|
|||||||
{
|
{
|
||||||
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
||||||
{
|
{
|
||||||
this->cancelled = TRUE;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
case IKE_DOWN_FAILED:
|
|
||||||
case IKE_DOWN_SUCCESS:
|
case IKE_DOWN_SUCCESS:
|
||||||
{
|
this->status = SUCCESS;
|
||||||
|
return FALSE;
|
||||||
|
case IKE_DOWN_FAILED:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -152,6 +249,56 @@ static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t sign
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute function for terminate_ike
|
||||||
|
*/
|
||||||
|
static status_t terminate_ike_execute(interface_job_t *job)
|
||||||
|
{
|
||||||
|
ike_sa_t *ike_sa;
|
||||||
|
interface_bus_listener_t *listener = &job->listener;
|
||||||
|
|
||||||
|
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
||||||
|
listener->id, FALSE);
|
||||||
|
if (ike_sa == NULL)
|
||||||
|
{
|
||||||
|
SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with "
|
||||||
|
"ID %d not found", listener->id);
|
||||||
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
|
listener->ike_sa = ike_sa;
|
||||||
|
|
||||||
|
if (ike_sa->delete(ike_sa) == DESTROY_ME)
|
||||||
|
{
|
||||||
|
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.terminate_ike.
|
||||||
|
*/
|
||||||
|
static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
|
||||||
|
interface_manager_cb_t callback, void *param)
|
||||||
|
{
|
||||||
|
interface_job_t job;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return terminate_ike_execute(&job);
|
||||||
|
}
|
||||||
|
charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
|
||||||
|
return job.listener.status;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* listener function for terminate_child
|
* listener function for terminate_child
|
||||||
*/
|
*/
|
||||||
@@ -163,18 +310,17 @@ static bool terminate_child_listener(interface_bus_listener_t *this, signal_t si
|
|||||||
{
|
{
|
||||||
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
||||||
{
|
{
|
||||||
this->cancelled = TRUE;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
case IKE_DOWN_FAILED:
|
|
||||||
case IKE_DOWN_SUCCESS:
|
|
||||||
case CHILD_DOWN_FAILED:
|
|
||||||
case CHILD_DOWN_SUCCESS:
|
case CHILD_DOWN_SUCCESS:
|
||||||
{
|
case IKE_DOWN_SUCCESS:
|
||||||
|
this->status = SUCCESS;
|
||||||
|
return FALSE;
|
||||||
|
case IKE_DOWN_FAILED:
|
||||||
|
case CHILD_DOWN_FAILED:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -182,6 +328,80 @@ static bool terminate_child_listener(interface_bus_listener_t *this, signal_t si
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute function for terminate_child
|
||||||
|
*/
|
||||||
|
static status_t terminate_child_execute(interface_job_t *job)
|
||||||
|
{
|
||||||
|
ike_sa_t *ike_sa;
|
||||||
|
child_sa_t *child_sa;
|
||||||
|
iterator_t *iterator;
|
||||||
|
interface_bus_listener_t *listener = &job->listener;
|
||||||
|
|
||||||
|
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
||||||
|
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) == listener->id)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
child_sa = NULL;
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
|
||||||
|
child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
|
||||||
|
{
|
||||||
|
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.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)
|
||||||
|
{
|
||||||
|
return terminate_child_execute(&job);
|
||||||
|
}
|
||||||
|
charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
|
||||||
|
return job.listener.status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listener function for route
|
* listener function for route
|
||||||
*/
|
*/
|
||||||
@@ -193,16 +413,15 @@ static bool route_listener(interface_bus_listener_t *this, signal_t signal,
|
|||||||
{
|
{
|
||||||
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
||||||
{
|
{
|
||||||
this->cancelled = TRUE;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
case CHILD_ROUTE_SUCCESS:
|
case CHILD_ROUTE_SUCCESS:
|
||||||
|
this->status = SUCCESS;
|
||||||
|
return FALSE;
|
||||||
case CHILD_ROUTE_FAILED:
|
case CHILD_ROUTE_FAILED:
|
||||||
{
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -210,6 +429,62 @@ static bool route_listener(interface_bus_listener_t *this, signal_t signal,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute function for route
|
||||||
|
*/
|
||||||
|
static status_t route_execute(interface_job_t *job)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ike_sa->set_peer_cfg(ike_sa, peer_cfg);
|
||||||
|
}
|
||||||
|
if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return route_execute(&job);
|
||||||
|
}
|
||||||
|
charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
|
||||||
|
return job.listener.status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listener function for unroute
|
* listener function for unroute
|
||||||
*/
|
*/
|
||||||
@@ -221,351 +496,44 @@ static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
|
|||||||
{
|
{
|
||||||
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
if (!this->callback(this->param, signal, level, ike_sa, format, args))
|
||||||
{
|
{
|
||||||
this->cancelled = TRUE;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
case CHILD_UNROUTE_SUCCESS:
|
case CHILD_UNROUTE_SUCCESS:
|
||||||
|
this->status = SUCCESS;
|
||||||
|
return FALSE;
|
||||||
case CHILD_UNROUTE_FAILED:
|
case CHILD_UNROUTE_FAILED:
|
||||||
{
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove a previously registered listener from the bus
|
* execute function for unroute
|
||||||
*/
|
*/
|
||||||
static void remove_listener(interface_bus_listener_t *listener)
|
static status_t unroute_execute(interface_job_t *job)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
ike_cfg_t *ike_cfg;
|
interface_bus_listener_t *listener = &job->listener;
|
||||||
status_t retval = FAILED;
|
|
||||||
interface_bus_listener_t 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)
|
|
||||||
{
|
|
||||||
/* don't wait for a result if no callback is specified */
|
|
||||||
charon->bus->set_listen_state(charon->bus, FALSE);
|
|
||||||
return NEED_MORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait until we get a result */
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
charon->bus->set_listen_state(charon->bus, FALSE);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of interface_manager_t.terminate_ike.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
||||||
unique_id, FALSE);
|
listener->id, TRUE);
|
||||||
if (ike_sa == NULL)
|
if (ike_sa == NULL)
|
||||||
{
|
{
|
||||||
|
SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with "
|
||||||
|
"ID %d not found", listener->id);
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
listener->ike_sa = ike_sa;
|
||||||
/* we listen passively to catch the signals we are raising in
|
if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME)
|
||||||
* 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);
|
return charon->ike_sa_manager->checkin_and_destroy(
|
||||||
|
charon->ike_sa_manager, ike_sa);
|
||||||
}
|
}
|
||||||
charon->bus->set_listen_state(charon->bus, TRUE);
|
return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
status = ike_sa->delete(ike_sa);
|
|
||||||
if (status == DESTROY_ME)
|
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
|
||||||
|
|
||||||
/* wait until IKE_SA is cleanly deleted using a delete message */
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
charon->bus->set_listen_state(charon->bus, FALSE);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
ike_sa_t *ike_sa;
|
|
||||||
child_sa_t *child_sa;
|
|
||||||
iterator_t *iterator;
|
|
||||||
status_t status = FAILED;
|
|
||||||
interface_bus_listener_t listener;
|
|
||||||
|
|
||||||
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
|
||||||
reqid, TRUE);
|
|
||||||
if (ike_sa == NULL)
|
|
||||||
{
|
|
||||||
return NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
child_sa = NULL;
|
|
||||||
}
|
|
||||||
iterator->destroy(iterator);
|
|
||||||
|
|
||||||
if (child_sa == NULL)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
charon->bus->add_listener(charon->bus, &listener.listener);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
|
||||||
|
|
||||||
/* wait until CHILD_SA is cleanly deleted using a delete message */
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
charon->bus->set_listen_state(charon->bus, FALSE);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
ike_sa_t *ike_sa;
|
|
||||||
ike_cfg_t *ike_cfg;
|
|
||||||
status_t status = SUCCESS;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we listen passively only, as routing is done by one thread only */
|
|
||||||
if (callback)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ike_sa->route(ike_sa, child_cfg) != SUCCESS)
|
|
||||||
{
|
|
||||||
status = FAILED;
|
|
||||||
}
|
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -574,39 +542,23 @@ static status_t route(interface_manager_t *this,
|
|||||||
static status_t unroute(interface_manager_t *this, u_int32_t reqid,
|
static status_t unroute(interface_manager_t *this, u_int32_t reqid,
|
||||||
interface_manager_cb_t callback, void *param)
|
interface_manager_cb_t callback, void *param)
|
||||||
{
|
{
|
||||||
ike_sa_t *ike_sa;
|
interface_job_t job;
|
||||||
status_t status;
|
|
||||||
|
|
||||||
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
|
job.listener.public.signal = (void*)unroute_listener;
|
||||||
reqid, TRUE);
|
job.listener.ike_sa = NULL;
|
||||||
if (ike_sa == NULL)
|
job.listener.callback = callback;
|
||||||
{
|
job.listener.param = param;
|
||||||
return NOT_FOUND;
|
job.listener.status = FAILED;
|
||||||
}
|
job.listener.id = reqid;
|
||||||
|
job.public.execute = (void*)unroute_execute;
|
||||||
|
job.public.destroy = nop;
|
||||||
|
|
||||||
/* we listen passively only, as routing is done by one thread only */
|
if (callback == NULL)
|
||||||
if (callback)
|
|
||||||
{
|
{
|
||||||
interface_bus_listener_t listener;
|
return unroute_execute(&job);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
status = ike_sa->unroute(ike_sa, reqid);
|
charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
|
||||||
if (status == DESTROY_ME)
|
return job.listener.status;
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
|
|
||||||
status = SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1692,7 +1692,6 @@ static job_requeue_t stroke_process(int *fdp)
|
|||||||
return JOB_REQUEUE_NONE;
|
return JOB_REQUEUE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of private_stroke_interface_t.stroke_receive.
|
* Implementation of private_stroke_interface_t.stroke_receive.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ static void execute(private_callback_job_t *this)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this->thread = 0;
|
||||||
unregister(this);
|
unregister(this);
|
||||||
pthread_cleanup_pop(cleanup);
|
pthread_cleanup_pop(cleanup);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user