Introduces a new lightweight array collection having minimal memory overhead.
The new class replaces various linked lists that are used during the full
lifetime of an SA, reducing memory requirements by about 5KB or more per tunnel.
#include "proposal.h"
#include <daemon.h>
-#include <collections/linked_list.h>
+#include <collections/array.h>
#include <utils/identification.h>
#include <crypto/transform.h>
);
typedef struct private_proposal_t private_proposal_t;
-typedef struct algorithm_t algorithm_t;
/**
* Private data of an proposal_t object
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
/**
* 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;
}
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,
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, ¤t, NULL))
{
- algorithm_t *current;
- enumerator_t *enumerator;
-
- enumerator = this->dh_groups->create_enumerator(this->dh_groups);
- while (enumerator->enumerate(enumerator, (void**)¤t))
+ 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, "
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;
}
}
/**
- * 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;
}
}
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;
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;
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);
}
/**
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);
}
},
.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;
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);
return &this->public;
}
-
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);
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);
return &this->public;
}
-
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);
}
/**
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",
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);
}
/**
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;
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");
}
return &this->public;
}
-
#include <hydra.h>
#include <daemon.h>
+#include <collections/array.h>
ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
"CREATED",
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
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;
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;
};
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;
}
.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,
);
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);
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);
}
/**
+ * 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,
.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),
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;
}
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);
#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>
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
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
/**
* 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
{
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, ¤t, NULL, NULL);
{
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);
}
}
{
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);
}
/**
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);
}
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
{
}
else
{
- this->other_vips->insert_last(this->other_vips, ip->clone(ip));
+ array_insert_create(&this->other_vips, ARRAY_TAIL, ip->clone(ip));
}
}
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)
{
{
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);
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,
{
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),
}
}
enumerator->destroy(enumerator);
+
+ vips->destroy(vips);
}
}
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 */
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*,
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**)¤t))
{
if (current->get_spi(current, inbound) == spi &&
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,
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;
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
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)
}
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)
/* 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
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);
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))
{
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;
* 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)
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*,
{
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;
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 */
#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 */
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);
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)
{
/* 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)
{
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);
},
.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),
.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,
/**
* 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;
}
/**
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,
{
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);
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
{
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)
{
{
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);
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)
{
#include <math.h>
+#include <collections/array.h>
#include <daemon.h>
#include <sa/ikev2/tasks/ike_init.h>
#include <sa/ikev2/tasks/ike_natd.h>
} 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
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);
}
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;
}
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)
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))
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))
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:
}
message->destroy(message);
+ array_compress(this->active_tasks);
+ array_compress(this->queued_tasks);
+
return retransmit(this, this->initiating.mid);
}
/* 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:
/* 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;
this->initiating.packet->destroy(this->initiating.packet);
this->initiating.packet = NULL;
+ array_compress(this->active_tasks);
+
return initiate(this);
}
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))
{
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);
/* 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:
}
return DESTROY_ME;
}
+
+ array_compress(this->passive_tasks);
+
return SUCCESS;
}
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:
{
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:
{
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:
}
/* 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:
/* 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;
enumerator_t *enumerator;
task_t *current;
- enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
- while (enumerator->enumerate(enumerator, (void**)¤t))
+ enumerator = array_create_enumerator(this->queued_tasks);
+ while (enumerator->enumerate(enumerator, ¤t))
{
if (current->get_type(current) == TASK_IKE_MOBIKE)
{
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);
}
/**
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)
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,
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);
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;
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();
}
{
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);
},
.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,
{ /* 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;
}
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);
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);
*/
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;
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
{
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);
}
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 \
LOCAL_SHARED_LIBRARIES += libdl libvstr
include $(BUILD_SHARED_LIBRARY)
-
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 \
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 \
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ @}*/
#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>
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;
.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)
{
this->value = NULL;
break;
}
- return this;
}
/**
*/
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);
}
}
}
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);
}
}
/* 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))
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*,
private_auth_cfg_t *this)
{
purge(this, FALSE);
- this->entries->destroy(this->entries);
+ array_destroy(this->entries);
free(this);
}
.clone = _clone_,
.destroy = _destroy,
},
- .entries = linked_list_create(),
+ .entries = array_create(sizeof(entry_t), 0),
);
return &this->public;
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 \
--- /dev/null
+/*
+ * 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;
+}
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());
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();