Merge branch 'array'
authorMartin Willi <martin@revosec.ch>
Wed, 17 Jul 2013 15:28:18 +0000 (17:28 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 17 Jul 2013 15:28:18 +0000 (17:28 +0200)
Introduces a new lightweight array collection having minimal memory overhead.
The new class replaces various linked lists that are used during the full
lifetime of an SA, reducing memory requirements by about 5KB or more per tunnel.

24 files changed:
src/libcharon/config/proposal.c
src/libcharon/plugins/farp/farp_listener.c
src/libcharon/plugins/ha/ha_child.c
src/libcharon/plugins/smp/smp.c
src/libcharon/plugins/stroke/stroke_list.c
src/libcharon/plugins/uci/uci_control.c
src/libcharon/sa/child_sa.c
src/libcharon/sa/child_sa.h
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ikev1/task_manager_v1.c
src/libcharon/sa/ikev1/tasks/quick_delete.c
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev2/task_manager_v2.c
src/libcharon/sa/ikev2/tasks/child_create.c
src/libcharon/sa/ikev2/tasks/child_delete.c
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/collections/array.c [new file with mode: 0644]
src/libstrongswan/collections/array.h [new file with mode: 0644]
src/libstrongswan/credentials/auth_cfg.c
src/libstrongswan/tests/Makefile.am
src/libstrongswan/tests/test_array.c [new file with mode: 0644]
src/libstrongswan/tests/test_runner.c
src/libstrongswan/tests/test_runner.h

index 4803c7b..a927a1f 100644 (file)
@@ -19,7 +19,7 @@
 #include "proposal.h"
 
 #include <daemon.h>
-#include <collections/linked_list.h>
+#include <collections/array.h>
 #include <utils/identification.h>
 
 #include <crypto/transform.h>
@@ -36,7 +36,6 @@ ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
 );
 
 typedef struct private_proposal_t private_proposal_t;
-typedef struct algorithm_t algorithm_t;
 
 /**
  * Private data of an proposal_t object
@@ -54,29 +53,9 @@ struct private_proposal_t {
        protocol_id_t protocol;
 
        /**
-        * priority ordered list of encryption algorithms
+        * Priority ordered list of transforms, as entry_t
         */
-       linked_list_t *encryption_algos;
-
-       /**
-        * priority ordered list of integrity algorithms
-        */
-       linked_list_t *integrity_algos;
-
-       /**
-        * priority ordered list of pseudo random functions
-        */
-       linked_list_t *prf_algos;
-
-       /**
-        * priority ordered list of dh groups
-        */
-       linked_list_t *dh_groups;
-
-       /**
-        * priority ordered list of extended sequence number flags
-        */
-       linked_list_t *esns;
+       array_t *transforms;
 
        /**
         * senders SPI
@@ -92,68 +71,47 @@ struct private_proposal_t {
 /**
  * Struct used to store different kinds of algorithms.
  */
-struct algorithm_t {
-       /**
-        * Value from an encryption_algorithm_t/integrity_algorithm_t/...
-        */
-       u_int16_t algorithm;
-
-       /**
-        * the associated key size in bits, or zero if not needed
-        */
+typedef struct {
+       /** Type of the transform */
+       transform_type_t type;
+       /** algorithm identifier */
+       u_int16_t alg;
+       /** key size in bits, or zero if not needed */
        u_int16_t key_size;
-};
-
-/**
- * Add algorithm/keysize to a algorithm list
- */
-static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size)
-{
-       algorithm_t *algo_key;
-
-       algo_key = malloc_thing(algorithm_t);
-       algo_key->algorithm = algo;
-       algo_key->key_size = key_size;
-       list->insert_last(list, (void*)algo_key);
-}
+} entry_t;
 
 METHOD(proposal_t, add_algorithm, void,
        private_proposal_t *this, transform_type_t type,
-       u_int16_t algo, u_int16_t key_size)
+       u_int16_t alg, u_int16_t key_size)
 {
-       switch (type)
-       {
-               case ENCRYPTION_ALGORITHM:
-                       add_algo(this->encryption_algos, algo, key_size);
-                       break;
-               case INTEGRITY_ALGORITHM:
-                       add_algo(this->integrity_algos, algo, key_size);
-                       break;
-               case PSEUDO_RANDOM_FUNCTION:
-                       add_algo(this->prf_algos, algo, key_size);
-                       break;
-               case DIFFIE_HELLMAN_GROUP:
-                       add_algo(this->dh_groups, algo, 0);
-                       break;
-               case EXTENDED_SEQUENCE_NUMBERS:
-                       add_algo(this->esns, algo, 0);
-                       break;
-               default:
-                       break;
-       }
+       entry_t entry = {
+               .type = type,
+               .alg = alg,
+               .key_size = key_size,
+       };
+
+       array_insert(this->transforms, ARRAY_TAIL, &entry);
 }
 
 /**
  * filter function for peer configs
  */
-static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
+static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg,
                                           void **unused, u_int16_t *key_size)
 {
-       algorithm_t *algo = *in;
-       *alg = algo->algorithm;
+       entry_t *entry = *in;
+
+       if (entry->type != type)
+       {
+               return FALSE;
+       }
+       if (alg)
+       {
+               *alg = entry->alg;
+       }
        if (key_size)
        {
-               *key_size = algo->key_size;
+               *key_size = entry->key_size;
        }
        return TRUE;
 }
@@ -161,30 +119,9 @@ static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
 METHOD(proposal_t, create_enumerator, enumerator_t*,
        private_proposal_t *this, transform_type_t type)
 {
-       linked_list_t *list;
-
-       switch (type)
-       {
-               case ENCRYPTION_ALGORITHM:
-                       list = this->encryption_algos;
-                       break;
-               case INTEGRITY_ALGORITHM:
-                       list = this->integrity_algos;
-                       break;
-               case PSEUDO_RANDOM_FUNCTION:
-                       list = this->prf_algos;
-                       break;
-               case DIFFIE_HELLMAN_GROUP:
-                       list = this->dh_groups;
-                       break;
-               case EXTENDED_SEQUENCE_NUMBERS:
-                       list = this->esns;
-                       break;
-               default:
-                       return NULL;
-       }
-       return enumerator_create_filter(list->create_enumerator(list),
-                                                                       (void*)alg_filter, NULL, NULL);
+       return enumerator_create_filter(
+                                               array_create_enumerator(this->transforms),
+                                               (void*)alg_filter, (void*)(uintptr_t)type, NULL);
 }
 
 METHOD(proposal_t, get_algorithm, bool,
@@ -200,84 +137,91 @@ METHOD(proposal_t, get_algorithm, bool,
                found = TRUE;
        }
        enumerator->destroy(enumerator);
+
        return found;
 }
 
 METHOD(proposal_t, has_dh_group, bool,
        private_proposal_t *this, diffie_hellman_group_t group)
 {
-       bool result = FALSE;
+       bool found = FALSE, any = FALSE;
+       enumerator_t *enumerator;
+       u_int16_t current;
 
-       if (this->dh_groups->get_count(this->dh_groups))
+       enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
+       while (enumerator->enumerate(enumerator, &current, NULL))
        {
-               algorithm_t *current;
-               enumerator_t *enumerator;
-
-               enumerator = this->dh_groups->create_enumerator(this->dh_groups);
-               while (enumerator->enumerate(enumerator, (void**)&current))
+               any = TRUE;
+               if (current == group)
                {
-                       if (current->algorithm == group)
-                       {
-                               result = TRUE;
-                               break;
-                       }
+                       found = TRUE;
+                       break;
                }
-               enumerator->destroy(enumerator);
        }
-       else if (group == MODP_NONE)
+       enumerator->destroy(enumerator);
+
+       if (!any && group == MODP_NONE)
        {
-               result = TRUE;
+               found = TRUE;
        }
-       return result;
+       return found;
 }
 
 METHOD(proposal_t, strip_dh, void,
        private_proposal_t *this, diffie_hellman_group_t keep)
 {
        enumerator_t *enumerator;
-       algorithm_t *alg;
+       entry_t *entry;
 
-       enumerator = this->dh_groups->create_enumerator(this->dh_groups);
-       while (enumerator->enumerate(enumerator, (void**)&alg))
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
        {
-               if (alg->algorithm != keep)
+               if (entry->type == DIFFIE_HELLMAN_GROUP &&
+                       entry->alg != keep)
                {
-                       this->dh_groups->remove_at(this->dh_groups, enumerator);
-                       free(alg);
+                       array_remove_at(this->transforms, enumerator);
                }
        }
        enumerator->destroy(enumerator);
 }
 
 /**
- * Find a matching alg/keysize in two linked lists
+ * Select a matching proposal from this and other, insert into selected.
  */
-static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
-                                               bool *add, u_int16_t *alg, size_t *key_size)
+static bool select_algo(private_proposal_t *this, proposal_t *other,
+                                               proposal_t *selected, transform_type_t type, bool priv)
 {
        enumerator_t *e1, *e2;
-       algorithm_t *alg1, *alg2;
+       u_int16_t alg1, alg2, ks1, ks2;
+       bool found = FALSE;
 
-       /* if in both are zero algorithms specified, we HAVE a match */
-       if (first->get_count(first) == 0 && second->get_count(second) == 0)
+       if (type == INTEGRITY_ALGORITHM &&
+               selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
+               encryption_algorithm_is_aead(alg1))
        {
-               *add = FALSE;
+               /* no integrity algorithm required, we have an AEAD */
                return TRUE;
        }
 
-       e1 = first->create_enumerator(first);
-       e2 = second->create_enumerator(second);
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL))
+       {
+               found = TRUE;
+       }
+
+       e1->destroy(e1);
+       e1 = create_enumerator(this, type);
        /* compare algs, order of algs in "first" is preferred */
-       while (e1->enumerate(e1, &alg1))
+       while (!found && e1->enumerate(e1, &alg1, &ks1))
        {
                e2->destroy(e2);
-               e2 = second->create_enumerator(second);
-               while (e2->enumerate(e2, &alg2))
+               e2 = other->create_enumerator(other, type);
+               while (e2->enumerate(e2, &alg2, &ks2))
                {
-                       if (alg1->algorithm == alg2->algorithm &&
-                               alg1->key_size == alg2->key_size)
+                       if (alg1 == alg2 && ks1 == ks2)
                        {
-                               if (!priv && alg1->algorithm >= 1024)
+                               if (!priv && alg1 >= 1024)
                                {
                                        /* accept private use algorithms only if requested */
                                        DBG1(DBG_CFG, "an algorithm from private space would match, "
@@ -285,132 +229,52 @@ static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
                                        continue;
                                }
                                /* ok, we have an algorithm */
-                               *alg = alg1->algorithm;
-                               *key_size = alg1->key_size;
-                               *add = TRUE;
-                               e1->destroy(e1);
-                               e2->destroy(e2);
-                               return TRUE;
+                               selected->add_algorithm(selected, type, alg1, ks1);
+                               found = TRUE;
+                               break;
                        }
                }
        }
        /* no match in all comparisons */
        e1->destroy(e1);
        e2->destroy(e2);
-       return FALSE;
+
+       if (!found)
+       {
+               DBG2(DBG_CFG, "  no acceptable %N found", transform_type_names, type);
+       }
+       return found;
 }
 
 METHOD(proposal_t, select_proposal, proposal_t*,
-       private_proposal_t *this, proposal_t *other_pub, bool private)
+       private_proposal_t *this, proposal_t *other, bool private)
 {
-       private_proposal_t *other = (private_proposal_t*)other_pub;
        proposal_t *selected;
-       u_int16_t algo;
-       size_t key_size;
-       bool add;
 
        DBG2(DBG_CFG, "selecting proposal:");
 
-       /* check protocol */
-       if (this->protocol != other->protocol)
+       if (this->protocol != other->get_protocol(other))
        {
                DBG2(DBG_CFG, "  protocol mismatch, skipping");
                return NULL;
        }
 
-       selected = proposal_create(this->protocol, other->number);
+       selected = proposal_create(this->protocol, other->get_number(other));
 
-       /* select encryption algorithm */
-       if (select_algo(this->encryption_algos, other->encryption_algos, private,
-                                       &add, &algo, &key_size))
-       {
-               if (add)
-               {
-                       selected->add_algorithm(selected, ENCRYPTION_ALGORITHM,
-                                                                       algo, key_size);
-               }
-       }
-       else
-       {
-               selected->destroy(selected);
-               DBG2(DBG_CFG, "  no acceptable %N found",
-                        transform_type_names, ENCRYPTION_ALGORITHM);
-               return NULL;
-       }
-       /* select integrity algorithm */
-       if (!encryption_algorithm_is_aead(algo))
-       {
-               if (select_algo(this->integrity_algos, other->integrity_algos, private,
-                                               &add, &algo, &key_size))
-               {
-                       if (add)
-                       {
-                               selected->add_algorithm(selected, INTEGRITY_ALGORITHM,
-                                                                               algo, key_size);
-                       }
-               }
-               else
-               {
-                       selected->destroy(selected);
-                       DBG2(DBG_CFG, "  no acceptable %N found",
-                                transform_type_names, INTEGRITY_ALGORITHM);
-                       return NULL;
-               }
-       }
-       /* select prf algorithm */
-       if (select_algo(this->prf_algos, other->prf_algos, private,
-                                       &add, &algo, &key_size))
-       {
-               if (add)
-               {
-                       selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION,
-                                                                       algo, key_size);
-               }
-       }
-       else
-       {
-               selected->destroy(selected);
-               DBG2(DBG_CFG, "  no acceptable %N found",
-                        transform_type_names, PSEUDO_RANDOM_FUNCTION);
-               return NULL;
-       }
-       /* select a DH-group */
-       if (select_algo(this->dh_groups, other->dh_groups, private,
-                                       &add, &algo, &key_size))
-       {
-               if (add)
-               {
-                       selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
-               }
-       }
-       else
+       if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
+               !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
+               !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
+               !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
+               !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
        {
                selected->destroy(selected);
-               DBG2(DBG_CFG, "  no acceptable %N found",
-                        transform_type_names, DIFFIE_HELLMAN_GROUP);
-               return NULL;
-       }
-       /* select if we use ESNs (has no private use space) */
-       if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size))
-       {
-               if (add)
-               {
-                       selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
-               }
-       }
-       else
-       {
-               selected->destroy(selected);
-               DBG2(DBG_CFG, "  no acceptable %N found",
-                        transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
                return NULL;
        }
+
        DBG2(DBG_CFG, "  proposal matches");
 
-       /* apply SPI from "other" */
-       selected->set_spi(selected, other->spi);
+       selected->set_spi(selected, other->get_spi(other));
 
-       /* everything matched, return new proposal */
        return selected;
 }
 
@@ -433,50 +297,39 @@ METHOD(proposal_t, get_spi, u_int64_t,
 }
 
 /**
- * Clone a algorithm list
- */
-static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
-{
-       algorithm_t *algo, *clone_algo;
-       enumerator_t *enumerator;
-
-       enumerator = list->create_enumerator(list);
-       while (enumerator->enumerate(enumerator, &algo))
-       {
-               clone_algo = malloc_thing(algorithm_t);
-               memcpy(clone_algo, algo, sizeof(algorithm_t));
-               clone_list->insert_last(clone_list, (void*)clone_algo);
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * check if an algorithm list equals
+ * Check if two proposals have the same algorithms for a given transform type
  */
-static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2)
+static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
+                                                        transform_type_t type)
 {
        enumerator_t *e1, *e2;
-       algorithm_t *alg1, *alg2;
+       u_int16_t alg1, alg2, ks1, ks2;
        bool equals = TRUE;
 
-       if (l1->get_count(l1) != l2->get_count(l2))
+       e1 = create_enumerator(this, type);
+       e2 = other->create_enumerator(other, type);
+       while (e1->enumerate(e1, &alg1, &ks1))
        {
-               return FALSE;
-       }
-
-       e1 = l1->create_enumerator(l1);
-       e2 = l2->create_enumerator(l2);
-       while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2))
-       {
-               if (alg1->algorithm != alg2->algorithm ||
-                       alg1->key_size != alg2->key_size)
+               if (!e2->enumerate(e2, &alg2, &ks2))
                {
+                       /* this has more algs */
                        equals = FALSE;
                        break;
                }
+               if (alg1 != alg2 || ks1 != ks2)
+               {
+                       equals = FALSE;
+                       break;
+               }
+       }
+       if (e2->enumerate(e2, &alg2, ks2))
+       {
+               /* other has more algs */
+               equals = FALSE;
        }
        e1->destroy(e1);
        e2->destroy(e2);
+
        return equals;
 }
 
@@ -487,33 +340,35 @@ METHOD(proposal_t, get_number, u_int,
 }
 
 METHOD(proposal_t, equals, bool,
-       private_proposal_t *this, proposal_t *other_pub)
+       private_proposal_t *this, proposal_t *other)
 {
-       private_proposal_t *other = (private_proposal_t*)other_pub;
-
-       if (this == other)
+       if (&this->public == other)
        {
                return TRUE;
        }
        return (
-               algo_list_equals(this->encryption_algos, other->encryption_algos) &&
-               algo_list_equals(this->integrity_algos, other->integrity_algos) &&
-               algo_list_equals(this->prf_algos, other->prf_algos) &&
-               algo_list_equals(this->dh_groups, other->dh_groups) &&
-               algo_list_equals(this->esns, other->esns));
+               algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
+               algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
+               algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
+               algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
+               algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
 }
 
 METHOD(proposal_t, clone_, proposal_t*,
        private_proposal_t *this)
 {
        private_proposal_t *clone;
+       enumerator_t *enumerator;
+       entry_t *entry;
 
        clone = (private_proposal_t*)proposal_create(this->protocol, 0);
-       clone_algo_list(this->encryption_algos, clone->encryption_algos);
-       clone_algo_list(this->integrity_algos, clone->integrity_algos);
-       clone_algo_list(this->prf_algos, clone->prf_algos);
-       clone_algo_list(this->dh_groups, clone->dh_groups);
-       clone_algo_list(this->esns, clone->esns);
+
+       enumerator = array_create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               array_insert(clone->transforms, ARRAY_TAIL, entry);
+       }
+       enumerator->destroy(enumerator);
 
        clone->spi = this->spi;
        clone->number = this->number;
@@ -544,34 +399,40 @@ static const struct {
 static void check_proposal(private_proposal_t *this)
 {
        enumerator_t *e;
-       algorithm_t *alg;
+       entry_t *entry;
+       u_int16_t alg, ks;
        bool all_aead = TRUE;
        int i;
 
-       if (this->protocol == PROTO_IKE &&
-               this->prf_algos->get_count(this->prf_algos) == 0)
-       {       /* No explicit PRF found. We assume the same algorithm as used
-                * for integrity checking */
-               e = this->integrity_algos->create_enumerator(this->integrity_algos);
-               while (e->enumerate(e, &alg))
+       if (this->protocol == PROTO_IKE)
+       {
+               e = create_enumerator(this, PSEUDO_RANDOM_FUNCTION);
+               if (!e->enumerate(e, &alg, &ks))
                {
-                       for (i = 0; i < countof(integ_prf_map); i++)
+                       /* No explicit PRF found. We assume the same algorithm as used
+                        * for integrity checking */
+                       e->destroy(e);
+                       e = create_enumerator(this, INTEGRITY_ALGORITHM);
+                       while (e->enumerate(e, &alg, &ks))
                        {
-                               if (alg->algorithm == integ_prf_map[i].integ)
+                               for (i = 0; i < countof(integ_prf_map); i++)
                                {
-                                       add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
-                                                                 integ_prf_map[i].prf, 0);
-                                       break;
+                                       if (alg == integ_prf_map[i].integ)
+                                       {
+                                               add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
+                                                                         integ_prf_map[i].prf, 0);
+                                               break;
+                                       }
                                }
                        }
                }
                e->destroy(e);
        }
 
-       e = this->encryption_algos->create_enumerator(this->encryption_algos);
-       while (e->enumerate(e, &alg))
+       e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+       while (e->enumerate(e, &alg, &ks))
        {
-               if (!encryption_algorithm_is_aead(alg->algorithm))
+               if (!encryption_algorithm_is_aead(alg))
                {
                        all_aead = FALSE;
                        break;
@@ -581,24 +442,30 @@ static void check_proposal(private_proposal_t *this)
 
        if (all_aead)
        {
-               /* if all encryption algorithms in the proposal are authenticated encryption
-                * algorithms we MUST NOT propose any integrity algorithms */
-               while (this->integrity_algos->remove_last(this->integrity_algos,
-                                                                                                 (void**)&alg) == SUCCESS)
+               /* if all encryption algorithms in the proposal are AEADs,
+                * we MUST NOT propose any integrity algorithms */
+               e = array_create_enumerator(this->transforms);
+               while (e->enumerate(e, &entry))
                {
-                       free(alg);
+                       if (entry->type == INTEGRITY_ALGORITHM)
+                       {
+                               array_remove_at(this->transforms, e);
+                       }
                }
+               e->destroy(e);
        }
 
        if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
        {
-               e = this->esns->create_enumerator(this->esns);
-               if (!e->enumerate(e, &alg))
+               e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS);
+               if (!e->enumerate(e, NULL, NULL))
                {       /* ESN not specified, assume not supported */
                        add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
                }
                e->destroy(e);
        }
+
+       array_compress(this->transforms);
 }
 
 /**
@@ -704,11 +571,7 @@ int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
 METHOD(proposal_t, destroy, void,
        private_proposal_t *this)
 {
-       this->encryption_algos->destroy_function(this->encryption_algos, free);
-       this->integrity_algos->destroy_function(this->integrity_algos, free);
-       this->prf_algos->destroy_function(this->prf_algos, free);
-       this->dh_groups->destroy_function(this->dh_groups, free);
-       this->esns->destroy_function(this->esns, free);
+       array_destroy(this->transforms);
        free(this);
 }
 
@@ -737,11 +600,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number)
                },
                .protocol = protocol,
                .number = number,
-               .encryption_algos = linked_list_create(),
-               .integrity_algos = linked_list_create(),
-               .prf_algos = linked_list_create(),
-               .dh_groups = linked_list_create(),
-               .esns = linked_list_create(),
+               .transforms = array_create(sizeof(entry_t), 0),
        );
 
        return &this->public;
index 81d5d24..87c8435 100644 (file)
@@ -58,19 +58,30 @@ METHOD(listener_t, child_updown, bool,
        bool up)
 {
        enumerator_t *enumerator;
+       traffic_selector_t *ts;
        entry_t *entry;
 
        if (up)
        {
                INIT(entry,
-                       .local = child_sa->get_traffic_selectors(child_sa, TRUE),
-                       .remote = child_sa->get_traffic_selectors(child_sa, FALSE),
+                       .local = linked_list_create(),
+                       .remote = linked_list_create(),
                        .reqid = child_sa->get_reqid(child_sa),
                );
-               entry->local = entry->local->clone_offset(entry->local,
-                                                                               offsetof(traffic_selector_t, clone));
-               entry->remote = entry->remote->clone_offset(entry->remote,
-                                                                               offsetof(traffic_selector_t, clone));
+
+               enumerator = child_sa->create_ts_enumerator(child_sa, TRUE);
+               while (enumerator->enumerate(enumerator, &ts))
+               {
+                       entry->local->insert_last(entry->local, ts->clone(ts));
+               }
+               enumerator->destroy(enumerator);
+
+               enumerator = child_sa->create_ts_enumerator(child_sa, FALSE);
+               while (enumerator->enumerate(enumerator, &ts))
+               {
+                       entry->remote->insert_last(entry->remote, ts->clone(ts));
+               }
+               enumerator->destroy(enumerator);
 
                this->lock->write_lock(this->lock);
                this->entries->insert_last(this->entries, entry);
@@ -160,4 +171,3 @@ farp_listener_t *farp_listener_create()
 
        return &this->public;
 }
-
index 707add9..c166d72 100644 (file)
@@ -103,18 +103,22 @@ METHOD(listener_t, child_keys, bool,
                chunk_clear(&secret);
        }
 
-       local_ts = child_sa->get_traffic_selectors(child_sa, TRUE);
-       enumerator = local_ts->create_enumerator(local_ts);
+       local_ts = linked_list_create();
+       remote_ts = linked_list_create();
+
+       enumerator = child_sa->create_ts_enumerator(child_sa, TRUE);
        while (enumerator->enumerate(enumerator, &ts))
        {
                m->add_attribute(m, HA_LOCAL_TS, ts);
+               local_ts->insert_last(local_ts, ts);
        }
        enumerator->destroy(enumerator);
-       remote_ts = child_sa->get_traffic_selectors(child_sa, FALSE);
-       enumerator = remote_ts->create_enumerator(remote_ts);
+
+       enumerator = child_sa->create_ts_enumerator(child_sa, FALSE);
        while (enumerator->enumerate(enumerator, &ts))
        {
                m->add_attribute(m, HA_REMOTE_TS, ts);
+               remote_ts->insert_last(remote_ts, ts);
        }
        enumerator->destroy(enumerator);
 
@@ -128,6 +132,9 @@ METHOD(listener_t, child_keys, bool,
                seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
                seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
 
+       local_ts->destroy(local_ts);
+       remote_ts->destroy(remote_ts);
+
        this->socket->push(this->socket, m);
        m->destroy(m);
 
@@ -195,4 +202,3 @@ ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
 
        return &this->public;
 }
-
index d13b822..1236088 100644 (file)
@@ -165,8 +165,10 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca
 
        xmlTextWriterWriteFormatElement(writer, "spi", "%x",
                                                                        htonl(child->get_spi(child, local)));
-       list = child->get_traffic_selectors(child, local);
+       list = linked_list_create_from_enumerator(
+                                                                       child->create_ts_enumerator(child, local));
        write_networks(writer, "networks", list);
+       list->destroy(list);
 }
 
 /**
index e76afec..e81f3fc 100644 (file)
@@ -207,8 +207,10 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
        time_t use_in, use_out, rekey, now;
        u_int64_t bytes_in, bytes_out, packets_in, packets_out;
        proposal_t *proposal;
-       child_cfg_t *config = child_sa->get_config(child_sa);
+       linked_list_t *my_ts, *other_ts;
+       child_cfg_t *config;
 
+       config = child_sa->get_config(child_sa);
        now = time_monotonic(NULL);
 
        fprintf(out, "%12s{%d}:  %N, %N%s",
@@ -319,10 +321,15 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
                fprintf(out, ", expires in %V", &now, &rekey);
        }
 
+       my_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, TRUE));
+       other_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, FALSE));
        fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
                        child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa->get_traffic_selectors(child_sa, TRUE),
-                       child_sa->get_traffic_selectors(child_sa, FALSE));
+                       my_ts, other_ts);
+       my_ts->destroy(my_ts);
+       other_ts->destroy(other_ts);
 }
 
 /**
index 53221b7..cebc389 100644 (file)
@@ -72,6 +72,7 @@ static void write_fifo(private_uci_control_t *this, char *format, ...)
 static void status(private_uci_control_t *this, char *name)
 {
        enumerator_t *configs, *sas, *children;
+       linked_list_t *list;
        ike_sa_t *ike_sa;
        child_sa_t *child_sa;
        peer_cfg_t *peer_cfg;
@@ -108,8 +109,10 @@ static void status(private_uci_control_t *this, char *name)
                        children = ike_sa->create_child_sa_enumerator(ike_sa);
                        while (children->enumerate(children, (void**)&child_sa))
                        {
-                               fprintf(out, "%#R",
-                                               child_sa->get_traffic_selectors(child_sa, FALSE));
+                               list = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, FALSE));
+                               fprintf(out, "%#R", list);
+                               list->destroy(list);
                        }
                        children->destroy(children);
                        fprintf(out, "\n");
@@ -296,4 +299,3 @@ uci_control_t *uci_control_create()
        }
        return &this->public;
 }
-
index 1069b2d..46e4b6f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <hydra.h>
 #include <daemon.h>
+#include <collections/array.h>
 
 ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
        "CREATED",
@@ -79,14 +80,14 @@ struct private_child_sa_t {
        u_int16_t other_cpi;
 
        /**
-        * List for local traffic selectors
+        * Array for local traffic selectors
         */
-       linked_list_t *my_ts;
+       array_t *my_ts;
 
        /**
-        * List for remote traffic selectors
+        * Array for remote traffic selectors
         */
-       linked_list_t *other_ts;
+       array_t *other_ts;
 
        /**
         * Protocol used to protect this SA, ESP|AH
@@ -331,10 +332,14 @@ METHOD(child_sa_t, set_proposal, void,
        this->proposal = proposal->clone(proposal);
 }
 
-METHOD(child_sa_t, get_traffic_selectors, linked_list_t*,
-          private_child_sa_t *this, bool local)
+METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
+       private_child_sa_t *this, bool local)
 {
-       return local ? this->my_ts : this->other_ts;
+       if (local)
+       {
+               return array_create_enumerator(this->my_ts);
+       }
+       return array_create_enumerator(this->other_ts);
 }
 
 typedef struct policy_enumerator_t policy_enumerator_t;
@@ -349,8 +354,8 @@ struct policy_enumerator_t {
        enumerator_t *mine;
        /** enumerator over others TS */
        enumerator_t *other;
-       /** list of others TS, to recreate enumerator */
-       linked_list_t *list;
+       /** array of others TS, to recreate enumerator */
+       array_t *array;
        /** currently enumerating TS for "me" side */
        traffic_selector_t *ts;
 };
@@ -366,7 +371,7 @@ METHOD(enumerator_t, policy_enumerate, bool,
                if (!this->other->enumerate(this->other, &other_ts))
                {       /* end of others list, restart with new of mine */
                        this->other->destroy(this->other);
-                       this->other = this->list->create_enumerator(this->list);
+                       this->other = array_create_enumerator(this->array);
                        this->ts = NULL;
                        continue;
                }
@@ -405,9 +410,9 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
                        .enumerate = (void*)_policy_enumerate,
                        .destroy = _policy_destroy,
                },
-               .mine = this->my_ts->create_enumerator(this->my_ts),
-               .other = this->other_ts->create_enumerator(this->other_ts),
-               .list = this->other_ts,
+               .mine = array_create_enumerator(this->my_ts),
+               .other = array_create_enumerator(this->other_ts),
+               .array = this->other_ts,
                .ts = NULL,
        );
 
@@ -772,13 +777,13 @@ METHOD(child_sa_t, add_policies, status_t,
        enumerator = my_ts_list->create_enumerator(my_ts_list);
        while (enumerator->enumerate(enumerator, &my_ts))
        {
-               this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
+               array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
        }
        enumerator->destroy(enumerator);
        enumerator = other_ts_list->create_enumerator(other_ts_list);
        while (enumerator->enumerate(enumerator, &other_ts))
        {
-               this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
+               array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
        }
        enumerator->destroy(enumerator);
 
@@ -1069,8 +1074,8 @@ METHOD(child_sa_t, destroy, void,
                enumerator->destroy(enumerator);
        }
 
-       this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
-       this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
+       array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
+       array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
        this->my_addr->destroy(this->my_addr);
        this->other_addr->destroy(this->other_addr);
        DESTROY_IF(this->proposal);
@@ -1079,6 +1084,41 @@ METHOD(child_sa_t, destroy, void,
 }
 
 /**
+ * Get proxy address for one side, if any
+ */
+static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
+{
+       host_t *host = NULL;
+       u_int8_t mask;
+       enumerator_t *enumerator;
+       linked_list_t *ts_list, *list;
+       traffic_selector_t *ts;
+
+       list = linked_list_create_with_items(ike, NULL);
+       ts_list = config->get_traffic_selectors(config, local, NULL, list);
+       list->destroy(list);
+
+       enumerator = ts_list->create_enumerator(ts_list);
+       while (enumerator->enumerate(enumerator, &ts))
+       {
+               if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
+               {
+                       DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
+                                local ? "my" : "other", ike, host);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
+
+       if (!host)
+       {
+               host = ike->clone(ike);
+       }
+       return host;
+}
+
+/**
  * Described in header.
  */
 child_sa_t * child_sa_create(host_t *me, host_t* other,
@@ -1117,17 +1157,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
                        .install = _install,
                        .update = _update,
                        .add_policies = _add_policies,
-                       .get_traffic_selectors = _get_traffic_selectors,
+                       .create_ts_enumerator = _create_ts_enumerator,
                        .create_policy_enumerator = _create_policy_enumerator,
                        .destroy = _destroy,
                },
-               .my_addr = me->clone(me),
-               .other_addr = other->clone(other),
                .encap = encap,
                .ipcomp = IPCOMP_NONE,
                .state = CHILD_CREATED,
-               .my_ts = linked_list_create(),
-               .other_ts = linked_list_create(),
+               .my_ts = array_create(0, 0),
+               .other_ts = array_create(0, 0),
                .protocol = PROTO_NONE,
                .mode = MODE_TUNNEL,
                .close_action = config->get_close_action(config),
@@ -1170,62 +1208,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        if (config->get_mode(config) == MODE_TRANSPORT &&
                config->use_proxy_mode(config))
        {
-               ts_type_t type;
-               int family;
-               chunk_t addr;
-               host_t *host;
-               enumerator_t *enumerator;
-               linked_list_t *my_ts_list, *other_ts_list, *list;
-               traffic_selector_t *my_ts, *other_ts;
-
                this->mode = MODE_TRANSPORT;
 
-               list = linked_list_create_with_items(me, NULL);
-               my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, list);
-               list->destroy(list);
-               enumerator = my_ts_list->create_enumerator(my_ts_list);
-               if (enumerator->enumerate(enumerator, &my_ts))
-               {
-                       if (my_ts->is_host(my_ts, NULL) &&
-                          !my_ts->is_host(my_ts, this->my_addr))
-                       {
-                               type = my_ts->get_type(my_ts);
-                               family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
-                               addr = my_ts->get_from_address(my_ts);
-                               host = host_create_from_chunk(family, addr, 0);
-                               free(addr.ptr);
-                               DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
-                                                          this->my_addr, host);
-                               this->my_addr->destroy(this->my_addr);
-                               this->my_addr = host;
-                       }
-               }
-               enumerator->destroy(enumerator);
-               my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
-
-               list = linked_list_create_with_items(other, NULL);
-               other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, list);
-               list->destroy(list);
-               enumerator = other_ts_list->create_enumerator(other_ts_list);
-               if (enumerator->enumerate(enumerator, &other_ts))
-               {
-                       if (other_ts->is_host(other_ts, NULL) &&
-                          !other_ts->is_host(other_ts, this->other_addr))
-                       {
-                               type = other_ts->get_type(other_ts);
-                               family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
-                               addr = other_ts->get_from_address(other_ts);
-                               host = host_create_from_chunk(family, addr, 0);
-                               free(addr.ptr);
-                               DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
-                                                          this->other_addr, host);
-                               this->other_addr->destroy(this->other_addr);
-                               this->other_addr = host;
-                       }
-               }
-               enumerator->destroy(enumerator);
-               other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
+               this->my_addr = get_proxy_addr(config, me, TRUE);
+               this->other_addr = get_proxy_addr(config, other, FALSE);
+       }
+       else
+       {
+               this->my_addr = me->clone(me);
+               this->other_addr = other->clone(other);
        }
-
        return &this->public;
 }
index aa44dbf..44c5293 100644 (file)
@@ -284,17 +284,20 @@ struct child_sa_t {
        mark_t (*get_mark)(child_sa_t *this, bool inbound);
 
        /**
-        * Get the traffic selectors list added for one side.
+        * Create an enumerator over traffic selectors of one side.
         *
-        * @param local         TRUE for own traffic selectors, FALSE for remote
-        * @return                      list of traffic selectors
+        * @param local         TRUE for own traffic selectors, FALSE for remote.
+        * @return                      enumerator over traffic_selector_t*
         */
-       linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
+       enumerator_t* (*create_ts_enumerator)(child_sa_t *this, bool local);
 
        /**
         * Create an enumerator over installed policies.
         *
-        * @return                      enumerator over pairs of traffic selectors.
+        * The enumerated traffic selectors is a full mesh of compatible local
+        * and remote traffic selectors.
+        *
+        * @return                      enumerator over a pair of traffic_selector_t*
         */
        enumerator_t* (*create_policy_enumerator)(child_sa_t *this);
 
index 19c6248..50d9694 100644 (file)
@@ -26,7 +26,7 @@
 #include <library.h>
 #include <hydra.h>
 #include <daemon.h>
-#include <collections/linked_list.h>
+#include <collections/array.h>
 #include <utils/lexparser.h>
 #include <processing/jobs/retransmit_job.h>
 #include <processing/jobs/delete_ike_sa_job.h>
@@ -95,24 +95,24 @@ struct private_ike_sa_t {
        peer_cfg_t *peer_cfg;
 
        /**
-        * currently used authentication ruleset, local (as auth_cfg_t)
+        * currently used authentication ruleset, local
         */
        auth_cfg_t *my_auth;
 
        /**
-        * list of completed local authentication rounds
+        * currently used authentication constraints, remote
         */
-       linked_list_t *my_auths;
+       auth_cfg_t *other_auth;
 
        /**
-        * list of completed remote authentication rounds
+        * Array of completed local authentication rounds (as auth_cfg_t)
         */
-       linked_list_t *other_auths;
+       array_t *my_auths;
 
        /**
-        * currently used authentication constraints, remote (as auth_cfg_t)
+        * Array of completed remote authentication rounds (as auth_cfg_t)
         */
-       auth_cfg_t *other_auth;
+       array_t *other_auths;
 
        /**
         * Selected IKE proposal
@@ -172,9 +172,9 @@ struct private_ike_sa_t {
        ike_condition_t conditions;
 
        /**
-        * Linked List containing the child sa's of the current IKE_SA.
+        * Array containing the child sa's of the current IKE_SA.
         */
-       linked_list_t *child_sas;
+       array_t *child_sas;
 
        /**
         * keymat of this IKE_SA
@@ -184,22 +184,22 @@ struct private_ike_sa_t {
        /**
         * Virtual IPs on local host
         */
-       linked_list_t *my_vips;
+       array_t *my_vips;
 
        /**
         * Virtual IPs on remote host
         */
-       linked_list_t *other_vips;
+       array_t *other_vips;
 
        /**
         * List of configuration attributes (attribute_entry_t)
         */
-       linked_list_t *attributes;
+       array_t *attributes;
 
        /**
         * list of peer's addresses, additional ones transmitted via MOBIKE
         */
-       linked_list_t *peer_addresses;
+       array_t *peer_addresses;
 
        /**
         * previously value of received DESTINATION_IP hash
@@ -282,7 +282,8 @@ static time_t get_use_time(private_ike_sa_t* this, bool inbound)
        {
                use_time = this->stats[STAT_OUTBOUND];
        }
-       enumerator = this->child_sas->create_enumerator(this->child_sas);
+
+       enumerator = array_create_enumerator(this->child_sas);
        while (enumerator->enumerate(enumerator, &child_sa))
        {
                child_sa->get_usestats(child_sa, inbound, &current, NULL, NULL);
@@ -389,11 +390,11 @@ METHOD(ike_sa_t, add_auth_cfg, void,
 {
        if (local)
        {
-               this->my_auths->insert_last(this->my_auths, cfg);
+               array_insert(this->my_auths, ARRAY_TAIL, cfg);
        }
        else
        {
-               this->other_auths->insert_last(this->other_auths, cfg);
+               array_insert(this->other_auths, ARRAY_TAIL, cfg);
        }
 }
 
@@ -402,9 +403,9 @@ METHOD(ike_sa_t, create_auth_cfg_enumerator, enumerator_t*,
 {
        if (local)
        {
-               return this->my_auths->create_enumerator(this->my_auths);
+               return array_create_enumerator(this->my_auths);
        }
-       return this->other_auths->create_enumerator(this->other_auths);
+       return array_create_enumerator(this->other_auths);
 }
 
 /**
@@ -417,13 +418,11 @@ static void flush_auth_cfgs(private_ike_sa_t *this)
        this->my_auth->purge(this->my_auth, FALSE);
        this->other_auth->purge(this->other_auth, FALSE);
 
-       while (this->my_auths->remove_last(this->my_auths,
-                                                                          (void**)&cfg) == SUCCESS)
+       while (array_remove(this->my_auths, ARRAY_TAIL, &cfg))
        {
                cfg->destroy(cfg);
        }
-       while (this->other_auths->remove_last(this->other_auths,
-                                                                                 (void**)&cfg) == SUCCESS)
+       while (array_remove(this->other_auths, ARRAY_TAIL, &cfg))
        {
                cfg->destroy(cfg);
        }
@@ -750,7 +749,7 @@ METHOD(ike_sa_t, add_virtual_ip, void,
                        if (hydra->kernel_interface->add_ip(hydra->kernel_interface,
                                                                                                ip, -1, iface) == SUCCESS)
                        {
-                               this->my_vips->insert_last(this->my_vips, ip->clone(ip));
+                               array_insert_create(&this->my_vips, ARRAY_TAIL, ip->clone(ip));
                        }
                        else
                        {
@@ -765,7 +764,7 @@ METHOD(ike_sa_t, add_virtual_ip, void,
        }
        else
        {
-               this->other_vips->insert_last(this->other_vips, ip->clone(ip));
+               array_insert_create(&this->other_vips, ARRAY_TAIL, ip->clone(ip));
        }
 }
 
@@ -773,14 +772,15 @@ METHOD(ike_sa_t, add_virtual_ip, void,
 METHOD(ike_sa_t, clear_virtual_ips, void,
        private_ike_sa_t *this, bool local)
 {
-       linked_list_t *vips = local ? this->my_vips : this->other_vips;
+       array_t *vips;
        host_t *vip;
 
-       if (!local && vips->get_count(vips))
+       vips = local ? this->my_vips : this->other_vips;
+       if (!local && array_count(vips))
        {
                charon->bus->assign_vips(charon->bus, &this->public, FALSE);
        }
-       while (vips->remove_first(vips, (void**)&vip) == SUCCESS)
+       while (array_remove(vips, ARRAY_HEAD, &vip))
        {
                if (local)
                {
@@ -796,23 +796,23 @@ METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*,
 {
        if (local)
        {
-               return this->my_vips->create_enumerator(this->my_vips);
+               return array_create_enumerator(this->my_vips);
        }
-       return this->other_vips->create_enumerator(this->other_vips);
+       return array_create_enumerator(this->other_vips);
 }
 
 METHOD(ike_sa_t, add_peer_address, void,
        private_ike_sa_t *this, host_t *host)
 {
-       this->peer_addresses->insert_last(this->peer_addresses, host);
+       array_insert_create(&this->peer_addresses, ARRAY_TAIL, host);
 }
 
 METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*,
        private_ike_sa_t *this)
 {
-       if (this->peer_addresses->get_count(this->peer_addresses))
+       if (this->peer_addresses)
        {
-               return this->peer_addresses->create_enumerator(this->peer_addresses);
+               return array_create_enumerator(this->peer_addresses);
        }
        /* in case we don't have MOBIKE */
        return enumerator_create_single(this->other_host, NULL);
@@ -821,17 +821,8 @@ METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*,
 METHOD(ike_sa_t, clear_peer_addresses, void,
        private_ike_sa_t *this)
 {
-       enumerator_t *enumerator;
-       host_t *host;
-
-       enumerator = this->peer_addresses->create_enumerator(this->peer_addresses);
-       while (enumerator->enumerate(enumerator, (void**)&host))
-       {
-               this->peer_addresses->remove_at(this->peer_addresses,
-                                                                               enumerator);
-               host->destroy(host);
-       }
-       enumerator->destroy(enumerator);
+       array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy));
+       this->peer_addresses = NULL;
 }
 
 METHOD(ike_sa_t, has_mapping_changed, bool,
@@ -927,13 +918,16 @@ METHOD(ike_sa_t, update_hosts, void,
        {
                enumerator_t *enumerator;
                child_sa_t *child_sa;
+               linked_list_t *vips;
 
-               enumerator = this->child_sas->create_enumerator(this->child_sas);
-               while (enumerator->enumerate(enumerator, (void**)&child_sa))
+               vips = linked_list_create_from_enumerator(
+                                                                       array_create_enumerator(this->my_vips));
+
+               enumerator = array_create_enumerator(this->child_sas);
+               while (enumerator->enumerate(enumerator, &child_sa))
                {
-                       if (child_sa->update(child_sa, this->my_host,
-                                               this->other_host, this->my_vips,
-                                               has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
+                       if (child_sa->update(child_sa, this->my_host, this->other_host,
+                                       vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
                        {
                                this->public.rekey_child_sa(&this->public,
                                                child_sa->get_protocol(child_sa),
@@ -941,6 +935,8 @@ METHOD(ike_sa_t, update_hosts, void,
                        }
                }
                enumerator->destroy(enumerator);
+
+               vips->destroy(vips);
        }
 }
 
@@ -1326,7 +1322,7 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*,
        enumerator_t *enumerator;
        auth_cfg_t *cfg;
 
-       enumerator = this->other_auths->create_enumerator(this->other_auths);
+       enumerator = array_create_enumerator(this->other_auths);
        while (enumerator->enumerate(enumerator, &cfg))
        {
                /* prefer EAP-Identity of last round */
@@ -1363,7 +1359,7 @@ METHOD(ike_sa_t, set_other_id, void,
 METHOD(ike_sa_t, add_child_sa, void,
        private_ike_sa_t *this, child_sa_t *child_sa)
 {
-       this->child_sas->insert_last(this->child_sas, child_sa);
+       array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
 }
 
 METHOD(ike_sa_t, get_child_sa, child_sa_t*,
@@ -1372,7 +1368,7 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*,
        enumerator_t *enumerator;
        child_sa_t *current, *found = NULL;
 
-       enumerator = this->child_sas->create_enumerator(this->child_sas);
+       enumerator = array_create_enumerator(this->child_sas);
        while (enumerator->enumerate(enumerator, (void**)&current))
        {
                if (current->get_spi(current, inbound) == spi &&
@@ -1388,19 +1384,19 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*,
 METHOD(ike_sa_t, get_child_count, int,
        private_ike_sa_t *this)
 {
-       return this->child_sas->get_count(this->child_sas);
+       return array_count(this->child_sas);
 }
 
 METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*,
        private_ike_sa_t *this)
 {
-       return this->child_sas->create_enumerator(this->child_sas);
+       return array_create_enumerator(this->child_sas);
 }
 
 METHOD(ike_sa_t, remove_child_sa, void,
        private_ike_sa_t *this, enumerator_t *enumerator)
 {
-       this->child_sas->remove_at(this->child_sas, enumerator);
+       array_remove_at(this->child_sas, enumerator);
 }
 
 METHOD(ike_sa_t, rekey_child_sa, status_t,
@@ -1433,13 +1429,13 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
        child_sa_t *child_sa;
        status_t status = NOT_FOUND;
 
-       enumerator = this->child_sas->create_enumerator(this->child_sas);
+       enumerator = array_create_enumerator(this->child_sas);
        while (enumerator->enumerate(enumerator, (void**)&child_sa))
        {
                if (child_sa->get_protocol(child_sa) == protocol &&
                        child_sa->get_spi(child_sa, TRUE) == spi)
                {
-                       this->child_sas->remove_at(this->child_sas, enumerator);
+                       array_remove_at(this->child_sas, enumerator);
                        child_sa->destroy(child_sa);
                        status = SUCCESS;
                        break;
@@ -1506,7 +1502,7 @@ METHOD(ike_sa_t, reauth, status_t,
        if (!has_condition(this, COND_ORIGINAL_INITIATOR))
        {
                DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
-               if (this->other_vips->get_count(this->other_vips) != 0 ||
+               if (array_count(this->other_vips) != 0 ||
                        has_condition(this, COND_XAUTH_AUTHENTICATED) ||
                        has_condition(this, COND_EAP_AUTHENTICATED)
 #ifdef ME
@@ -1553,7 +1549,7 @@ METHOD(ike_sa_t, reestablish, status_t,
 
        if (has_condition(this, COND_REAUTHENTICATING))
        {       /* only reauthenticate if we have children */
-               if (this->child_sas->get_count(this->child_sas) == 0
+               if (array_count(this->child_sas) == 0
 #ifdef ME
                        /* allow reauth of mediation connections without CHILD_SAs */
                        && !this->peer_cfg->is_mediation(this->peer_cfg)
@@ -1570,7 +1566,7 @@ METHOD(ike_sa_t, reestablish, status_t,
        }
        else
        {       /* check if we have children to keep up at all */
-               enumerator = this->child_sas->create_enumerator(this->child_sas);
+               enumerator = array_create_enumerator(this->child_sas);
                while (enumerator->enumerate(enumerator, (void**)&child_sa))
                {
                        if (this->state == IKE_DELETING)
@@ -1611,7 +1607,7 @@ METHOD(ike_sa_t, reestablish, status_t,
 
        /* check if we are able to reestablish this IKE_SA */
        if (!has_condition(this, COND_ORIGINAL_INITIATOR) &&
-               (this->other_vips->get_count(this->other_vips) != 0 ||
+               (array_count(this->other_vips) != 0 ||
                 has_condition(this, COND_EAP_AUTHENTICATED)
 #ifdef ME
                 || this->is_mediation_server
@@ -1634,7 +1630,7 @@ METHOD(ike_sa_t, reestablish, status_t,
        host = this->my_host;
        new->set_my_host(new, host->clone(host));
        /* if we already have a virtual IP, we reuse it */
-       enumerator = this->my_vips->create_enumerator(this->my_vips);
+       enumerator = array_create_enumerator(this->my_vips);
        while (enumerator->enumerate(enumerator, &host))
        {
                new->add_virtual_ip(new, TRUE, host);
@@ -1649,7 +1645,7 @@ METHOD(ike_sa_t, reestablish, status_t,
        else
 #endif /* ME */
        {
-               enumerator = this->child_sas->create_enumerator(this->child_sas);
+               enumerator = array_create_enumerator(this->child_sas);
                while (enumerator->enumerate(enumerator, (void**)&child_sa))
                {
                        if (has_condition(this, COND_REAUTHENTICATING))
@@ -1658,7 +1654,7 @@ METHOD(ike_sa_t, reestablish, status_t,
                                {
                                        case CHILD_ROUTED:
                                        {       /* move routed child directly */
-                                               this->child_sas->remove_at(this->child_sas, enumerator);
+                                               array_remove_at(this->child_sas, enumerator);
                                                new->add_child_sa(new, child_sa);
                                                action = ACTION_NONE;
                                                break;
@@ -1789,7 +1785,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t,
         * We send the notify in IKE_AUTH if not yet ESTABLISHED. */
        send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 &&
                                  !has_condition(this, COND_ORIGINAL_INITIATOR) &&
-                                 (this->other_vips->get_count(this->other_vips) != 0 ||
+                                 (array_count(this->other_vips) != 0 ||
                                  has_condition(this, COND_EAP_AUTHENTICATED));
 
        if (lifetime < diff)
@@ -1963,13 +1959,12 @@ METHOD(ike_sa_t, add_configuration_attribute, void,
        private_ike_sa_t *this, attribute_handler_t *handler,
        configuration_attribute_type_t type, chunk_t data)
 {
-       attribute_entry_t *entry = malloc_thing(attribute_entry_t);
-
-       entry->handler = handler;
-       entry->type = type;
-       entry->data = chunk_clone(data);
-
-       this->attributes->insert_last(this->attributes, entry);
+       attribute_entry_t entry = {
+               .handler = handler,
+               .type = type,
+               .data = chunk_clone(data),
+       };
+       array_insert(this->attributes, ARRAY_TAIL, &entry);
 }
 
 METHOD(ike_sa_t, create_task_enumerator, enumerator_t*,
@@ -1995,8 +1990,8 @@ METHOD(ike_sa_t, inherit, void,
 {
        private_ike_sa_t *other = (private_ike_sa_t*)other_public;
        child_sa_t *child_sa;
-       attribute_entry_t *entry;
        enumerator_t *enumerator;
+       attribute_entry_t entry;
        auth_cfg_t *cfg;
        host_t *vip;
 
@@ -2011,35 +2006,33 @@ METHOD(ike_sa_t, inherit, void,
        this->other_id = other->other_id->clone(other->other_id);
 
        /* apply assigned virtual IPs... */
-       while (other->my_vips->remove_last(other->my_vips, (void**)&vip) == SUCCESS)
+       while (array_remove(other->my_vips, ARRAY_HEAD, &vip))
        {
-               this->my_vips->insert_first(this->my_vips, vip);
+               array_insert_create(&this->my_vips, ARRAY_TAIL, vip);
        }
-       while (other->other_vips->remove_last(other->other_vips,
-                                                                                 (void**)&vip) == SUCCESS)
+       while (array_remove(other->other_vips, ARRAY_HEAD, &vip))
        {
-               this->other_vips->insert_first(this->other_vips, vip);
+               array_insert_create(&this->other_vips, ARRAY_TAIL, vip);
        }
 
        /* authentication information */
-       enumerator = other->my_auths->create_enumerator(other->my_auths);
+       enumerator = array_create_enumerator(other->my_auths);
        while (enumerator->enumerate(enumerator, &cfg))
        {
-               this->my_auths->insert_last(this->my_auths, cfg->clone(cfg));
+               array_insert(this->my_auths, ARRAY_TAIL, cfg->clone(cfg));
        }
        enumerator->destroy(enumerator);
-       enumerator = other->other_auths->create_enumerator(other->other_auths);
+       enumerator = array_create_enumerator(other->other_auths);
        while (enumerator->enumerate(enumerator, &cfg))
        {
-               this->other_auths->insert_last(this->other_auths, cfg->clone(cfg));
+               array_insert(this->other_auths, ARRAY_TAIL, cfg->clone(cfg));
        }
        enumerator->destroy(enumerator);
 
        /* ... and configuration attributes */
-       while (other->attributes->remove_last(other->attributes,
-                                                                                 (void**)&entry) == SUCCESS)
+       while (array_remove(other->attributes, ARRAY_HEAD, &entry))
        {
-               this->attributes->insert_first(this->attributes, entry);
+               array_insert(this->attributes, ARRAY_TAIL, &entry);
        }
 
        /* inherit all conditions */
@@ -2062,10 +2055,9 @@ METHOD(ike_sa_t, inherit, void,
 #endif /* ME */
 
        /* adopt all children */
-       while (other->child_sas->remove_last(other->child_sas,
-                                                                                (void**)&child_sa) == SUCCESS)
+       while (array_remove(other->child_sas, ARRAY_HEAD, &child_sa))
        {
-               this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+               array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
        }
 
        /* move pending tasks to the new IKE_SA */
@@ -2092,7 +2084,7 @@ METHOD(ike_sa_t, inherit, void,
 METHOD(ike_sa_t, destroy, void,
        private_ike_sa_t *this)
 {
-       attribute_entry_t *entry;
+       attribute_entry_t entry;
        host_t *vip;
 
        charon->bus->set_sa(charon->bus, &this->public);
@@ -2101,25 +2093,22 @@ METHOD(ike_sa_t, destroy, void,
        DESTROY_IF(this->task_manager);
 
        /* remove attributes first, as we pass the IKE_SA to the handler */
-       while (this->attributes->remove_last(this->attributes,
-                                                                                (void**)&entry) == SUCCESS)
+       while (array_remove(this->attributes, ARRAY_TAIL, &entry))
        {
-               hydra->attributes->release(hydra->attributes, entry->handler,
-                                                                  this->other_id, entry->type, entry->data);
-               free(entry->data.ptr);
-               free(entry);
+               hydra->attributes->release(hydra->attributes, entry.handler,
+                                                                  this->other_id, entry.type, entry.data);
+               free(entry.data.ptr);
        }
-       while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS)
+       while (array_remove(this->my_vips, ARRAY_TAIL, &vip))
        {
                hydra->kernel_interface->del_ip(hydra->kernel_interface, vip, -1, TRUE);
                vip->destroy(vip);
        }
-       if (this->other_vips->get_count(this->other_vips))
+       if (array_count(this->other_vips))
        {
                charon->bus->assign_vips(charon->bus, &this->public, FALSE);
        }
-       while (this->other_vips->remove_last(this->other_vips,
-                                                                                (void**)&vip) == SUCCESS)
+       while (array_remove(this->other_vips, ARRAY_TAIL, &vip))
        {
                if (this->peer_cfg)
                {
@@ -2138,13 +2127,12 @@ METHOD(ike_sa_t, destroy, void,
        /* unset SA after here to avoid usage by the listeners */
        charon->bus->set_sa(charon->bus, NULL);
 
-       this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
+       array_destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
        DESTROY_IF(this->keymat);
-       this->attributes->destroy(this->attributes);
-       this->my_vips->destroy(this->my_vips);
-       this->other_vips->destroy(this->other_vips);
-       this->peer_addresses->destroy_offset(this->peer_addresses,
-                                                                                offsetof(host_t, destroy));
+       array_destroy(this->attributes);
+       array_destroy(this->my_vips);
+       array_destroy(this->other_vips);
+       array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy));
 #ifdef ME
        if (this->is_mediation_server)
        {
@@ -2168,10 +2156,8 @@ METHOD(ike_sa_t, destroy, void,
        DESTROY_IF(this->proposal);
        this->my_auth->destroy(this->my_auth);
        this->other_auth->destroy(this->other_auth);
-       this->my_auths->destroy_offset(this->my_auths,
-                                                                  offsetof(auth_cfg_t, destroy));
-       this->other_auths->destroy_offset(this->other_auths,
-                                                                         offsetof(auth_cfg_t, destroy));
+       array_destroy_offset(this->my_auths, offsetof(auth_cfg_t, destroy));
+       array_destroy_offset(this->other_auths, offsetof(auth_cfg_t, destroy));
 
        this->ike_sa_id->destroy(this->ike_sa_id);
        free(this);
@@ -2283,7 +2269,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                },
                .ike_sa_id = ike_sa_id->clone(ike_sa_id),
                .version = version,
-               .child_sas = linked_list_create(),
                .my_host = host_create_any(AF_INET),
                .other_host = host_create_any(AF_INET),
                .my_id = identification_create_from_encoding(ID_ANY, chunk_empty),
@@ -2294,13 +2279,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
                .stats[STAT_OUTBOUND] = time_monotonic(NULL),
                .my_auth = auth_cfg_create(),
                .other_auth = auth_cfg_create(),
-               .my_auths = linked_list_create(),
-               .other_auths = linked_list_create(),
+               .my_auths = array_create(0, 0),
+               .other_auths = array_create(0, 0),
+               .attributes = array_create(sizeof(attribute_entry_t), 0),
                .unique_id = ref_get(&unique_id),
-               .peer_addresses = linked_list_create(),
-               .my_vips = linked_list_create(),
-               .other_vips = linked_list_create(),
-               .attributes = linked_list_create(),
                .keepalive_interval = lib->settings->get_time(lib->settings,
                                                        "%s.keep_alive", KEEPALIVE_INTERVAL, charon->name),
                .retry_initiate_interval = lib->settings->get_time(lib->settings,
index 709033c..bfa6fc8 100644 (file)
@@ -1753,21 +1753,22 @@ METHOD(task_manager_t, queue_child, void,
 /**
  * Check if two CHILD_SAs have the same traffic selector
  */
-static bool have_equal_ts(child_sa_t *a, child_sa_t *b, bool local)
+static bool have_equal_ts(child_sa_t *child1, child_sa_t *child2, bool local)
 {
-       linked_list_t *list;
-       traffic_selector_t *ts_a, *ts_b;
+       enumerator_t *e1, *e2;
+       traffic_selector_t *ts1, *ts2;
+       bool equal = FALSE;
 
-       list = a->get_traffic_selectors(a, local);
-       if (list->get_first(list, (void**)&ts_a) == SUCCESS)
+       e1 = child1->create_ts_enumerator(child1, local);
+       e2 = child2->create_ts_enumerator(child2, local);
+       if (e1->enumerate(e1, &ts1) && e2->enumerate(e2, &ts2))
        {
-               list = b->get_traffic_selectors(b, local);
-               if (list->get_first(list, (void**)&ts_b) == SUCCESS)
-               {
-                       return ts_a->equals(ts_a, ts_b);
-               }
+               equal = ts1->equals(ts1, ts2);
        }
-       return FALSE;
+       e1->destroy(e1);
+       e1->destroy(e1);
+
+       return equal;
 }
 
 /**
@@ -1806,14 +1807,13 @@ static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa)
 static traffic_selector_t* get_first_ts(child_sa_t *child_sa, bool local)
 {
        traffic_selector_t *ts = NULL;
-       linked_list_t *list;
+       enumerator_t *enumerator;
 
-       list = child_sa->get_traffic_selectors(child_sa, local);
-       if (list->get_first(list, (void**)&ts) == SUCCESS)
-       {
-               return ts;
-       }
-       return NULL;
+       enumerator = child_sa->create_ts_enumerator(child_sa, local);
+       enumerator->enumerate(enumerator, &ts);
+       enumerator->destroy(enumerator);
+
+       return ts;
 }
 
 METHOD(task_manager_t, queue_child_rekey, void,
index e9f06cb..5b3e35e 100644 (file)
@@ -69,6 +69,7 @@ static bool delete_child(private_quick_delete_t *this,
 {
        u_int64_t bytes_in, bytes_out;
        child_sa_t *child_sa;
+       linked_list_t *my_ts, *other_ts;
        bool rekeyed;
 
        child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE);
@@ -85,15 +86,17 @@ static bool delete_child(private_quick_delete_t *this,
        rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING;
        child_sa->set_state(child_sa, CHILD_DELETING);
 
+       my_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, TRUE));
+       other_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, FALSE));
        if (this->expired)
        {
                DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
                         "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
                         child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
                         ntohl(child_sa->get_spi(child_sa, TRUE)),
-                        ntohl(child_sa->get_spi(child_sa, FALSE)),
-                        child_sa->get_traffic_selectors(child_sa, TRUE),
-                        child_sa->get_traffic_selectors(child_sa, FALSE));
+                        ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
        }
        else
        {
@@ -105,9 +108,10 @@ static bool delete_child(private_quick_delete_t *this,
                         child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
                         ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
                         ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
-                        child_sa->get_traffic_selectors(child_sa, TRUE),
-                        child_sa->get_traffic_selectors(child_sa, FALSE));
+                        my_ts, other_ts);
        }
+       my_ts->destroy(my_ts);
+       other_ts->destroy(other_ts);
 
        if (!rekeyed)
        {
index 52ea34b..92df0f0 100644 (file)
@@ -259,7 +259,7 @@ static bool install(private_quick_mode_t *this)
 {
        status_t status, status_i, status_o;
        chunk_t encr_i, encr_r, integ_i, integ_r;
-       linked_list_t *tsi, *tsr;
+       linked_list_t *tsi, *tsr, *my_ts, *other_ts;
        child_sa_t *old = NULL;
 
        this->child_sa->set_proposal(this->child_sa, this->proposal);
@@ -362,14 +362,20 @@ static bool install(private_quick_mode_t *this)
        this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
        this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
 
+       my_ts = linked_list_create_from_enumerator(
+                               this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
+       other_ts = linked_list_create_from_enumerator(
+                               this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+
        DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
                 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
                 this->child_sa->get_name(this->child_sa),
                 this->child_sa->get_reqid(this->child_sa),
                 ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
-                ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
-                this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
-                this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
+                ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+
+       my_ts->destroy(my_ts);
+       other_ts->destroy(other_ts);
 
        if (this->rekey)
        {
index 839bdb9..79a9aa5 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <math.h>
 
+#include <collections/array.h>
 #include <daemon.h>
 #include <sa/ikev2/tasks/ike_init.h>
 #include <sa/ikev2/tasks/ike_natd.h>
@@ -122,19 +123,19 @@ struct private_task_manager_t {
        } initiating;
 
        /**
-        * List of queued tasks not yet in action
+        * Array of queued tasks not yet in action
         */
-       linked_list_t *queued_tasks;
+       array_t *queued_tasks;
 
        /**
-        * List of active tasks, initiated by ourselve
+        * Array of active tasks, initiated by ourselve
         */
-       linked_list_t *active_tasks;
+       array_t *active_tasks;
 
        /**
-        * List of tasks initiated by peer
+        * Array of tasks initiated by peer
         */
-       linked_list_t *passive_tasks;
+       array_t *passive_tasks;
 
        /**
         * the task manager has been reset
@@ -160,24 +161,24 @@ struct private_task_manager_t {
 METHOD(task_manager_t, flush_queue, void,
        private_task_manager_t *this, task_queue_t queue)
 {
-       linked_list_t *list;
+       array_t *array;
        task_t *task;
 
        switch (queue)
        {
                case TASK_QUEUE_ACTIVE:
-                       list = this->active_tasks;
+                       array = this->active_tasks;
                        break;
                case TASK_QUEUE_PASSIVE:
-                       list = this->passive_tasks;
+                       array = this->passive_tasks;
                        break;
                case TASK_QUEUE_QUEUED:
-                       list = this->queued_tasks;
+                       array = this->queued_tasks;
                        break;
                default:
                        return;
        }
-       while (list->remove_last(list, (void**)&task) == SUCCESS)
+       while (array_remove(array, ARRAY_TAIL, &task))
        {
                task->destroy(task);
        }
@@ -202,14 +203,14 @@ static bool activate_task(private_task_manager_t *this, task_type_t type)
        task_t *task;
        bool found = FALSE;
 
-       enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+       enumerator = array_create_enumerator(this->queued_tasks);
        while (enumerator->enumerate(enumerator, (void**)&task))
        {
                if (task->get_type(task) == type)
                {
                        DBG2(DBG_IKE, "  activating %N task", task_type_names, type);
-                       this->queued_tasks->remove_at(this->queued_tasks, enumerator);
-                       this->active_tasks->insert_last(this->active_tasks, task);
+                       array_remove_at(this->queued_tasks, enumerator);
+                       array_insert(this->active_tasks, ARRAY_TAIL, task);
                        found = TRUE;
                        break;
                }
@@ -231,7 +232,7 @@ METHOD(task_manager_t, retransmit, status_t,
                ike_mobike_t *mobike = NULL;
 
                /* check if we are retransmitting a MOBIKE routability check */
-               enumerator = this->active_tasks->create_enumerator(this->active_tasks);
+               enumerator = array_create_enumerator(this->active_tasks);
                while (enumerator->enumerate(enumerator, (void*)&task))
                {
                        if (task->get_type(task) == TASK_IKE_MOBIKE)
@@ -319,7 +320,7 @@ METHOD(task_manager_t, initiate, status_t,
                return SUCCESS;
        }
 
-       if (this->active_tasks->get_count(this->active_tasks) == 0)
+       if (array_count(this->active_tasks) == 0)
        {
                DBG2(DBG_IKE, "activating new tasks");
                switch (this->ike_sa->get_state(this->ike_sa))
@@ -414,8 +415,8 @@ METHOD(task_manager_t, initiate, status_t,
        else
        {
                DBG2(DBG_IKE, "reinitiating already active tasks");
-               enumerator = this->active_tasks->create_enumerator(this->active_tasks);
-               while (enumerator->enumerate(enumerator, (void**)&task))
+               enumerator = array_create_enumerator(this->active_tasks);
+               while (enumerator->enumerate(enumerator, &task))
                {
                        DBG2(DBG_IKE, "  %N task", task_type_names, task->get_type(task));
                        switch (task->get_type(task))
@@ -460,14 +461,14 @@ METHOD(task_manager_t, initiate, status_t,
        this->initiating.type = exchange;
        this->initiating.retransmitted = 0;
 
-       enumerator = this->active_tasks->create_enumerator(this->active_tasks);
-       while (enumerator->enumerate(enumerator, (void*)&task))
+       enumerator = array_create_enumerator(this->active_tasks);
+       while (enumerator->enumerate(enumerator, &task))
        {
                switch (task->build(task, message))
                {
                        case SUCCESS:
                                /* task completed, remove it */
-                               this->active_tasks->remove_at(this->active_tasks, enumerator);
+                               array_remove_at(this->active_tasks, enumerator);
                                task->destroy(task);
                                break;
                        case NEED_MORE:
@@ -507,6 +508,9 @@ METHOD(task_manager_t, initiate, status_t,
        }
        message->destroy(message);
 
+       array_compress(this->active_tasks);
+       array_compress(this->queued_tasks);
+
        return retransmit(this, this->initiating.mid);
 }
 
@@ -530,14 +534,14 @@ static status_t process_response(private_task_manager_t *this,
 
        /* catch if we get resetted while processing */
        this->reset = FALSE;
-       enumerator = this->active_tasks->create_enumerator(this->active_tasks);
-       while (enumerator->enumerate(enumerator, (void*)&task))
+       enumerator = array_create_enumerator(this->active_tasks);
+       while (enumerator->enumerate(enumerator, &task))
        {
                switch (task->process(task, message))
                {
                        case SUCCESS:
                                /* task completed, remove it */
-                               this->active_tasks->remove_at(this->active_tasks, enumerator);
+                               array_remove_at(this->active_tasks, enumerator);
                                task->destroy(task);
                                break;
                        case NEED_MORE:
@@ -549,7 +553,7 @@ static status_t process_response(private_task_manager_t *this,
                                /* FALL */
                        case DESTROY_ME:
                                /* critical failure, destroy IKE_SA */
-                               this->active_tasks->remove_at(this->active_tasks, enumerator);
+                               array_remove_at(this->active_tasks, enumerator);
                                enumerator->destroy(enumerator);
                                task->destroy(task);
                                return DESTROY_ME;
@@ -568,6 +572,8 @@ static status_t process_response(private_task_manager_t *this,
        this->initiating.packet->destroy(this->initiating.packet);
        this->initiating.packet = NULL;
 
+       array_compress(this->active_tasks);
+
        return initiate(this);
 }
 
@@ -588,8 +594,8 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task)
                type == TASK_IKE_REAUTH)
        {
                /* find an exchange collision, and notify these tasks */
-               enumerator = this->active_tasks->create_enumerator(this->active_tasks);
-               while (enumerator->enumerate(enumerator, (void**)&active))
+               enumerator = array_create_enumerator(this->active_tasks);
+               while (enumerator->enumerate(enumerator, &active))
                {
                        switch (active->get_type(active))
                        {
@@ -646,14 +652,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
        message->set_message_id(message, this->responding.mid);
        message->set_request(message, FALSE);
 
-       enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+       enumerator = array_create_enumerator(this->passive_tasks);
        while (enumerator->enumerate(enumerator, (void*)&task))
        {
                switch (task->build(task, message))
                {
                        case SUCCESS:
                                /* task completed, remove it */
-                               this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+                               array_remove_at(this->passive_tasks, enumerator);
                                if (!handle_collisions(this, task))
                                {
                                        task->destroy(task);
@@ -663,8 +669,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
                                /* processed, but task needs another exchange */
                                if (handle_collisions(this, task))
                                {
-                                       this->passive_tasks->remove_at(this->passive_tasks,
-                                                                                                  enumerator);
+                                       array_remove_at(this->passive_tasks, enumerator);
                                }
                                break;
                        case FAILED:
@@ -721,6 +726,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
                }
                return DESTROY_ME;
        }
+
+       array_compress(this->passive_tasks);
+
        return SUCCESS;
 }
 
@@ -736,37 +744,37 @@ static status_t process_request(private_task_manager_t *this,
        notify_payload_t *notify;
        delete_payload_t *delete;
 
-       if (this->passive_tasks->get_count(this->passive_tasks) == 0)
+       if (array_count(this->passive_tasks) == 0)
        {       /* create tasks depending on request type, if not already some queued */
                switch (message->get_exchange_type(message))
                {
                        case IKE_SA_INIT:
                        {
                                task = (task_t*)ike_vendor_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
 #ifdef ME
                                task = (task_t*)ike_me_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
 #endif /* ME */
                                task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_config_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE,
                                                                                                        NULL, NULL);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                break;
                        }
                        case CREATE_CHILD_SA:
@@ -817,7 +825,7 @@ static status_t process_request(private_task_manager_t *this,
                                {
                                        task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
                                }
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                break;
                        }
                        case INFORMATIONAL:
@@ -889,14 +897,14 @@ static status_t process_request(private_task_manager_t *this,
                                {
                                        task = (task_t*)ike_dpd_create(FALSE);
                                }
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                                break;
                        }
 #ifdef ME
                        case ME_CONNECT:
                        {
                                task = (task_t*)ike_me_create(this->ike_sa, FALSE);
-                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                               array_insert(this->passive_tasks, ARRAY_TAIL, task);
                        }
 #endif /* ME */
                        default:
@@ -905,14 +913,14 @@ static status_t process_request(private_task_manager_t *this,
        }
 
        /* let the tasks process the message */
-       enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+       enumerator = array_create_enumerator(this->passive_tasks);
        while (enumerator->enumerate(enumerator, (void*)&task))
        {
                switch (task->process(task, message))
                {
                        case SUCCESS:
                                /* task completed, remove it */
-                               this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+                               array_remove_at(this->passive_tasks, enumerator);
                                task->destroy(task);
                                break;
                        case NEED_MORE:
@@ -924,7 +932,7 @@ static status_t process_request(private_task_manager_t *this,
                                /* FALL */
                        case DESTROY_ME:
                                /* critical failure, destroy IKE_SA */
-                               this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+                               array_remove_at(this->passive_tasks, enumerator);
                                enumerator->destroy(enumerator);
                                task->destroy(task);
                                return DESTROY_ME;
@@ -1230,8 +1238,8 @@ METHOD(task_manager_t, queue_task, void,
                enumerator_t *enumerator;
                task_t *current;
 
-               enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
-               while (enumerator->enumerate(enumerator, (void**)&current))
+               enumerator = array_create_enumerator(this->queued_tasks);
+               while (enumerator->enumerate(enumerator, &current))
                {
                        if (current->get_type(current) == TASK_IKE_MOBIKE)
                        {
@@ -1243,7 +1251,7 @@ METHOD(task_manager_t, queue_task, void,
                enumerator->destroy(enumerator);
        }
        DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
-       this->queued_tasks->insert_last(this->queued_tasks, task);
+       array_insert(this->queued_tasks, ARRAY_TAIL, task);
 }
 
 /**
@@ -1255,7 +1263,7 @@ static bool has_queued(private_task_manager_t *this, task_type_t type)
        bool found = FALSE;
        task_t *task;
 
-       enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+       enumerator = array_create_enumerator(this->queued_tasks);
        while (enumerator->enumerate(enumerator, &task))
        {
                if (task->get_type(task) == type)
@@ -1410,19 +1418,18 @@ METHOD(task_manager_t, adopt_tasks, void,
        task_t *task;
 
        /* move queued tasks from other to this */
-       while (other->queued_tasks->remove_last(other->queued_tasks,
-                                                                                               (void**)&task) == SUCCESS)
+       while (array_remove(other->queued_tasks, ARRAY_TAIL, &task))
        {
                DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
                task->migrate(task, this->ike_sa);
-               this->queued_tasks->insert_first(this->queued_tasks, task);
+               array_insert(this->queued_tasks, ARRAY_HEAD, task);
        }
 }
 
 METHOD(task_manager_t, busy, bool,
        private_task_manager_t *this)
 {
-       return (this->active_tasks->get_count(this->active_tasks) > 0);
+       return array_count(this->active_tasks) > 0;
 }
 
 METHOD(task_manager_t, reset, void,
@@ -1447,7 +1454,7 @@ METHOD(task_manager_t, reset, void,
        this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
 
        /* reset queued tasks */
-       enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+       enumerator = array_create_enumerator(this->queued_tasks);
        while (enumerator->enumerate(enumerator, &task))
        {
                task->migrate(task, this->ike_sa);
@@ -1455,11 +1462,10 @@ METHOD(task_manager_t, reset, void,
        enumerator->destroy(enumerator);
 
        /* reset active tasks */
-       while (this->active_tasks->remove_last(this->active_tasks,
-                                                                                  (void**)&task) == SUCCESS)
+       while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
        {
                task->migrate(task, this->ike_sa);
-               this->queued_tasks->insert_first(this->queued_tasks, task);
+               array_insert(this->queued_tasks, ARRAY_HEAD, task);
        }
 
        this->reset = TRUE;
@@ -1471,11 +1477,11 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
        switch (queue)
        {
                case TASK_QUEUE_ACTIVE:
-                       return this->active_tasks->create_enumerator(this->active_tasks);
+                       return array_create_enumerator(this->active_tasks);
                case TASK_QUEUE_PASSIVE:
-                       return this->passive_tasks->create_enumerator(this->passive_tasks);
+                       return array_create_enumerator(this->passive_tasks);
                case TASK_QUEUE_QUEUED:
-                       return this->queued_tasks->create_enumerator(this->queued_tasks);
+                       return array_create_enumerator(this->queued_tasks);
                default:
                        return enumerator_create_empty();
        }
@@ -1486,9 +1492,9 @@ METHOD(task_manager_t, destroy, void,
 {
        flush(this);
 
-       this->active_tasks->destroy(this->active_tasks);
-       this->queued_tasks->destroy(this->queued_tasks);
-       this->passive_tasks->destroy(this->passive_tasks);
+       array_destroy(this->active_tasks);
+       array_destroy(this->queued_tasks);
+       array_destroy(this->passive_tasks);
 
        DESTROY_IF(this->responding.packet);
        DESTROY_IF(this->initiating.packet);
@@ -1529,9 +1535,9 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
                },
                .ike_sa = ike_sa,
                .initiating.type = EXCHANGE_TYPE_UNDEFINED,
-               .queued_tasks = linked_list_create(),
-               .active_tasks = linked_list_create(),
-               .passive_tasks = linked_list_create(),
+               .queued_tasks = array_create(0, 0),
+               .active_tasks = array_create(0, 0),
+               .passive_tasks = array_create(0, 0),
                .retransmit_tries = lib->settings->get_int(lib->settings,
                                        "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name),
                .retransmit_timeout = lib->settings->get_double(lib->settings,
index dd3813e..8ae36af 100644 (file)
@@ -673,6 +673,22 @@ static status_t select_and_install(private_child_create_t *this,
        {       /* a rekeyed SA uses the same reqid, no need for a new job */
                schedule_inactivity_timeout(this);
        }
+
+       my_ts = linked_list_create_from_enumerator(
+                               this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
+       other_ts = linked_list_create_from_enumerator(
+                               this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+
+       DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
+                "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+                this->child_sa->get_name(this->child_sa),
+                this->child_sa->get_reqid(this->child_sa),
+                ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
+                ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+
+       my_ts->destroy(my_ts);
+       other_ts->destroy(other_ts);
+
        return SUCCESS;
 }
 
@@ -1245,15 +1261,6 @@ METHOD(task_t, build_r, status_t,
 
        build_payloads(this, message);
 
-       DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
-                "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
-                this->child_sa->get_name(this->child_sa),
-                this->child_sa->get_reqid(this->child_sa),
-                ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
-                ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
-                this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
-                this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
-
        if (!this->rekey)
        {       /* invoke the child_up() hook if we are not rekeying */
                charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
@@ -1431,15 +1438,6 @@ METHOD(task_t, process_i, status_t,
 
        if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
        {
-               DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
-                        "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
-                        this->child_sa->get_name(this->child_sa),
-                        this->child_sa->get_reqid(this->child_sa),
-                        ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
-                        ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
-                        this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
-                        this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
-
                if (!this->rekey)
                {       /* invoke the child_up() hook if we are not rekeying */
                        charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
index 9f12d73..eaaca20 100644 (file)
@@ -249,6 +249,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
  */
 static void log_children(private_child_delete_t *this)
 {
+       linked_list_t *my_ts, *other_ts;
        enumerator_t *enumerator;
        child_sa_t *child_sa;
        u_int64_t bytes_in, bytes_out;
@@ -256,15 +257,17 @@ static void log_children(private_child_delete_t *this)
        enumerator = this->child_sas->create_enumerator(this->child_sas);
        while (enumerator->enumerate(enumerator, (void**)&child_sa))
        {
+               my_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, TRUE));
+               other_ts = linked_list_create_from_enumerator(
+                                                       child_sa->create_ts_enumerator(child_sa, FALSE));
                if (this->expired)
                {
                        DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
                                 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
                                 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
                                 ntohl(child_sa->get_spi(child_sa, TRUE)),
-                                ntohl(child_sa->get_spi(child_sa, FALSE)),
-                                child_sa->get_traffic_selectors(child_sa, TRUE),
-                                child_sa->get_traffic_selectors(child_sa, FALSE));
+                                ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
                }
                else
                {
@@ -276,9 +279,10 @@ static void log_children(private_child_delete_t *this)
                                 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
                                 ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
                                 ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
-                                child_sa->get_traffic_selectors(child_sa, TRUE),
-                                child_sa->get_traffic_selectors(child_sa, FALSE));
+                                my_ts, other_ts);
                }
+               my_ts->destroy(my_ts);
+               other_ts->destroy(other_ts);
        }
        enumerator->destroy(enumerator);
 }
index 75b501f..dc533a3 100644 (file)
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES := \
 library.c \
 asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
 collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
+collections/array.c \
 collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
 crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
 crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
@@ -110,4 +111,3 @@ LOCAL_PRELINK_MODULE := false
 LOCAL_SHARED_LIBRARIES += libdl libvstr
 
 include $(BUILD_SHARED_LIBRARY)
-
index 567bdfe..bde5f71 100644 (file)
@@ -4,6 +4,7 @@ libstrongswan_la_SOURCES = \
 library.c \
 asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
 collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
+collections/array.c \
 collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
 crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
 crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
@@ -39,7 +40,7 @@ nobase_strongswan_include_HEADERS = \
 library.h \
 asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \
 collections/blocking_queue.h collections/enumerator.h collections/hashtable.h \
-collections/linked_list.h \
+collections/linked_list.h collections/array.h \
 crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \
 crypto/proposal/proposal_keywords.h crypto/proposal/proposal_keywords_static.h \
 crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \
diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c
new file mode 100644 (file)
index 0000000..d92eaac
--- /dev/null
@@ -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, int 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 (file)
index 0000000..3e6180b
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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 effecient 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 end.
+ *
+ * If data is given, the element is copied to that position.
+ *
+ * @param array                        array to remove element from, or NULL
+ * @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_ @}*/
index d2d0a7d..2203519 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <library.h>
 #include <utils/debug.h>
-#include <collections/linked_list.h>
+#include <collections/array.h>
 #include <utils/identification.h>
 #include <eap/eap.h>
 #include <credentials/certificates/certificate.h>
@@ -109,9 +109,9 @@ struct private_auth_cfg_t {
        auth_cfg_t public;
 
        /**
-        * list of entry_t
+        * Array of entry_t
         */
-       linked_list_t *entries;
+       array_t *entries;
 };
 
 typedef struct entry_t entry_t;
@@ -184,18 +184,16 @@ METHOD(auth_cfg_t, create_enumerator, enumerator_t*,
                        .enumerate = (void*)enumerate,
                        .destroy = (void*)entry_enumerator_destroy,
                },
-               .inner = this->entries->create_enumerator(this->entries),
+               .inner = array_create_enumerator(this->entries),
        );
        return &enumerator->public;
 }
 
 /**
- * Create an entry from the given arguments.
+ * Initialize an entry.
  */
-static entry_t *entry_create(auth_rule_t type, va_list args)
+static void init_entry(entry_t *this, auth_rule_t type, va_list args)
 {
-       entry_t *this = malloc_thing(entry_t);
-
        this->type = type;
        switch (type)
        {
@@ -233,7 +231,6 @@ static entry_t *entry_create(auth_rule_t type, va_list args)
                        this->value = NULL;
                        break;
        }
-       return this;
 }
 
 /**
@@ -481,21 +478,21 @@ METHOD(auth_cfg_t, get, void*,
  */
 static void add(private_auth_cfg_t *this, auth_rule_t type, ...)
 {
-       entry_t *entry;
+       entry_t entry;
        va_list args;
 
        va_start(args, type);
-       entry = entry_create(type, args);
+       init_entry(&entry, type, args);
        va_end(args);
 
        if (is_multi_value_rule(type))
        {       /* insert rules that may occur multiple times at the end */
-               this->entries->insert_last(this->entries, entry);
+               array_insert(this->entries, ARRAY_TAIL, &entry);
        }
        else
        {       /* insert rules we expect only once at the front (get() will return
                 * the latest value) */
-               this->entries->insert_first(this->entries, entry);
+               array_insert(this->entries, ARRAY_HEAD, &entry);
        }
 }
 
@@ -917,13 +914,13 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy
        }
        else
        {
-               entry_t *entry;
+               entry_t entry;
 
-               while (other->entries->remove_first(other->entries,
-                                                                                       (void**)&entry) == SUCCESS)
+               while (array_remove(other->entries, ARRAY_HEAD, &entry))
                {
-                       this->entries->insert_last(this->entries, entry);
+                       array_insert(this->entries, ARRAY_TAIL, &entry);
                }
+               array_compress(other->entries);
        }
 }
 
@@ -938,12 +935,12 @@ static bool auth_cfg_equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
 
        /* the rule count does not have to be equal for the two, as we only compare
         * the first value found for some rules */
-       e1 = this->entries->create_enumerator(this->entries);
+       e1 = array_create_enumerator(this->entries);
        while (e1->enumerate(e1, &i1))
        {
                found = FALSE;
 
-               e2 = other->entries->create_enumerator(other->entries);
+               e2 = array_create_enumerator(other->entries);
                while (e2->enumerate(e2, &i2))
                {
                        if (entry_equals(i1, i2))
@@ -984,27 +981,21 @@ static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other)
 METHOD(auth_cfg_t, purge, void,
        private_auth_cfg_t *this, bool keep_ca)
 {
+       enumerator_t *enumerator;
        entry_t *entry;
-       linked_list_t *cas;
 
-       cas = linked_list_create();
-       while (this->entries->remove_last(this->entries, (void**)&entry) == SUCCESS)
+       enumerator = array_create_enumerator(this->entries);
+       while (enumerator->enumerate(enumerator, &entry))
        {
-               if (keep_ca && entry->type == AUTH_RULE_CA_CERT)
-               {
-                       cas->insert_first(cas, entry);
-               }
-               else
+               if (!keep_ca || entry->type != AUTH_RULE_CA_CERT)
                {
+                       array_remove_at(this->entries, enumerator);
                        destroy_entry_value(entry);
-                       free(entry);
                }
        }
-       while (cas->remove_last(cas, (void**)&entry) == SUCCESS)
-       {
-               this->entries->insert_first(this->entries, entry);
-       }
-       cas->destroy(cas);
+       enumerator->destroy(enumerator);
+
+       array_compress(this->entries);
 }
 
 METHOD(auth_cfg_t, clone_, auth_cfg_t*,
@@ -1074,7 +1065,7 @@ METHOD(auth_cfg_t, destroy, void,
        private_auth_cfg_t *this)
 {
        purge(this, FALSE);
-       this->entries->destroy(this->entries);
+       array_destroy(this->entries);
        free(this);
 }
 
@@ -1098,7 +1089,7 @@ auth_cfg_t *auth_cfg_create()
                        .clone = _clone_,
                        .destroy = _destroy,
                },
-               .entries = linked_list_create(),
+               .entries = array_create(sizeof(entry_t), 0),
        );
 
        return &this->public;
index ca0a8c1..f175aa4 100644 (file)
@@ -7,7 +7,7 @@ test_runner_SOURCES = \
   test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \
   test_bio_reader.c test_bio_writer.c test_chunk.c test_enum.c test_hashtable.c \
   test_identification.c test_threading.c test_utils.c test_vectors.c \
-  test_ecdsa.c test_rsa.c
+  test_array.c test_ecdsa.c test_rsa.c
 
 test_runner_CFLAGS = \
   -I$(top_srcdir)/src/libstrongswan \
diff --git a/src/libstrongswan/tests/test_array.c b/src/libstrongswan/tests/test_array.c
new file mode 100644 (file)
index 0000000..2220d5a
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * 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 "test_suite.h"
+
+#include <collections/array.h>
+
+START_TEST(test_append_ptr)
+{
+       array_t *array;
+       uintptr_t x;
+       int i;
+
+       array = array_create(0, 0);
+
+       for (i = 0; i < 4; i++)
+       {
+               ck_assert_int_eq(array_count(array), 0);
+
+               array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)3);
+               array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)4);
+               ck_assert_int_eq(array_count(array), 2);
+
+               /* 3, 4 */
+
+               array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)1);
+               array_insert(array, 1, (void*)(uintptr_t)2);
+               ck_assert_int_eq(array_count(array), 4);
+
+               /* 1, 2, 3, 4 */
+
+               array_insert(array, ARRAY_TAIL, (void*)(uintptr_t)5);
+               array_insert(array, ARRAY_HEAD, (void*)(uintptr_t)0);
+               ck_assert_int_eq(array_count(array), 6);
+
+               /* 0, 1, 2, 3, 4, 5 */
+
+               ck_assert(array_remove(array, ARRAY_TAIL, &x));
+               ck_assert_int_eq(x, 5);
+               ck_assert(array_remove(array, 4, &x));
+               ck_assert_int_eq(x, 4);
+
+               if (i < 3)
+               {
+                       array_compress(array);
+               }
+
+               /* 0, 1, 2, 3 */
+
+               ck_assert(array_remove(array, 1, &x));
+               ck_assert_int_eq(x, 1);
+               ck_assert(array_remove(array, ARRAY_HEAD, &x));
+               ck_assert_int_eq(x, 0);
+
+               if (i < 2)
+               {
+                       array_compress(array);
+               }
+
+               /* 2, 3 */
+
+               ck_assert(array_remove(array, ARRAY_TAIL, &x));
+               ck_assert_int_eq(x, 3);
+               ck_assert(array_remove(array, ARRAY_TAIL, &x));
+               ck_assert_int_eq(x, 2);
+
+               if (i < 1)
+               {
+                       array_compress(array);
+               }
+
+               ck_assert_int_eq(array_count(array), 0);
+
+               ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE);
+               ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE);
+       }
+
+       array_destroy(array);
+}
+END_TEST
+
+START_TEST(test_append_obj)
+{
+       array_t *array;
+       int i, x, y[6] = {0, 1, 2, 3, 4, 5};
+
+       array = array_create(sizeof(y[0]), 0);
+
+       for (i = 0; i < 4; i++)
+       {
+               ck_assert_int_eq(array_count(array), 0);
+
+               array_insert(array, ARRAY_HEAD, &y[3]);
+               array_insert(array, ARRAY_TAIL, &y[4]);
+               ck_assert_int_eq(array_count(array), 2);;
+
+               /* 3, 4 */
+
+               array_insert(array, ARRAY_HEAD, &y[1]);
+               array_insert(array, 1, &y[2]);
+               ck_assert_int_eq(array_count(array), 4);
+
+               /* 1, 2, 3, 4 */
+
+               array_insert(array, ARRAY_TAIL, &y[5]);
+               array_insert(array, ARRAY_HEAD, &y[0]);
+               ck_assert_int_eq(array_count(array), 6);
+
+               /* 0, 1, 2, 3, 4, 5 */
+
+               ck_assert(array_remove(array, ARRAY_TAIL, &x));
+               ck_assert_int_eq(x, 5);
+               ck_assert(array_remove(array, 4, &x));
+               ck_assert_int_eq(x, 4);
+
+               if (i < 3)
+               {
+                       array_compress(array);
+               }
+
+               /* 0, 1, 2, 3 */
+
+               ck_assert(array_remove(array, ARRAY_HEAD, &x));
+               ck_assert_int_eq(x, 0);
+               ck_assert(array_remove(array, ARRAY_HEAD, &x));
+               ck_assert_int_eq(x, 1);
+
+               if (i < 2)
+               {
+                       array_compress(array);
+               }
+
+               /* 2, 3 */
+
+               ck_assert(array_remove(array, ARRAY_TAIL, &x));
+               ck_assert_int_eq(x, 3);
+               ck_assert(array_remove(array, ARRAY_HEAD, &x));
+               ck_assert_int_eq(x, 2);
+
+               if (i < 1)
+               {
+                       array_compress(array);
+               }
+
+               ck_assert_int_eq(array_count(array), 0);
+
+               ck_assert(array_remove(array, ARRAY_HEAD, NULL) == FALSE);
+               ck_assert(array_remove(array, ARRAY_TAIL, NULL) == FALSE);
+       }
+
+       array_destroy(array);
+}
+END_TEST
+
+START_TEST(test_enumerate)
+{
+       array_t *array;
+       int i, *x, y[6] = {0, 1, 2, 3, 4, 5};
+       enumerator_t *enumerator;
+
+       array = array_create(sizeof(y[0]), 0);
+
+       array_insert(array, ARRAY_TAIL, &y[0]);
+       array_insert(array, ARRAY_TAIL, &y[1]);
+       array_insert(array, ARRAY_TAIL, &y[2]);
+       array_insert(array, ARRAY_TAIL, &y[3]);
+       array_insert(array, ARRAY_TAIL, &y[4]);
+       array_insert(array, ARRAY_TAIL, &y[5]);
+
+       ck_assert_int_eq(array_count(array), 6);
+
+       /* 0, 1, 2, 3, 4, 5 */
+
+       i = 0;
+       enumerator = array_create_enumerator(array);
+       while (enumerator->enumerate(enumerator, &x))
+       {
+               ck_assert_int_eq(*x, y[i]);
+               i++;
+       }
+       enumerator->destroy(enumerator);
+       ck_assert_int_eq(i, 6);
+
+       i = 0;
+       enumerator = array_create_enumerator(array);
+       while (enumerator->enumerate(enumerator, &x))
+       {
+               ck_assert_int_eq(*x, y[i]);
+               if (i == 0 || i == 3 || i == 5)
+               {
+                       array_remove_at(array, enumerator);
+               }
+               i++;
+       }
+       enumerator->destroy(enumerator);
+       ck_assert_int_eq(i, 6);
+       ck_assert_int_eq(array_count(array), 3);
+
+       /* 1, 2, 4 */
+
+       i = 0;
+       enumerator = array_create_enumerator(array);
+       while (enumerator->enumerate(enumerator, &x))
+       {
+               switch (i++)
+               {
+                       case 0:
+                               ck_assert_int_eq(*x, y[1]);
+                               break;
+                       case 1:
+                               ck_assert_int_eq(*x, y[2]);
+                               break;
+                       case 2:
+                               ck_assert_int_eq(*x, y[4]);
+                               break;
+                       default:
+                               ck_assert(0);
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       array_compress(array);
+
+       i = 0;
+       enumerator = array_create_enumerator(array);
+       while (enumerator->enumerate(enumerator, &x))
+       {
+               switch (i++)
+               {
+                       case 0:
+                               ck_assert_int_eq(*x, y[1]);
+                               break;
+                       case 1:
+                               ck_assert_int_eq(*x, y[2]);
+                               break;
+                       case 2:
+                               ck_assert_int_eq(*x, y[4]);
+                               break;
+                       default:
+                               ck_assert(0);
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       array_destroy(array);
+}
+END_TEST
+
+static void invoke(void *data, int idx, void *user)
+{
+       int *y = user, *x = data;
+
+       ck_assert(idx < 3);
+
+       ck_assert_int_eq(y[idx], *x);
+       y[idx] = 0;
+}
+
+START_TEST(test_invoke)
+{
+       array_t *array;
+       int y[] = {1, 2, 3};
+
+       array = array_create(sizeof(y[0]), 0);
+
+       array_insert(array, ARRAY_TAIL, &y[0]);
+       array_insert(array, ARRAY_TAIL, &y[1]);
+       array_insert(array, ARRAY_TAIL, &y[2]);
+
+       array_invoke(array, invoke, y);
+
+       ck_assert_int_eq(y[0], 0);
+       ck_assert_int_eq(y[0], 0);
+       ck_assert_int_eq(y[0], 0);
+
+       array_destroy(array);
+}
+END_TEST
+
+typedef struct obj_t obj_t;
+
+struct obj_t {
+       void (*fun)(obj_t *obj);
+       int x;
+       int *counter;
+};
+
+static void fun(obj_t *obj)
+{
+       ck_assert(obj->x == (*obj->counter)++);
+}
+
+START_TEST(test_invoke_offset)
+{
+       array_t *array;
+       obj_t objs[5];
+       int i, counter = 0;
+
+       array = array_create(0, 0);
+
+       for (i = 0; i < countof(objs); i++)
+       {
+               objs[i].x = i;
+               objs[i].counter = &counter;
+               objs[i].fun = fun;
+
+               array_insert(array, ARRAY_TAIL, &objs[i]);
+       }
+
+       ck_assert_int_eq(countof(objs), array_count(array));
+
+       array_invoke_offset(array, offsetof(obj_t, fun));
+
+       ck_assert_int_eq(counter, countof(objs));
+
+       array_destroy(array);
+}
+END_TEST
+
+Suite *array_suite_create()
+{
+       Suite *s;
+       TCase *tc;
+
+       s = suite_create("array");
+
+       tc = tcase_create("add/remove ptr");
+       tcase_add_test(tc, test_append_ptr);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("add/remove obj");
+       tcase_add_test(tc, test_append_obj);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("enumerate");
+       tcase_add_test(tc, test_enumerate);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("invoke");
+       tcase_add_test(tc, test_invoke);
+       suite_add_tcase(s, tc);
+
+       tc = tcase_create("invoke offset");
+       tcase_add_test(tc, test_invoke_offset);
+       suite_add_tcase(s, tc);
+
+       return s;
+}
index 2f9e4dc..b9e1901 100644 (file)
@@ -78,6 +78,7 @@ int main()
        srunner_add_suite(sr, linked_list_suite_create());
        srunner_add_suite(sr, linked_list_enumerator_suite_create());
        srunner_add_suite(sr, hashtable_suite_create());
+       srunner_add_suite(sr, array_suite_create());
        srunner_add_suite(sr, identification_suite_create());
        srunner_add_suite(sr, threading_suite_create());
        srunner_add_suite(sr, utils_suite_create());
index 5c60588..34aa0cf 100644 (file)
@@ -26,6 +26,7 @@ Suite *enumerator_suite_create();
 Suite *linked_list_suite_create();
 Suite *linked_list_enumerator_suite_create();
 Suite *hashtable_suite_create();
+Suite *array_suite_create();
 Suite *identification_suite_create();
 Suite *threading_suite_create();
 Suite *utils_suite_create();