[strongSwan-dev] [PATCH 6/8] trap-manager: Changed how acquires we acted on are tracked

Timo Teräs timo.teras at iki.fi
Wed Aug 27 15:05:22 CEST 2014


From: Tobias Brunner <tobias at strongswan.org>

---
 src/libcharon/sa/trap_manager.c | 115 ++++++++++++++++++++++++++++------------
 1 file changed, 80 insertions(+), 35 deletions(-)

diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 9e933d1..e70f400 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -18,10 +18,10 @@
 
 #include <hydra.h>
 #include <daemon.h>
+#include <threading/mutex.h>
 #include <threading/rwlock.h>
 #include <collections/linked_list.h>
 
-
 typedef struct private_trap_manager_t private_trap_manager_t;
 typedef struct trap_listener_t trap_listener_t;
 
@@ -65,6 +65,16 @@ struct private_trap_manager_t {
 	 * listener to track acquiring IKE_SAs
 	 */
 	trap_listener_t listener;
+
+	/**
+	 * list of acquires we currently handle
+	 */
+	linked_list_t *acquires;
+
+	/**
+	 * mutex for list of acquires
+	 */
+	mutex_t *mutex;
 };
 
 /**
@@ -75,23 +85,45 @@ typedef struct {
 	char *name;
 	/** ref to peer_cfg to initiate */
 	peer_cfg_t *peer_cfg;
-	/** ref to instanciated CHILD_SA */
+	/** ref to instantiated CHILD_SA (i.e the trap policy) */
 	child_sa_t *child_sa;
-	/** TRUE if an acquire is pending */
-	bool pending;
+} entry_t;
+
+/**
+ * A handled acquire
+ */
+typedef struct {
 	/** pending IKE_SA connecting upon acquire */
 	ike_sa_t *ike_sa;
-} entry_t;
+	/** reqid of pending trap policy */
+	u_int32_t reqid;
+} acquire_t;
 
 /**
  * actually uninstall and destroy an installed entry
  */
-static void destroy_entry(entry_t *entry)
+static void destroy_entry(entry_t *this)
 {
-	entry->child_sa->destroy(entry->child_sa);
-	entry->peer_cfg->destroy(entry->peer_cfg);
-	free(entry->name);
-	free(entry);
+	this->child_sa->destroy(this->child_sa);
+	this->peer_cfg->destroy(this->peer_cfg);
+	free(this->name);
+	free(this);
+}
+
+/**
+ * destroy a cached acquire entry
+ */
+static void destroy_acquire(acquire_t *this)
+{
+	free(this);
+}
+
+/**
+ * match an acquire entry by reqid
+ */
+static bool acquire_by_reqid(acquire_t *this, u_int32_t *reqid)
+{
+	return this->reqid == *reqid;
 }
 
 METHOD(trap_manager_t, install, u_int32_t,
@@ -309,6 +341,7 @@ METHOD(trap_manager_t, acquire, void,
 {
 	enumerator_t *enumerator;
 	entry_t *entry, *found = NULL;
+	acquire_t *acquire;
 	peer_cfg_t *peer;
 	child_cfg_t *child;
 	ike_sa_t *ike_sa;
@@ -332,16 +365,29 @@ METHOD(trap_manager_t, acquire, void,
 		this->lock->unlock(this->lock);
 		return;
 	}
-	if (!cas_bool(&found->pending, FALSE, TRUE))
+
+	this->mutex->lock(this->mutex);
+	reqid = found->child_sa->get_reqid(found->child_sa);
+	if (this->acquires->find_first(this->acquires, (void*)acquire_by_reqid,
+								  (void**)&acquire, &reqid) == SUCCESS)
 	{
 		DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
+		this->mutex->unlock(this->mutex);
 		this->lock->unlock(this->lock);
 		return;
 	}
+	else
+	{
+		INIT(acquire,
+			.reqid = reqid,
+		);
+		this->acquires->insert_last(this->acquires, acquire);
+	}
+	this->mutex->unlock(this->mutex);
+
 	peer = found->peer_cfg->get_ref(found->peer_cfg);
 	child = found->child_sa->get_config(found->child_sa);
 	child = child->get_ref(child);
-	reqid = found->child_sa->get_reqid(found->child_sa);
 	/* don't hold the lock while checking out the IKE_SA */
 	this->lock->unlock(this->lock);
 
@@ -361,14 +407,9 @@ METHOD(trap_manager_t, acquire, void,
 		}
 		if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
 		{
-			/* make sure the entry is still there */
-			this->lock->read_lock(this->lock);
-			if (this->traps->find_first(this->traps, NULL,
-										(void**)&found) == SUCCESS)
-			{
-				found->ike_sa = ike_sa;
-			}
-			this->lock->unlock(this->lock);
+			this->mutex->lock(this->mutex);
+			acquire->ike_sa = ike_sa;
+			this->mutex->unlock(this->mutex);
 			charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 		}
 		else
@@ -387,26 +428,25 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
 					 child_sa_t *child_sa)
 {
 	enumerator_t *enumerator;
-	entry_t *entry;
+	acquire_t *acquire;
 
-	this->lock->read_lock(this->lock);
-	enumerator = this->traps->create_enumerator(this->traps);
-	while (enumerator->enumerate(enumerator, &entry))
+	this->mutex->lock(this->mutex);
+	enumerator = this->acquires->create_enumerator(this->acquires);
+	while (enumerator->enumerate(enumerator, &acquire))
 	{
-		if (entry->ike_sa != ike_sa)
+		if (acquire->ike_sa != ike_sa)
 		{
 			continue;
 		}
-		if (child_sa && child_sa->get_reqid(child_sa) !=
-									entry->child_sa->get_reqid(entry->child_sa))
+		if (child_sa && child_sa->get_reqid(child_sa) != acquire->reqid)
 		{
 			continue;
 		}
-		entry->ike_sa = NULL;
-		entry->pending = FALSE;
+		this->acquires->remove_at(this->acquires, enumerator);
+		destroy_acquire(acquire);
 	}
 	enumerator->destroy(enumerator);
-	this->lock->unlock(this->lock);
+	this->mutex->unlock(this->mutex);
 }
 
 METHOD(listener_t, ike_state_change, bool,
@@ -440,14 +480,15 @@ METHOD(listener_t, child_state_change, bool,
 METHOD(trap_manager_t, flush, void,
 	private_trap_manager_t *this)
 {
-	linked_list_t *traps;
-	/* since destroying the CHILD_SA results in events which require a read
-	 * lock we cannot destroy the list while holding the write lock */
 	this->lock->write_lock(this->lock);
-	traps = this->traps;
+	this->traps->destroy_function(this->traps, (void*)destroy_entry);
 	this->traps = linked_list_create();
 	this->lock->unlock(this->lock);
-	traps->destroy_function(traps, (void*)destroy_entry);
+
+	this->mutex->lock(this->mutex);
+	this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
+	this->acquires = linked_list_create();
+	this->mutex->unlock(this->mutex);
 }
 
 METHOD(trap_manager_t, destroy, void,
@@ -455,6 +496,8 @@ METHOD(trap_manager_t, destroy, void,
 {
 	charon->bus->remove_listener(charon->bus, &this->listener.listener);
 	this->traps->destroy_function(this->traps, (void*)destroy_entry);
+	this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
+	this->mutex->destroy(this->mutex);
 	this->lock->destroy(this->lock);
 	free(this);
 }
@@ -484,6 +527,8 @@ trap_manager_t *trap_manager_create(void)
 			},
 		},
 		.traps = linked_list_create(),
+		.acquires = linked_list_create(),
+		.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
 		.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
 	);
 	charon->bus->add_listener(charon->bus, &this->listener.listener);
-- 
2.1.0



More information about the Dev mailing list