diff options
Diffstat (limited to 'src/libcharon/attributes/attribute_manager.c')
-rw-r--r-- | src/libcharon/attributes/attribute_manager.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/libcharon/attributes/attribute_manager.c b/src/libcharon/attributes/attribute_manager.c new file mode 100644 index 000000000..2ab7ed118 --- /dev/null +++ b/src/libcharon/attributes/attribute_manager.c @@ -0,0 +1,347 @@ +/* + * 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 "attribute_manager.h" + +#include <utils/debug.h> +#include <collections/linked_list.h> +#include <threading/rwlock.h> + +typedef struct private_attribute_manager_t private_attribute_manager_t; + +/** + * private data of attribute_manager + */ +struct private_attribute_manager_t { + + /** + * public functions + */ + attribute_manager_t public; + + /** + * list of registered providers + */ + linked_list_t *providers; + + /** + * list of registered handlers + */ + linked_list_t *handlers; + + /** + * rwlock provider list + */ + rwlock_t *lock; +}; + +/** + * Data to pass to enumerator filters + */ +typedef struct { + /** attribute group pools */ + linked_list_t *pools; + /** associated IKE_SA */ + ike_sa_t *ike_sa; + /** requesting/assigned virtual IPs */ + linked_list_t *vips; +} enum_data_t; + +METHOD(attribute_manager_t, acquire_address, host_t*, + private_attribute_manager_t *this, linked_list_t *pools, + ike_sa_t *ike_sa, host_t *requested) +{ + enumerator_t *enumerator; + attribute_provider_t *current; + host_t *host = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->providers->create_enumerator(this->providers); + while (enumerator->enumerate(enumerator, ¤t)) + { + host = current->acquire_address(current, pools, ike_sa, requested); + if (host) + { + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return host; +} + +METHOD(attribute_manager_t, release_address, bool, + private_attribute_manager_t *this, linked_list_t *pools, host_t *address, + ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + attribute_provider_t *current; + bool found = FALSE; + + this->lock->read_lock(this->lock); + enumerator = this->providers->create_enumerator(this->providers); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->release_address(current, pools, address, ike_sa)) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return found; +} + +/** + * inner enumerator constructor for responder attributes + */ +static enumerator_t *responder_enum_create(attribute_provider_t *provider, + enum_data_t *data) +{ + return provider->create_attribute_enumerator(provider, data->pools, + data->ike_sa, data->vips); +} + +METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*, + private_attribute_manager_t *this, linked_list_t *pools, + ike_sa_t *ike_sa, linked_list_t *vips) +{ + enum_data_t *data; + + INIT(data, + .pools = pools, + .ike_sa = ike_sa, + .vips = vips, + ); + this->lock->read_lock(this->lock); + return enumerator_create_cleaner( + enumerator_create_nested( + this->providers->create_enumerator(this->providers), + (void*)responder_enum_create, data, free), + (void*)this->lock->unlock, this->lock); +} + +METHOD(attribute_manager_t, add_provider, void, + private_attribute_manager_t *this, attribute_provider_t *provider) +{ + this->lock->write_lock(this->lock); + this->providers->insert_last(this->providers, provider); + this->lock->unlock(this->lock); +} + +METHOD(attribute_manager_t, remove_provider, void, + private_attribute_manager_t *this, attribute_provider_t *provider) +{ + this->lock->write_lock(this->lock); + this->providers->remove(this->providers, provider, NULL); + this->lock->unlock(this->lock); +} + +METHOD(attribute_manager_t, handle, attribute_handler_t*, + private_attribute_manager_t *this, ike_sa_t *ike_sa, + attribute_handler_t *handler, configuration_attribute_type_t type, + chunk_t data) +{ + enumerator_t *enumerator; + attribute_handler_t *current, *handled = NULL; + + this->lock->read_lock(this->lock); + + /* try to find the passed handler */ + enumerator = this->handlers->create_enumerator(this->handlers); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current == handler && current->handle(current, ike_sa, type, data)) + { + handled = current; + break; + } + } + enumerator->destroy(enumerator); + if (!handled) + { /* handler requesting this attribute not found, try any other */ + enumerator = this->handlers->create_enumerator(this->handlers); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->handle(current, ike_sa, type, data)) + { + handled = current; + break; + } + } + enumerator->destroy(enumerator); + } + this->lock->unlock(this->lock); + + if (!handled) + { + DBG1(DBG_CFG, "handling %N attribute failed", + configuration_attribute_type_names, type); + } + return handled; +} + +METHOD(attribute_manager_t, release, void, + private_attribute_manager_t *this, attribute_handler_t *handler, + ike_sa_t *ike_sa, configuration_attribute_type_t type, chunk_t data) +{ + enumerator_t *enumerator; + attribute_handler_t *current; + + this->lock->read_lock(this->lock); + enumerator = this->handlers->create_enumerator(this->handlers); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current == handler) + { + current->release(current, ike_sa, type, data); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +/** + * Enumerator implementation to enumerate nested initiator attributes + */ +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** back ref */ + private_attribute_manager_t *this; + /** currently processing handler */ + attribute_handler_t *handler; + /** outer enumerator over handlers */ + enumerator_t *outer; + /** inner enumerator over current handlers attributes */ + enumerator_t *inner; + /** IKE_SA to request attributes for */ + ike_sa_t *ike_sa; + /** virtual IPs we are requesting along with attriubutes */ + linked_list_t *vips; +} initiator_enumerator_t; + +/** + * Enumerator implementation for initiator attributes + */ +static bool initiator_enumerate(initiator_enumerator_t *this, + attribute_handler_t **handler, + configuration_attribute_type_t *type, + chunk_t *value) +{ + /* enumerate inner attributes using outer handler enumerator */ + while (!this->inner || !this->inner->enumerate(this->inner, type, value)) + { + if (!this->outer->enumerate(this->outer, &this->handler)) + { + return FALSE; + } + DESTROY_IF(this->inner); + this->inner = this->handler->create_attribute_enumerator(this->handler, + this->ike_sa, this->vips); + } + /* inject the handler as additional attribute */ + *handler = this->handler; + return TRUE; +} + +/** + * Cleanup function of initiator attribute enumerator + */ +static void initiator_destroy(initiator_enumerator_t *this) +{ + this->this->lock->unlock(this->this->lock); + this->outer->destroy(this->outer); + DESTROY_IF(this->inner); + free(this); +} + +METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*, + private_attribute_manager_t *this, ike_sa_t *ike_sa, linked_list_t *vips) +{ + initiator_enumerator_t *enumerator; + + this->lock->read_lock(this->lock); + + INIT(enumerator, + .public = { + .enumerate = (void*)initiator_enumerate, + .destroy = (void*)initiator_destroy, + }, + .this = this, + .ike_sa = ike_sa, + .vips = vips, + .outer = this->handlers->create_enumerator(this->handlers), + ); + return &enumerator->public; +} + +METHOD(attribute_manager_t, add_handler, void, + private_attribute_manager_t *this, attribute_handler_t *handler) +{ + this->lock->write_lock(this->lock); + this->handlers->insert_last(this->handlers, handler); + this->lock->unlock(this->lock); +} + +METHOD(attribute_manager_t, remove_handler, void, + private_attribute_manager_t *this, attribute_handler_t *handler) +{ + this->lock->write_lock(this->lock); + this->handlers->remove(this->handlers, handler, NULL); + this->lock->unlock(this->lock); +} + +METHOD(attribute_manager_t, destroy, void, + private_attribute_manager_t *this) +{ + this->providers->destroy(this->providers); + this->handlers->destroy(this->handlers); + this->lock->destroy(this->lock); + free(this); +} + +/* + * see header file + */ +attribute_manager_t *attribute_manager_create() +{ + private_attribute_manager_t *this; + + INIT(this, + .public = { + .acquire_address = _acquire_address, + .release_address = _release_address, + .create_responder_enumerator = _create_responder_enumerator, + .add_provider = _add_provider, + .remove_provider = _remove_provider, + .handle = _handle, + .release = _release, + .create_initiator_enumerator = _create_initiator_enumerator, + .add_handler = _add_handler, + .remove_handler = _remove_handler, + .destroy = _destroy, + }, + .providers = linked_list_create(), + .handlers = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} |