diff options
Diffstat (limited to 'src/libcharon/processing')
37 files changed, 3973 insertions, 0 deletions
diff --git a/src/libcharon/processing/jobs/acquire_job.c b/src/libcharon/processing/jobs/acquire_job.c new file mode 100644 index 000000000..45ace9312 --- /dev/null +++ b/src/libcharon/processing/jobs/acquire_job.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "acquire_job.h" + +#include <daemon.h> + + +typedef struct private_acquire_job_t private_acquire_job_t; + +/** + * Private data of an acquire_job_t object. + */ +struct private_acquire_job_t { + /** + * Public acquire_job_t interface. + */ + acquire_job_t public; + + /** + * reqid of the child to rekey + */ + u_int32_t reqid; + + /** + * acquired source traffic selector + */ + traffic_selector_t *src_ts; + + /** + * acquired destination traffic selector + */ + traffic_selector_t *dst_ts; +}; + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_acquire_job_t *this) +{ + DESTROY_IF(this->src_ts); + DESTROY_IF(this->dst_ts); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_acquire_job_t *this) +{ + charon->traps->acquire(charon->traps, this->reqid, + this->src_ts, this->dst_ts); + destroy(this); +} + +/* + * Described in header + */ +acquire_job_t *acquire_job_create(u_int32_t reqid, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts) +{ + private_acquire_job_t *this = malloc_thing(private_acquire_job_t); + + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + this->reqid = reqid; + this->src_ts = src_ts; + this->dst_ts = dst_ts; + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/acquire_job.h b/src/libcharon/processing/jobs/acquire_job.h new file mode 100644 index 000000000..eff79a9b0 --- /dev/null +++ b/src/libcharon/processing/jobs/acquire_job.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup acquire_job acquire_job + * @{ @ingroup jobs + */ + +#ifndef ACQUIRE_JOB_H_ +#define ACQUIRE_JOB_H_ + +typedef struct acquire_job_t acquire_job_t; + +#include <library.h> +#include <selectors/traffic_selector.h> +#include <processing/jobs/job.h> + +/** + * Class representing an ACQUIRE Job. + * + * This job initiates a CHILD SA on kernel request. + */ +struct acquire_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type ACQUIRE. + * + * @param reqid reqid of the trapped CHILD_SA to acquire + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @return acquire_job_t object + */ +acquire_job_t *acquire_job_create(u_int32_t reqid, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts); + +#endif /** REKEY_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/callback_job.c b/src/libcharon/processing/jobs/callback_job.c new file mode 100644 index 000000000..45e49112e --- /dev/null +++ b/src/libcharon/processing/jobs/callback_job.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "callback_job.h" + +#include <semaphore.h> + +#include <daemon.h> +#include <threading/thread.h> +#include <threading/condvar.h> +#include <threading/mutex.h> + +typedef struct private_callback_job_t private_callback_job_t; + +/** + * Private data of an callback_job_t Object. + */ +struct private_callback_job_t { + /** + * Public callback_job_t interface. + */ + callback_job_t public; + + /** + * Callback to call on execution + */ + callback_job_cb_t callback; + + /** + * parameter to supply to callback + */ + void *data; + + /** + * cleanup function for data + */ + callback_job_cleanup_t cleanup; + + /** + * thread of the job, if running + */ + thread_t *thread; + + /** + * mutex to access jobs interna + */ + mutex_t *mutex; + + /** + * list of asociated child jobs + */ + linked_list_t *children; + + /** + * parent of this job, or NULL + */ + private_callback_job_t *parent; + + /** + * TRUE if the job got cancelled + */ + bool cancelled; + + /** + * condvar to synchronize the cancellation/destruction of the job + */ + condvar_t *destroyable; + + /** + * semaphore to synchronize the termination of the assigned thread. + * + * separately allocated during cancellation, so that we can wait on it + * without risking that it gets freed too early during destruction. + */ + sem_t *terminated; +}; + +/** + * unregister a child from its parent, if any. + * note: this->mutex has to be locked + */ +static void unregister(private_callback_job_t *this) +{ + if (this->parent) + { + this->parent->mutex->lock(this->parent->mutex); + if (this->parent->cancelled && !this->cancelled) + { + /* if the parent has been cancelled but we have not yet, we do not + * unregister until we got cancelled by the parent. */ + this->parent->mutex->unlock(this->parent->mutex); + this->destroyable->wait(this->destroyable, this->mutex); + this->parent->mutex->lock(this->parent->mutex); + } + this->parent->children->remove(this->parent->children, this, NULL); + this->parent->mutex->unlock(this->parent->mutex); + this->parent = NULL; + } +} + +/** + * Implements job_t.destroy. + */ +static void destroy(private_callback_job_t *this) +{ + this->mutex->lock(this->mutex); + unregister(this); + if (this->cleanup) + { + this->cleanup(this->data); + } + if (this->terminated) + { + sem_post(this->terminated); + } + this->children->destroy(this->children); + this->destroyable->destroy(this->destroyable); + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * Implementation of callback_job_t.cancel. + */ +static void cancel(private_callback_job_t *this) +{ + callback_job_t *child; + sem_t *terminated = NULL; + + this->mutex->lock(this->mutex); + this->cancelled = TRUE; + /* terminate children */ + while (this->children->get_first(this->children, (void**)&child) == SUCCESS) + { + this->mutex->unlock(this->mutex); + child->cancel(child); + this->mutex->lock(this->mutex); + } + if (this->thread) + { + /* terminate the thread, if there is currently one executing the job. + * we wait for its termination using a semaphore */ + this->thread->cancel(this->thread); + terminated = this->terminated = malloc_thing(sem_t); + sem_init(terminated, 0, 0); + } + else + { + /* if the job is currently queued, it gets terminated later. + * we can't wait, because it might not get executed at all. + * we also unregister the queued job manually from its parent (the + * others get unregistered during destruction) */ + unregister(this); + } + this->destroyable->signal(this->destroyable); + this->mutex->unlock(this->mutex); + + if (terminated) + { + sem_wait(terminated); + sem_destroy(terminated); + free(terminated); + } +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_callback_job_t *this) +{ + bool cleanup = FALSE, requeue = FALSE; + + thread_cleanup_push((thread_cleanup_t)destroy, this); + + this->mutex->lock(this->mutex); + this->thread = thread_current(); + this->mutex->unlock(this->mutex); + + while (TRUE) + { + this->mutex->lock(this->mutex); + if (this->cancelled) + { + this->mutex->unlock(this->mutex); + cleanup = TRUE; + break; + } + this->mutex->unlock(this->mutex); + switch (this->callback(this->data)) + { + case JOB_REQUEUE_DIRECT: + continue; + case JOB_REQUEUE_FAIR: + { + requeue = TRUE; + break; + } + case JOB_REQUEUE_NONE: + default: + { + cleanup = TRUE; + break; + } + } + break; + } + this->mutex->lock(this->mutex); + this->thread = NULL; + this->mutex->unlock(this->mutex); + /* manually create a cancellation point to avoid that a cancelled thread + * goes back into the thread pool */ + thread_cancellation_point(); + if (requeue) + { + charon->processor->queue_job(charon->processor, + &this->public.job_interface); + } + thread_cleanup_pop(cleanup); +} + +/* + * Described in header. + */ +callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, + callback_job_cleanup_t cleanup, + callback_job_t *parent) +{ + private_callback_job_t *this = malloc_thing(private_callback_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + this->public.cancel = (void(*)(callback_job_t*))cancel; + + /* private variables */ + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->callback = cb; + this->data = data; + this->cleanup = cleanup; + this->thread = 0; + this->children = linked_list_create(); + this->parent = (private_callback_job_t*)parent; + this->cancelled = FALSE; + this->destroyable = condvar_create(CONDVAR_TYPE_DEFAULT); + this->terminated = NULL; + + /* register us at parent */ + if (parent) + { + this->parent->mutex->lock(this->parent->mutex); + this->parent->children->insert_last(this->parent->children, this); + this->parent->mutex->unlock(this->parent->mutex); + } + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/callback_job.h b/src/libcharon/processing/jobs/callback_job.h new file mode 100644 index 000000000..62da1edd1 --- /dev/null +++ b/src/libcharon/processing/jobs/callback_job.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup callback_job callback_job + * @{ @ingroup jobs + */ + +#ifndef CALLBACK_JOB_H_ +#define CALLBACK_JOB_H_ + +typedef struct callback_job_t callback_job_t; + +#include <library.h> +#include <processing/jobs/job.h> + + +typedef enum job_requeue_t job_requeue_t; + +/** + * Job requeueing policy + * + * The job requeueing policy defines how a job is handled when the callback + * function returns. + */ +enum job_requeue_t { + + /** + * Do not requeue job, destroy it + */ + JOB_REQUEUE_NONE, + + /** + * Reque the job fairly, meaning it has to requeue as any other job + */ + JOB_REQUEUE_FAIR, + + /** + * Reexecute the job directly, without the need of requeueing it + */ + JOB_REQUEUE_DIRECT, +}; + +/** + * The callback function to use for the callback job. + * + * This is the function to use as callback for a callback job. It receives + * a parameter supplied to the callback jobs constructor. + * + * @param data param supplied to job + * @return requeing policy how to requeue the job + */ +typedef job_requeue_t (*callback_job_cb_t)(void *data); + +/** + * Cleanup function to use for data cleanup. + * + * The callback has an optional user argument which receives data. However, + * this data may be cleaned up if it is allocated. This is the function + * to supply to the constructor. + * + * @param data param supplied to job + * @return requeing policy how to requeue the job + */ +typedef void (*callback_job_cleanup_t)(void *data); + +/** + * Class representing an callback Job. + * + * This is a special job which allows a simple callback function to + * be executed by a thread of the thread pool. This allows simple execution + * of asynchronous methods, without to manage threads. + */ +struct callback_job_t { + /** + * The job_t interface. + */ + job_t job_interface; + + /** + * Cancel the job's thread and wait for its termination. This only works + * reliably for jobs that always use JOB_REQUEUE_FAIR or JOB_REQUEUE_DIRECT, + * otherwise the job may already be destroyed when cancel is called. */ + void (*cancel)(callback_job_t *this); +}; + +/** + * Creates a callback job. + * + * The cleanup function is called when the job gets destroyed to destroy + * the associated data. + * If parent is not NULL, the specified job gets an association. Whenever + * the parent gets cancelled (or runs out), all of its children are cancelled, + * too. + * + * @param cb callback to call from the processor + * @param data user data to supply to callback + * @param cleanup destructor for data on destruction, or NULL + * @param parent parent of this job + * @return callback_job_t object + */ +callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, + callback_job_cleanup_t cleanup, + callback_job_t *parent); + +#endif /** CALLBACK_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c new file mode 100644 index 000000000..ca55721f2 --- /dev/null +++ b/src/libcharon/processing/jobs/delete_child_sa_job.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "delete_child_sa_job.h" + +#include <daemon.h> + + +typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t; + +/** + * Private data of an delete_child_sa_job_t object. + */ +struct private_delete_child_sa_job_t { + /** + + * Public delete_child_sa_job_t interface. + */ + delete_child_sa_job_t public; + + /** + * reqid of the CHILD_SA + */ + u_int32_t reqid; + + /** + * protocol of the CHILD_SA (ESP/AH) + */ + protocol_id_t protocol; + + /** + * inbound SPI of the CHILD_SA + */ + u_int32_t spi; +}; + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_delete_child_sa_job_t *this) +{ + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_delete_child_sa_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + this->reqid, TRUE); + if (ike_sa == NULL) + { + DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete", + this->reqid); + } + else + { + ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); +} + +/* + * Described in header + */ +delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, + protocol_id_t protocol, + u_int32_t spi) +{ + private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->reqid = reqid; + this->protocol = protocol; + this->spi = spi; + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h new file mode 100644 index 000000000..662a7b7c7 --- /dev/null +++ b/src/libcharon/processing/jobs/delete_child_sa_job.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup delete_child_sa_job delete_child_sa_job + * @{ @ingroup jobs + */ + +#ifndef DELETE_CHILD_SA_JOB_H_ +#define DELETE_CHILD_SA_JOB_H_ + +typedef struct delete_child_sa_job_t delete_child_sa_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> +#include <config/proposal.h> + + +/** + * Class representing an DELETE_CHILD_SA Job. + * + * This job initiates the delete of a CHILD SA. + */ +struct delete_child_sa_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type DELETE_CHILD_SA. + * + * The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its + * inbound SPI. + * + * @param reqid reqid of the CHILD_SA, as used in kernel + * @param protocol protocol of the CHILD_SA + * @param spi security parameter index of the CHILD_SA + * @return delete_child_sa_job_t object + */ +delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, + protocol_id_t protocol, + u_int32_t spi); + +#endif /** DELETE_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/delete_ike_sa_job.c b/src/libcharon/processing/jobs/delete_ike_sa_job.c new file mode 100644 index 000000000..dffd08ba3 --- /dev/null +++ b/src/libcharon/processing/jobs/delete_ike_sa_job.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "delete_ike_sa_job.h" + +#include <daemon.h> + +typedef struct private_delete_ike_sa_job_t private_delete_ike_sa_job_t; + +/** + * Private data of an delete_ike_sa_job_t Object + */ +struct private_delete_ike_sa_job_t { + /** + * public delete_ike_sa_job_t interface + */ + delete_ike_sa_job_t public; + + /** + * ID of the ike_sa to delete + */ + ike_sa_id_t *ike_sa_id; + + /** + * Should the IKE_SA be deleted if it is in ESTABLISHED state? + */ + bool delete_if_established; +}; + + +/** + * Implements job_t.destroy. + */ +static void destroy(private_delete_ike_sa_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_delete_ike_sa_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + if (ike_sa->get_state(ike_sa) == IKE_PASSIVE) + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return destroy(this); + } + if (this->delete_if_established) + { + if (ike_sa->delete(ike_sa) == 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); + } + } + else + { + /* destroy only if not ESTABLISHED */ + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED) + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + DBG1(DBG_JOB, "deleting half open IKE_SA after timeout"); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + } + } + destroy(this); +} + +/* + * Described in header + */ +delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id, + bool delete_if_established) +{ + private_delete_ike_sa_job_t *this = malloc_thing(private_delete_ike_sa_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t *)) destroy;; + + /* private variables */ + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->delete_if_established = delete_if_established; + + return &(this->public); +} diff --git a/src/libcharon/processing/jobs/delete_ike_sa_job.h b/src/libcharon/processing/jobs/delete_ike_sa_job.h new file mode 100644 index 000000000..f641deea3 --- /dev/null +++ b/src/libcharon/processing/jobs/delete_ike_sa_job.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 delete_child_sa_job delete_child_sa_job + * @{ @ingroup jobs + */ + +#ifndef DELETE_IKE_SA_JOB_H_ +#define DELETE_IKE_SA_JOB_H_ + +typedef struct delete_ike_sa_job_t delete_ike_sa_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> + + +/** + * Class representing an DELETE_IKE_SA Job. + * + * This job is responsible for deleting established or half open IKE_SAs. + * A half open IKE_SA is every IKE_SA which hasn't reache the SA_ESTABLISHED + * state. + */ +struct delete_ike_sa_job_t { + + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type DELETE_IKE_SA. + * + * @param ike_sa_id id of the IKE_SA to delete + * @param delete_if_established should the IKE_SA be deleted if it is established? + * @return created delete_ike_sa_job_t object + */ +delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id, + bool delete_if_established); + +#endif /** DELETE_IKE_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/inactivity_job.c b/src/libcharon/processing/jobs/inactivity_job.c new file mode 100644 index 000000000..13fc5e3d0 --- /dev/null +++ b/src/libcharon/processing/jobs/inactivity_job.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "inactivity_job.h" + +#include <daemon.h> + +typedef struct private_inactivity_job_t private_inactivity_job_t; + +/** + * Private data of an inactivity_job_t object. + */ +struct private_inactivity_job_t { + + /** + * Public inactivity_job_t interface. + */ + inactivity_job_t public; + + /** + * Reqid of CHILD_SA to check + */ + u_int32_t reqid; + + /** + * Inactivity timeout + */ + u_int32_t timeout; + + /** + * Close IKE_SA if last remaining CHILD inactive? + */ + bool close_ike; +}; + +METHOD(job_t, destroy, void, + private_inactivity_job_t *this) +{ + free(this); +} + +METHOD(job_t, execute, void, + private_inactivity_job_t *this) +{ + ike_sa_t *ike_sa; + bool rescheduled = FALSE; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + this->reqid, TRUE); + if (ike_sa) + { + iterator_t *iterator; + child_sa_t *child_sa; + u_int32_t delete = 0; + protocol_id_t proto = 0; + int children = 0; + status_t status = SUCCESS; + + iterator = ike_sa->create_child_sa_iterator(ike_sa); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + if (child_sa->get_reqid(child_sa) == this->reqid) + { + time_t in, out, diff; + + child_sa->get_usestats(child_sa, TRUE, &in, NULL); + child_sa->get_usestats(child_sa, FALSE, &out, NULL); + + diff = time_monotonic(NULL) - max(in, out); + + if (diff >= this->timeout) + { + delete = child_sa->get_spi(child_sa, TRUE); + proto = child_sa->get_protocol(child_sa); + } + else + { + charon->scheduler->schedule_job(charon->scheduler, + &this->public.job_interface, this->timeout - diff); + rescheduled = TRUE; + } + } + children++; + } + iterator->destroy(iterator); + + if (delete) + { + if (children == 1 && this->close_ike) + { + DBG1(DBG_JOB, "deleting IKE_SA after %d seconds " + "of CHILD_SA inactivity", this->timeout); + status = ike_sa->delete(ike_sa); + } + else + { + DBG1(DBG_JOB, "deleting CHILD_SA after %d seconds " + "of inactivity", this->timeout); + status = ike_sa->delete_child_sa(ike_sa, proto, delete); + } + } + 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); + } + } + if (!rescheduled) + { + destroy(this); + } +} + +/** + * See header + */ +inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout, + bool close_ike) +{ + private_inactivity_job_t *this; + + INIT(this, + .public.job_interface = { + .execute = _execute, + .destroy = _destroy, + }, + .reqid = reqid, + .timeout = timeout, + .close_ike = close_ike, + ); + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/inactivity_job.h b/src/libcharon/processing/jobs/inactivity_job.h new file mode 100644 index 000000000..9c9daced8 --- /dev/null +++ b/src/libcharon/processing/jobs/inactivity_job.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup inactivity_job inactivity_job + * @{ @ingroup jobs + */ + +#ifndef INACTIVITY_JOB_H_ +#define INACTIVITY_JOB_H_ + +#include <library.h> +#include <processing/jobs/job.h> + +typedef struct inactivity_job_t inactivity_job_t; + +/** + * Job checking for inactivity of CHILD_SA to close them. + * + * The inactivity job reschedules itself to check CHILD_SAs prediodically. + */ +struct inactivity_job_t { + + /** + * Implements job_t. + */ + job_t job_interface; +}; + +/** + * Create a inactivity_job instance. + * + * @param reqid reqid of CHILD_SA to check for inactivity + * @param timeout inactivity timeout in s + * @param close_ike close IKE_SA if the last remaining CHILD_SA is inactive? + * @return inactivity checking job + */ +inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout, + bool close_ike); + +#endif /** INACTIVITY_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c new file mode 100644 index 000000000..ffe8755e2 --- /dev/null +++ b/src/libcharon/processing/jobs/initiate_mediation_job.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2007-2008 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. + */ + +#include "initiate_mediation_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_initiate_mediation_job_t private_initiate_mediation_job_t; + +/** + * Private data of an initiate_mediation_job_t Object + */ +struct private_initiate_mediation_job_t { + /** + * public initiate_mediation_job_t interface + */ + initiate_mediation_job_t public; + + /** + * ID of the IKE_SA of the mediated connection. + */ + ike_sa_id_t *mediated_sa_id; + + /** + * ID of the IKE_SA of the mediation connection. + */ + ike_sa_id_t *mediation_sa_id; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_initiate_mediation_job_t *this) +{ + DESTROY_IF(this->mediation_sa_id); + DESTROY_IF(this->mediated_sa_id); + free(this); +} + +/** + * Callback to handle initiation of mediation connection + */ +static bool initiate_callback(private_initiate_mediation_job_t *this, + debug_t group, level_t level, ike_sa_t *ike_sa, + char *format, va_list args) +{ + if (ike_sa && !this->mediation_sa_id) + { + this->mediation_sa_id = ike_sa->get_id(ike_sa); + this->mediation_sa_id = this->mediation_sa_id->clone(this->mediation_sa_id); + } + return TRUE; +} + +/** + * Implementation of job_t.execute. + */ +static void initiate(private_initiate_mediation_job_t *this) +{ + ike_sa_t *mediated_sa, *mediation_sa; + peer_cfg_t *mediated_cfg, *mediation_cfg; + enumerator_t *enumerator; + auth_cfg_t *auth_cfg; + + mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->mediated_sa_id); + if (mediated_sa) + { + DBG1(DBG_IKE, "initiating mediation connection"); + mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa); + mediated_cfg->get_ref(mediated_cfg); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa); + + mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg); + mediation_cfg->get_ref(mediation_cfg); + + enumerator = mediation_cfg->create_auth_cfg_enumerator(mediation_cfg, + TRUE); + if (!enumerator->enumerate(enumerator, &auth_cfg) || + auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY) == NULL) + { + mediated_cfg->destroy(mediated_cfg); + mediation_cfg->destroy(mediation_cfg); + enumerator->destroy(enumerator); + destroy(this); + return; + } + enumerator->destroy(enumerator); + + if (charon->connect_manager->check_and_register(charon->connect_manager, + auth_cfg->get(auth_cfg, AUTH_RULE_IDENTITY), + mediated_cfg->get_peer_id(mediated_cfg), + this->mediated_sa_id)) + { + mediated_cfg->destroy(mediated_cfg); + mediation_cfg->destroy(mediation_cfg); + + mediated_sa = charon->ike_sa_manager->checkout( + charon->ike_sa_manager, this->mediated_sa_id); + if (mediated_sa) + { + DBG1(DBG_IKE, "mediation with the same peer is already in " + "progress, queued"); + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, mediated_sa); + } + destroy(this); + return; + } + /* we need an additional reference because initiate consumes one */ + mediation_cfg->get_ref(mediation_cfg); + + if (charon->controller->initiate(charon->controller, mediation_cfg, + NULL, (controller_cb_t)initiate_callback, this) != SUCCESS) + { + mediation_cfg->destroy(mediation_cfg); + mediated_cfg->destroy(mediated_cfg); + mediated_sa = charon->ike_sa_manager->checkout( + charon->ike_sa_manager, this->mediated_sa_id); + if (mediated_sa) + { + DBG1(DBG_IKE, "initiating mediation connection failed"); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, mediated_sa); + } + destroy(this); + return; + } + mediation_cfg->destroy(mediation_cfg); + + mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->mediation_sa_id); + if (mediation_sa) + { + if (mediation_sa->initiate_mediation(mediation_sa, + mediated_cfg) != SUCCESS) + { + mediated_cfg->destroy(mediated_cfg); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, mediation_sa); + mediated_sa = charon->ike_sa_manager->checkout( + charon->ike_sa_manager, this->mediated_sa_id); + if (mediated_sa) + { + DBG1(DBG_IKE, "establishing mediation connection failed"); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, mediated_sa); + } + destroy(this); + return; + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, + mediation_sa); + } + mediated_cfg->destroy(mediated_cfg); + } + destroy(this); +} + +/** + * Implementation of job_t.execute. + */ +static void reinitiate(private_initiate_mediation_job_t *this) +{ + ike_sa_t *mediated_sa, *mediation_sa; + peer_cfg_t *mediated_cfg; + + mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->mediated_sa_id); + if (mediated_sa) + { + mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa); + mediated_cfg->get_ref(mediated_cfg); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa); + + mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->mediation_sa_id); + if (mediation_sa) + { + if (mediation_sa->initiate_mediation(mediation_sa, + mediated_cfg) != SUCCESS) + { + DBG1(DBG_JOB, "initiating mediated connection '%s' failed", + mediated_cfg->get_name(mediated_cfg)); + mediated_cfg->destroy(mediated_cfg); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, + mediation_sa); + mediated_sa = charon->ike_sa_manager->checkout( + charon->ike_sa_manager, + this->mediated_sa_id); + if (mediated_sa) + { + DBG1(DBG_IKE, "establishing mediation connection failed"); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, + mediated_sa); + } + destroy(this); + return; + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, + mediation_sa); + } + + mediated_cfg->destroy(mediated_cfg); + } + destroy(this); +} + +/** + * Creates an empty job + */ +static private_initiate_mediation_job_t *initiate_mediation_job_create_empty() +{ + private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t); + + /* interface functions */ + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + /* private variables */ + this->mediation_sa_id = NULL; + this->mediated_sa_id = NULL; + + return this; +} + +/* + * Described in header + */ +initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id) +{ + private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty(); + + this->public.job_interface.execute = (void (*) (job_t *)) initiate; + + this->mediated_sa_id = ike_sa_id->clone(ike_sa_id); + + return &this->public; +} + +/* + * Described in header + */ +initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id, + ike_sa_id_t *mediated_sa_id) +{ + private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty(); + + this->public.job_interface.execute = (void (*) (job_t *)) reinitiate; + + this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id); + this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.h b/src/libcharon/processing/jobs/initiate_mediation_job.h new file mode 100644 index 000000000..fddb1dd7b --- /dev/null +++ b/src/libcharon/processing/jobs/initiate_mediation_job.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007-2008 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 initiate_mediation_job initiate_mediation_job + * @{ @ingroup jobs + */ + +#ifndef INITIATE_MEDIATION_JOB_H_ +#define INITIATE_MEDIATION_JOB_H_ + +typedef struct initiate_mediation_job_t initiate_mediation_job_t; + +#include <processing/jobs/job.h> +#include <sa/ike_sa_id.h> + +/** + * Class representing a INITIATE_MEDIATION Job. + * + * This job will initiate a mediation on behalf of a mediated connection. + * If required the mediation connection is established. + */ +struct initiate_mediation_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type INITIATE_MEDIATION. + * + * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) + * @return job object + */ +initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id); + +/** + * Creates a special job of type INITIATE_MEDIATION that reinitiates a + * specific connection. + * + * @param mediation_sa_id identification of the mediation sa (gets cloned) + * @param mediated_sa_id identification of the mediated sa (gets cloned) + * @return job object + */ +initiate_mediation_job_t *reinitiate_mediation_job_create( + ike_sa_id_t *mediation_sa_id, + ike_sa_id_t *mediated_sa_id); + +#endif /** INITIATE_MEDIATION_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/job.h b/src/libcharon/processing/jobs/job.h new file mode 100644 index 000000000..0f1c16ebe --- /dev/null +++ b/src/libcharon/processing/jobs/job.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 job job + * @{ @ingroup jobs + */ + +#ifndef JOB_H_ +#define JOB_H_ + +typedef struct job_t job_t; + +#include <library.h> + +/** + * Job-Interface as it is stored in the job queue. + */ +struct job_t { + + /** + * Execute a job. + * + * The processing facility executes a job using this method. Jobs are + * one-shot, they destroy themself after execution, so don't use a job + * once it has been executed. + */ + void (*execute) (job_t *this); + + /** + * Destroy a job. + * + * Is only called whenever a job was not executed (e.g. due daemon shutdown). + * After execution, jobs destroy themself. + */ + void (*destroy) (job_t *job); +}; + +#endif /** JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/mediation_job.c b/src/libcharon/processing/jobs/mediation_job.c new file mode 100644 index 000000000..b5b8af3b3 --- /dev/null +++ b/src/libcharon/processing/jobs/mediation_job.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2007 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. + */ + +#include "mediation_job.h" + +#include <encoding/payloads/endpoint_notify.h> +#include <daemon.h> + + +typedef struct private_mediation_job_t private_mediation_job_t; + +/** + * Private data of an mediation_job_t Object + */ +struct private_mediation_job_t { + /** + * public mediation_job_t interface + */ + mediation_job_t public; + + /** + * ID of target peer. + */ + identification_t *target; + + /** + * ID of the source peer. + */ + identification_t *source; + + /** + * ME_CONNECTID + */ + chunk_t connect_id; + + /** + * ME_CONNECTKEY + */ + chunk_t connect_key; + + /** + * Submitted endpoints + */ + linked_list_t *endpoints; + + /** + * Is this a callback job? + */ + bool callback; + + /** + * Is this a response? + */ + bool response; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_mediation_job_t *this) +{ + DESTROY_IF(this->target); + DESTROY_IF(this->source); + chunk_free(&this->connect_id); + chunk_free(&this->connect_key); + DESTROY_OFFSET_IF(this->endpoints, offsetof(endpoint_notify_t, destroy)); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_mediation_job_t *this) +{ + ike_sa_id_t *target_sa_id; + + target_sa_id = charon->mediation_manager->check(charon->mediation_manager, this->target); + + if (target_sa_id) + { + ike_sa_t *target_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + target_sa_id); + if (target_sa) + { + if (this->callback) + { + /* send callback to a peer */ + if (target_sa->callback(target_sa, this->source) != SUCCESS) + { + DBG1(DBG_JOB, "callback for '%Y' to '%Y' failed", + this->source, this->target); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); + destroy(this); + return; + } + } + else + { + /* normal mediation between two peers */ + if (target_sa->relay(target_sa, this->source, this->connect_id, + this->connect_key, this->endpoints, this->response) != SUCCESS) + { + DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed", + this->source, this->target); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); + /* FIXME: notify the initiator */ + destroy(this); + return; + } + } + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); + } + else + { + DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed: " + "SA not found", this->source, this->target); + } + } + else + { + DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed: " + "peer is not online anymore", this->source, this->target); + } + destroy(this); +} + +/** + * Creates an empty mediation job + */ +static private_mediation_job_t *mediation_job_create_empty() +{ + private_mediation_job_t *this = malloc_thing(private_mediation_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + /* private variables */ + this->target = NULL; + this->source = NULL; + this->callback = FALSE; + this->connect_id = chunk_empty; + this->connect_key = chunk_empty; + this->endpoints = NULL; + this->response = FALSE; + + return this; +} + +/* + * Described in header + */ +mediation_job_t *mediation_job_create(identification_t *peer_id, + identification_t *requester, chunk_t connect_id, chunk_t connect_key, + linked_list_t *endpoints, bool response) +{ + private_mediation_job_t *this = mediation_job_create_empty(); + + this->target = peer_id->clone(peer_id); + this->source = requester->clone(requester); + this->connect_id = chunk_clone(connect_id); + this->connect_key = chunk_clone(connect_key); + this->endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone)); + this->response = response; + + return &this->public; +} + +/* + * Described in header + */ +mediation_job_t *mediation_callback_job_create(identification_t *requester, + identification_t *peer_id) +{ + private_mediation_job_t *this = mediation_job_create_empty(); + + this->target = requester->clone(requester); + this->source = peer_id->clone(peer_id); + this->callback = TRUE; + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/mediation_job.h b/src/libcharon/processing/jobs/mediation_job.h new file mode 100644 index 000000000..0574c65eb --- /dev/null +++ b/src/libcharon/processing/jobs/mediation_job.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 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 mediation_job mediation_job + * @{ @ingroup jobs + */ + +#ifndef MEDIATION_JOB_H_ +#define MEDIATION_JOB_H_ + +typedef struct mediation_job_t mediation_job_t; + +#include <library.h> +#include <processing/jobs/job.h> +#include <utils/identification.h> +#include <utils/linked_list.h> + +/** + * Class representing a MEDIATION Job. + * + * This job handles the mediation on the mediation server. + */ +struct mediation_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type MEDIATION. + * + * Parameters get cloned. + * + * @param peer_id ID of the requested peer + * @param requester ID of the requesting peer + * @param connect_id content of ME_CONNECTID (could be NULL) + * @param connect_key content of ME_CONNECTKEY + * @param endpoints list of submitted endpoints + * @param response TRUE if this is a response + * @return job object + */ +mediation_job_t *mediation_job_create(identification_t *peer_id, + identification_t *requester, chunk_t connect_id, chunk_t connect_key, + linked_list_t *endpoints, bool response); + + +/** + * Creates a special job of type MEDIATION that is used to send a callback + * notification to a peer. + * + * Parameters get cloned. + * + * @param requester ID of the waiting peer + * @param peer_id ID of the requested peer + * @return job object + */ +mediation_job_t *mediation_callback_job_create(identification_t *requester, + identification_t *peer_id); + +#endif /** MEDIATION_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/migrate_job.c b/src/libcharon/processing/jobs/migrate_job.c new file mode 100644 index 000000000..05f47340c --- /dev/null +++ b/src/libcharon/processing/jobs/migrate_job.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2008 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "migrate_job.h" + +#include <daemon.h> + +#include <config/child_cfg.h> + + +typedef struct private_migrate_job_t private_migrate_job_t; + +/** + * Private data of a migrate_job_t object. + */ +struct private_migrate_job_t { + /** + * Public migrate_job_t interface. + */ + migrate_job_t public; + + /** + * reqid of the CHILD_SA if it already exists + */ + u_int32_t reqid; + + /** + * source traffic selector + */ + traffic_selector_t *src_ts; + + /** + * destination traffic selector + */ + traffic_selector_t *dst_ts; + + /** + * local host address to be used for IKE + */ + host_t *local; + + /** + * remote host address to be used for IKE + */ + host_t *remote; +}; + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_migrate_job_t *this) +{ + DESTROY_IF(this->src_ts); + DESTROY_IF(this->dst_ts); + DESTROY_IF(this->local); + DESTROY_IF(this->remote); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_migrate_job_t *this) +{ + ike_sa_t *ike_sa = NULL; + + if (this->reqid) + { + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + this->reqid, TRUE); + } + if (ike_sa) + { + iterator_t *children; + child_sa_t *child_sa; + host_t *host; + + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if (child_sa->get_reqid(child_sa) == this->reqid) + { + break; + } + } + children->destroy(children); + DBG2(DBG_JOB, "found CHILD_SA with reqid {%d}", this->reqid); + + ike_sa->set_kmaddress(ike_sa, this->local, this->remote); + + host = this->local->clone(this->local); + host->set_port(host, IKEV2_UDP_PORT); + ike_sa->set_my_host(ike_sa, host); + + host = this->remote->clone(this->remote); + host->set_port(host, IKEV2_UDP_PORT); + ike_sa->set_other_host(ike_sa, host); + + if (child_sa->update(child_sa, this->local, this->remote, + ike_sa->get_virtual_ip(ike_sa, TRUE), + ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) + { + ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)); + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + DBG1(DBG_JOB, "no CHILD_SA found with reqid {%d}", this->reqid); + } + destroy(this); +} + +/* + * Described in header + */ +migrate_job_t *migrate_job_create(u_int32_t reqid, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t dir, + host_t *local, host_t *remote) +{ + private_migrate_job_t *this = malloc_thing(private_migrate_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->reqid = reqid; + this->src_ts = (dir == POLICY_OUT) ? src_ts : dst_ts; + this->dst_ts = (dir == POLICY_OUT) ? dst_ts : src_ts; + this->local = local; + this->remote = remote; + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/migrate_job.h b/src/libcharon/processing/jobs/migrate_job.h new file mode 100644 index 000000000..de313d517 --- /dev/null +++ b/src/libcharon/processing/jobs/migrate_job.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 Andreas Steffen + * 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 migrate_job migrate_job + * @{ @ingroup jobs + */ + +#ifndef MIGRATE_JOB_H_ +#define MIGRATE_JOB_H_ + +typedef struct migrate_job_t migrate_job_t; + +#include <library.h> +#include <utils/host.h> +#include <selectors/traffic_selector.h> +#include <kernel/kernel_ipsec.h> +#include <processing/jobs/job.h> + +/** + * Class representing a MIGRATE Job. + * + * This job sets a routed CHILD_SA for an existing IPsec policy. + */ +struct migrate_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type MIGRATE. + * + * We use the reqid or the traffic selectors to find a matching CHILD_SA. + * + * @param reqid reqid of the CHILD_SA to acquire + * @param src_ts source traffic selector to be used in the policy + * @param dst_ts destination traffic selector to be used in the policy + * @param dir direction of the policy (in|out) + * @param local local host address to be used in the IKE_SA + * @param remote remote host address to be used in the IKE_SA + * @return migrate_job_t object + */ +migrate_job_t *migrate_job_create(u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t dir, host_t *local, host_t *remote); + +#endif /** MIGRATE_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/process_message_job.c b/src/libcharon/processing/jobs/process_message_job.c new file mode 100644 index 000000000..a47d48e38 --- /dev/null +++ b/src/libcharon/processing/jobs/process_message_job.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "process_message_job.h" + +#include <daemon.h> + +typedef struct private_process_message_job_t private_process_message_job_t; + +/** + * Private data of an process_message_job_t Object + */ +struct private_process_message_job_t { + /** + * public process_message_job_t interface + */ + process_message_job_t public; + + /** + * Message associated with this job + */ + message_t *message; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_process_message_job_t *this) +{ + this->message->destroy(this->message); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_process_message_job_t *this) +{ + ike_sa_t *ike_sa; + +#ifdef ME + /* if this is an unencrypted INFORMATIONAL exchange it is likely a + * connectivity check. */ + if (this->message->get_exchange_type(this->message) == INFORMATIONAL && + this->message->get_first_payload_type(this->message) != ENCRYPTED) + { + /* theoretically this could also be an error message + * see RFC 4306, section 1.5. */ + DBG1(DBG_NET, "received unencrypted informational: from %#H to %#H", + this->message->get_source(this->message), + this->message->get_destination(this->message)); + charon->connect_manager->process_check(charon->connect_manager, this->message); + destroy(this); + return; + } +#endif /* ME */ + + ike_sa = charon->ike_sa_manager->checkout_by_message(charon->ike_sa_manager, + this->message); + if (ike_sa) + { + DBG1(DBG_NET, "received packet: from %#H to %#H", + this->message->get_source(this->message), + this->message->get_destination(this->message)); + if (ike_sa->process_message(ike_sa, this->message) == 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); + } + } + destroy(this); +} + +/* + * Described in header + */ +process_message_job_t *process_message_job_create(message_t *message) +{ + private_process_message_job_t *this = malloc_thing(private_process_message_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void(*)(job_t*))destroy; + + /* private variables */ + this->message = message; + + return &(this->public); +} diff --git a/src/libcharon/processing/jobs/process_message_job.h b/src/libcharon/processing/jobs/process_message_job.h new file mode 100644 index 000000000..5e3f44d1f --- /dev/null +++ b/src/libcharon/processing/jobs/process_message_job.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 process_message_job process_message_job + * @{ @ingroup jobs + */ + +#ifndef PROCESS_MESSAGE_JOB_H_ +#define PROCESS_MESSAGE_JOB_H_ + +typedef struct process_message_job_t process_message_job_t; + +#include <library.h> +#include <encoding/message.h> +#include <processing/jobs/job.h> + +/** + * Class representing an PROCESS_MESSAGE job. + */ +struct process_message_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type PROCESS_MESSAGE. + * + * @param message message to process + * @return created process_message_job_t object + */ +process_message_job_t *process_message_job_create(message_t *message); + +#endif /** PROCESS_MESSAGE_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.c b/src/libcharon/processing/jobs/rekey_child_sa_job.c new file mode 100644 index 000000000..b797d181e --- /dev/null +++ b/src/libcharon/processing/jobs/rekey_child_sa_job.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "rekey_child_sa_job.h" + +#include <daemon.h> + + +typedef struct private_rekey_child_sa_job_t private_rekey_child_sa_job_t; + +/** + * Private data of an rekey_child_sa_job_t object. + */ +struct private_rekey_child_sa_job_t { + /** + * Public rekey_child_sa_job_t interface. + */ + rekey_child_sa_job_t public; + + /** + * reqid of the child to rekey + */ + u_int32_t reqid; + + /** + * protocol of the CHILD_SA (ESP/AH) + */ + protocol_id_t protocol; + + /** + * inbound SPI of the CHILD_SA + */ + u_int32_t spi; +}; + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_rekey_child_sa_job_t *this) +{ + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_rekey_child_sa_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + this->reqid, TRUE); + if (ike_sa == NULL) + { + DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying", + this->reqid); + } + else + { + ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); +} + +/* + * Described in header + */ +rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, + protocol_id_t protocol, + u_int32_t spi) +{ + private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->reqid = reqid; + this->protocol = protocol; + this->spi = spi; + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.h b/src/libcharon/processing/jobs/rekey_child_sa_job.h new file mode 100644 index 000000000..62887d6b9 --- /dev/null +++ b/src/libcharon/processing/jobs/rekey_child_sa_job.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup rekey_child_sa_job rekey_child_sa_job + * @{ @ingroup jobs + */ + +#ifndef REKEY_CHILD_SA_JOB_H_ +#define REKEY_CHILD_SA_JOB_H_ + +typedef struct rekey_child_sa_job_t rekey_child_sa_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> +#include <config/proposal.h> + +/** + * Class representing an REKEY_CHILD_SA Job. + * + * This job initiates the rekeying of a CHILD SA. + */ +struct rekey_child_sa_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type REKEY_CHILD_SA. + * + * The CHILD_SA is identified by its protocol (AH/ESP) and its + * inbound SPI. + * + * @param reqid reqid of the CHILD_SA to rekey + * @param protocol protocol of the CHILD_SA + * @param spi security parameter index of the CHILD_SA + * @return rekey_child_sa_job_t object + */ +rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid, + protocol_id_t protocol, + u_int32_t spi); +#endif /** REKEY_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/rekey_ike_sa_job.c b/src/libcharon/processing/jobs/rekey_ike_sa_job.c new file mode 100644 index 000000000..5ec0b1b88 --- /dev/null +++ b/src/libcharon/processing/jobs/rekey_ike_sa_job.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "rekey_ike_sa_job.h" + +#include <daemon.h> + +typedef struct private_rekey_ike_sa_job_t private_rekey_ike_sa_job_t; + +/** + * Private data of an rekey_ike_sa_job_t object. + */ +struct private_rekey_ike_sa_job_t { + /** + * Public rekey_ike_sa_job_t interface. + */ + rekey_ike_sa_job_t public; + + /** + * ID of the IKE_SA to rekey + */ + ike_sa_id_t *ike_sa_id; + + /** + * force reauthentication of the peer (full IKE_SA setup) + */ + bool reauth; +}; + +/** + * Implementation of job_t.destroy. + */ +static void destroy(private_rekey_ike_sa_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_rekey_ike_sa_job_t *this) +{ + ike_sa_t *ike_sa; + status_t status = SUCCESS; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa == NULL) + { + DBG2(DBG_JOB, "IKE_SA to rekey not found"); + } + else + { + if (this->reauth) + { + status = ike_sa->reauth(ike_sa); + } + else + { + status = ike_sa->rekey(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); + } + } + destroy(this); +} + +/* + * Described in header + */ +rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth) +{ + private_rekey_ike_sa_job_t *this = malloc_thing(private_rekey_ike_sa_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*)(job_t*)) destroy; + + /* private variables */ + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + this->reauth = reauth; + + return &(this->public); +} diff --git a/src/libcharon/processing/jobs/rekey_ike_sa_job.h b/src/libcharon/processing/jobs/rekey_ike_sa_job.h new file mode 100644 index 000000000..a5c1028aa --- /dev/null +++ b/src/libcharon/processing/jobs/rekey_ike_sa_job.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup rekey_ike_sa_job rekey_ike_sa_job + * @{ @ingroup jobs + */ + +#ifndef REKEY_IKE_SA_JOB_H_ +#define REKEY_IKE_SA_JOB_H_ + +typedef struct rekey_ike_sa_job_t rekey_ike_sa_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> + +/** + * Class representing an REKEY_IKE_SA Job. + * + * This job initiates the rekeying of an IKE_SA. + */ +struct rekey_ike_sa_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type REKEY_IKE_SA. + * + * @param ike_sa_id ID of the IKE_SA to rekey + * @param reauth TRUE to reauthenticate peer, FALSE for rekeying only + * @return rekey_ike_sa_job_t object + */ +rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth); + +#endif /** REKEY_IKE_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/retransmit_job.c b/src/libcharon/processing/jobs/retransmit_job.c new file mode 100644 index 000000000..fc787f208 --- /dev/null +++ b/src/libcharon/processing/jobs/retransmit_job.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "retransmit_job.h" + +#include <daemon.h> + +typedef struct private_retransmit_job_t private_retransmit_job_t; + +/** + * Private data of an retransmit_job_t Object. + */ +struct private_retransmit_job_t { + /** + * Public retransmit_job_t interface. + */ + retransmit_job_t public; + + /** + * Message ID of the request to resend. + */ + u_int32_t message_id; + + /** + * ID of the IKE_SA which the message belongs to. + */ + ike_sa_id_t *ike_sa_id; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_retransmit_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_retransmit_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + if (ike_sa->retransmit(ike_sa, this->message_id) == DESTROY_ME) + { + /* retransmitted to many times, giving up */ + 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); + } + } + destroy(this); +} + +/* + * Described in header. + */ +retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id) +{ + private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + /* private variables */ + this->message_id = message_id; + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/retransmit_job.h b/src/libcharon/processing/jobs/retransmit_job.h new file mode 100644 index 000000000..c8c13479b --- /dev/null +++ b/src/libcharon/processing/jobs/retransmit_job.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 retransmit_job retransmit_job + * @{ @ingroup jobs + */ + +#ifndef RETRANSMIT_JOB_H_ +#define RETRANSMIT_JOB_H_ + +typedef struct retransmit_job_t retransmit_job_t; + +#include <library.h> +#include <processing/jobs/job.h> +#include <sa/ike_sa_id.h> + +/** + * Class representing an retransmit Job. + * + * This job is scheduled every time a request is sent over the + * wire. If the response to the request is not received at schedule + * time, the retransmission will be initiated. + */ +struct retransmit_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a job of type retransmit. + * + * @param message_id message_id of the request to resend + * @param ike_sa_id identification of the ike_sa as ike_sa_id_t + * @return retransmit_job_t object + */ +retransmit_job_t *retransmit_job_create(u_int32_t message_id, + ike_sa_id_t *ike_sa_id); + +#endif /** RETRANSMIT_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/roam_job.c b/src/libcharon/processing/jobs/roam_job.c new file mode 100644 index 000000000..adc884a8a --- /dev/null +++ b/src/libcharon/processing/jobs/roam_job.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> + +#include "roam_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_roam_job_t private_roam_job_t; + +/** + * Private data of an roam_job_t Object + */ +struct private_roam_job_t { + /** + * public roam_job_t interface + */ + roam_job_t public; + + /** + * has the address list changed, or the routing only? + */ + bool address; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_roam_job_t *this) +{ + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_roam_job_t *this) +{ + ike_sa_t *ike_sa; + linked_list_t *list; + ike_sa_id_t *id; + enumerator_t *enumerator; + + /* enumerator over all IKE_SAs gives us no way to checkin_and_destroy + * after a DESTROY_ME, so we check out each available IKE_SA by hand. */ + list = linked_list_create(); + enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + id = ike_sa->get_id(ike_sa); + list->insert_last(list, id->clone(id)); + } + enumerator->destroy(enumerator); + + while (list->remove_last(list, (void**)&id) == SUCCESS) + { + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); + if (ike_sa) + { + if (ike_sa->roam(ike_sa, this->address) == 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); + } + } + id->destroy(id); + } + list->destroy(list); + + destroy(this); +} + +/* + * Described in header + */ +roam_job_t *roam_job_create(bool address) +{ + private_roam_job_t *this = malloc_thing(private_roam_job_t); + + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + this->address = address; + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/roam_job.h b/src/libcharon/processing/jobs/roam_job.h new file mode 100644 index 000000000..55bdf2b28 --- /dev/null +++ b/src/libcharon/processing/jobs/roam_job.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup roam_job roam_job + * @{ @ingroup jobs + */ + +#ifndef ROAM_JOB_H_ +#define ROAM_JOB_H_ + +typedef struct roam_job_t roam_job_t; + +#include <library.h> +#include <sa/ike_sa_id.h> +#include <processing/jobs/job.h> + +/** + * A job to inform IKE_SAs about changed local address setup. + * + * If a local address appears or disappears, the kernel fires this job to + * update all IKE_SAs. + */ +struct roam_job_t { + + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job to inform IKE_SAs about an updated address list. + * + * @param address TRUE if address list changed, FALSE if routing changed + * @return initiate_ike_sa_job_t object + */ +roam_job_t *roam_job_create(bool address); + +#endif /** ROAM_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/send_dpd_job.c b/src/libcharon/processing/jobs/send_dpd_job.c new file mode 100644 index 000000000..1c2da52b8 --- /dev/null +++ b/src/libcharon/processing/jobs/send_dpd_job.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> + +#include "send_dpd_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_send_dpd_job_t private_send_dpd_job_t; + +/** + * Private data of an send_dpd_job_t Object + */ +struct private_send_dpd_job_t { + /** + * public send_dpd_job_t interface + */ + send_dpd_job_t public; + + /** + * ID of the IKE_SA which the message belongs to. + */ + ike_sa_id_t *ike_sa_id; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_send_dpd_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_send_dpd_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + if (ike_sa->send_dpd(ike_sa) == 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); + } + } + destroy(this); +} + +/* + * Described in header + */ +send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id) +{ + private_send_dpd_job_t *this = malloc_thing(private_send_dpd_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + /* private variables */ + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/send_dpd_job.h b/src/libcharon/processing/jobs/send_dpd_job.h new file mode 100644 index 000000000..8078a38bc --- /dev/null +++ b/src/libcharon/processing/jobs/send_dpd_job.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * 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 send_dpd_job send_dpd_job + * @{ @ingroup jobs + */ + +#ifndef SEND_DPD_JOB_H_ +#define SEND_DPD_JOB_H_ + +typedef struct send_dpd_job_t send_dpd_job_t; + +#include <library.h> +#include <processing/jobs/job.h> +#include <sa/ike_sa_id.h> + +/** + * Class representing a SEND_DPD Job. + * + * Job to periodically send a Dead Peer Detection (DPD) request, + * ie. an IKE request with no payloads other than the encrypted payload + * required by the syntax. + */ +struct send_dpd_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type SEND_DPD. + * + * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) + * @return initiate_ike_sa_job_t object + */ +send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id); + +#endif /** SEND_DPD_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/send_keepalive_job.c b/src/libcharon/processing/jobs/send_keepalive_job.c new file mode 100644 index 000000000..3d02cea2e --- /dev/null +++ b/src/libcharon/processing/jobs/send_keepalive_job.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> + +#include "send_keepalive_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_send_keepalive_job_t private_send_keepalive_job_t; + +/** + * Private data of an send_keepalive_job_t Object + */ +struct private_send_keepalive_job_t { + /** + * public send_keepalive_job_t interface + */ + send_keepalive_job_t public; + + /** + * ID of the IKE_SA which the message belongs to. + */ + ike_sa_id_t *ike_sa_id; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_send_keepalive_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_send_keepalive_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + ike_sa->send_keepalive(ike_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); +} + +/* + * Described in header + */ +send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id) +{ + private_send_keepalive_job_t *this = malloc_thing(private_send_keepalive_job_t); + + /* interface functions */ + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + /* private variables */ + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/send_keepalive_job.h b/src/libcharon/processing/jobs/send_keepalive_job.h new file mode 100644 index 000000000..cda83cd7e --- /dev/null +++ b/src/libcharon/processing/jobs/send_keepalive_job.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * 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 send_keepalive_job send_keepalive_job + * @{ @ingroup jobs + */ + +#ifndef SEND_KEEPALIVE_JOB_H_ +#define SEND_KEEPALIVE_JOB_H_ + +typedef struct send_keepalive_job_t send_keepalive_job_t; + +#include <library.h> +#include <processing/jobs/job.h> +#include <sa/ike_sa_id.h> + +/** + * Class representing a SEND_KEEPALIVE Job. + * + * This job will send a NAT keepalive packet if the IKE SA is still alive, + * and reinsert itself into the event queue. + */ +struct send_keepalive_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type SEND_KEEPALIVE. + * + * @param ike_sa_id identification of the ike_sa as ike_sa_id_t object (gets cloned) + * @return initiate_ike_sa_job_t object + */ +send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id); + +#endif /** SEND_KEEPALIVE_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/update_sa_job.c b/src/libcharon/processing/jobs/update_sa_job.c new file mode 100644 index 000000000..17dce2548 --- /dev/null +++ b/src/libcharon/processing/jobs/update_sa_job.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> + +#include "update_sa_job.h" + +#include <sa/ike_sa.h> +#include <daemon.h> + + +typedef struct private_update_sa_job_t private_update_sa_job_t; + +/** + * Private data of an update_sa_job_t Object + */ +struct private_update_sa_job_t { + /** + * public update_sa_job_t interface + */ + update_sa_job_t public; + + /** + * reqid of the CHILD_SA + */ + u_int32_t reqid; + + /** + * New SA address and port + */ + host_t *new; +}; + +/** + * Implements job_t.destroy. + */ +static void destroy(private_update_sa_job_t *this) +{ + this->new->destroy(this->new); + free(this); +} + +/** + * Implementation of job_t.execute. + */ +static void execute(private_update_sa_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + this->reqid, TRUE); + if (ike_sa == NULL) + { + DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for update", this->reqid); + } + else + { + /* we update only if other host is NATed, but not our */ + if (ike_sa->has_condition(ike_sa, COND_NAT_THERE) && + !ike_sa->has_condition(ike_sa, COND_NAT_HERE)) + { + ike_sa->update_hosts(ike_sa, NULL, this->new); + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); +} + +/* + * Described in header + */ +update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new) +{ + private_update_sa_job_t *this = malloc_thing(private_update_sa_job_t); + + this->public.job_interface.execute = (void (*) (job_t *)) execute; + this->public.job_interface.destroy = (void (*) (job_t *)) destroy; + + this->reqid = reqid; + this->new = new; + + return &this->public; +} + diff --git a/src/libcharon/processing/jobs/update_sa_job.h b/src/libcharon/processing/jobs/update_sa_job.h new file mode 100644 index 000000000..11d1ac9b6 --- /dev/null +++ b/src/libcharon/processing/jobs/update_sa_job.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup update_sa_job update_sa_job + * @{ @ingroup jobs + */ + +#ifndef UPDATE_SA_JOB_H_ +#define UPDATE_SA_JOB_H_ + +typedef struct update_sa_job_t update_sa_job_t; + +#include <library.h> +#include <utils/host.h> +#include <processing/jobs/job.h> + +/** + * Update the addresses of an IKE and its CHILD_SAs. + */ +struct update_sa_job_t { + + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job to update IKE and CHILD_SA addresses. + * + * @param reqid reqid of the CHILD_SA + * @param new new address and port + * @return update_sa_job_t object + */ +update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new); + +#endif /** UPDATE_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/processor.c b/src/libcharon/processing/processor.c new file mode 100644 index 000000000..d5774af26 --- /dev/null +++ b/src/libcharon/processing/processor.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "processor.h" + +#include <daemon.h> +#include <threading/thread.h> +#include <threading/condvar.h> +#include <threading/mutex.h> +#include <utils/linked_list.h> + + +typedef struct private_processor_t private_processor_t; + +/** + * Private data of processor_t class. + */ +struct private_processor_t { + /** + * Public processor_t interface. + */ + processor_t public; + + /** + * Number of running threads + */ + u_int total_threads; + + /** + * Desired number of threads + */ + u_int desired_threads; + + /** + * Number of threads waiting for work + */ + u_int idle_threads; + + /** + * All threads managed in the pool (including threads that have been + * cancelled, this allows to join them during destruction) + */ + linked_list_t *threads; + + /** + * The jobs are stored in a linked list + */ + linked_list_t *list; + + /** + * access to linked_list is locked through this mutex + */ + mutex_t *mutex; + + /** + * Condvar to wait for new jobs + */ + condvar_t *job_added; + + /** + * Condvar to wait for terminated threads + */ + condvar_t *thread_terminated; +}; + +static void process_jobs(private_processor_t *this); + +/** + * restart a terminated thread + */ +static void restart(private_processor_t *this) +{ + thread_t *thread; + + DBG2(DBG_JOB, "terminated worker thread, ID: %u", thread_current_id()); + + /* respawn thread if required */ + this->mutex->lock(this->mutex); + if (this->desired_threads < this->total_threads || + (thread = thread_create((thread_main_t)process_jobs, this)) == NULL) + { + this->total_threads--; + this->thread_terminated->signal(this->thread_terminated); + } + else + { + this->threads->insert_last(this->threads, thread); + } + this->mutex->unlock(this->mutex); +} + +/** + * Process queued jobs, called by the worker threads + */ +static void process_jobs(private_processor_t *this) +{ + /* worker threads are not cancellable by default */ + thread_cancelability(FALSE); + + DBG2(DBG_JOB, "started worker thread, ID: %u", thread_current_id()); + + this->mutex->lock(this->mutex); + while (this->desired_threads >= this->total_threads) + { + job_t *job; + + if (this->list->get_count(this->list) == 0) + { + this->idle_threads++; + this->job_added->wait(this->job_added, this->mutex); + this->idle_threads--; + continue; + } + this->list->remove_first(this->list, (void**)&job); + this->mutex->unlock(this->mutex); + /* terminated threads are restarted, so we have a constant pool */ + thread_cleanup_push((thread_cleanup_t)restart, this); + job->execute(job); + thread_cleanup_pop(FALSE); + this->mutex->lock(this->mutex); + } + this->mutex->unlock(this->mutex); + restart(this); +} + +/** + * Implementation of processor_t.get_total_threads. + */ +static u_int get_total_threads(private_processor_t *this) +{ + u_int count; + this->mutex->lock(this->mutex); + count = this->total_threads; + this->mutex->unlock(this->mutex); + return count; +} + +/** + * Implementation of processor_t.get_idle_threads. + */ +static u_int get_idle_threads(private_processor_t *this) +{ + u_int count; + this->mutex->lock(this->mutex); + count = this->idle_threads; + this->mutex->unlock(this->mutex); + return count; +} + +/** + * implements processor_t.get_job_load + */ +static u_int get_job_load(private_processor_t *this) +{ + u_int load; + this->mutex->lock(this->mutex); + load = this->list->get_count(this->list); + this->mutex->unlock(this->mutex); + return load; +} + +/** + * implements function processor_t.queue_job + */ +static void queue_job(private_processor_t *this, job_t *job) +{ + this->mutex->lock(this->mutex); + this->list->insert_last(this->list, job); + this->job_added->signal(this->job_added); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of processor_t.set_threads. + */ +static void set_threads(private_processor_t *this, u_int count) +{ + this->mutex->lock(this->mutex); + if (count > this->total_threads) + { /* increase thread count */ + int i; + thread_t *current; + + this->desired_threads = count; + DBG1(DBG_JOB, "spawning %d worker threads", count - this->total_threads); + for (i = this->total_threads; i < count; i++) + { + current = thread_create((thread_main_t)process_jobs, this); + if (current) + { + this->threads->insert_last(this->threads, current); + this->total_threads++; + } + } + } + else if (count < this->total_threads) + { /* decrease thread count */ + this->desired_threads = count; + } + this->job_added->broadcast(this->job_added); + this->mutex->unlock(this->mutex); +} + +/** + * Implementation of processor_t.destroy. + */ +static void destroy(private_processor_t *this) +{ + thread_t *current; + set_threads(this, 0); + this->mutex->lock(this->mutex); + while (this->total_threads > 0) + { + this->job_added->broadcast(this->job_added); + this->thread_terminated->wait(this->thread_terminated, this->mutex); + } + while (this->threads->remove_first(this->threads, + (void**)¤t) == SUCCESS) + { + current->join(current); + } + this->mutex->unlock(this->mutex); + this->thread_terminated->destroy(this->thread_terminated); + this->job_added->destroy(this->job_added); + this->mutex->destroy(this->mutex); + this->list->destroy_offset(this->list, offsetof(job_t, destroy)); + this->threads->destroy(this->threads); + free(this); +} + +/* + * Described in header. + */ +processor_t *processor_create(size_t pool_size) +{ + private_processor_t *this = malloc_thing(private_processor_t); + + this->public.get_total_threads = (u_int(*)(processor_t*))get_total_threads; + this->public.get_idle_threads = (u_int(*)(processor_t*))get_idle_threads; + this->public.get_job_load = (u_int(*)(processor_t*))get_job_load; + this->public.queue_job = (void(*)(processor_t*, job_t*))queue_job; + this->public.set_threads = (void(*)(processor_t*, u_int))set_threads; + this->public.destroy = (void(*)(processor_t*))destroy; + + this->list = linked_list_create(); + this->threads = linked_list_create(); + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->job_added = condvar_create(CONDVAR_TYPE_DEFAULT); + this->thread_terminated = condvar_create(CONDVAR_TYPE_DEFAULT); + this->total_threads = 0; + this->desired_threads = 0; + this->idle_threads = 0; + + return &this->public; +} + diff --git a/src/libcharon/processing/processor.h b/src/libcharon/processing/processor.h new file mode 100644 index 000000000..5bf8cf573 --- /dev/null +++ b/src/libcharon/processing/processor.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 processor processor + * @{ @ingroup processing + */ + +#ifndef PROCESSOR_H_ +#define PROCESSOR_H_ + +typedef struct processor_t processor_t; + +#include <stdlib.h> + +#include <library.h> +#include <processing/jobs/job.h> + +/** + * The processor uses threads to process queued jobs. + */ +struct processor_t { + + /** + * Get the total number of threads used by the processor. + * + * @return size of thread pool + */ + u_int (*get_total_threads) (processor_t *this); + + /** + * Get the number of threads currently waiting. + * + * @return number of idle threads + */ + u_int (*get_idle_threads) (processor_t *this); + + /** + * Get the number of queued jobs. + * + * @returns number of items in queue + */ + u_int (*get_job_load) (processor_t *this); + + /** + * Adds a job to the queue. + * + * This function is non blocking and adds a job_t to the queue. + * + * @param job job to add to the queue + */ + void (*queue_job) (processor_t *this, job_t *job); + + /** + * Set the number of threads to use in the processor. + * + * If the number of threads is smaller than number of currently running + * threads, thread count is decreased. Use 0 to disable the processor. + * This call blocks if it decreases thread count until threads have + * terminated, so make sure there are not too many blocking jobs. + * + * @param count number of threads to allocate + */ + void (*set_threads)(processor_t *this, u_int count); + + /** + * Destroy a processor object. + */ + void (*destroy) (processor_t *processor); +}; + +/** + * Create the thread pool without any threads. + * + * Use the set_threads method to start processing jobs. + * + * @return processor_t object + */ +processor_t *processor_create(); + +#endif /** PROCESSOR_H_ @}*/ diff --git a/src/libcharon/processing/scheduler.c b/src/libcharon/processing/scheduler.c new file mode 100644 index 000000000..345af502a --- /dev/null +++ b/src/libcharon/processing/scheduler.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> + +#include "scheduler.h" + +#include <daemon.h> +#include <processing/processor.h> +#include <processing/jobs/callback_job.h> +#include <threading/thread.h> +#include <threading/condvar.h> +#include <threading/mutex.h> + +/* the initial size of the heap */ +#define HEAP_SIZE_DEFAULT 64 + +typedef struct event_t event_t; + +/** + * Event containing a job and a schedule time + */ +struct event_t { + /** + * Time to fire the event. + */ + timeval_t time; + + /** + * Every event has its assigned job. + */ + job_t *job; +}; + +/** + * destroy an event and its job + */ +static void event_destroy(event_t *event) +{ + event->job->destroy(event->job); + free(event); +} + +typedef struct private_scheduler_t private_scheduler_t; + +/** + * Private data of a scheduler_t object. + */ +struct private_scheduler_t { + + /** + * Public part of a scheduler_t object. + */ + scheduler_t public; + + /** + * Job which queues scheduled jobs to the processor. + */ + callback_job_t *job; + + /** + * The heap in which the events are stored. + */ + event_t **heap; + + /** + * The size of the heap. + */ + u_int heap_size; + + /** + * The number of scheduled events. + */ + u_int event_count; + + /** + * Exclusive access to list + */ + mutex_t *mutex; + + /** + * Condvar to wait for next job. + */ + condvar_t *condvar; +}; + +/** + * Comparse two timevals, return >0 if a > b, <0 if a < b and =0 if equal + */ +static int timeval_cmp(timeval_t *a, timeval_t *b) +{ + if (a->tv_sec > b->tv_sec) + { + return 1; + } + if (a->tv_sec < b->tv_sec) + { + return -1; + } + if (a->tv_usec > b->tv_usec) + { + return 1; + } + if (a->tv_usec < b->tv_usec) + { + return -1; + } + return 0; +} + +/** + * Returns the top event without removing it. Returns NULL if the heap is empty. + */ +static event_t *peek_event(private_scheduler_t *this) +{ + return this->event_count > 0 ? this->heap[1] : NULL; +} + +/** + * Removes the top event from the heap and returns it. Returns NULL if the heap + * is empty. + */ +static event_t *remove_event(private_scheduler_t *this) +{ + event_t *event, *top; + if (!this->event_count) + { + return NULL; + } + + /* store the value to return */ + event = this->heap[1]; + /* move the bottom event to the top */ + top = this->heap[1] = this->heap[this->event_count]; + + if (--this->event_count > 1) + { + /* seep down the top event */ + u_int position = 1; + while ((position << 1) <= this->event_count) + { + u_int child = position << 1; + + if ((child + 1) <= this->event_count && + timeval_cmp(&this->heap[child + 1]->time, + &this->heap[child]->time) < 0) + { + /* the "right" child is smaller */ + child++; + } + + if (timeval_cmp(&top->time, &this->heap[child]->time) <= 0) + { + /* the top event fires before the smaller of the two children, + * stop */ + break; + } + + /* swap with the smaller child */ + this->heap[position] = this->heap[child]; + position = child; + } + this->heap[position] = top; + } + return event; +} + +/** + * Get events from the queue and pass it to the processor + */ +static job_requeue_t schedule(private_scheduler_t * this) +{ + timeval_t now; + event_t *event; + bool timed = FALSE, oldstate; + + this->mutex->lock(this->mutex); + + time_monotonic(&now); + + if ((event = peek_event(this)) != NULL) + { + if (timeval_cmp(&now, &event->time) >= 0) + { + remove_event(this); + this->mutex->unlock(this->mutex); + DBG2(DBG_JOB, "got event, queuing job for execution"); + charon->processor->queue_job(charon->processor, event->job); + free(event); + return JOB_REQUEUE_DIRECT; + } + timersub(&event->time, &now, &now); + if (now.tv_sec) + { + DBG2(DBG_JOB, "next event in %ds %dms, waiting", + now.tv_sec, now.tv_usec/1000); + } + else + { + DBG2(DBG_JOB, "next event in %dms, waiting", now.tv_usec/1000); + } + timed = TRUE; + } + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + oldstate = thread_cancelability(TRUE); + + if (timed) + { + this->condvar->timed_wait_abs(this->condvar, this->mutex, event->time); + } + else + { + DBG2(DBG_JOB, "no events, waiting"); + this->condvar->wait(this->condvar, this->mutex); + } + thread_cancelability(oldstate); + thread_cleanup_pop(TRUE); + return JOB_REQUEUE_DIRECT; +} + +/** + * Implements scheduler_t.get_job_load + */ +static u_int get_job_load(private_scheduler_t *this) +{ + int count; + this->mutex->lock(this->mutex); + count = this->event_count; + this->mutex->unlock(this->mutex); + return count; +} + +/** + * Implements scheduler_t.schedule_job_tv. + */ +static void schedule_job_tv(private_scheduler_t *this, job_t *job, timeval_t tv) +{ + event_t *event; + u_int position; + + event = malloc_thing(event_t); + event->job = job; + event->time = tv; + + this->mutex->lock(this->mutex); + + this->event_count++; + if (this->event_count > this->heap_size) + { + /* double the size of the heap */ + this->heap_size <<= 1; + this->heap = (event_t**)realloc(this->heap, + (this->heap_size + 1) * sizeof(event_t*)); + } + /* "put" the event to the bottom */ + position = this->event_count; + + /* then bubble it up */ + while (position > 1 && timeval_cmp(&this->heap[position >> 1]->time, + &event->time) > 0) + { + /* parent has to be fired after the new event, move up */ + this->heap[position] = this->heap[position >> 1]; + position >>= 1; + } + this->heap[position] = event; + + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); +} + +/** + * Implements scheduler_t.schedule_job. + */ +static void schedule_job(private_scheduler_t *this, job_t *job, u_int32_t s) +{ + timeval_t tv; + + time_monotonic(&tv); + tv.tv_sec += s; + + schedule_job_tv(this, job, tv); +} + +/** + * Implements scheduler_t.schedule_job_ms. + */ +static void schedule_job_ms(private_scheduler_t *this, job_t *job, u_int32_t ms) +{ + timeval_t tv, add; + + time_monotonic(&tv); + add.tv_sec = ms / 1000; + add.tv_usec = (ms % 1000) * 1000; + + timeradd(&tv, &add, &tv); + + schedule_job_tv(this, job, tv); +} + +/** + * Implementation of scheduler_t.destroy. + */ +static void destroy(private_scheduler_t *this) +{ + event_t *event; + this->job->cancel(this->job); + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); + while ((event = remove_event(this)) != NULL) + { + event_destroy(event); + } + free(this->heap); + free(this); +} + +/* + * Described in header. + */ +scheduler_t * scheduler_create() +{ + private_scheduler_t *this = malloc_thing(private_scheduler_t); + + this->public.get_job_load = (u_int (*) (scheduler_t *this)) get_job_load; + this->public.schedule_job = (void (*) (scheduler_t *this, job_t *job, u_int32_t s)) schedule_job; + this->public.schedule_job_ms = (void (*) (scheduler_t *this, job_t *job, u_int32_t ms)) schedule_job_ms; + this->public.schedule_job_tv = (void (*) (scheduler_t *this, job_t *job, timeval_t tv)) schedule_job_tv; + this->public.destroy = (void(*)(scheduler_t*)) destroy; + + /* Note: the root of the heap is at index 1 */ + this->event_count = 0; + this->heap_size = HEAP_SIZE_DEFAULT; + this->heap = (event_t**)calloc(this->heap_size + 1, sizeof(event_t*)); + + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); + + this->job = callback_job_create((callback_job_cb_t)schedule, this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); + + return &this->public; +} + diff --git a/src/libcharon/processing/scheduler.h b/src/libcharon/processing/scheduler.h new file mode 100644 index 000000000..5f5d2a563 --- /dev/null +++ b/src/libcharon/processing/scheduler.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * 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 scheduler scheduler + * @{ @ingroup processing + */ + +#ifndef SCHEDULER_H_ +#define SCHEDULER_H_ + +typedef struct scheduler_t scheduler_t; + +#include <library.h> +#include <processing/jobs/job.h> + +/** + * The scheduler queues timed events which are then passed to the processor. + * + * The scheduler is implemented as a heap. A heap is a special kind of tree- + * based data structure that satisfies the following property: if B is a child + * node of A, then key(A) >= (or <=) key(B). So either the element with the + * greatest (max-heap) or the smallest (min-heap) key is the root of the heap. + * We use a min-heap whith the key being the absolute unix time at which an + * event is scheduled. So the root is always the event that will fire next. + * + * An earlier implementation of the scheduler used a sorted linked list to store + * the events. That had the advantage that removing the next event was extremely + * fast, also, adding an event scheduled before or after all other events was + * equally fast (all in O(1)). The problem was, though, that adding an event + * in-between got slower, as the number of events grew larger (O(n)). + * For each connection there could be several events: IKE-rekey, NAT-keepalive, + * retransmissions, expire (half-open), and others. So a gateway that probably + * has to handle thousands of concurrent connnections has to be able to queue a + * large number of events as fast as possible. Locking makes this even worse, to + * provide thread-safety, no events can be processed, while an event is queued, + * so making the insertion fast is even more important. + * + * That's the advantage of the heap. Adding an element to the heap can be + * achieved in O(log n) - on the other hand, removing the root node also + * requires O(log n) operations. Consider 10000 queued events. Inserting a new + * event in the list implementation required up to 10000 comparisons. In the + * heap implementation, the worst case is about 13.3 comparisons. That's a + * drastic improvement. + * + * The implementation itself uses a binary tree mapped to a one-based array to + * store the elements. This reduces storage overhead and simplifies navigation: + * the children of the node at position n are at position 2n and 2n+1 (likewise + * the parent node of the node at position n is at position [n/2]). Thus, + * navigating up and down the tree is reduced to simple index computations. + * + * Adding an element to the heap works as follows: The heap is always filled + * from left to right, until a row is full, then the next row is filled. Mapped + * to an array this gets as simple as putting the new element to the first free + * position. In a one-based array that position equals the number of elements + * currently stored in the heap. Then the heap property has to be restored, i.e. + * the new element has to be "bubbled up" the tree until the parent node's key + * is smaller or the element got the new root of the tree. + * + * Removing the next event from the heap works similarly. The event itself is + * the root node and stored at position 1 of the array. After removing it, the + * root has to be replaced and the heap property has to be restored. This is + * done by moving the bottom element (last row, rightmost element) to the root + * and then "seep it down" by swapping it with child nodes until none of the + * children has a smaller key or it is again a leaf node. + */ +struct scheduler_t { + + /** + * Adds a event to the queue, using a relative time offset in s. + * + * @param job job to schedule + * @param time relative time to schedule job, in s + */ + void (*schedule_job) (scheduler_t *this, job_t *job, u_int32_t s); + + /** + * Adds a event to the queue, using a relative time offset in ms. + * + * @param job job to schedule + * @param time relative time to schedule job, in ms + */ + void (*schedule_job_ms) (scheduler_t *this, job_t *job, u_int32_t ms); + + /** + * Adds a event to the queue, using an absolut time. + * + * The passed timeval should be calculated based on the time_monotonic() + * function. + * + * @param job job to schedule + * @param time absolut time to schedule job + */ + void (*schedule_job_tv) (scheduler_t *this, job_t *job, timeval_t tv); + + /** + * Returns number of jobs scheduled. + * + * @return number of scheduled jobs + */ + u_int (*get_job_load) (scheduler_t *this); + + /** + * Destroys a scheduler object. + */ + void (*destroy) (scheduler_t *this); +}; + +/** + * Create a scheduler. + * + * @return scheduler_t object + */ +scheduler_t *scheduler_create(void); + +#endif /** SCHEDULER_H_ @}*/ |