Added class to relay IPsec events (like expiration) to listeners
authorTobias Brunner <tobias@strongswan.org>
Fri, 13 Jul 2012 11:32:27 +0000 (13:32 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 Aug 2012 13:41:03 +0000 (15:41 +0200)
Currently, only expiration of IPsec SAs is supported.  Later other events
for e.g. acquires or changed NAT endpoints could be added.

src/libipsec/Android.mk
src/libipsec/Makefile.am
src/libipsec/ipsec.c
src/libipsec/ipsec.h
src/libipsec/ipsec_event_listener.h [new file with mode: 0644]
src/libipsec/ipsec_event_relay.c [new file with mode: 0644]
src/libipsec/ipsec_event_relay.h [new file with mode: 0644]

index a5d93df..0248109 100644 (file)
@@ -6,6 +6,8 @@ LOCAL_SRC_FILES := \
 ipsec.c ipsec.h \
 esp_context.c esp_context.h \
 esp_packet.c esp_packet.h \
+ipsec_event_listener.h \
+ipsec_event_relay.c ipsec_event_relay.h \
 ipsec_sa.c ipsec_sa.h \
 ipsec_sa_mgr.c ipsec_sa_mgr.h
 
index 3de8f82..c102493 100644 (file)
@@ -4,6 +4,8 @@ libipsec_la_SOURCES = \
 ipsec.c ipsec.h \
 esp_context.c esp_context.h \
 esp_packet.c esp_packet.h \
+ipsec_event_listener.h \
+ipsec_event_relay.c ipsec_event_relay.h \
 ipsec_sa.c ipsec_sa.h \
 ipsec_sa_mgr.c ipsec_sa_mgr.h
 
index 5ae6c74..49773ab 100644 (file)
@@ -43,6 +43,7 @@ ipsec_t *ipsec;
 void libipsec_deinit()
 {
        private_ipsec_t *this = (private_ipsec_t*)ipsec;
+       DESTROY_IF(this->public.events);
        DESTROY_IF(this->public.sas);
        free(this);
        ipsec = NULL;
@@ -66,6 +67,7 @@ bool libipsec_init()
        }
 
        this->public.sas = ipsec_sa_mgr_create();
+       this->public.events = ipsec_event_relay_create();
        return TRUE;
 }
 
index e4055a8..3047381 100644 (file)
@@ -26,6 +26,7 @@
 #define IPSEC_H_
 
 #include "ipsec_sa_mgr.h"
+#include "ipsec_event_relay.h"
 
 #include <library.h>
 
@@ -41,6 +42,11 @@ struct ipsec_t {
         */
        ipsec_sa_mgr_t *sas;
 
+       /**
+        * Event relay instance
+        */
+       ipsec_event_relay_t *events;
+
 };
 
 /**
diff --git a/src/libipsec/ipsec_event_listener.h b/src/libipsec/ipsec_event_listener.h
new file mode 100644 (file)
index 0000000..c5c39b0
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_event_listener ipsec_event_listener
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_EVENT_LISTENER_H_
+#define IPSEC_EVENT_LISTENER_H_
+
+typedef struct ipsec_event_listener_t ipsec_event_listener_t;
+
+#include <library.h>
+
+/**
+ * Listener interface for IPsec events
+ *
+ * All methods are optional.
+ */
+struct ipsec_event_listener_t {
+
+       /**
+        * Called when the lifetime of an IPsec SA expired
+        *
+        * @param reqid                 reqid of the expired SA
+        * @param protocol              protocol of the expired SA
+        * @param spi                   spi of the expired SA
+        * @param hard                  TRUE if this is a hard expire, FALSE otherwise
+        */
+       void (*expire)(u_int32_t reqid, u_int8_t protocol, u_int32_t spi,
+                                  bool hard);
+
+};
+
+#endif /** IPSEC_EVENT_LISTENER_H_ @}*/
diff --git a/src/libipsec/ipsec_event_relay.c b/src/libipsec/ipsec_event_relay.c
new file mode 100644 (file)
index 0000000..3422225
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "ipsec_event_relay.h"
+
+#include <library.h>
+#include <debug.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
+#include <utils/blocking_queue.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_ipsec_event_relay_t private_ipsec_event_relay_t;
+
+/**
+ * Private additions to ipsec_event_relay_t.
+ */
+struct private_ipsec_event_relay_t {
+
+       /**
+        * Public members
+        */
+       ipsec_event_relay_t public;
+
+       /**
+        * Registered listeners
+        */
+       linked_list_t *listeners;
+
+       /**
+        * Lock to safely access the list of listeners
+        */
+       rwlock_t *lock;
+
+       /**
+        * Blocking queue for events
+        */
+       blocking_queue_t *queue;
+};
+
+/**
+ * Helper struct used to manage events in a queue
+ */
+typedef struct {
+
+       /**
+        * Type of the event
+        */
+       enum {
+               IPSEC_EVENT_EXPIRE,
+       } type;
+
+       /**
+        * Reqid of the SA, if any
+        */
+       u_int32_t reqid;
+
+       /**
+        * SPI of the SA, if any
+        */
+       u_int32_t spi;
+
+       /**
+        * Additional data for specific event types
+        */
+       union {
+
+               struct {
+                       /** Protocol of the SA */
+                       u_int8_t protocol;
+                       /** TRUE in case of a hard expire */
+                       bool hard;
+               } expire;
+
+       } data;
+
+} ipsec_event_t;
+
+/**
+ * Dequeue events and relay them to listeners
+ */
+static job_requeue_t handle_events(private_ipsec_event_relay_t *this)
+{
+       enumerator_t *enumerator;
+       ipsec_event_listener_t *current;
+       ipsec_event_t *event;
+
+       event = this->queue->dequeue(this->queue);
+
+       this->lock->read_lock(this->lock);
+       enumerator = this->listeners->create_enumerator(this->listeners);
+       while (enumerator->enumerate(enumerator, (void**)&current))
+       {
+               switch (event->type)
+               {
+                       case IPSEC_EVENT_EXPIRE:
+                               if (current->expire)
+                               {
+                                       current->expire(event->reqid, event->data.expire.protocol,
+                                                                       event->spi, event->data.expire.hard);
+                               }
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       this->lock->unlock(this->lock);
+       return JOB_REQUEUE_DIRECT;
+}
+
+METHOD(ipsec_event_relay_t, expire, void,
+       private_ipsec_event_relay_t *this, u_int32_t reqid, u_int8_t protocol,
+       u_int32_t spi, bool hard)
+{
+       ipsec_event_t *event;
+
+       INIT(event,
+               .type = IPSEC_EVENT_EXPIRE,
+               .reqid = reqid,
+               .spi = spi,
+               .data = {
+                       .expire = {
+                               .protocol = protocol,
+                               .hard = hard,
+                       },
+               },
+       );
+       this->queue->enqueue(this->queue, event);
+}
+
+METHOD(ipsec_event_relay_t, register_listener, void,
+       private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
+{
+       this->lock->write_lock(this->lock);
+       this->listeners->insert_last(this->listeners, listener);
+       this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_event_relay_t, unregister_listener, void,
+       private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
+{
+       this->lock->write_lock(this->lock);
+       this->listeners->remove(this->listeners, listener, NULL);
+       this->lock->unlock(this->lock);
+}
+
+METHOD(ipsec_event_relay_t, destroy, void,
+       private_ipsec_event_relay_t *this)
+{
+       this->queue->destroy_function(this->queue, free);
+       this->listeners->destroy(this->listeners);
+       this->lock->destroy(this->lock);
+       free(this);
+}
+
+/**
+ * Described in header.
+ */
+ipsec_event_relay_t *ipsec_event_relay_create()
+{
+       private_ipsec_event_relay_t *this;
+
+       INIT(this,
+               .public = {
+                       .expire = _expire,
+                       .register_listener = _register_listener,
+                       .unregister_listener = _unregister_listener,
+                       .destroy = _destroy,
+               },
+               .listeners = linked_list_create(),
+               .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+               .queue = blocking_queue_create(),
+       );
+
+       lib->processor->queue_job(lib->processor,
+               (job_t*)callback_job_create((callback_job_cb_t)handle_events, this,
+                       NULL, (callback_job_cancel_t)return_false));
+
+       return &this->public;
+}
diff --git a/src/libipsec/ipsec_event_relay.h b/src/libipsec/ipsec_event_relay.h
new file mode 100644 (file)
index 0000000..c6935d5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Giuliano Grassi
+ * Copyright (C) 2012 Ralf Sager
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ipsec_event_relay ipsec_event_relay
+ * @{ @ingroup libipsec
+ */
+
+#ifndef IPSEC_EVENT_RELAY_H_
+#define IPSEC_EVENT_RELAY_H_
+
+#include "ipsec_event_listener.h"
+
+#include <library.h>
+
+typedef struct ipsec_event_relay_t ipsec_event_relay_t;
+
+/**
+ *  Event relay manager.
+ *
+ *  Used to notify upper layers about changes
+ */
+struct ipsec_event_relay_t {
+
+       /**
+        * Raise an expire event.
+        *
+        * @param reqid                 reqid of the expired IPsec SA
+        * @param protocol              protocol (e.g ESP) of the expired SA
+        * @param spi                   SPI of the expired SA
+        * @param hard                  TRUE for a hard expire, FALSE otherwise
+        */
+       void (*expire)(ipsec_event_relay_t *this, u_int32_t reqid,
+                                  u_int8_t protocol, u_int32_t spi, bool hard);
+
+       /**
+        * Register a listener to events raised by this manager
+        *
+        * @param listener              the listener to register
+        */
+       void (*register_listener)(ipsec_event_relay_t *this,
+                                                         ipsec_event_listener_t *listener);
+
+       /**
+        * Unregister a listener
+        *
+        * @param listener              the listener to unregister
+        */
+       void (*unregister_listener)(ipsec_event_relay_t *this,
+                                                               ipsec_event_listener_t *listener);
+
+       /**
+        * Destroy an ipsec_event_relay_t
+        */
+       void (*destroy)(ipsec_event_relay_t *this);
+
+};
+
+/**
+ * Create an ipsec_event_relay_t instance
+ *
+ * @return                     IPsec event relay instance
+ */
+ipsec_event_relay_t *ipsec_event_relay_create();
+
+#endif /** IPSEC_EVENT_RELAY_H_ @}*/