peer-cfg: Add method to atomically replace child configs
authorTobias Brunner <tobias@strongswan.org>
Fri, 16 Oct 2015 10:31:38 +0000 (12:31 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 8 Mar 2016 09:21:58 +0000 (10:21 +0100)
src/libcharon/config/peer_cfg.c
src/libcharon/config/peer_cfg.h

index a0e3362..d28a795 100644 (file)
@@ -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,
index 3e78039..b612a2e 100644 (file)
@@ -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.