diff options
author | Tobias Brunner <tobias@strongswan.org> | 2015-10-16 12:31:38 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2016-03-08 10:21:58 +0100 |
commit | 622c2b2c3386dd8fad321fc3bbd4d019b99fbb71 (patch) | |
tree | 83ba85a0f061efaf5a16e04581a43d357992d47a /src/libcharon/config/peer_cfg.c | |
parent | 8db4f19ad9531afa12f671343fb0e9738ac00727 (diff) | |
download | strongswan-622c2b2c3386.tar.bz2 strongswan-622c2b2c3386.tar.xz |
peer-cfg: Add method to atomically replace child configs
Diffstat (limited to 'src/libcharon/config/peer_cfg.c')
-rw-r--r-- | src/libcharon/config/peer_cfg.c | 114 |
1 files changed, 113 insertions, 1 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, |