aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/config/proposal.c477
-rw-r--r--src/libcharon/plugins/farp/farp_listener.c24
-rw-r--r--src/libcharon/plugins/ha/ha_child.c16
-rw-r--r--src/libcharon/plugins/smp/smp.c4
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c13
-rw-r--r--src/libcharon/plugins/uci/uci_control.c8
-rw-r--r--src/libcharon/sa/child_sa.c143
-rw-r--r--src/libcharon/sa/child_sa.h13
-rw-r--r--src/libcharon/sa/ike_sa.c214
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c36
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c14
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c14
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c146
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c34
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c14
-rw-r--r--src/libstrongswan/Android.mk2
-rw-r--r--src/libstrongswan/Makefile.am3
-rw-r--r--src/libstrongswan/collections/array.c416
-rw-r--r--src/libstrongswan/collections/array.h194
-rw-r--r--src/libstrongswan/credentials/auth_cfg.c61
-rw-r--r--src/libstrongswan/tests/Makefile.am2
-rw-r--r--src/libstrongswan/tests/test_array.c360
-rw-r--r--src/libstrongswan/tests/test_runner.c1
-rw-r--r--src/libstrongswan/tests/test_runner.h1
24 files changed, 1527 insertions, 683 deletions
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
index 4803c7be2..a927a1f75 100644
--- a/src/libcharon/config/proposal.c
+++ b/src/libcharon/config/proposal.c
@@ -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;
diff --git a/src/libcharon/plugins/farp/farp_listener.c b/src/libcharon/plugins/farp/farp_listener.c
index 81d5d2405..87c84359c 100644
--- a/src/libcharon/plugins/farp/farp_listener.c
+++ b/src/libcharon/plugins/farp/farp_listener.c
@@ -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;
}
-
diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c
index 707add94d..c166d72ac 100644
--- a/src/libcharon/plugins/ha/ha_child.c
+++ b/src/libcharon/plugins/ha/ha_child.c
@@ -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;
}
-
diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c
index d13b82216..123608819 100644
--- a/src/libcharon/plugins/smp/smp.c
+++ b/src/libcharon/plugins/smp/smp.c
@@ -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);
}
/**
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index e76afec68..e81f3fc32 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -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);
}
/**
diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c
index 53221b786..cebc389e7 100644
--- a/src/libcharon/plugins/uci/uci_control.c
+++ b/src/libcharon/plugins/uci/uci_control.c
@@ -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;
}
-
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 1069b2d91..46e4b6f7b 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -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;
}
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index aa44dbfad..44c529391 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -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);
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 19c6248ec..50d969430 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -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,
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 709033cb5..bfa6fc81e 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -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,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index e9f06cbe3..5b3e35ed3 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -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)
{
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 52ea34b1a..92df0f0f8 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -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)
{
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 839bdb990..79a9aa5a0 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -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,
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index dd3813e85..8ae36af84 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -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);
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 9f12d7385..eaaca2039 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -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);
}
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk
index 75b501fdd..dc533a38b 100644
--- a/src/libstrongswan/Android.mk
+++ b/src/libstrongswan/Android.mk
@@ -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)
-
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 567bdfe6f..bde5f710a 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -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
index 000000000..d92eaacfe
--- /dev/null
+++ b/src/libstrongswan/collections/array.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2013 Martin Willi
+ * Copyright (C) 2013 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "array.h"
+
+/**
+ * Data is an allocated block, with potentially unused head and tail:
+ *
+ * "esize" each (or sizeof(void*) if esize = 0)
+ * /-\ /-\ /-\ /-\ /-\ /-\
+ *
+ * +---------------+-------------------------------+---------------+
+ * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l |
+ * +---------------+-------------------------------+---------------+
+ *
+ * \--------------/ \-----------------------------/ \-------------/
+ * unused used unused
+ * "head" "count" "tail"
+ *
+ */
+struct array_t {
+ /** number of elements currently in array (not counting head/tail) */
+ u_int32_t count;
+ /** size of each element, 0 for a pointer based array */
+ u_int16_t esize;
+ /** allocated but unused elements at array front */
+ u_int8_t head;
+ /** allocated but unused elements at array end */
+ u_int8_t tail;
+ /** array elements */
+ void *data;
+};
+
+/** maximum number of unused head/tail elements before cleanup */
+#define ARRAY_MAX_UNUSED 32
+
+/**
+ * Get the actual size of a number of elements
+ */
+static size_t get_size(array_t *array, 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
index 000000000..3e6180b54
--- /dev/null
+++ b/src/libstrongswan/collections/array.h
@@ -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_ @}*/
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index d2d0a7d72..2203519e2 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -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;
diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am
index ca0a8c1ed..f175aa4a7 100644
--- a/src/libstrongswan/tests/Makefile.am
+++ b/src/libstrongswan/tests/Makefile.am
@@ -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
index 000000000..2220d5a2b
--- /dev/null
+++ b/src/libstrongswan/tests/test_array.c
@@ -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;
+}
diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c
index 2f9e4dc0a..b9e1901b0 100644
--- a/src/libstrongswan/tests/test_runner.c
+++ b/src/libstrongswan/tests/test_runner.c
@@ -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());
diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h
index 5c60588e9..34aa0cf18 100644
--- a/src/libstrongswan/tests/test_runner.h
+++ b/src/libstrongswan/tests/test_runner.h
@@ -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();