summaryrefslogtreecommitdiff
path: root/src/libstrongswan/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/collections')
-rw-r--r--src/libstrongswan/collections/array.c416
-rw-r--r--src/libstrongswan/collections/array.h195
-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.c550
-rw-r--r--src/libstrongswan/collections/enumerator.h159
-rw-r--r--src/libstrongswan/collections/hashtable.c476
-rw-r--r--src/libstrongswan/collections/hashtable.h171
-rw-r--r--src/libstrongswan/collections/linked_list.c553
-rw-r--r--src/libstrongswan/collections/linked_list.h274
10 files changed, 3020 insertions, 0 deletions
diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c
new file mode 100644
index 000000000..387e2a57d
--- /dev/null
+++ b/src/libstrongswan/collections/array.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 "array.h"
+
+/**
+ * Data is an allocated block, with potentially unused head and tail:
+ *
+ * "esize" each (or sizeof(void*) if esize = 0)
+ * /-\ /-\ /-\ /-\ /-\ /-\
+ *
+ * +---------------+-------------------------------+---------------+
+ * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l |
+ * +---------------+-------------------------------+---------------+
+ *
+ * \--------------/ \-----------------------------/ \-------------/
+ * unused used unused
+ * "head" "count" "tail"
+ *
+ */
+struct array_t {
+ /** number of elements currently in array (not counting head/tail) */
+ u_int32_t count;
+ /** size of each element, 0 for a pointer based array */
+ u_int16_t esize;
+ /** allocated but unused elements at array front */
+ u_int8_t head;
+ /** allocated but unused elements at array end */
+ u_int8_t tail;
+ /** array elements */
+ void *data;
+};
+
+/** maximum number of unused head/tail elements before cleanup */
+#define ARRAY_MAX_UNUSED 32
+
+/**
+ * Get the actual size of a number of elements
+ */
+static size_t get_size(array_t *array, u_int32_t num)
+{
+ if (array->esize)
+ {
+ return array->esize * num;
+ }
+ return sizeof(void*) * num;
+}
+
+/**
+ * Increase allocated but unused tail room to at least "room"
+ */
+static void make_tail_room(array_t *array, u_int8_t room)
+{
+ if (array->tail < room)
+ {
+ array->data = realloc(array->data,
+ get_size(array, array->count + array->head + room));
+ array->tail = room;
+ }
+}
+
+/**
+ * Increase allocated but unused head room to at least "room"
+ */
+static void make_head_room(array_t *array, u_int8_t room)
+{
+ if (array->head < room)
+ {
+ u_int8_t increase = room - array->head;
+
+ array->data = realloc(array->data,
+ get_size(array, array->count + array->tail + room));
+ memmove(array->data + get_size(array, increase), array->data,
+ get_size(array, array->count + array->tail + array->head));
+ array->head = room;
+ }
+}
+
+/**
+ * Make space for an item at index using tail room
+ */
+static void insert_tail(array_t *array, int idx)
+{
+ make_tail_room(array, 1);
+ /* move up all elements after idx by one */
+ memmove(array->data + get_size(array, array->head + idx + 1),
+ array->data + get_size(array, array->head + idx),
+ get_size(array, array->count - idx));
+
+ array->tail--;
+ array->count++;
+}
+
+/**
+ * Make space for an item at index using head room
+ */
+static void insert_head(array_t *array, int idx)
+{
+ make_head_room(array, 1);
+ /* move down all elements before idx by one */
+ memmove(array->data + get_size(array, array->head - 1),
+ array->data + get_size(array, array->head),
+ get_size(array, idx));
+
+ array->head--;
+ array->count++;
+}
+
+/**
+ * Remove an item, increase tail
+ */
+static void remove_tail(array_t *array, int idx)
+{
+ /* move all items after idx one down */
+ memmove(array->data + get_size(array, idx + array->head),
+ array->data + get_size(array, idx + array->head + 1),
+ get_size(array, array->count - idx));
+ array->count--;
+ array->tail++;
+}
+
+/**
+ * Remove an item, increase head
+ */
+static void remove_head(array_t *array, int idx)
+{
+ /* move all items before idx one up */
+ memmove(array->data + get_size(array, array->head + 1),
+ array->data + get_size(array, array->head), get_size(array, idx));
+ array->count--;
+ array->head++;
+}
+
+array_t *array_create(u_int esize, u_int8_t reserve)
+{
+ array_t *array;
+
+ INIT(array,
+ .esize = esize,
+ .tail = reserve,
+ );
+ if (array->tail)
+ {
+ array->data = malloc(array->tail * array->esize);
+ }
+ return array;
+}
+
+int array_count(array_t *array)
+{
+ if (array)
+ {
+ return array->count;
+ }
+ return 0;
+}
+
+void array_compress(array_t *array)
+{
+ if (array)
+ {
+ u_int32_t tail;
+
+ tail = array->tail;
+ if (array->head)
+ {
+ memmove(array->data, array->data + get_size(array, array->head),
+ get_size(array, array->count + array->tail));
+ tail += array->head;
+ array->head = 0;
+ }
+ if (tail)
+ {
+ array->data = realloc(array->data, get_size(array, array->count));
+ array->tail = 0;
+ }
+ }
+}
+
+typedef struct {
+ /** public enumerator interface */
+ enumerator_t public;
+ /** enumerated array */
+ array_t *array;
+ /** current index +1, initialized at 0 */
+ int idx;
+} array_enumerator_t;
+
+METHOD(enumerator_t, enumerate, bool,
+ array_enumerator_t *this, void **out)
+{
+ void *pos;
+
+ if (this->idx >= this->array->count)
+ {
+ return FALSE;
+ }
+
+ pos = this->array->data +
+ get_size(this->array, this->idx + this->array->head);
+ if (this->array->esize)
+ {
+ /* for element based arrays we return a pointer to the element */
+ *out = pos;
+ }
+ else
+ {
+ /* for pointer based arrays we return the pointer directly */
+ *out = *(void**)pos;
+ }
+ this->idx++;
+ return TRUE;
+}
+
+enumerator_t* array_create_enumerator(array_t *array)
+{
+ array_enumerator_t *enumerator;
+
+ if (!array)
+ {
+ return enumerator_create_empty();
+ }
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_enumerate,
+ .destroy = (void*)free,
+ },
+ .array = array,
+ );
+ return &enumerator->public;
+}
+
+void array_remove_at(array_t *array, enumerator_t *public)
+{
+ array_enumerator_t *enumerator = (array_enumerator_t*)public;
+
+ if (enumerator->idx)
+ {
+ array_remove(array, --enumerator->idx, NULL);
+ }
+}
+
+void array_insert_create(array_t **array, int idx, void *ptr)
+{
+ if (*array == NULL)
+ {
+ *array = array_create(0, 0);
+ }
+ array_insert(*array, idx, ptr);
+}
+
+void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator)
+{
+ void *ptr;
+
+ while (enumerator->enumerate(enumerator, &ptr))
+ {
+ array_insert(array, idx, ptr);
+ }
+ enumerator->destroy(enumerator);
+}
+
+void array_insert(array_t *array, int idx, void *data)
+{
+ if (idx < 0 || idx <= array_count(array))
+ {
+ void *pos;
+
+ if (idx < 0)
+ {
+ idx = array_count(array);
+ }
+
+ if (array->head && !array->tail)
+ {
+ insert_head(array, idx);
+ }
+ else if (array->tail && !array->head)
+ {
+ insert_tail(array, idx);
+ }
+ else if (idx > array_count(array) / 2)
+ {
+ insert_tail(array, idx);
+ }
+ else
+ {
+ insert_head(array, idx);
+ }
+
+ pos = array->data + get_size(array, array->head + idx);
+ if (array->esize)
+ {
+ memcpy(pos, data, get_size(array, 1));
+ }
+ else
+ {
+ /* pointer based array, copy pointer value */
+ *(void**)pos = data;
+ }
+ }
+}
+
+bool array_remove(array_t *array, int idx, void *data)
+{
+ if (!array)
+ {
+ return FALSE;
+ }
+ if (idx >= 0 && idx >= array_count(array))
+ {
+ return FALSE;
+ }
+ if (idx < 0)
+ {
+ if (array_count(array) == 0)
+ {
+ return FALSE;
+ }
+ idx = array_count(array) - 1;
+ }
+ if (data)
+ {
+ memcpy(data, array->data + get_size(array, array->head + idx),
+ get_size(array, 1));
+ }
+ if (idx > array_count(array) / 2)
+ {
+ remove_tail(array, idx);
+ }
+ else
+ {
+ remove_head(array, idx);
+ }
+ if (array->head + array->tail > ARRAY_MAX_UNUSED)
+ {
+ array_compress(array);
+ }
+ return TRUE;
+}
+
+void array_invoke(array_t *array, array_callback_t cb, void *user)
+{
+ if (array)
+ {
+ void *obj;
+ int i;
+
+ for (i = array->head; i < array->count + array->head; i++)
+ {
+ obj = array->data + get_size(array, i);
+ if (!array->esize)
+ {
+ /* dereference if we store store pointers */
+ obj = *(void**)obj;
+ }
+ cb(obj, i - array->head, user);
+ }
+ }
+}
+
+void array_invoke_offset(array_t *array, size_t offset)
+{
+ if (array)
+ {
+ void (*method)(void *data);
+ void *obj;
+ int i;
+
+ for (i = array->head; i < array->count + array->head; i++)
+ {
+ obj = array->data + get_size(array, i);
+ if (!array->esize)
+ {
+ /* dereference if we store store pointers */
+ obj = *(void**)obj;
+ }
+ method = *(void**)(obj + offset);
+ method(obj);
+ }
+ }
+}
+
+void array_destroy(array_t *array)
+{
+ if (array)
+ {
+ free(array->data);
+ free(array);
+ }
+}
+
+void array_destroy_function(array_t *array, array_callback_t cb, void *user)
+{
+ array_invoke(array, cb, user);
+ array_destroy(array);
+}
+
+void array_destroy_offset(array_t *array, size_t offset)
+{
+ array_invoke_offset(array, offset);
+ array_destroy(array);
+}
diff --git a/src/libstrongswan/collections/array.h b/src/libstrongswan/collections/array.h
new file mode 100644
index 000000000..0dc7b2250
--- /dev/null
+++ b/src/libstrongswan/collections/array.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * 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 array array
+ * @{ @ingroup collections
+ */
+
+#ifndef ARRAY_H_
+#define ARRAY_H_
+
+#include <collections/enumerator.h>
+
+/**
+ * Variable sized array with fixed size elements.
+ *
+ * An array is a primitive object with associated functions to avoid the
+ * overhead of an object with methods. It is efficient in memory usage, but
+ * less efficient than a linked list in manipulating elements.
+ */
+typedef struct array_t array_t;
+
+typedef enum array_idx_t array_idx_t;
+
+/**
+ * Special array index values for insert/remove.
+ */
+enum array_idx_t {
+ ARRAY_HEAD = 0,
+ ARRAY_TAIL = -1,
+};
+
+/**
+ * Callback function invoked for each array element.
+ *
+ * Data is a pointer to the array element. If this is a pointer based array,
+ * (esize is zero), data is the pointer itself.
+ *
+ * @param data pointer to array data, or the pointer itself
+ * @param idx array index
+ * @param user user data passed with callback
+ */
+typedef void (*array_callback_t)(void *data, int idx, void *user);
+
+/**
+ * Create a array instance.
+ *
+ * Elements get tight packed to each other. If any alignment is required, pass
+ * appropriate padding to each element. The reserved space does not affect
+ * array_count(), but just preallocates buffer space.
+ *
+ * @param esize element size for this array, use 0 for a pointer array
+ * @param reserve number of items to allocate space for
+ * @return array instance
+ */
+array_t *array_create(u_int esize, u_int8_t reserve);
+
+/**
+ * Get the number of elements currently in the array.
+ *
+ * @return number of elements
+ */
+int array_count(array_t *array);
+
+/**
+ * Compress an array, remove unused head/tail space.
+ *
+ * @param array array to compress, or NULL
+ */
+void array_compress(array_t *array);
+
+/**
+ * Create an enumerator over an array.
+ *
+ * The enumerater enumerates directly over the array element (pass a pointer to
+ * element types), unless the array is pointer based. If zero is passed as
+ * element size during construction, the enumerator enumerates over the
+ * deferenced pointer values.
+ *
+ * @param array array to create enumerator for, or NULL
+ * @return enumerator, over elements or pointers
+ */
+enumerator_t* array_create_enumerator(array_t *array);
+
+/**
+ * Remove an element at enumerator position.
+ *
+ * @param array array to remove element in
+ * @param enumerator enumerator position, from array_create_enumerator()
+ */
+void array_remove_at(array_t *array, enumerator_t *enumerator);
+
+/**
+ * Insert an element to an array.
+ *
+ * If the array is pointer based (esize = 0), the pointer itself is appended.
+ * Otherwise the element gets copied from the pointer.
+ * The idx must be either within array_count() or one above to append the item.
+ * Passing -1 has the same effect as passing array_count(), i.e. appends the
+ * item. It is always valid to pass idx 0 to prepend the item.
+ *
+ * @param array array to append element to
+ * @param idx index to insert item at
+ * @param data pointer to array element to copy
+ */
+void array_insert(array_t *array, int idx, void *data);
+
+/**
+ * Create an pointer based array if it does not exist, insert pointer.
+ *
+ * This is a convenience function for insert a pointer and implicitly
+ * create a pointer based array if array is NULL. Array is set the the newly
+ * created array, if any.
+ *
+ * @param array pointer to array reference, potentially NULL
+ * @param idx index to insert item at
+ * @param ptr pointer to append
+ */
+void array_insert_create(array_t **array, int idx, void *ptr);
+
+/**
+ * Insert all items from an enumerator to an array.
+ *
+ * @param array array to add items to
+ * @param idx index to insert each item with
+ * @param enumerator enumerator over void*, gets destroyed
+ */
+void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator);
+
+/**
+ * Remove an element from the array.
+ *
+ * If data is given, the element is copied to that position.
+ *
+ * @param array array to remove element from, or NULL
+ * @param idx index of the item to remove
+ * @param data data to copy element to, or NULL
+ * @return TRUE if idx existed and item removed
+ */
+bool array_remove(array_t *array, int idx, void *data);
+
+/**
+ * Invoke a callback for all array members.
+ *
+ * @param array array to traverse, or NULL
+ * @param cb callback function to invoke each element with
+ * @param user user data to pass to callback
+ */
+void array_invoke(array_t *array, array_callback_t cb, void *user);
+
+/**
+ * Invoke a method of each element defined with offset.
+ *
+ * @param array array to traverse, or NULL
+ * @param offset offset of element method, use offsetof()
+ */
+void array_invoke_offset(array_t *array, size_t offset);
+
+/**
+ * Destroy an array.
+ *
+ * @param array array to destroy, or NULL
+ */
+void array_destroy(array_t *array);
+
+/**
+ * Destroy an array, call a function to clean up all elements.
+ *
+ * @param array array to destroy, or NULL
+ * @param cb callback function to free element data
+ * @param user user data to pass to callback
+ */
+void array_destroy_function(array_t *array, array_callback_t cb, void *user);
+
+/**
+ * Destroy an array, call element method defined with offset.
+ *
+ * @param array array to destroy, or NULL
+ * @param offset offset of element method, use offsetof()
+ */
+void array_destroy_offset(array_t *array, size_t offset);
+
+#endif /** ARRAY_H_ @}*/
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..8049ac016
--- /dev/null
+++ b/src/libstrongswan/collections/enumerator.c
@@ -0,0 +1,550 @@
+/*
+ * 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 */
+ pos--;
+ while (pos >= *token)
+ {
+ trim = this->trim;
+ while (*trim)
+ {
+ if (*trim == *pos)
+ {
+ *(pos--) = '\0';
+ break;
+ }
+ trim++;
+ }
+ if (!*trim)
+ {
+ 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..1003aa0fa
--- /dev/null
+++ b/src/libstrongswan/collections/hashtable.c
@@ -0,0 +1,476 @@
+/*
+ * 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"
+
+#include <utils/chunk.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;
+};
+
+/*
+ * See header.
+ */
+u_int hashtable_hash_ptr(void *key)
+{
+ return chunk_hash(chunk_from_thing(key));
+}
+
+/*
+ * See header.
+ */
+u_int hashtable_hash_str(void *key)
+{
+ return chunk_hash(chunk_from_str((char*)key));
+}
+
+/*
+ * See header.
+ */
+bool hashtable_equals_ptr(void *key, void *other_key)
+{
+ return key == other_key;
+}
+
+/*
+ * See header.
+ */
+bool hashtable_equals_str(void *key, void *other_key)
+{
+ return streq(key, other_key);
+}
+
+/**
+ * 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..520a86c90
--- /dev/null
+++ b/src/libstrongswan/collections/hashtable.h
@@ -0,0 +1,171 @@
+/*
+ * 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);
+
+/**
+ * Hashtable hash function calculation the hash solely based on the key pointer.
+ *
+ * @param key key to hash
+ * @return hash of key
+ */
+u_int hashtable_hash_ptr(void *key);
+
+/**
+ * Hashtable hash function calculation the hash for char* keys.
+ *
+ * @param key key to hash, a char*
+ * @return hash of key
+ */
+u_int hashtable_hash_str(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);
+
+/**
+ * Hashtable equals function comparing pointers.
+ *
+ * @param key key to compare
+ * @param other_key other key to compare
+ * @return TRUE if key == other_key
+ */
+bool hashtable_equals_ptr(void *key, void *other_key);
+
+/**
+ * Hashtable equals function comparing char* keys.
+ *
+ * @param key key to compare
+ * @param other_key other key to compare
+ * @return TRUE if streq(key, other_key)
+ */
+bool hashtable_equals_str(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..a176e5a54
--- /dev/null
+++ b/src/libstrongswan/collections/linked_list.c
@@ -0,0 +1,553 @@
+/*
+ * 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;
+ }
+ if (item)
+ {
+ *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, 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, 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, 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, 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,
+ .get_first = _get_first,
+ .get_last = _get_last,
+ .find_first = (void*)_find_first,
+ .insert_first = _insert_first,
+ .insert_last = _insert_last,
+ .insert_before = (void*)_insert_before,
+ .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,
+ .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..abc33c12a
--- /dev/null
+++ b/src/libstrongswan/collections/linked_list.h
@@ -0,0 +1,274 @@
+/*
+ * 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);
+
+ /**
+ * 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);
+
+ /**
+ * 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, ...);
+
+ /**
+ * 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);
+
+ /**
+ * 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_ @}*/