Added reload support to eap-radius plugin
authorMartin Willi <martin@revosec.ch>
Tue, 12 Apr 2011 09:36:03 +0000 (11:36 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 15 Apr 2011 08:07:13 +0000 (10:07 +0200)
src/libcharon/plugins/eap_radius/eap_radius_plugin.c
src/libcharon/plugins/eap_radius/radius_client.c
src/libcharon/plugins/eap_radius/radius_server.c
src/libcharon/plugins/eap_radius/radius_server.h

index 7ae3da0..9b15256 100644 (file)
@@ -20,6 +20,7 @@
 #include "radius_server.h"
 
 #include <daemon.h>
+#include <threading/rwlock.h>
 
 /**
  * Default RADIUS server port, when not configured
@@ -42,6 +43,11 @@ struct private_eap_radius_plugin_t {
         * List of RADIUS servers
         */
        linked_list_t *servers;
+
+       /**
+        * Lock for server list
+        */
+       rwlock_t *lock;
 };
 
 /**
@@ -49,26 +55,10 @@ struct private_eap_radius_plugin_t {
  */
 static private_eap_radius_plugin_t *instance = NULL;
 
-METHOD(plugin_t, get_name, char*,
-       private_eap_radius_plugin_t *this)
-{
-       return "eap-radius";
-}
-
-METHOD(plugin_t, destroy, void,
-       private_eap_radius_plugin_t *this)
-{
-       charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create);
-       this->servers->destroy_offset(this->servers,
-                                                                 offsetof(radius_server_t, destroy));
-       free(this);
-       instance = NULL;
-}
-
 /**
  * Load RADIUS servers from configuration
  */
-static bool load_servers(private_eap_radius_plugin_t *this)
+static void load_servers(private_eap_radius_plugin_t *this)
 {
        enumerator_t *enumerator;
        radius_server_t *server;
@@ -84,7 +74,7 @@ static bool load_servers(private_eap_radius_plugin_t *this)
                if (!secret)
                {
                        DBG1(DBG_CFG, "no RADUIS secret defined");
-                       return FALSE;
+                       return;
                }
                nas_identifier = lib->settings->get_str(lib->settings,
                                        "charon.plugins.eap-radius.nas_identifier", "strongSwan");
@@ -97,10 +87,10 @@ static bool load_servers(private_eap_radius_plugin_t *this)
                if (!server)
                {
                        DBG1(DBG_CFG, "no RADUIS server defined");
-                       return FALSE;
+                       return;
                }
                this->servers->insert_last(this->servers, server);
-               return TRUE;
+               return;
        }
 
        enumerator = lib->settings->create_section_enumerator(lib->settings,
@@ -141,14 +131,40 @@ static bool load_servers(private_eap_radius_plugin_t *this)
        }
        enumerator->destroy(enumerator);
 
-       if (this->servers->get_count(this->servers) == 0)
-       {
-               DBG1(DBG_CFG, "no valid RADIUS server configuration found");
-               return FALSE;
-       }
+       DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
+                this->servers->get_count(this->servers),
+                this->servers->get_count(this->servers) == 1 ? "" : "s");
+}
+
+METHOD(plugin_t, get_name, char*,
+       private_eap_radius_plugin_t *this)
+{
+       return "eap-radius";
+}
+
+METHOD(plugin_t, reload, bool,
+       private_eap_radius_plugin_t *this)
+{
+       this->lock->write_lock(this->lock);
+       this->servers->destroy_offset(this->servers,
+                                                                 offsetof(radius_server_t, destroy));
+       this->servers = linked_list_create();
+       load_servers(this);
+       this->lock->unlock(this->lock);
        return TRUE;
 }
 
+METHOD(plugin_t, destroy, void,
+       private_eap_radius_plugin_t *this)
+{
+       charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create);
+       this->servers->destroy_offset(this->servers,
+                                                                 offsetof(radius_server_t, destroy));
+       this->lock->destroy(this->lock);
+       free(this);
+       instance = NULL;
+}
+
 /*
  * see header file
  */
@@ -160,18 +176,16 @@ plugin_t *eap_radius_plugin_create()
                .public = {
                        .plugin = {
                                .get_name = _get_name,
-                               .reload = (void*)return_false,
+                               .reload = _reload,
                                .destroy = _destroy,
                        },
                },
                .servers = linked_list_create(),
+               .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        );
 
-       if (!load_servers(this))
-       {
-               destroy(this);
-               return NULL;
-       }
+       load_servers(this);
+
        charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
                                                        EAP_SERVER, (eap_constructor_t)eap_radius_create);
 
@@ -187,7 +201,10 @@ enumerator_t *eap_radius_create_server_enumerator()
 {
        if (instance)
        {
-               return instance->servers->create_enumerator(instance->servers);
+               instance->lock->read_lock(instance->lock);
+               return enumerator_create_cleaner(
+                                       instance->servers->create_enumerator(instance->servers),
+                                       (void*)instance->lock->unlock, instance->lock);
        }
        return enumerator_create_empty();
 }
index 232b913..0d7276a 100644 (file)
@@ -128,6 +128,7 @@ METHOD(radius_client_t, get_msk, chunk_t,
 METHOD(radius_client_t, destroy, void,
        private_radius_client_t *this)
 {
+       this->server->destroy(this->server);
        chunk_clear(&this->msk);
        free(this->state.ptr);
        free(this);
@@ -162,7 +163,8 @@ radius_client_t *radius_client_create()
                        DBG2(DBG_CFG, "RADIUS server %H is candidate: %d",
                                 server->get_address(server), current);
                        best = current;
-                       this->server = server;
+                       DESTROY_IF(this->server);
+                       this->server = server->get_ref(server);
                }
                else
                {
index f54b8b2..d166280 100644 (file)
@@ -80,6 +80,11 @@ struct private_radius_server_t {
         * Retry counter for unreachable servers
         */
        int retry;
+
+       /**
+        * reference count
+        */
+       refcount_t ref;
 };
 
 METHOD(radius_server_t, get_socket, radius_socket_t*,
@@ -153,15 +158,26 @@ METHOD(radius_server_t, get_address, host_t*,
        return this->host;
 }
 
+METHOD(radius_server_t, get_ref, radius_server_t*,
+       private_radius_server_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public;
+}
+
+
 METHOD(radius_server_t, destroy, void,
        private_radius_server_t *this)
 {
-       DESTROY_IF(this->host);
-       this->mutex->destroy(this->mutex);
-       this->condvar->destroy(this->condvar);
-       this->sockets->destroy_offset(this->sockets,
-                                                                 offsetof(radius_socket_t, destroy));
-       free(this);
+       if (ref_put(&this->ref))
+       {
+               DESTROY_IF(this->host);
+               this->mutex->destroy(this->mutex);
+               this->condvar->destroy(this->condvar);
+               this->sockets->destroy_offset(this->sockets,
+                                                                         offsetof(radius_socket_t, destroy));
+               free(this);
+       }
 }
 
 /**
@@ -180,6 +196,7 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
                        .get_nas_identifier = _get_nas_identifier,
                        .get_preference = _get_preference,
                        .get_address = _get_address,
+                       .get_ref = _get_ref,
                        .destroy = _destroy,
                },
                .reachable = TRUE,
@@ -190,6 +207,7 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
                .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
                .host = host_create_from_dns(server, 0, port),
                .preference = preference,
+               .ref = 1,
        );
 
        if (!this->host)
index ba4c946..a9bc721 100644 (file)
@@ -68,6 +68,13 @@ struct radius_server_t {
        host_t* (*get_address)(radius_server_t *this);
 
        /**
+        * Increase reference count of this server.
+        *
+        * @return                      this
+        */
+       radius_server_t* (*get_ref)(radius_server_t *this);
+
+       /**
         * Destroy a radius_server_t.
         */
        void (*destroy)(radius_server_t *this);