summaryrefslogtreecommitdiff
path: root/src/libstrongswan/collections
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-02-07 13:27:27 +0100
committerYves-Alexis Perez <corsac@debian.org>2013-02-07 13:27:27 +0100
commit7585facf05d927eb6df3929ce09ed5e60d905437 (patch)
treee4d14b4dc180db20356b6b01ce0112f3a2d7897e /src/libstrongswan/collections
parentc1343b3278cdf99533b7902744d15969f9d6fdc1 (diff)
downloadvyos-strongswan-7585facf05d927eb6df3929ce09ed5e60d905437.tar.gz
vyos-strongswan-7585facf05d927eb6df3929ce09ed5e60d905437.zip
Imported Upstream version 5.0.2
Diffstat (limited to 'src/libstrongswan/collections')
-rw-r--r--src/libstrongswan/collections/blocking_queue.c129
-rw-r--r--src/libstrongswan/collections/blocking_queue.h97
-rw-r--r--src/libstrongswan/collections/enumerator.c560
-rw-r--r--src/libstrongswan/collections/enumerator.h159
-rw-r--r--src/libstrongswan/collections/hashtable.c444
-rw-r--r--src/libstrongswan/collections/hashtable.h138
-rw-r--r--src/libstrongswan/collections/linked_list.c615
-rw-r--r--src/libstrongswan/collections/linked_list.h319
8 files changed, 2461 insertions, 0 deletions
diff --git a/src/libstrongswan/collections/blocking_queue.c b/src/libstrongswan/collections/blocking_queue.c
new file mode 100644
index 000000000..da3356970
--- /dev/null
+++ b/src/libstrongswan/collections/blocking_queue.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * 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 "blocking_queue.h"
+
+#include <threading/mutex.h>
+#include <threading/thread.h>
+#include <threading/condvar.h>
+#include <collections/linked_list.h>
+
+typedef struct private_blocking_queue_t private_blocking_queue_t;
+
+/**
+ * Private data of a blocking_queue_t object.
+ */
+struct private_blocking_queue_t {
+
+ /**
+ * Public part
+ */
+ blocking_queue_t public;
+
+ /**
+ * Linked list containing all items in the queue
+ */
+ linked_list_t *list;
+
+ /**
+ * Mutex used to synchronize access to the queue
+ */
+ mutex_t *mutex;
+
+ /**
+ * Condvar used to wait for items
+ */
+ condvar_t *condvar;
+
+};
+
+METHOD(blocking_queue_t, enqueue, void,
+ private_blocking_queue_t *this, void *item)
+{
+ this->mutex->lock(this->mutex);
+ this->list->insert_first(this->list, item);
+ this->condvar->signal(this->condvar);
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(blocking_queue_t, dequeue, void*,
+ private_blocking_queue_t *this)
+{
+ bool oldstate;
+ void *item;
+
+
+ this->mutex->lock(this->mutex);
+ thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
+ /* ensure that a canceled thread does not dequeue any items */
+ thread_cancellation_point();
+ while (this->list->remove_last(this->list, &item) != SUCCESS)
+ {
+ oldstate = thread_cancelability(TRUE);
+ this->condvar->wait(this->condvar, this->mutex);
+ thread_cancelability(oldstate);
+ }
+ thread_cleanup_pop(TRUE);
+ return item;
+}
+
+METHOD(blocking_queue_t, destroy, void,
+ private_blocking_queue_t *this)
+{
+ this->list->destroy(this->list);
+ this->condvar->destroy(this->condvar);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+METHOD(blocking_queue_t, destroy_offset, void,
+ private_blocking_queue_t *this, size_t offset)
+{
+ this->list->invoke_offset(this->list, offset);
+ destroy(this);
+}
+
+METHOD(blocking_queue_t, destroy_function, void,
+ private_blocking_queue_t *this, void (*fn)(void*))
+{
+ this->list->invoke_function(this->list, (linked_list_invoke_t)fn);
+ destroy(this);
+}
+
+/*
+ * Described in header.
+ */
+blocking_queue_t *blocking_queue_create()
+{
+ private_blocking_queue_t *this;
+
+ INIT(this,
+ .public = {
+ .enqueue = _enqueue,
+ .dequeue = _dequeue,
+ .destroy = _destroy,
+ .destroy_offset = _destroy_offset,
+ .destroy_function = _destroy_function,
+ },
+ .list = linked_list_create(),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/collections/blocking_queue.h b/src/libstrongswan/collections/blocking_queue.h
new file mode 100644
index 000000000..9b014f719
--- /dev/null
+++ b/src/libstrongswan/collections/blocking_queue.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * 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 blocking_queue blocking_queue
+ * @{ @ingroup collections
+ */
+
+#ifndef BLOCKING_QUEUE_H_
+#define BLOCKING_QUEUE_H_
+
+typedef struct blocking_queue_t blocking_queue_t;
+
+#include <library.h>
+
+/**
+ * Class implementing a synchronized blocking queue based on linked_list_t
+ */
+struct blocking_queue_t {
+
+ /**
+ * Inserts a new item at the tail of the queue
+ *
+ * @param item item to insert in queue
+ */
+ void (*enqueue)(blocking_queue_t *this, void *item);
+
+ /**
+ * Removes the first item in the queue and returns its value.
+ * If the queue is empty, this call blocks until a new item is inserted.
+ *
+ * @note This is a thread cancellation point
+ *
+ * @return removed item
+ */
+ void *(*dequeue)(blocking_queue_t *this);
+
+ /**
+ * Destroys a blocking_queue_t object.
+ *
+ * @note No thread must wait in dequeue() when this function is called
+ */
+ void (*destroy)(blocking_queue_t *this);
+
+ /**
+ * Destroys a queue and its objects using the given destructor.
+ *
+ * If a queue and the contained objects should be destroyed, use
+ * destroy_offset. The supplied offset specifies the destructor to
+ * call on each object. The offset may be calculated using the offsetof
+ * macro, e.g.: queue->destroy_offset(queue, offsetof(object_t, destroy));
+ *
+ * @note No thread must wait in dequeue() when this function is called
+ *
+ * @param offset offset of the objects destructor
+ */
+ void (*destroy_offset)(blocking_queue_t *this, size_t offset);
+
+ /**
+ * Destroys a queue and its objects using a cleanup function.
+ *
+ * If a queue and its contents should get destroyed using a specific
+ * cleanup function, use destroy_function. This is useful when the
+ * list contains malloc()-ed blocks which should get freed,
+ * e.g.: queue->destroy_function(queue, free);
+ *
+ * @note No thread must wait in dequeue() when this function is called
+ *
+ * @param function function to call on each object
+ */
+ void (*destroy_function)(blocking_queue_t *this, void (*)(void*));
+
+};
+
+/**
+ * Creates an empty queue object.
+ *
+ * @return blocking_queue_t object.
+ */
+blocking_queue_t *blocking_queue_create();
+
+#endif /** BLOCKING_QUEUE_H_ @}*/
+
diff --git a/src/libstrongswan/collections/enumerator.c b/src/libstrongswan/collections/enumerator.c
new file mode 100644
index 000000000..f80cdabd2
--- /dev/null
+++ b/src/libstrongswan/collections/enumerator.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2008 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 "enumerator.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+
+#include <utils/debug.h>
+
+/**
+ * Implementation of enumerator_create_empty().enumerate
+ */
+static bool enumerate_empty(enumerator_t *enumerator, ...)
+{
+ return FALSE;
+}
+
+/**
+ * See header
+ */
+enumerator_t* enumerator_create_empty()
+{
+ enumerator_t *this = malloc_thing(enumerator_t);
+ this->enumerate = enumerate_empty;
+ this->destroy = (void*)free;
+ return this;
+}
+
+/**
+ * Enumerator implementation for directory enumerator
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** directory handle */
+ DIR *dir;
+ /** absolute path of current file */
+ char full[PATH_MAX];
+ /** where directory part of full ends and relative file gets written */
+ char *full_end;
+} dir_enum_t;
+
+/**
+ * Implementation of enumerator_create_directory().destroy
+ */
+static void destroy_dir_enum(dir_enum_t *this)
+{
+ closedir(this->dir);
+ free(this);
+}
+
+/**
+ * Implementation of enumerator_create_directory().enumerate
+ */
+static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
+ char **absolute, struct stat *st)
+{
+ struct dirent *entry = readdir(this->dir);
+ size_t remaining;
+ int len;
+
+ if (!entry)
+ {
+ return FALSE;
+ }
+ if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
+ {
+ return enumerate_dir_enum(this, relative, absolute, st);
+ }
+ if (relative)
+ {
+ *relative = entry->d_name;
+ }
+ if (absolute || st)
+ {
+ remaining = sizeof(this->full) - (this->full_end - this->full);
+ len = snprintf(this->full_end, remaining, "%s", entry->d_name);
+ if (len < 0 || len >= remaining)
+ {
+ DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
+ entry->d_name);
+ return FALSE;
+ }
+ if (absolute)
+ {
+ *absolute = this->full;
+ }
+ if (st)
+ {
+ if (stat(this->full, st))
+ {
+ DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
+ strerror(errno));
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * See header
+ */
+enumerator_t* enumerator_create_directory(const char *path)
+{
+ int len;
+ dir_enum_t *this = malloc_thing(dir_enum_t);
+ this->public.enumerate = (void*)enumerate_dir_enum;
+ this->public.destroy = (void*)destroy_dir_enum;
+
+ if (*path == '\0')
+ {
+ path = "./";
+ }
+ len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
+ if (len < 0 || len >= sizeof(this->full)-1)
+ {
+ DBG1(DBG_LIB, "path string '%s' too long", path);
+ free(this);
+ return NULL;
+ }
+ /* append a '/' if not already done */
+ if (this->full[len-1] != '/')
+ {
+ this->full[len++] = '/';
+ this->full[len] = '\0';
+ }
+ this->full_end = &this->full[len];
+
+ this->dir = opendir(path);
+ if (this->dir == NULL)
+ {
+ DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
+ free(this);
+ return NULL;
+ }
+ return &this->public;
+}
+
+/**
+ * Enumerator implementation for directory enumerator
+ */
+typedef struct {
+ /** implements enumerator_t */
+ enumerator_t public;
+ /** string to parse */
+ char *string;
+ /** current position */
+ char *pos;
+ /** separater chars */
+ const char *sep;
+ /** trim chars */
+ const char *trim;
+} token_enum_t;
+
+/**
+ * Implementation of enumerator_create_token().destroy
+ */
+static void destroy_token_enum(token_enum_t *this)
+{
+ free(this->string);
+ free(this);
+}
+
+/**
+ * Implementation of enumerator_create_token().enumerate
+ */
+static bool enumerate_token_enum(token_enum_t *this, char **token)
+{
+ const char *sep, *trim;
+ char *pos = NULL, *tmp;
+ bool last = FALSE;
+
+ /* trim leading characters/separators */
+ while (*this->pos)
+ {
+ trim = this->trim;
+ while (*trim)
+ {
+ if (*trim == *this->pos)
+ {
+ this->pos++;
+ break;
+ }
+ trim++;
+ }
+ sep = this->sep;
+ while (*sep)
+ {
+ if (*sep == *this->pos)
+ {
+ this->pos++;
+ break;
+ }
+ sep++;
+ }
+ if (!*trim && !*sep)
+ {
+ break;
+ }
+ }
+
+ switch (*this->pos)
+ {
+ case '"':
+ case '\'':
+ {
+ /* read quoted token */
+ tmp = strchr(this->pos + 1, *this->pos);
+ if (tmp)
+ {
+ *token = this->pos + 1;
+ *tmp = '\0';
+ this->pos = tmp + 1;
+ return TRUE;
+ }
+ /* unterminated string, FALL-THROUGH */
+ }
+ default:
+ {
+ /* find nearest separator */
+ sep = this->sep;
+ while (*sep)
+ {
+ tmp = strchr(this->pos, *sep);
+ if (tmp && (pos == NULL || tmp < pos))
+ {
+ pos = tmp;
+ }
+ sep++;
+ }
+ *token = this->pos;
+ if (pos)
+ {
+ *pos = '\0';
+ this->pos = pos + 1;
+ }
+ else
+ {
+ last = TRUE;
+ pos = this->pos = strchr(this->pos, '\0');
+ }
+ break;
+ }
+ }
+
+ /* trim trailing characters/separators */
+ pos--;
+ while (pos >= *token)
+ {
+ trim = this->trim;
+ while (*trim)
+ {
+ if (*trim == *pos)
+ {
+ *(pos--) = '\0';
+ break;
+ }
+ trim++;
+ }
+ sep = this->sep;
+ while (*sep)
+ {
+ if (*sep == *pos)
+ {
+ *(pos--) = '\0';
+ break;
+ }
+ sep++;
+ }
+ if (!*trim && !*sep)
+ {
+ break;
+ }
+ }
+
+ if (!last || pos >= *token)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * See header
+ */
+enumerator_t* enumerator_create_token(const char *string, const char *sep,
+ const char *trim)
+{
+ token_enum_t *enumerator = malloc_thing(token_enum_t);
+
+ enumerator->public.enumerate = (void*)enumerate_token_enum;
+ enumerator->public.destroy = (void*)destroy_token_enum;
+ enumerator->string = strdup(string);
+ enumerator->pos = enumerator->string;
+ enumerator->sep = sep;
+ enumerator->trim = trim;
+
+ return &enumerator->public;
+}
+
+/**
+ * enumerator for nested enumerations
+ */
+typedef struct {
+ /* implements enumerator_t */
+ enumerator_t public;
+ /* outer enumerator */
+ enumerator_t *outer;
+ /* inner enumerator */
+ enumerator_t *inner;
+ /* constructor for inner enumerator */
+ enumerator_t *(*create_inner)(void *outer, void *data);
+ /* data to pass to constructor above */
+ void *data;
+ /* destructor for data */
+ void (*destroy_data)(void *data);
+} nested_enumerator_t;
+
+
+/**
+ * Implementation of enumerator_create_nested().enumerate()
+ */
+static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
+ void *v3, void *v4, void *v5)
+{
+ while (TRUE)
+ {
+ while (this->inner == NULL)
+ {
+ void *outer;
+
+ if (!this->outer->enumerate(this->outer, &outer))
+ {
+ return FALSE;
+ }
+ this->inner = this->create_inner(outer, this->data);
+ }
+ if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
+ {
+ return TRUE;
+ }
+ this->inner->destroy(this->inner);
+ this->inner = NULL;
+ }
+}
+
+/**
+ * Implementation of enumerator_create_nested().destroy()
+ **/
+static void destroy_nested(nested_enumerator_t *this)
+{
+ if (this->destroy_data)
+ {
+ this->destroy_data(this->data);
+ }
+ DESTROY_IF(this->inner);
+ this->outer->destroy(this->outer);
+ free(this);
+}
+
+/**
+ * See header
+ */
+enumerator_t *enumerator_create_nested(enumerator_t *outer,
+ enumerator_t *(inner_constructor)(void *outer, void *data),
+ void *data, void (*destroy_data)(void *data))
+{
+ nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
+
+ enumerator->public.enumerate = (void*)enumerate_nested;
+ enumerator->public.destroy = (void*)destroy_nested;
+ enumerator->outer = outer;
+ enumerator->inner = NULL;
+ enumerator->create_inner = (void*)inner_constructor;
+ enumerator->data = data;
+ enumerator->destroy_data = destroy_data;
+
+ return &enumerator->public;
+}
+
+/**
+ * enumerator for filtered enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ enumerator_t *unfiltered;
+ void *data;
+ bool (*filter)(void *data, ...);
+ void (*destructor)(void *data);
+} filter_enumerator_t;
+
+/**
+ * Implementation of enumerator_create_filter().destroy
+ */
+static void destroy_filter(filter_enumerator_t *this)
+{
+ if (this->destructor)
+ {
+ this->destructor(this->data);
+ }
+ this->unfiltered->destroy(this->unfiltered);
+ free(this);
+}
+
+/**
+ * Implementation of enumerator_create_filter().enumerate
+ */
+static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
+ void *o3, void *o4, void *o5)
+{
+ void *i1, *i2, *i3, *i4, *i5;
+
+ while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
+ {
+ if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * see header
+ */
+enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
+ bool (*filter)(void *data, ...),
+ void *data, void (*destructor)(void *data))
+{
+ filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
+
+ this->public.enumerate = (void*)enumerate_filter;
+ this->public.destroy = (void*)destroy_filter;
+ this->unfiltered = unfiltered;
+ this->filter = filter;
+ this->data = data;
+ this->destructor = destructor;
+
+ return &this->public;
+}
+
+/**
+ * enumerator for cleaner enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ enumerator_t *wrapped;
+ void (*cleanup)(void *data);
+ void *data;
+} cleaner_enumerator_t;
+
+/**
+ * Implementation of enumerator_create_cleanup().destroy
+ */
+static void destroy_cleaner(cleaner_enumerator_t *this)
+{
+ this->cleanup(this->data);
+ this->wrapped->destroy(this->wrapped);
+ free(this);
+}
+
+/**
+ * Implementation of enumerator_create_cleaner().enumerate
+ */
+static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
+ void *v3, void *v4, void *v5)
+{
+ return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
+}
+
+/**
+ * see header
+ */
+enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
+ void (*cleanup)(void *data), void *data)
+{
+ cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
+
+ this->public.enumerate = (void*)enumerate_cleaner;
+ this->public.destroy = (void*)destroy_cleaner;
+ this->wrapped = wrapped;
+ this->cleanup = cleanup;
+ this->data = data;
+
+ return &this->public;
+}
+
+/**
+ * enumerator for single enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ void *item;
+ void (*cleanup)(void *item);
+ bool done;
+} single_enumerator_t;
+
+/**
+ * Implementation of enumerator_create_single().destroy
+ */
+static void destroy_single(single_enumerator_t *this)
+{
+ if (this->cleanup)
+ {
+ this->cleanup(this->item);
+ }
+ free(this);
+}
+
+/**
+ * Implementation of enumerator_create_single().enumerate
+ */
+static bool enumerate_single(single_enumerator_t *this, void **item)
+{
+ if (this->done)
+ {
+ return FALSE;
+ }
+ *item = this->item;
+ this->done = TRUE;
+ return TRUE;
+}
+
+/**
+ * see header
+ */
+enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
+{
+ single_enumerator_t *this = malloc_thing(single_enumerator_t);
+
+ this->public.enumerate = (void*)enumerate_single;
+ this->public.destroy = (void*)destroy_single;
+ this->item = item;
+ this->cleanup = cleanup;
+ this->done = FALSE;
+
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/collections/enumerator.h b/src/libstrongswan/collections/enumerator.h
new file mode 100644
index 000000000..299373a3e
--- /dev/null
+++ b/src/libstrongswan/collections/enumerator.h
@@ -0,0 +1,159 @@
+/*
+ * 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 enumerator enumerator
+ * @{ @ingroup collections
+ */
+
+#ifndef ENUMERATOR_H_
+#define ENUMERATOR_H_
+
+typedef struct enumerator_t enumerator_t;
+
+#include <utils/utils.h>
+
+/**
+ * Enumerator interface, allows enumeration over collections.
+ */
+struct enumerator_t {
+
+ /**
+ * Enumerate collection.
+ *
+ * The enumerate function takes a variable argument list containing
+ * pointers where the enumerated values get written.
+ *
+ * @param ... variable list of enumerated items, implementation dependent
+ * @return TRUE if pointers returned
+ */
+ bool (*enumerate)(enumerator_t *this, ...);
+
+ /**
+ * Destroy a enumerator instance.
+ */
+ void (*destroy)(enumerator_t *this);
+};
+
+/**
+ * Create an enumerator which enumerates over nothing
+ *
+ * @return an enumerator over no values
+ */
+enumerator_t* enumerator_create_empty();
+
+/**
+ * Create an enumerator which enumerates over a single item
+ *
+ * @param item item to enumerate
+ * @param cleanup cleanup function called on destroy with the item
+ * @return an enumerator over a single value
+ */
+enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item));
+
+/**
+ * Create an enumerator over files/subdirectories in a directory.
+ *
+ * This enumerator_t.enumerate() function returns a (to the directory) relative
+ * filename (as a char*), an absolute filename (as a char*) and a file status
+ * (to a struct stat), which all may be NULL. "." and ".." entries are
+ * skipped. Example:
+ *
+ * @code
+ char *rel, *abs;
+ struct stat st;
+ enumerator_t *e;
+
+ e = enumerator_create_directory("/tmp");
+ if (e)
+ {
+ while (e->enumerate(e, &rel, &abs, &st))
+ {
+ if (S_ISDIR(st.st_mode) && *rel != '.')
+ {
+ printf("%s\n", abs);
+ }
+ }
+ e->destroy(e);
+ }
+ @endcode
+ *
+ * @param path path of the directory
+ * @return the directory enumerator, NULL on failure
+ */
+enumerator_t* enumerator_create_directory(const char *path);
+
+/**
+ * Create an enumerator over tokens of a string.
+ *
+ * Tokens are separated by one of the characters in sep and trimmed by the
+ * characters in trim.
+ *
+ * @param string string to parse
+ * @param sep separator characters
+ * @param trim characters to trim from tokens
+ * @return enumerator over char* tokens
+ */
+enumerator_t* enumerator_create_token(const char *string, const char *sep,
+ const char *trim);
+
+/**
+ * Creates an enumerator which enumerates over enumerated enumerators :-).
+ *
+ * The variable argument list of enumeration values is limit to 5.
+ *
+ * @param outer outer enumerator
+ * @param inner_constructor constructor to inner enumerator
+ * @param data data to pass to each inner_constructor call
+ * @param destroy_data destructor to pass to data
+ * @return the nested enumerator
+ */
+enumerator_t *enumerator_create_nested(enumerator_t *outer,
+ enumerator_t *(*inner_constructor)(void *outer, void *data),
+ void *data, void (*destroy_data)(void *data));
+
+/**
+ * Creates an enumerator which filters output of another enumerator.
+ *
+ * The filter function receives the user supplied "data" followed by a
+ * unfiltered enumeration item, followed by an output pointer where to write
+ * the filtered data. Then the next input/output pair follows.
+ * It returns TRUE to deliver the
+ * values to the caller of enumerate(), FALSE to filter this enumeration.
+ *
+ * The variable argument list of enumeration values is limit to 5.
+ *
+ * @param unfiltered unfiltered enumerator to wrap, gets destroyed
+ * @param filter filter function
+ * @param data user data to supply to filter
+ * @param destructor destructor function to clean up data after use
+ * @return the filtered enumerator
+ */
+enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
+ bool (*filter)(void *data, ...),
+ void *data, void (*destructor)(void *data));
+
+/**
+ * Create an enumerator wrapper which does a cleanup on destroy.
+ *
+ * @param wrapped wrapped enumerator
+ * @param cleanup cleanup function called on destroy
+ * @param data user data to supply to cleanup
+ * @return the enumerator with cleanup
+ */
+enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
+ void (*cleanup)(void *data), void *data);
+
+#endif /** ENUMERATOR_H_ @}*/
diff --git a/src/libstrongswan/collections/hashtable.c b/src/libstrongswan/collections/hashtable.c
new file mode 100644
index 000000000..d181d8ec8
--- /dev/null
+++ b/src/libstrongswan/collections/hashtable.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2008-2012 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 "hashtable.h"
+
+/** The maximum capacity of the hash table (MUST be a power of 2) */
+#define MAX_CAPACITY (1 << 30)
+
+typedef struct pair_t pair_t;
+
+/**
+ * This pair holds a pointer to the key and value it represents.
+ */
+struct pair_t {
+ /**
+ * Key of a hash table item.
+ */
+ void *key;
+
+ /**
+ * Value of a hash table item.
+ */
+ void *value;
+
+ /**
+ * Cached hash (used in case of a resize).
+ */
+ u_int hash;
+
+ /**
+ * Next pair in an overflow list.
+ */
+ pair_t *next;
+};
+
+/**
+ * Creates an empty pair object.
+ */
+static inline pair_t *pair_create(void *key, void *value, u_int hash)
+{
+ pair_t *this;
+
+ INIT(this,
+ .key = key,
+ .value = value,
+ .hash = hash,
+ );
+
+ return this;
+}
+
+typedef struct private_hashtable_t private_hashtable_t;
+
+/**
+ * Private data of a hashtable_t object.
+ *
+ */
+struct private_hashtable_t {
+ /**
+ * Public part of hash table.
+ */
+ hashtable_t public;
+
+ /**
+ * The number of items in the hash table.
+ */
+ u_int count;
+
+ /**
+ * The current capacity of the hash table (always a power of 2).
+ */
+ u_int capacity;
+
+ /**
+ * The current mask to calculate the row index (capacity - 1).
+ */
+ u_int mask;
+
+ /**
+ * The load factor.
+ */
+ float load_factor;
+
+ /**
+ * The actual table.
+ */
+ pair_t **table;
+
+ /**
+ * The hashing function.
+ */
+ hashtable_hash_t hash;
+
+ /**
+ * The equality function.
+ */
+ hashtable_equals_t equals;
+};
+
+typedef struct private_enumerator_t private_enumerator_t;
+
+/**
+ * hash table enumerator implementation
+ */
+struct private_enumerator_t {
+
+ /**
+ * implements enumerator interface
+ */
+ enumerator_t enumerator;
+
+ /**
+ * associated hash table
+ */
+ private_hashtable_t *table;
+
+ /**
+ * current row index
+ */
+ u_int row;
+
+ /**
+ * number of remaining items in hashtable
+ */
+ u_int count;
+
+ /**
+ * current pair
+ */
+ pair_t *current;
+
+ /**
+ * previous pair (used by remove_at)
+ */
+ pair_t *prev;
+
+};
+
+/**
+ * This function returns the next-highest power of two for the given number.
+ * The algorithm works by setting all bits on the right-hand side of the most
+ * significant 1 to 1 and then increments the whole number so it rolls over
+ * to the nearest power of two. Note: returns 0 for n == 0
+ */
+static u_int get_nearest_powerof2(u_int n)
+{
+ u_int i;
+
+ --n;
+ for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
+ {
+ n |= n >> i;
+ }
+ return ++n;
+}
+
+/**
+ * Init hash table parameters
+ */
+static void init_hashtable(private_hashtable_t *this, u_int capacity)
+{
+ capacity = max(1, min(capacity, MAX_CAPACITY));
+ this->capacity = get_nearest_powerof2(capacity);
+ this->mask = this->capacity - 1;
+ this->load_factor = 0.75;
+
+ this->table = calloc(this->capacity, sizeof(pair_t*));
+}
+
+/**
+ * Double the size of the hash table and rehash all the elements.
+ */
+static void rehash(private_hashtable_t *this)
+{
+ pair_t **old_table;
+ u_int row, old_capacity;
+
+ if (this->capacity >= MAX_CAPACITY)
+ {
+ return;
+ }
+
+ old_capacity = this->capacity;
+ old_table = this->table;
+
+ init_hashtable(this, old_capacity << 1);
+
+ for (row = 0; row < old_capacity; row++)
+ {
+ pair_t *pair, *next;
+ u_int new_row;
+
+ pair = old_table[row];
+ while (pair)
+ { /* insert pair at the front of new bucket*/
+ next = pair->next;
+ new_row = pair->hash & this->mask;
+ pair->next = this->table[new_row];
+ this->table[new_row] = pair;
+ pair = next;
+ }
+ }
+ free(old_table);
+}
+
+METHOD(hashtable_t, put, void*,
+ private_hashtable_t *this, void *key, void *value)
+{
+ void *old_value = NULL;
+ pair_t *pair;
+ u_int hash, row;
+
+ hash = this->hash(key);
+ row = hash & this->mask;
+ pair = this->table[row];
+ while (pair)
+ { /* search existing bucket for key */
+ if (this->equals(key, pair->key))
+ {
+ old_value = pair->value;
+ pair->value = value;
+ pair->key = key;
+ break;
+ }
+ pair = pair->next;
+ }
+ if (!pair)
+ { /* insert at the front of bucket */
+ pair = pair_create(key, value, hash);
+ pair->next = this->table[row];
+ this->table[row] = pair;
+ this->count++;
+ }
+ if (this->count >= this->capacity * this->load_factor)
+ {
+ rehash(this);
+ }
+ return old_value;
+}
+
+static void *get_internal(private_hashtable_t *this, void *key,
+ hashtable_equals_t equals)
+{
+ void *value = NULL;
+ pair_t *pair;
+
+ if (!this->count)
+ { /* no need to calculate the hash */
+ return NULL;
+ }
+
+ pair = this->table[this->hash(key) & this->mask];
+ while (pair)
+ {
+ if (equals(key, pair->key))
+ {
+ value = pair->value;
+ break;
+ }
+ pair = pair->next;
+ }
+ return value;
+}
+
+METHOD(hashtable_t, get, void*,
+ private_hashtable_t *this, void *key)
+{
+ return get_internal(this, key, this->equals);
+}
+
+METHOD(hashtable_t, get_match, void*,
+ private_hashtable_t *this, void *key, hashtable_equals_t match)
+{
+ return get_internal(this, key, match);
+}
+
+METHOD(hashtable_t, remove_, void*,
+ private_hashtable_t *this, void *key)
+{
+ void *value = NULL;
+ pair_t *pair, *prev = NULL;
+ u_int row;
+
+ row = this->hash(key) & this->mask;
+ pair = this->table[row];
+ while (pair)
+ {
+ if (this->equals(key, pair->key))
+ {
+ if (prev)
+ {
+ prev->next = pair->next;
+ }
+ else
+ {
+ this->table[row] = pair->next;
+ }
+ value = pair->value;
+ this->count--;
+ free(pair);
+ break;
+ }
+ prev = pair;
+ pair = pair->next;
+ }
+ return value;
+}
+
+METHOD(hashtable_t, remove_at, void,
+ private_hashtable_t *this, private_enumerator_t *enumerator)
+{
+ if (enumerator->table == this && enumerator->current)
+ {
+ pair_t *current = enumerator->current;
+ if (enumerator->prev)
+ {
+ enumerator->prev->next = current->next;
+ }
+ else
+ {
+ this->table[enumerator->row] = current->next;
+ }
+ enumerator->current = enumerator->prev;
+ free(current);
+ this->count--;
+ }
+}
+
+METHOD(hashtable_t, get_count, u_int,
+ private_hashtable_t *this)
+{
+ return this->count;
+}
+
+METHOD(enumerator_t, enumerate, bool,
+ private_enumerator_t *this, void **key, void **value)
+{
+ while (this->count && this->row < this->table->capacity)
+ {
+ this->prev = this->current;
+ if (this->current)
+ {
+ this->current = this->current->next;
+ }
+ else
+ {
+ this->current = this->table->table[this->row];
+ }
+ if (this->current)
+ {
+ if (key)
+ {
+ *key = this->current->key;
+ }
+ if (value)
+ {
+ *value = this->current->value;
+ }
+ this->count--;
+ return TRUE;
+ }
+ this->row++;
+ }
+ return FALSE;
+}
+
+METHOD(hashtable_t, create_enumerator, enumerator_t*,
+ private_hashtable_t *this)
+{
+ private_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .enumerator = {
+ .enumerate = (void*)_enumerate,
+ .destroy = (void*)free,
+ },
+ .table = this,
+ .count = this->count,
+ );
+
+ return &enumerator->enumerator;
+}
+
+METHOD(hashtable_t, destroy, void,
+ private_hashtable_t *this)
+{
+ pair_t *pair, *next;
+ u_int row;
+
+ for (row = 0; row < this->capacity; row++)
+ {
+ pair = this->table[row];
+ while (pair)
+ {
+ next = pair->next;
+ free(pair);
+ pair = next;
+ }
+ }
+ free(this->table);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
+ u_int capacity)
+{
+ private_hashtable_t *this;
+
+ INIT(this,
+ .public = {
+ .put = _put,
+ .get = _get,
+ .get_match = _get_match,
+ .remove = _remove_,
+ .remove_at = (void*)_remove_at,
+ .get_count = _get_count,
+ .create_enumerator = _create_enumerator,
+ .destroy = _destroy,
+ },
+ .hash = hash,
+ .equals = equals,
+ );
+
+ init_hashtable(this, capacity);
+
+ return &this->public;
+}
+
diff --git a/src/libstrongswan/collections/hashtable.h b/src/libstrongswan/collections/hashtable.h
new file mode 100644
index 000000000..e38850ded
--- /dev/null
+++ b/src/libstrongswan/collections/hashtable.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008-2012 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 hashtable hashtable
+ * @{ @ingroup collections
+ */
+
+#ifndef HASHTABLE_H_
+#define HASHTABLE_H_
+
+#include <collections/enumerator.h>
+
+typedef struct hashtable_t hashtable_t;
+
+/**
+ * Prototype for a function that computes the hash code from the given key.
+ *
+ * @param key key to hash
+ * @return hash code
+ */
+typedef u_int (*hashtable_hash_t)(void *key);
+
+/**
+ * Prototype for a function that compares the two keys for equality.
+ *
+ * @param key first key (the one we are looking for)
+ * @param other_key second key
+ * @return TRUE if the keys are equal
+ */
+typedef bool (*hashtable_equals_t)(void *key, void *other_key);
+
+/**
+ * Class implementing a hash table.
+ *
+ * General purpose hash table. This hash table is not synchronized.
+ */
+struct hashtable_t {
+
+ /**
+ * Create an enumerator over the hash table key/value pairs.
+ *
+ * @return enumerator over (void *key, void *value)
+ */
+ enumerator_t *(*create_enumerator) (hashtable_t *this);
+
+ /**
+ * Adds the given value with the given key to the hash table, if there
+ * exists no entry with that key. NULL is returned in this case.
+ * Otherwise the existing value is replaced and the function returns the
+ * old value.
+ *
+ * @param key the key to store
+ * @param value the value to store
+ * @return NULL if no item was replaced, the old value otherwise
+ */
+ void *(*put) (hashtable_t *this, void *key, void *value);
+
+ /**
+ * Returns the value with the given key, if the hash table contains such an
+ * entry, otherwise NULL is returned.
+ *
+ * @param key the key of the requested value
+ * @return the value, NULL if not found
+ */
+ void *(*get) (hashtable_t *this, void *key);
+
+ /**
+ * Returns the value with a matching key, if the hash table contains such an
+ * entry, otherwise NULL is returned.
+ *
+ * Compared to get() the given match function is used to compare the keys
+ * for equality. The hash function does have to be deviced properly in
+ * order to make this work if the match function compares keys differently
+ * than the equals function provided to the constructor. This basically
+ * allows to enumerate all entries with the same hash value.
+ *
+ * @param key the key to match against
+ * @param match match function to be used when comparing keys
+ * @return the value, NULL if not found
+ */
+ void *(*get_match) (hashtable_t *this, void *key, hashtable_equals_t match);
+
+ /**
+ * Removes the value with the given key from the hash table and returns the
+ * removed value (or NULL if no such value existed).
+ *
+ * @param key the key of the value to remove
+ * @return the removed value, NULL if not found
+ */
+ void *(*remove) (hashtable_t *this, void *key);
+
+ /**
+ * Removes the key and value pair from the hash table at which the given
+ * enumerator currently points.
+ *
+ * @param enumerator enumerator, from create_enumerator
+ */
+ void (*remove_at) (hashtable_t *this, enumerator_t *enumerator);
+
+ /**
+ * Gets the number of items in the hash table.
+ *
+ * @return number of items
+ */
+ u_int (*get_count) (hashtable_t *this);
+
+ /**
+ * Destroys a hash table object.
+ */
+ void (*destroy) (hashtable_t *this);
+
+};
+
+/**
+ * Creates an empty hash table object.
+ *
+ * @param hash hash function
+ * @param equals equals function
+ * @param capacity initial capacity
+ * @return hashtable_t object.
+ */
+hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
+ u_int capacity);
+
+#endif /** HASHTABLE_H_ @}*/
diff --git a/src/libstrongswan/collections/linked_list.c b/src/libstrongswan/collections/linked_list.c
new file mode 100644
index 000000000..1ff80999b
--- /dev/null
+++ b/src/libstrongswan/collections/linked_list.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2007-2011 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 <stdarg.h>
+
+#include "linked_list.h"
+
+typedef struct element_t element_t;
+
+/**
+ * This element holds a pointer to the value it represents.
+ */
+struct element_t {
+
+ /**
+ * Value of a list item.
+ */
+ void *value;
+
+ /**
+ * Previous list element.
+ *
+ * NULL if first element in list.
+ */
+ element_t *previous;
+
+ /**
+ * Next list element.
+ *
+ * NULL if last element in list.
+ */
+ element_t *next;
+};
+
+/**
+ * Creates an empty linked list object.
+ */
+element_t *element_create(void *value)
+{
+ element_t *this;
+ INIT(this,
+ .value = value,
+ );
+ return this;
+}
+
+
+typedef struct private_linked_list_t private_linked_list_t;
+
+/**
+ * Private data of a linked_list_t object.
+ *
+ */
+struct private_linked_list_t {
+ /**
+ * Public part of linked list.
+ */
+ linked_list_t public;
+
+ /**
+ * Number of items in the list.
+ */
+ int count;
+
+ /**
+ * First element in list.
+ * NULL if no elements in list.
+ */
+ element_t *first;
+
+ /**
+ * Last element in list.
+ * NULL if no elements in list.
+ */
+ element_t *last;
+};
+
+typedef struct private_enumerator_t private_enumerator_t;
+
+/**
+ * linked lists enumerator implementation
+ */
+struct private_enumerator_t {
+
+ /**
+ * implements enumerator interface
+ */
+ enumerator_t enumerator;
+
+ /**
+ * associated linked list
+ */
+ private_linked_list_t *list;
+
+ /**
+ * current item
+ */
+ element_t *current;
+
+ /**
+ * enumerator has enumerated all items
+ */
+ bool finished;
+};
+
+METHOD(enumerator_t, enumerate, bool,
+ private_enumerator_t *this, void **item)
+{
+ if (this->finished)
+ {
+ return FALSE;
+ }
+ if (!this->current)
+ {
+ this->current = this->list->first;
+ }
+ else
+ {
+ this->current = this->current->next;
+ }
+ if (!this->current)
+ {
+ this->finished = TRUE;
+ return FALSE;
+ }
+ *item = this->current->value;
+ return TRUE;
+}
+
+METHOD(linked_list_t, create_enumerator, enumerator_t*,
+ private_linked_list_t *this)
+{
+ private_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .enumerator = {
+ .enumerate = (void*)_enumerate,
+ .destroy = (void*)free,
+ },
+ .list = this,
+ );
+
+ return &enumerator->enumerator;
+}
+
+METHOD(linked_list_t, reset_enumerator, void,
+ private_linked_list_t *this, private_enumerator_t *enumerator)
+{
+ enumerator->current = NULL;
+ enumerator->finished = FALSE;
+}
+
+METHOD(linked_list_t, has_more, bool,
+ private_linked_list_t *this, private_enumerator_t *enumerator)
+{
+ if (enumerator->current)
+ {
+ return enumerator->current->next != NULL;
+ }
+ return !enumerator->finished && this->first != NULL;
+}
+
+METHOD(linked_list_t, get_count, int,
+ private_linked_list_t *this)
+{
+ return this->count;
+}
+
+METHOD(linked_list_t, insert_first, void,
+ private_linked_list_t *this, void *item)
+{
+ element_t *element;
+
+ element = element_create(item);
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ }
+ else
+ {
+ element->next = this->first;
+ this->first->previous = element;
+ this->first = element;
+ }
+ this->count++;
+}
+
+/**
+ * unlink an element form the list, returns following element
+ */
+static element_t* remove_element(private_linked_list_t *this,
+ element_t *element)
+{
+ element_t *next, *previous;
+
+ next = element->next;
+ previous = element->previous;
+ free(element);
+ if (next)
+ {
+ next->previous = previous;
+ }
+ else
+ {
+ this->last = previous;
+ }
+ if (previous)
+ {
+ previous->next = next;
+ }
+ else
+ {
+ this->first = next;
+ }
+ if (--this->count == 0)
+ {
+ this->first = NULL;
+ this->last = NULL;
+ }
+ return next;
+}
+
+METHOD(linked_list_t, get_first, status_t,
+ private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+ *item = this->first->value;
+ return SUCCESS;
+}
+
+METHOD(linked_list_t, remove_first, status_t,
+ private_linked_list_t *this, void **item)
+{
+ if (get_first(this, item) == SUCCESS)
+ {
+ remove_element(this, this->first);
+ return SUCCESS;
+ }
+ return NOT_FOUND;
+}
+
+METHOD(linked_list_t, insert_last, void,
+ private_linked_list_t *this, void *item)
+{
+ element_t *element;
+
+ element = element_create(item);
+ if (this->count == 0)
+ {
+ /* first entry in list */
+ this->first = element;
+ this->last = element;
+ }
+ else
+ {
+ element->previous = this->last;
+ this->last->next = element;
+ this->last = element;
+ }
+ this->count++;
+}
+
+METHOD(linked_list_t, insert_before, void,
+ private_linked_list_t *this, private_enumerator_t *enumerator,
+ void *item)
+{
+ element_t *current, *element;
+
+ current = enumerator->current;
+ if (!current)
+ {
+ if (enumerator->finished)
+ {
+ this->public.insert_last(&this->public, item);
+ }
+ else
+ {
+ this->public.insert_first(&this->public, item);
+ }
+ return;
+ }
+ element = element_create(item);
+ if (current->previous)
+ {
+ current->previous->next = element;
+ element->previous = current->previous;
+ current->previous = element;
+ element->next = current;
+ }
+ else
+ {
+ current->previous = element;
+ element->next = current;
+ this->first = element;
+ }
+ this->count++;
+}
+
+METHOD(linked_list_t, replace, void*,
+ private_linked_list_t *this, private_enumerator_t *enumerator,
+ void *item)
+{
+ void *old = NULL;
+
+ if (enumerator->current)
+ {
+ old = enumerator->current->value;
+ enumerator->current->value = item;
+ }
+ return old;
+}
+
+METHOD(linked_list_t, get_last, status_t,
+ private_linked_list_t *this, void **item)
+{
+ if (this->count == 0)
+ {
+ return NOT_FOUND;
+ }
+ *item = this->last->value;
+ return SUCCESS;
+}
+
+METHOD(linked_list_t, remove_last, status_t,
+ private_linked_list_t *this, void **item)
+{
+ if (get_last(this, item) == SUCCESS)
+ {
+ remove_element(this, this->last);
+ return SUCCESS;
+ }
+ return NOT_FOUND;
+}
+
+METHOD(linked_list_t, remove_, int,
+ private_linked_list_t *this, void *item, bool (*compare)(void*,void*))
+{
+ element_t *current = this->first;
+ int removed = 0;
+
+ while (current)
+ {
+ if ((compare && compare(current->value, item)) ||
+ (!compare && current->value == item))
+ {
+ removed++;
+ current = remove_element(this, current);
+ }
+ else
+ {
+ current = current->next;
+ }
+ }
+ return removed;
+}
+
+METHOD(linked_list_t, remove_at, void,
+ private_linked_list_t *this, private_enumerator_t *enumerator)
+{
+ element_t *current;
+
+ if (enumerator->current)
+ {
+ current = enumerator->current;
+ enumerator->current = current->previous;
+ remove_element(this, current);
+ }
+}
+
+METHOD(linked_list_t, find_first, status_t,
+ private_linked_list_t *this, linked_list_match_t match,
+ void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
+{
+ element_t *current = this->first;
+
+ while (current)
+ {
+ if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
+ (!match && item && current->value == *item))
+ {
+ if (item != NULL)
+ {
+ *item = current->value;
+ }
+ return SUCCESS;
+ }
+ current = current->next;
+ }
+ return NOT_FOUND;
+}
+
+METHOD(linked_list_t, find_last, status_t,
+ private_linked_list_t *this, linked_list_match_t match,
+ void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
+{
+ element_t *current = this->last;
+
+ while (current)
+ {
+ if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
+ (!match && item && current->value == *item))
+ {
+ if (item != NULL)
+ {
+ *item = current->value;
+ }
+ return SUCCESS;
+ }
+ current = current->previous;
+ }
+ return NOT_FOUND;
+}
+
+METHOD(linked_list_t, invoke_offset, void,
+ private_linked_list_t *this, size_t offset,
+ void *d1, void *d2, void *d3, void *d4, void *d5)
+{
+ element_t *current = this->first;
+ linked_list_invoke_t *method;
+
+ while (current)
+ {
+ method = current->value + offset;
+ (*method)(current->value, d1, d2, d3, d4, d5);
+ current = current->next;
+ }
+}
+
+METHOD(linked_list_t, invoke_function, void,
+ private_linked_list_t *this, linked_list_invoke_t fn,
+ void *d1, void *d2, void *d3, void *d4, void *d5)
+{
+ element_t *current = this->first;
+
+ while (current)
+ {
+ fn(current->value, d1, d2, d3, d4, d5);
+ current = current->next;
+ }
+}
+
+METHOD(linked_list_t, clone_offset, linked_list_t*,
+ private_linked_list_t *this, size_t offset)
+{
+ element_t *current = this->first;
+ linked_list_t *clone;
+
+ clone = linked_list_create();
+ while (current)
+ {
+ void* (**method)(void*) = current->value + offset;
+ clone->insert_last(clone, (*method)(current->value));
+ current = current->next;
+ }
+
+ return clone;
+}
+
+METHOD(linked_list_t, clone_function, linked_list_t*,
+ private_linked_list_t *this, void* (*fn)(void*))
+{
+ element_t *current = this->first;
+ linked_list_t *clone;
+
+ clone = linked_list_create();
+ while (current)
+ {
+ clone->insert_last(clone, fn(current->value));
+ current = current->next;
+ }
+ return clone;
+}
+
+METHOD(linked_list_t, destroy, void,
+ private_linked_list_t *this)
+{
+ void *value;
+
+ /* Remove all list items before destroying list */
+ while (remove_first(this, &value) == SUCCESS)
+ {
+ /* values are not destroyed so memory leaks are possible
+ * if list is not empty when deleting */
+ }
+ free(this);
+}
+
+METHOD(linked_list_t, destroy_offset, void,
+ private_linked_list_t *this, size_t offset)
+{
+ element_t *current = this->first, *next;
+
+ while (current)
+ {
+ void (**method)(void*) = current->value + offset;
+ (*method)(current->value);
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ free(this);
+}
+
+METHOD(linked_list_t, destroy_function, void,
+ private_linked_list_t *this, void (*fn)(void*))
+{
+ element_t *current = this->first, *next;
+
+ while (current)
+ {
+ fn(current->value);
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+linked_list_t *linked_list_create()
+{
+ private_linked_list_t *this;
+
+ INIT(this,
+ .public = {
+ .get_count = _get_count,
+ .create_enumerator = _create_enumerator,
+ .reset_enumerator = (void*)_reset_enumerator,
+ .has_more = (void*)_has_more,
+ .get_first = _get_first,
+ .get_last = _get_last,
+ .find_first = (void*)_find_first,
+ .find_last = (void*)_find_last,
+ .insert_first = _insert_first,
+ .insert_last = _insert_last,
+ .insert_before = (void*)_insert_before,
+ .replace = (void*)_replace,
+ .remove_first = _remove_first,
+ .remove_last = _remove_last,
+ .remove = _remove_,
+ .remove_at = (void*)_remove_at,
+ .invoke_offset = (void*)_invoke_offset,
+ .invoke_function = (void*)_invoke_function,
+ .clone_offset = _clone_offset,
+ .clone_function = _clone_function,
+ .destroy = _destroy,
+ .destroy_offset = _destroy_offset,
+ .destroy_function = _destroy_function,
+ },
+ );
+
+ return &this->public;
+}
+
+/*
+ * See header.
+ */
+linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator)
+{
+ linked_list_t *list;
+ void *item;
+
+ list = linked_list_create();
+
+ while (enumerator->enumerate(enumerator, &item))
+ {
+ list->insert_last(list, item);
+ }
+ enumerator->destroy(enumerator);
+
+ return list;
+}
+
+/*
+ * See header.
+ */
+linked_list_t *linked_list_create_with_items(void *item, ...)
+{
+ linked_list_t *list;
+ va_list args;
+
+ list = linked_list_create();
+
+ va_start(args, item);
+ while (item)
+ {
+ list->insert_last(list, item);
+ item = va_arg(args, void*);
+ }
+ va_end(args);
+
+ return list;
+}
diff --git a/src/libstrongswan/collections/linked_list.h b/src/libstrongswan/collections/linked_list.h
new file mode 100644
index 000000000..da539a231
--- /dev/null
+++ b/src/libstrongswan/collections/linked_list.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2007-2011 Tobias Brunner
+ * Copyright (C) 2005-2008 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 linked_list linked_list
+ * @{ @ingroup collections
+ */
+
+#ifndef LINKED_LIST_H_
+#define LINKED_LIST_H_
+
+typedef struct linked_list_t linked_list_t;
+
+#include <collections/enumerator.h>
+
+/**
+ * Method to match elements in a linked list (used in find_* functions)
+ *
+ * @param item current list item
+ * @param ... user supplied data (only pointers, at most 5)
+ * @return
+ * - TRUE, if the item matched
+ * - FALSE, otherwise
+ */
+typedef bool (*linked_list_match_t)(void *item, ...);
+
+/**
+ * Method to be invoked on elements in a linked list (used in invoke_* functions)
+ *
+ * @param item current list item
+ * @param ... user supplied data (only pointers, at most 5)
+ */
+typedef void (*linked_list_invoke_t)(void *item, ...);
+
+/**
+ * Class implementing a double linked list.
+ *
+ * General purpose linked list. This list is not synchronized.
+ */
+struct linked_list_t {
+
+ /**
+ * Gets the count of items in the list.
+ *
+ * @return number of items in list
+ */
+ int (*get_count) (linked_list_t *this);
+
+ /**
+ * Create an enumerator over the list.
+ *
+ * @note The enumerator's position is invalid before the first call
+ * to enumerate().
+ *
+ * @return enumerator over list items
+ */
+ enumerator_t* (*create_enumerator)(linked_list_t *this);
+
+ /**
+ * Resets the enumerator's current position to the beginning of the list.
+ *
+ * @param enumerator enumerator to reset
+ */
+ void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator);
+
+ /**
+ * Checks if there are more elements following after the enumerator's
+ * current position.
+ *
+ * @param enumerator enumerator to check
+ */
+ bool (*has_more)(linked_list_t *this, enumerator_t *enumerator);
+
+ /**
+ * Inserts a new item at the beginning of the list.
+ *
+ * @param item item value to insert in list
+ */
+ void (*insert_first) (linked_list_t *this, void *item);
+
+ /**
+ * Removes the first item in the list and returns its value.
+ *
+ * @param item returned value of first item, or NULL
+ * @return SUCCESS, or NOT_FOUND if list is empty
+ */
+ status_t (*remove_first) (linked_list_t *this, void **item);
+
+ /**
+ * Inserts a new item before the item the enumerator currently points to.
+ *
+ * If this method is called before starting the enumeration the item is
+ * inserted first. If it is called after all items have been enumerated
+ * the item is inserted last. This is helpful when inserting items into
+ * a sorted list.
+ *
+ * @note The position of the enumerator is not changed.
+ *
+ * @param enumerator enumerator with position
+ * @param item item value to insert in list
+ */
+ void (*insert_before)(linked_list_t *this, enumerator_t *enumerator,
+ void *item);
+
+ /**
+ * Replaces the item the enumerator currently points to with the given item.
+ *
+ * @param enumerator enumerator with position
+ * @param item item value to replace current item with
+ * @return current item or NULL if the enumerator is at an
+ * invalid position
+ */
+ void *(*replace)(linked_list_t *this, enumerator_t *enumerator, void *item);
+
+ /**
+ * Remove an item from the list where the enumerator points to.
+ *
+ * @param enumerator enumerator with position
+ */
+ void (*remove_at)(linked_list_t *this, enumerator_t *enumerator);
+
+ /**
+ * Remove items from the list matching the given item.
+ *
+ * If a compare function is given, it is called for each item, with the
+ * first parameter being the current list item and the second parameter
+ * being the supplied item. Return TRUE from the compare function to remove
+ * the item, return FALSE to keep it in the list.
+ *
+ * If compare is NULL, comparison is done by pointers.
+ *
+ * @param item item to remove/pass to comparator
+ * @param compare compare function, or NULL
+ * @return number of removed items
+ */
+ int (*remove)(linked_list_t *this, void *item, bool (*compare)(void*,void*));
+
+ /**
+ * Returns the value of the first list item without removing it.
+ *
+ * @param item returned value of first item
+ * @return SUCCESS, NOT_FOUND if list is empty
+ */
+ status_t (*get_first) (linked_list_t *this, void **item);
+
+ /**
+ * Inserts a new item at the end of the list.
+ *
+ * @param item value to insert into list
+ */
+ void (*insert_last) (linked_list_t *this, void *item);
+
+ /**
+ * Removes the last item in the list and returns its value.
+ *
+ * @param item returned value of last item, or NULL
+ * @return SUCCESS, NOT_FOUND if list is empty
+ */
+ status_t (*remove_last) (linked_list_t *this, void **item);
+
+ /**
+ * Returns the value of the last list item without removing it.
+ *
+ * @param item returned value of last item
+ * @return SUCCESS, NOT_FOUND if list is empty
+ */
+ status_t (*get_last) (linked_list_t *this, void **item);
+
+ /** Find the first matching element in the list.
+ *
+ * The first object passed to the match function is the current list item,
+ * followed by the user supplied data.
+ * If the supplied function returns TRUE this function returns SUCCESS, and
+ * the current object is returned in the third parameter, otherwise,
+ * the next item is checked.
+ *
+ * If match is NULL, *item and the current object are compared.
+ *
+ * @warning Only use pointers as user supplied data.
+ *
+ * @param match comparison function to call on each object, or NULL
+ * @param item the list item, if found
+ * @param ... user data to supply to match function (limited to 5 arguments)
+ * @return SUCCESS if found, NOT_FOUND otherwise
+ */
+ status_t (*find_first) (linked_list_t *this, linked_list_match_t match,
+ void **item, ...);
+
+ /** Find the last matching element in the list.
+ *
+ * The first object passed to the match function is the current list item,
+ * followed by the user supplied data.
+ * If the supplied function returns TRUE this function returns SUCCESS, and
+ * the current object is returned in the third parameter, otherwise,
+ * the next item is checked.
+ *
+ * If match is NULL, *item and the current object are compared.
+ *
+ * @warning Only use pointers as user supplied data.
+ *
+ * @param match comparison function to call on each object, or NULL
+ * @param item the list item, if found
+ * @param ... user data to supply to match function (limited to 5 arguments)
+ * @return SUCCESS if found, NOT_FOUND otherwise
+ */
+ status_t (*find_last) (linked_list_t *this, linked_list_match_t match,
+ void **item, ...);
+
+ /**
+ * Invoke a method on all of the contained objects.
+ *
+ * If a linked list contains objects with function pointers,
+ * invoke() can call a method on each of the objects. The
+ * method is specified by an offset of the function pointer,
+ * which can be evalutated at compile time using the offsetof
+ * macro, e.g.: list->invoke(list, offsetof(object_t, method));
+ *
+ * @warning Only use pointers as user supplied data.
+ *
+ * @param offset offset of the method to invoke on objects
+ * @param ... user data to supply to called function (limited to 5 arguments)
+ */
+ void (*invoke_offset) (linked_list_t *this, size_t offset, ...);
+
+ /**
+ * Invoke a function on all of the contained objects.
+ *
+ * @warning Only use pointers as user supplied data.
+ *
+ * @param function offset of the method to invoke on objects
+ * @param ... user data to supply to called function (limited to 5 arguments)
+ */
+ void (*invoke_function) (linked_list_t *this, linked_list_invoke_t function, ...);
+
+ /**
+ * Clones a list and its objects using the objects' clone method.
+ *
+ * @param offset offset ot the objects clone function
+ * @return cloned list
+ */
+ linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset);
+
+ /**
+ * Clones a list and its objects using a given function.
+ *
+ * @param function function that clones an object
+ * @return cloned list
+ */
+ linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*));
+
+ /**
+ * Destroys a linked_list object.
+ */
+ void (*destroy) (linked_list_t *this);
+
+ /**
+ * Destroys a list and its objects using the destructor.
+ *
+ * If a linked list and the contained objects should be destroyed, use
+ * destroy_offset. The supplied offset specifies the destructor to
+ * call on each object. The offset may be calculated using the offsetof
+ * macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy));
+ *
+ * @param offset offset of the objects destructor
+ */
+ void (*destroy_offset) (linked_list_t *this, size_t offset);
+
+ /**
+ * Destroys a list and its contents using a a cleanup function.
+ *
+ * If a linked list and its contents should get destroyed using a specific
+ * cleanup function, use destroy_function. This is useful when the
+ * list contains malloc()-ed blocks which should get freed,
+ * e.g.: list->destroy_function(list, free);
+ *
+ * @param function function to call on each object
+ */
+ void (*destroy_function) (linked_list_t *this, void (*)(void*));
+};
+
+/**
+ * Creates an empty linked list object.
+ *
+ * @return linked_list_t object.
+ */
+linked_list_t *linked_list_create(void);
+
+/**
+ * Creates a linked list from an enumerator.
+ *
+ * @param enumerator enumerator over void*, gets destroyed
+ * @return linked_list_t object, containing enumerated values
+ */
+linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator);
+
+/**
+ * Creates a linked list from a NULL terminated vararg list of items.
+ *
+ * @param first first item
+ * @param ... subsequent items, terminated by NULL
+ * @return linked_list_t object, containing passed items
+ */
+linked_list_t *linked_list_create_with_items(void *first, ...);
+
+#endif /** LINKED_LIST_H_ @}*/