Added reload support to eap-radius plugin

This commit is contained in:
Martin Willi
2011-04-15 10:07:13 +02:00
parent 3b71d3d033
commit f0331baf1a
4 changed files with 83 additions and 39 deletions
@@ -20,6 +20,7 @@
#include "radius_server.h" #include "radius_server.h"
#include <daemon.h> #include <daemon.h>
#include <threading/rwlock.h>
/** /**
* Default RADIUS server port, when not configured * Default RADIUS server port, when not configured
@@ -42,6 +43,11 @@ struct private_eap_radius_plugin_t {
* List of RADIUS servers * List of RADIUS servers
*/ */
linked_list_t *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; 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 * 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; enumerator_t *enumerator;
radius_server_t *server; radius_server_t *server;
@@ -84,7 +74,7 @@ static bool load_servers(private_eap_radius_plugin_t *this)
if (!secret) if (!secret)
{ {
DBG1(DBG_CFG, "no RADUIS secret defined"); DBG1(DBG_CFG, "no RADUIS secret defined");
return FALSE; return;
} }
nas_identifier = lib->settings->get_str(lib->settings, nas_identifier = lib->settings->get_str(lib->settings,
"charon.plugins.eap-radius.nas_identifier", "strongSwan"); "charon.plugins.eap-radius.nas_identifier", "strongSwan");
@@ -97,10 +87,10 @@ static bool load_servers(private_eap_radius_plugin_t *this)
if (!server) if (!server)
{ {
DBG1(DBG_CFG, "no RADUIS server defined"); DBG1(DBG_CFG, "no RADUIS server defined");
return FALSE; return;
} }
this->servers->insert_last(this->servers, server); this->servers->insert_last(this->servers, server);
return TRUE; return;
} }
enumerator = lib->settings->create_section_enumerator(lib->settings, 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); enumerator->destroy(enumerator);
if (this->servers->get_count(this->servers) == 0) DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
{ this->servers->get_count(this->servers),
DBG1(DBG_CFG, "no valid RADIUS server configuration found"); this->servers->get_count(this->servers) == 1 ? "" : "s");
return FALSE; }
}
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; 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 * see header file
*/ */
@@ -160,18 +176,16 @@ plugin_t *eap_radius_plugin_create()
.public = { .public = {
.plugin = { .plugin = {
.get_name = _get_name, .get_name = _get_name,
.reload = (void*)return_false, .reload = _reload,
.destroy = _destroy, .destroy = _destroy,
}, },
}, },
.servers = linked_list_create(), .servers = linked_list_create(),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
); );
if (!load_servers(this)) load_servers(this);
{
destroy(this);
return NULL;
}
charon->eap->add_method(charon->eap, EAP_RADIUS, 0, charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
EAP_SERVER, (eap_constructor_t)eap_radius_create); EAP_SERVER, (eap_constructor_t)eap_radius_create);
@@ -187,7 +201,10 @@ enumerator_t *eap_radius_create_server_enumerator()
{ {
if (instance) 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(); return enumerator_create_empty();
} }
@@ -128,6 +128,7 @@ METHOD(radius_client_t, get_msk, chunk_t,
METHOD(radius_client_t, destroy, void, METHOD(radius_client_t, destroy, void,
private_radius_client_t *this) private_radius_client_t *this)
{ {
this->server->destroy(this->server);
chunk_clear(&this->msk); chunk_clear(&this->msk);
free(this->state.ptr); free(this->state.ptr);
free(this); free(this);
@@ -162,7 +163,8 @@ radius_client_t *radius_client_create()
DBG2(DBG_CFG, "RADIUS server %H is candidate: %d", DBG2(DBG_CFG, "RADIUS server %H is candidate: %d",
server->get_address(server), current); server->get_address(server), current);
best = current; best = current;
this->server = server; DESTROY_IF(this->server);
this->server = server->get_ref(server);
} }
else else
{ {
@@ -80,6 +80,11 @@ struct private_radius_server_t {
* Retry counter for unreachable servers * Retry counter for unreachable servers
*/ */
int retry; int retry;
/**
* reference count
*/
refcount_t ref;
}; };
METHOD(radius_server_t, get_socket, radius_socket_t*, METHOD(radius_server_t, get_socket, radius_socket_t*,
@@ -153,15 +158,26 @@ METHOD(radius_server_t, get_address, host_t*,
return this->host; 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, METHOD(radius_server_t, destroy, void,
private_radius_server_t *this) private_radius_server_t *this)
{ {
DESTROY_IF(this->host); if (ref_put(&this->ref))
this->mutex->destroy(this->mutex); {
this->condvar->destroy(this->condvar); DESTROY_IF(this->host);
this->sockets->destroy_offset(this->sockets, this->mutex->destroy(this->mutex);
offsetof(radius_socket_t, destroy)); this->condvar->destroy(this->condvar);
free(this); 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_nas_identifier = _get_nas_identifier,
.get_preference = _get_preference, .get_preference = _get_preference,
.get_address = _get_address, .get_address = _get_address,
.get_ref = _get_ref,
.destroy = _destroy, .destroy = _destroy,
}, },
.reachable = TRUE, .reachable = TRUE,
@@ -190,6 +207,7 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT), .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
.host = host_create_from_dns(server, 0, port), .host = host_create_from_dns(server, 0, port),
.preference = preference, .preference = preference,
.ref = 1,
); );
if (!this->host) if (!this->host)
@@ -67,6 +67,13 @@ struct radius_server_t {
*/ */
host_t* (*get_address)(radius_server_t *this); 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. * Destroy a radius_server_t.
*/ */