shunt-manager: Add flush() method to properly uninstall shunts
authorTobias Brunner <tobias@strongswan.org>
Tue, 14 Jul 2015 14:55:36 +0000 (16:55 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 27 Jul 2015 11:51:10 +0000 (13:51 +0200)
This will allow us to uninstall shunts before unloading the
kernel-interface plugins.

src/libcharon/sa/shunt_manager.c
src/libcharon/sa/shunt_manager.h

index 2e42e7e..1a98443 100644 (file)
 #include <hydra.h>
 #include <daemon.h>
 #include <threading/rwlock.h>
+#include <threading/rwlock_condvar.h>
 #include <collections/linked_list.h>
 
+#define INSTALL_DISABLED ((u_int)~0)
+
 typedef struct private_shunt_manager_t private_shunt_manager_t;
 
 /**
@@ -42,6 +45,16 @@ struct private_shunt_manager_t {
         * Lock to safely access the list of shunts
         */
        rwlock_t *lock;
+
+       /**
+        * Number of threads currently installing shunts, or INSTALL_DISABLED
+        */
+       u_int installing;
+
+       /**
+        * Condvar to signal shunt installation
+        */
+       rwlock_condvar_t *condvar;
 };
 
 /**
@@ -126,6 +139,11 @@ METHOD(shunt_manager_t, install, bool,
 
        /* check if not already installed */
        this->lock->write_lock(this->lock);
+       if (this->installing == INSTALL_DISABLED)
+       {       /* flush() has been called */
+               this->lock->unlock(this->lock);
+               return FALSE;
+       }
        enumerator = this->shunts->create_enumerator(this->shunts);
        while (enumerator->enumerate(enumerator, &child_cfg))
        {
@@ -144,17 +162,20 @@ METHOD(shunt_manager_t, install, bool,
                return TRUE;
        }
        this->shunts->insert_last(this->shunts, child->get_ref(child));
+       this->installing++;
        this->lock->unlock(this->lock);
 
        success = install_shunt_policy(child);
 
+       this->lock->write_lock(this->lock);
        if (!success)
        {
-               this->lock->write_lock(this->lock);
                this->shunts->remove(this->shunts, child, NULL);
-               this->lock->unlock(this->lock);
                child->destroy(child);
        }
+       this->installing--;
+       this->condvar->signal(this->condvar);
+       this->lock->unlock(this->lock);
        return success;
 }
 
@@ -263,18 +284,31 @@ METHOD(shunt_manager_t, create_enumerator, enumerator_t*,
                                                        (void*)this->lock->unlock, this->lock);
 }
 
-METHOD(shunt_manager_t, destroy, void,
+METHOD(shunt_manager_t, flush, void,
        private_shunt_manager_t *this)
 {
        child_cfg_t *child;
 
+       this->lock->write_lock(this->lock);
+       while (this->installing)
+       {
+               this->condvar->wait(this->condvar, this->lock);
+       }
        while (this->shunts->remove_last(this->shunts, (void**)&child) == SUCCESS)
        {
                uninstall_shunt_policy(child);
                child->destroy(child);
        }
-       this->shunts->destroy(this->shunts);
+       this->installing = INSTALL_DISABLED;
+       this->lock->unlock(this->lock);
+}
+
+METHOD(shunt_manager_t, destroy, void,
+       private_shunt_manager_t *this)
+{
+       this->shunts->destroy_offset(this->shunts, offsetof(child_cfg_t, destroy));
        this->lock->destroy(this->lock);
+       this->condvar->destroy(this->condvar);
        free(this);
 }
 
@@ -290,10 +324,12 @@ shunt_manager_t *shunt_manager_create()
                        .install = _install,
                        .uninstall = _uninstall,
                        .create_enumerator = _create_enumerator,
+                       .flush = _flush,
                        .destroy = _destroy,
                },
                .shunts = linked_list_create(),
                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+               .condvar = rwlock_condvar_create(),
        );
 
        return &this->public;
index 28a795d..c43f5db 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015 Tobias Brunner
  * Copyright (C) 2011 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -56,6 +57,11 @@ struct shunt_manager_t {
        enumerator_t* (*create_enumerator)(shunt_manager_t *this);
 
        /**
+        * Clear any installed shunt.
+        */
+       void (*flush)(shunt_manager_t *this);
+
+       /**
         * Destroy a shunt_manager_t.
         */
        void (*destroy)(shunt_manager_t *this);