summaryrefslogtreecommitdiff
path: root/src/libhydra/attributes
diff options
context:
space:
mode:
Diffstat (limited to 'src/libhydra/attributes')
-rw-r--r--src/libhydra/attributes/attribute_handler.h72
-rw-r--r--src/libhydra/attributes/attribute_manager.c374
-rw-r--r--src/libhydra/attributes/attribute_manager.h149
-rw-r--r--src/libhydra/attributes/attribute_provider.h67
-rw-r--r--src/libhydra/attributes/attributes.c43
-rw-r--r--src/libhydra/attributes/attributes.h62
-rw-r--r--src/libhydra/attributes/mem_pool.c451
-rw-r--r--src/libhydra/attributes/mem_pool.h110
8 files changed, 1328 insertions, 0 deletions
diff --git a/src/libhydra/attributes/attribute_handler.h b/src/libhydra/attributes/attribute_handler.h
new file mode 100644
index 000000000..d042f47ef
--- /dev/null
+++ b/src/libhydra/attributes/attribute_handler.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/**
+ * @defgroup attribute_handler attribute_handler
+ * @{ @ingroup attributes
+ */
+
+#ifndef ATTRIBUTE_HANDLER_H_
+#define ATTRIBUTE_HANDLER_H_
+
+#include <chunk.h>
+#include <utils/host.h>
+#include <utils/identification.h>
+
+#include "attributes.h"
+
+typedef struct attribute_handler_t attribute_handler_t;
+
+/**
+ * Interface to handle configuration payload attributes.
+ */
+struct attribute_handler_t {
+
+ /**
+ * Handle a configuration attribute.
+ *
+ * After receiving a configuration attriubte, it is passed to each
+ * attribute handler until it is handled.
+ *
+ * @param server server from which the attribute was received
+ * @param type type of configuration attribute to handle
+ * @param data associated attribute data
+ * @return TRUE if attribute handled
+ */
+ bool (*handle)(attribute_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data);
+
+ /**
+ * Release an attribute handled during handle().
+ *
+ * A handler that handle()d an attribute gets a call to release() when the
+ * connection gets closed. Depending on the implementation, this is required
+ * to remove the attribute.
+ */
+ void (*release)(attribute_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data);
+
+ /**
+ * Enumerate attributes to request from a server.
+ *
+ * @param server server identity to request attributes from
+ * @param vip virtual IP we are requesting, if any
+ * @return enumerator (configuration_attribute_type_t, chunk_t)
+ */
+ enumerator_t* (*create_attribute_enumerator)(attribute_handler_t *this,
+ identification_t *server, host_t *vip);
+};
+
+#endif /** ATTRIBUTE_HANDLER_H_ @}*/
diff --git a/src/libhydra/attributes/attribute_manager.c b/src/libhydra/attributes/attribute_manager.c
new file mode 100644
index 000000000..3080b56eb
--- /dev/null
+++ b/src/libhydra/attributes/attribute_manager.c
@@ -0,0 +1,374 @@
+/*
+ * 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 <debug.h>
+#include <utils/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 {
+ /** server/peer identity */
+ identification_t *id;
+ /** requesting/assigned virtual IP */
+ host_t *vip;
+} enum_data_t;
+
+/**
+ * Implementation of attribute_manager_t.acquire_address.
+ */
+static host_t* acquire_address(private_attribute_manager_t *this,
+ char *pool, identification_t *id,
+ 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, &current))
+ {
+ host = current->acquire_address(current, pool, id, requested);
+ if (host)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ if (!host)
+ {
+ DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool);
+ }
+ return host;
+}
+
+/**
+ * Implementation of attribute_manager_t.release_address.
+ */
+static void release_address(private_attribute_manager_t *this,
+ char *pool, host_t *address, identification_t *id)
+{
+ 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, &current))
+ {
+ if (current->release_address(current, pool, address, id))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ if (!found)
+ {
+ DBG1(DBG_CFG, "releasing address to pool '%s' failed", pool);
+ }
+}
+
+/**
+ * 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->id, data->vip);
+}
+
+/**
+ * Implementation of attribute_manager_t.create_responder_enumerator
+ */
+static enumerator_t* create_responder_enumerator(
+ private_attribute_manager_t *this, identification_t *id, host_t *vip)
+{
+ enum_data_t *data = malloc_thing(enum_data_t);
+
+ data->id = id;
+ data->vip = vip;
+ 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);
+}
+
+/**
+ * Implementation of attribute_manager_t.add_provider.
+ */
+static void add_provider(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);
+}
+
+/**
+ * Implementation of attribute_manager_t.remove_provider.
+ */
+static void remove_provider(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);
+}
+
+/**
+ * Implementation of attribute_manager_t.handle
+ */
+static attribute_handler_t* handle(private_attribute_manager_t *this,
+ identification_t *server, 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, &current))
+ {
+ if (current == handler && current->handle(current, server, 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, &current))
+ {
+ if (current->handle(current, server, 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;
+}
+
+/**
+ * Implementation of attribute_manager_t.release
+ */
+static void release(private_attribute_manager_t *this,
+ attribute_handler_t *handler,
+ identification_t *server,
+ 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, &current))
+ {
+ if (current == handler)
+ {
+ current->release(current, server, 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;
+ /** server ID we want attributes for */
+ identification_t *id;
+ /** virtual IP we are requesting along with attriubutes */
+ host_t *vip;
+} 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->id, this->vip);
+ }
+ /* 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);
+}
+
+/**
+ * Implementation of attribute_manager_t.create_initiator_enumerator
+ */
+static enumerator_t* create_initiator_enumerator(
+ private_attribute_manager_t *this, identification_t *id, host_t *vip)
+{
+ initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t);
+
+ this->lock->read_lock(this->lock);
+ enumerator->public.enumerate = (void*)initiator_enumerate;
+ enumerator->public.destroy = (void*)initiator_destroy;
+ enumerator->this = this;
+ enumerator->id = id;
+ enumerator->vip = vip;
+ enumerator->outer = this->handlers->create_enumerator(this->handlers);
+ enumerator->inner = NULL;
+ enumerator->handler = NULL;
+
+ return &enumerator->public;
+}
+
+/**
+ * Implementation of attribute_manager_t.add_handler
+ */
+static void add_handler(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);
+}
+
+/**
+ * Implementation of attribute_manager_t.remove_handler
+ */
+static void remove_handler(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);
+}
+
+/**
+ * Implementation of attribute_manager_t.destroy
+ */
+static void destroy(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 = malloc_thing(private_attribute_manager_t);
+
+ this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,host_t*))acquire_address;
+ this->public.release_address = (void(*)(attribute_manager_t*, char *, host_t*, identification_t*))release_address;
+ this->public.create_responder_enumerator = (enumerator_t*(*)(attribute_manager_t*, identification_t*, host_t*))create_responder_enumerator;
+ this->public.add_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))add_provider;
+ this->public.remove_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))remove_provider;
+ this->public.handle = (attribute_handler_t*(*)(attribute_manager_t*,identification_t*, attribute_handler_t*, configuration_attribute_type_t, chunk_t))handle;
+ this->public.release = (void(*)(attribute_manager_t*, attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
+ this->public.create_initiator_enumerator = (enumerator_t*(*)(attribute_manager_t*, identification_t*, host_t*))create_initiator_enumerator;
+ this->public.add_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))add_handler;
+ this->public.remove_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))remove_handler;
+ this->public.destroy = (void(*)(attribute_manager_t*))destroy;
+
+ this->providers = linked_list_create();
+ this->handlers = linked_list_create();
+ this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
+
+ return &this->public;
+}
+
diff --git a/src/libhydra/attributes/attribute_manager.h b/src/libhydra/attributes/attribute_manager.h
new file mode 100644
index 000000000..642662366
--- /dev/null
+++ b/src/libhydra/attributes/attribute_manager.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2008-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.
+ */
+
+/**
+ * @defgroup attribute_manager attribute_manager
+ * @{ @ingroup attributes
+ */
+
+#ifndef ATTRIBUTE_MANAGER_H_
+#define ATTRIBUTE_MANAGER_H_
+
+#include "attribute_provider.h"
+#include "attribute_handler.h"
+
+typedef struct attribute_manager_t attribute_manager_t;
+
+/**
+ * The attribute manager hands out attributes or handles them.
+ *
+ * The attribute manager manages both, attribute providers and attribute
+ * handlers. Attribute providers are responsible to hand out attributes if
+ * a connecting peer requests them. Handlers handle such attributes if they
+ * are received on the requesting peer.
+ */
+struct attribute_manager_t {
+
+ /**
+ * Acquire a virtual IP address to assign to a peer.
+ *
+ * @param pool pool name to acquire address from
+ * @param id peer identity to get address forua
+ * @param requested IP in configuration request
+ * @return allocated address, NULL to serve none
+ */
+ host_t* (*acquire_address)(attribute_manager_t *this,
+ char *pool, identification_t *id,
+ host_t *requested);
+
+ /**
+ * Release a previously acquired address.
+ *
+ * @param pool pool name from which the address was acquired
+ * @param address address to release
+ * @param id peer identity to get address for
+ */
+ void (*release_address)(attribute_manager_t *this,
+ char *pool, host_t *address, identification_t *id);
+
+ /**
+ * Create an enumerator over attributes to hand out to a peer.
+ *
+ * @param id peer identity to hand out attributes to
+ * @param vip virtual IP to assign to peer, if any
+ * @return enumerator (configuration_attribute_type_t, chunk_t)
+ */
+ enumerator_t* (*create_responder_enumerator)(attribute_manager_t *this,
+ identification_t *id, host_t *vip);
+
+ /**
+ * Register an attribute provider to the manager.
+ *
+ * @param provider attribute provider to register
+ */
+ void (*add_provider)(attribute_manager_t *this,
+ attribute_provider_t *provider);
+ /**
+ * Unregister an attribute provider from the manager.
+ *
+ * @param provider attribute provider to unregister
+ */
+ void (*remove_provider)(attribute_manager_t *this,
+ attribute_provider_t *provider);
+
+ /**
+ * Handle a configuration attribute by passing them to the handlers.
+ *
+ * @param server server from which the attribute was received
+ * @param handler handler we requested the attribute for, if any
+ * @param type type of configuration attribute
+ * @param data associated attribute data
+ * @return handler which handled this attribute, NULL if none
+ */
+ attribute_handler_t* (*handle)(attribute_manager_t *this,
+ identification_t *server, attribute_handler_t *handler,
+ configuration_attribute_type_t type, chunk_t data);
+
+ /**
+ * Release an attribute previously handle()d by a handler.
+ *
+ * @param handler handler returned by handle() for this attribute
+ * @param server server from which the attribute was received
+ * @param type type of attribute to release
+ * @param data associated attribute data
+ */
+ void (*release)(attribute_manager_t *this, attribute_handler_t *handler,
+ identification_t *server,
+ configuration_attribute_type_t type,
+ chunk_t data);
+
+ /**
+ * Create an enumerator over attributes to request from server.
+ *
+ * @param id server identity to hand out attributes to
+ * @param vip virtual IP going to request, if any
+ * @return enumerator (attribute_handler_t, ca_type_t, chunk_t)
+ */
+ enumerator_t* (*create_initiator_enumerator)(attribute_manager_t *this,
+ identification_t *id, host_t *vip);
+
+ /**
+ * Register an attribute handler to the manager.
+ *
+ * @param handler attribute handler to register
+ */
+ void (*add_handler)(attribute_manager_t *this,
+ attribute_handler_t *handler);
+
+ /**
+ * Unregister an attribute handler from the manager.
+ *
+ * @param handler attribute handler to unregister
+ */
+ void (*remove_handler)(attribute_manager_t *this,
+ attribute_handler_t *handler);
+
+ /**
+ * Destroy a attribute_manager instance.
+ */
+ void (*destroy)(attribute_manager_t *this);
+};
+
+/**
+ * Create a attribute_manager instance.
+ */
+attribute_manager_t *attribute_manager_create();
+
+#endif /** ATTRIBUTE_MANAGER_H_ @}*/
diff --git a/src/libhydra/attributes/attribute_provider.h b/src/libhydra/attributes/attribute_provider.h
new file mode 100644
index 000000000..f8485cc6c
--- /dev/null
+++ b/src/libhydra/attributes/attribute_provider.h
@@ -0,0 +1,67 @@
+/*
+ * 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 attribute_provider attribute_provider
+ * @{ @ingroup attributes
+ */
+
+#ifndef ATTRIBUTE_PROVIDER_H_
+#define ATTRIBUTE_PROVIDER_H_
+
+#include <utils/host.h>
+#include <utils/identification.h>
+
+typedef struct attribute_provider_t attribute_provider_t;
+
+/**
+ * Interface to provide attributes to peers through attribute manager.
+ */
+struct attribute_provider_t {
+
+ /**
+ * Acquire a virtual IP address to assign to a peer.
+ *
+ * @param pool name of the pool to acquire address from
+ * @param id peer ID
+ * @param requested IP in configuration request
+ * @return allocated address, NULL to serve none
+ */
+ host_t* (*acquire_address)(attribute_provider_t *this,
+ char *pool, identification_t *id,
+ host_t *requested);
+ /**
+ * Release a previously acquired address.
+ *
+ * @param pool name of the pool this address was acquired from
+ * @param address address to release
+ * @param id peer ID
+ * @return TRUE if the address has been released by the provider
+ */
+ bool (*release_address)(attribute_provider_t *this,
+ char *pool, host_t *address, identification_t *id);
+
+ /**
+ * Create an enumerator over attributes to hand out to a peer.
+ *
+ * @param id peer ID
+ * @param vip virtual IP to assign to peer, if any
+ * @return enumerator (configuration_attribute_type_t, chunk_t)
+ */
+ enumerator_t* (*create_attribute_enumerator)(attribute_provider_t *this,
+ identification_t *id, host_t *vip);
+};
+
+#endif /** ATTRIBUTE_PROVIDER_H_ @}*/
diff --git a/src/libhydra/attributes/attributes.c b/src/libhydra/attributes/attributes.c
new file mode 100644
index 000000000..83feed17e
--- /dev/null
+++ b/src/libhydra/attributes/attributes.c
@@ -0,0 +1,43 @@
+/*
+ * 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 "attributes.h"
+
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_PREFIX,
+ "INTERNAL_IP4_ADDRESS",
+ "INTERNAL_IP4_NETMASK",
+ "INTERNAL_IP4_DNS",
+ "INTERNAL_IP4_NBNS",
+ "INTERNAL_ADDRESS_EXPIRY",
+ "INTERNAL_IP4_DHCP",
+ "APPLICATION_VERSION",
+ "INTERNAL_IP6_ADDRESS",
+ "INTERNAL_IP6_NETMASK",
+ "INTERNAL_IP6_DNS",
+ "INTERNAL_IP6_NBNS",
+ "INTERNAL_IP6_DHCP",
+ "INTERNAL_IP4_SUBNET",
+ "SUPPORTED_ATTRIBUTES",
+ "INTERNAL_IP6_SUBNET",
+ "MIP6_HOME_PREFIX",
+ "INTERNAL_IP6_LINK",
+ "INTERNAL_IP6_PREFIX");
+ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, INTERNAL_IP6_PREFIX,
+ "INTERNAL_IP4_SERVER",
+ "INTERNAL_IP6_SERVER");
+ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SERVER);
+
diff --git a/src/libhydra/attributes/attributes.h b/src/libhydra/attributes/attributes.h
new file mode 100644
index 000000000..f4a396f21
--- /dev/null
+++ b/src/libhydra/attributes/attributes.h
@@ -0,0 +1,62 @@
+/*
+ * 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 attributes_g attributes
+ * @{ @ingroup attributes
+ */
+
+#ifndef ATTRIBUTES_H_
+#define ATTRIBUTES_H_
+
+typedef enum configuration_attribute_type_t configuration_attribute_type_t;
+
+#include <enum.h>
+
+/**
+ * Type of the attribute, as in IKEv2 RFC 3.15.1 or IKEv1 ModeConfig.
+ */
+enum configuration_attribute_type_t {
+ INTERNAL_IP4_ADDRESS = 1,
+ INTERNAL_IP4_NETMASK = 2,
+ INTERNAL_IP4_DNS = 3,
+ INTERNAL_IP4_NBNS = 4,
+ INTERNAL_ADDRESS_EXPIRY = 5,
+ INTERNAL_IP4_DHCP = 6,
+ APPLICATION_VERSION = 7,
+ INTERNAL_IP6_ADDRESS = 8,
+ INTERNAL_IP6_NETMASK = 9,
+ INTERNAL_IP6_DNS = 10,
+ INTERNAL_IP6_NBNS = 11,
+ INTERNAL_IP6_DHCP = 12,
+ INTERNAL_IP4_SUBNET = 13,
+ SUPPORTED_ATTRIBUTES = 14,
+ INTERNAL_IP6_SUBNET = 15,
+ MIP6_HOME_PREFIX = 16,
+ INTERNAL_IP6_LINK = 17,
+ INTERNAL_IP6_PREFIX = 18,
+ /* proprietary Microsoft attributes */
+ INTERNAL_IP4_SERVER = 23456,
+ INTERNAL_IP6_SERVER = 23457
+};
+
+/**
+ * enum names for configuration_attribute_type_t.
+ */
+extern enum_name_t *configuration_attribute_type_names;
+
+
+#endif /** ATTRIBUTES_H_ @}*/
diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c
new file mode 100644
index 000000000..65018e3a9
--- /dev/null
+++ b/src/libhydra/attributes/mem_pool.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * 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 "mem_pool.h"
+
+#include <debug.h>
+#include <utils/hashtable.h>
+#include <threading/rwlock.h>
+
+#define POOL_LIMIT (sizeof(uintptr_t)*8)
+
+typedef struct private_mem_pool_t private_mem_pool_t;
+
+/**
+ * private data of mem_pool_t
+ */
+struct private_mem_pool_t {
+ /**
+ * public interface
+ */
+ mem_pool_t public;
+
+ /**
+ * name of the pool
+ */
+ char *name;
+
+ /**
+ * base address of the pool
+ */
+ host_t *base;
+
+ /**
+ * size of the pool
+ */
+ u_int size;
+
+ /**
+ * next unused address
+ */
+ u_int unused;
+
+ /**
+ * hashtable [identity => offset], for online leases
+ */
+ hashtable_t *online;
+
+ /**
+ * hashtable [identity => offset], for offline leases
+ */
+ hashtable_t *offline;
+
+ /**
+ * hashtable [identity => identity], handles identity references
+ */
+ hashtable_t *ids;
+
+ /**
+ * lock to safely access the pool
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * hashtable hash function for identities
+ */
+static u_int id_hash(identification_t *id)
+{
+ return chunk_hash(id->get_encoding(id));
+}
+
+/**
+ * hashtable equals function for identities
+ */
+static bool id_equals(identification_t *a, identification_t *b)
+{
+ return a->equals(a, b);
+}
+
+/**
+ * convert a pool offset to an address
+ */
+static host_t* offset2host(private_mem_pool_t *pool, int offset)
+{
+ chunk_t addr;
+ host_t *host;
+ u_int32_t *pos;
+
+ offset--;
+ if (offset > pool->size)
+ {
+ return NULL;
+ }
+
+ addr = chunk_clone(pool->base->get_address(pool->base));
+ if (pool->base->get_family(pool->base) == AF_INET6)
+ {
+ pos = (u_int32_t*)(addr.ptr + 12);
+ }
+ else
+ {
+ pos = (u_int32_t*)addr.ptr;
+ }
+ *pos = htonl(offset + ntohl(*pos));
+ host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
+ free(addr.ptr);
+ return host;
+}
+
+/**
+ * convert a host to a pool offset
+ */
+static int host2offset(private_mem_pool_t *pool, host_t *addr)
+{
+ chunk_t host, base;
+ u_int32_t hosti, basei;
+
+ if (addr->get_family(addr) != pool->base->get_family(pool->base))
+ {
+ return -1;
+ }
+ host = addr->get_address(addr);
+ base = pool->base->get_address(pool->base);
+ if (addr->get_family(addr) == AF_INET6)
+ {
+ /* only look at last /32 block */
+ if (!memeq(host.ptr, base.ptr, 12))
+ {
+ return -1;
+ }
+ host = chunk_skip(host, 12);
+ base = chunk_skip(base, 12);
+ }
+ hosti = ntohl(*(u_int32_t*)(host.ptr));
+ basei = ntohl(*(u_int32_t*)(base.ptr));
+ if (hosti > basei + pool->size)
+ {
+ return -1;
+ }
+ return hosti - basei + 1;
+}
+
+METHOD(mem_pool_t, get_name, const char*,
+ private_mem_pool_t *this)
+{
+ return this->name;
+}
+
+METHOD(mem_pool_t, get_size, u_int,
+ private_mem_pool_t *this)
+{
+ return this->size;
+}
+
+METHOD(mem_pool_t, get_online, u_int,
+ private_mem_pool_t *this)
+{
+ u_int count;
+ this->lock->read_lock(this->lock);
+ count = this->online->get_count(this->online);
+ this->lock->unlock(this->lock);
+ return count;
+}
+
+METHOD(mem_pool_t, get_offline, u_int,
+ private_mem_pool_t *this)
+{
+ u_int count;
+ this->lock->read_lock(this->lock);
+ count = this->offline->get_count(this->offline);
+ this->lock->unlock(this->lock);
+ return count;
+}
+
+METHOD(mem_pool_t, acquire_address, host_t*,
+ private_mem_pool_t *this, identification_t *id, host_t *requested)
+{
+ uintptr_t offset = 0;
+ enumerator_t *enumerator;
+ identification_t *old_id;
+
+ /* if the pool is empty (e.g. in the %config case) we simply return the
+ * requested address */
+ if (this->size == 0)
+ {
+ return requested->clone(requested);
+ }
+
+ if (!requested->is_anyaddr(requested) &&
+ requested->get_family(requested) !=
+ this->base->get_family(this->base))
+ {
+ DBG1(DBG_CFG, "IP pool address family mismatch");
+ return NULL;
+ }
+
+ this->lock->write_lock(this->lock);
+ while (TRUE)
+ {
+ /* check for a valid offline lease, refresh */
+ offset = (uintptr_t)this->offline->remove(this->offline, id);
+ if (offset)
+ {
+ id = this->ids->get(this->ids, id);
+ if (id)
+ {
+ DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
+ this->online->put(this->online, id, (void*)offset);
+ break;
+ }
+ }
+
+ /* check for a valid online lease, reassign */
+ offset = (uintptr_t)this->online->get(this->online, id);
+ if (offset && offset == host2offset(this, requested))
+ {
+ DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
+ break;
+ }
+
+ if (this->unused < this->size)
+ {
+ /* assigning offset, starting by 1. Handling 0 in hashtable
+ * is difficult. */
+ offset = ++this->unused;
+ id = id->clone(id);
+ this->ids->put(this->ids, id, id);
+ this->online->put(this->online, id, (void*)offset);
+ DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
+ break;
+ }
+
+ /* no more addresses, replace the first found offline lease */
+ enumerator = this->offline->create_enumerator(this->offline);
+ if (enumerator->enumerate(enumerator, &old_id, &offset))
+ {
+ offset = (uintptr_t)this->offline->remove(this->offline, old_id);
+ if (offset)
+ {
+ /* destroy reference to old ID */
+ old_id = this->ids->remove(this->ids, old_id);
+ DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
+ " to '%Y'", old_id, id);
+ if (old_id)
+ {
+ old_id->destroy(old_id);
+ }
+ id = id->clone(id);
+ this->ids->put(this->ids, id, id);
+ this->online->put(this->online, id, (void*)offset);
+ enumerator->destroy(enumerator);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
+ this->name);
+ break;
+ }
+ this->lock->unlock(this->lock);
+
+ if (offset)
+ {
+ return offset2host(this, offset);
+ }
+ return NULL;
+}
+
+METHOD(mem_pool_t, release_address, bool,
+ private_mem_pool_t *this, host_t *address, identification_t *id)
+{
+ bool found = FALSE;
+ if (this->size != 0)
+ {
+ uintptr_t offset;
+ this->lock->write_lock(this->lock);
+ offset = (uintptr_t)this->online->remove(this->online, id);
+ if (offset)
+ {
+ id = this->ids->get(this->ids, id);
+ if (id)
+ {
+ DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id);
+ this->offline->put(this->offline, id, (void*)offset);
+ found = TRUE;
+ }
+ }
+ this->lock->unlock(this->lock);
+ }
+ return found;
+}
+
+/**
+ * lease enumerator
+ */
+typedef struct {
+ /** implemented enumerator interface */
+ enumerator_t public;
+ /** inner hash-table enumerator */
+ enumerator_t *inner;
+ /** enumerated pool */
+ private_mem_pool_t *pool;
+ /** currently enumerated lease address */
+ host_t *current;
+} lease_enumerator_t;
+
+METHOD(enumerator_t, lease_enumerate, bool,
+ lease_enumerator_t *this, identification_t **id_out, host_t **addr_out,
+ bool *online)
+{
+ identification_t *id;
+ uintptr_t offset;
+
+ DESTROY_IF(this->current);
+ this->current = NULL;
+
+ if (this->inner->enumerate(this->inner, &id, NULL))
+ {
+ offset = (uintptr_t)this->pool->online->get(this->pool->online, id);
+ if (offset)
+ {
+ *id_out = id;
+ *addr_out = this->current = offset2host(this->pool, offset);
+ *online = TRUE;
+ return TRUE;
+ }
+ offset = (uintptr_t)this->pool->offline->get(this->pool->offline, id);
+ if (offset)
+ {
+ *id_out = id;
+ *addr_out = this->current = offset2host(this->pool, offset);
+ *online = FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, lease_enumerator_destroy, void,
+ lease_enumerator_t *this)
+{
+ DESTROY_IF(this->current);
+ this->inner->destroy(this->inner);
+ this->pool->lock->unlock(this->pool->lock);
+ free(this);
+}
+
+METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
+ private_mem_pool_t *this)
+{
+ lease_enumerator_t *enumerator;
+ this->lock->read_lock(this->lock);
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_lease_enumerate,
+ .destroy = (void*)_lease_enumerator_destroy,
+ },
+ .pool = this,
+ .inner = this->ids->create_enumerator(this->ids),
+ );
+ return &enumerator->public;
+}
+
+METHOD(mem_pool_t, destroy, void,
+ private_mem_pool_t *this)
+{
+ enumerator_t *enumerator;
+ identification_t *id;
+
+ enumerator = this->ids->create_enumerator(this->ids);
+ while (enumerator->enumerate(enumerator, &id, NULL))
+ {
+ id->destroy(id);
+ }
+ enumerator->destroy(enumerator);
+
+ this->ids->destroy(this->ids);
+ this->online->destroy(this->online);
+ this->offline->destroy(this->offline);
+ this->lock->destroy(this->lock);
+ DESTROY_IF(this->base);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Described in header
+ */
+mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
+{
+ private_mem_pool_t *this;
+
+ INIT(this,
+ .public = {
+ .get_name = _get_name,
+ .get_size = _get_size,
+ .get_online = _get_online,
+ .get_offline = _get_offline,
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_lease_enumerator = _create_lease_enumerator,
+ .destroy = _destroy,
+ },
+ .name = strdup(name),
+ .online = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ .offline = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ .ids = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ if (base)
+ {
+ int addr_bits = base->get_family(base) == AF_INET ? 32 : 128;
+ /* net bits -> host bits */
+ bits = addr_bits - bits;
+ if (bits > POOL_LIMIT)
+ {
+ bits = POOL_LIMIT;
+ DBG1(DBG_CFG, "virtual IP pool too large, limiting to %H/%d",
+ base, addr_bits - bits);
+ }
+ this->size = 1 << (bits);
+
+ if (this->size > 2)
+ { /* do not use first and last addresses of a block */
+ this->unused++;
+ this->size--;
+ }
+ this->base = base->clone(base);
+ }
+
+ return &this->public;
+}
+
diff --git a/src/libhydra/attributes/mem_pool.h b/src/libhydra/attributes/mem_pool.h
new file mode 100644
index 000000000..bb963de93
--- /dev/null
+++ b/src/libhydra/attributes/mem_pool.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 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 mem_pool mem_pool
+ * @{ @ingroup attributes
+ */
+
+#ifndef MEM_POOL_H
+#define MEM_POOL_H
+
+typedef struct mem_pool_t mem_pool_t;
+
+#include <utils/host.h>
+#include <utils/identification.h>
+
+/**
+ * An in-memory IP address pool.
+ */
+struct mem_pool_t {
+
+ /**
+ * Get the name of this pool.
+ *
+ * @return the name of this pool
+ */
+ const char* (*get_name)(mem_pool_t *this);
+
+ /**
+ * Get the size (i.e. number of addresses) of this pool.
+ *
+ * @return the size of this pool
+ */
+ u_int (*get_size)(mem_pool_t *this);
+
+ /**
+ * Get the number of online leases.
+ *
+ * @return the number of offline leases
+ */
+ u_int (*get_online)(mem_pool_t *this);
+
+ /**
+ * Get the number of offline leases.
+ *
+ * @return the number of online leases
+ */
+ u_int (*get_offline)(mem_pool_t *this);
+
+ /**
+ * Acquire an address for the given id from this pool.
+ *
+ * @param id the id to acquire an address for
+ * @param requested acquire this address, if possible
+ * @return the acquired address
+ */
+ host_t* (*acquire_address)(mem_pool_t *this, identification_t *id,
+ host_t *requested);
+
+ /**
+ * Release a previously acquired address.
+ *
+ * @param address the address to release
+ * @param id the id the address was assigned to
+ * @return TRUE, if the lease was found
+ */
+ bool (*release_address)(mem_pool_t *this, host_t *address,
+ identification_t *id);
+
+ /**
+ * Create an enumerator over the leases of this pool.
+ *
+ * Enumerator enumerates over
+ * identification_t *id, host_t *address, bool online
+ *
+ * @return enumerator
+ */
+ enumerator_t* (*create_lease_enumerator)(mem_pool_t *this);
+
+ /**
+ * Destroy a mem_pool_t instance.
+ */
+ void (*destroy)(mem_pool_t *this);
+};
+
+/**
+ * Create an in-memory IP address pool.
+ *
+ * An empty pool just returns the requested address.
+ *
+ * @param name name of this pool
+ * @param base base address of this pool, NULL to create an empty pool
+ * @param bits net mask
+ */
+mem_pool_t *mem_pool_create(char *name, host_t *base, int bits);
+
+#endif /** MEM_POOL_H_ @} */
+