aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2015-10-16 12:31:38 +0200
committerTobias Brunner <tobias@strongswan.org>2016-03-08 10:21:58 +0100
commit622c2b2c3386dd8fad321fc3bbd4d019b99fbb71 (patch)
tree83ba85a0f061efaf5a16e04581a43d357992d47a /src
parent8db4f19ad9531afa12f671343fb0e9738ac00727 (diff)
downloadstrongswan-622c2b2c3386dd8fad321fc3bbd4d019b99fbb71.tar.bz2
strongswan-622c2b2c3386dd8fad321fc3bbd4d019b99fbb71.tar.xz
peer-cfg: Add method to atomically replace child configs
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/config/peer_cfg.c114
-rw-r--r--src/libcharon/config/peer_cfg.h16
2 files changed, 128 insertions, 2 deletions
diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c
index a0e336201..d28a79507 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2008 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -200,6 +200,117 @@ METHOD(peer_cfg_t, add_child_cfg, void,
this->mutex->unlock(this->mutex);
}
+typedef struct {
+ enumerator_t public;
+ linked_list_t *removed;
+ linked_list_t *added;
+ enumerator_t *wrapped;
+ bool add;
+} child_cfgs_replace_enumerator_t;
+
+METHOD(enumerator_t, child_cfgs_replace_enumerate, bool,
+ child_cfgs_replace_enumerator_t *this, child_cfg_t **chd, bool *added)
+{
+ child_cfg_t *child_cfg;
+
+ if (!this->wrapped)
+ {
+ this->wrapped = this->removed->create_enumerator(this->removed);
+ }
+ while (TRUE)
+ {
+ if (this->wrapped->enumerate(this->wrapped, &child_cfg))
+ {
+ if (chd)
+ {
+ *chd = child_cfg;
+ }
+ if (added)
+ {
+ *added = this->add;
+ }
+ return TRUE;
+ }
+ if (this->add)
+ {
+ break;
+ }
+ this->wrapped = this->added->create_enumerator(this->added);
+ this->add = TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, child_cfgs_replace_enumerator_destroy, void,
+ child_cfgs_replace_enumerator_t *this)
+{
+ DESTROY_IF(this->wrapped);
+ this->removed->destroy_offset(this->removed, offsetof(child_cfg_t, destroy));
+ this->added->destroy_offset(this->added, offsetof(child_cfg_t, destroy));
+ free(this);
+}
+
+METHOD(peer_cfg_t, replace_child_cfgs, enumerator_t*,
+ private_peer_cfg_t *this, peer_cfg_t *other_pub)
+{
+ private_peer_cfg_t *other = (private_peer_cfg_t*)other_pub;
+ linked_list_t *removed, *added;
+ enumerator_t *mine, *others;
+ child_cfg_t *my_cfg, *other_cfg;
+ child_cfgs_replace_enumerator_t *enumerator;
+ bool found;
+
+ removed = linked_list_create();
+
+ other->mutex->lock(other->mutex);
+ added = linked_list_create_from_enumerator(
+ other->child_cfgs->create_enumerator(other->child_cfgs));
+ added->invoke_offset(added, offsetof(child_cfg_t, get_ref));
+ other->mutex->unlock(other->mutex);
+
+ this->mutex->lock(this->mutex);
+ others = added->create_enumerator(added);
+ mine = this->child_cfgs->create_enumerator(this->child_cfgs);
+ while (mine->enumerate(mine, &my_cfg))
+ {
+ found = FALSE;
+ while (others->enumerate(others, &other_cfg))
+ {
+ if (my_cfg->equals(my_cfg, other_cfg))
+ {
+ added->remove_at(added, others);
+ other_cfg->destroy(other_cfg);
+ found = TRUE;
+ break;
+ }
+ }
+ added->reset_enumerator(added, others);
+ if (!found)
+ {
+ this->child_cfgs->remove_at(this->child_cfgs, mine);
+ removed->insert_last(removed, my_cfg);
+ }
+ }
+ while (others->enumerate(others, &other_cfg))
+ {
+ this->child_cfgs->insert_last(this->child_cfgs,
+ other_cfg->get_ref(other_cfg));
+ }
+ others->destroy(others);
+ mine->destroy(mine);
+ this->mutex->unlock(this->mutex);
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_child_cfgs_replace_enumerate,
+ .destroy = (void*)_child_cfgs_replace_enumerator_destroy,
+ },
+ .removed = removed,
+ .added = added,
+ );
+ return &enumerator->public;
+}
+
/**
* child_cfg enumerator
*/
@@ -645,6 +756,7 @@ peer_cfg_t *peer_cfg_create(char *name,
.get_ike_cfg = _get_ike_cfg,
.add_child_cfg = _add_child_cfg,
.remove_child_cfg = (void*)_remove_child_cfg,
+ .replace_child_cfgs = _replace_child_cfgs,
.create_child_cfg_enumerator = _create_child_cfg_enumerator,
.select_child_cfg = _select_child_cfg,
.get_cert_policy = _get_cert_policy,
diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h
index 3e780394a..b612a2ef1 100644
--- a/src/libcharon/config/peer_cfg.h
+++ b/src/libcharon/config/peer_cfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2008 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -154,6 +154,20 @@ struct peer_cfg_t {
void (*remove_child_cfg)(peer_cfg_t *this, enumerator_t *enumerator);
/**
+ * Replace the CHILD configs with those in the given PEER config.
+ *
+ * Configs that are equal are not replaced.
+ *
+ * The enumerator enumerates the removed and added CHILD configs
+ * (child_cfg_t*, bool), where the flag is FALSE for removed configs and
+ * TRUE for added configs.
+ *
+ * @param other other config to get CHILD configs from
+ * @return an enumerator over removed/added CHILD configs
+ */
+ enumerator_t* (*replace_child_cfgs)(peer_cfg_t *this, peer_cfg_t *other);
+
+ /**
* Create an enumerator for all attached CHILD configs.
*
* @return an enumerator over all CHILD configs.