/*
* Copyright (C) 2010 Tobias Brunner
* Copyright (C) 2008-2010 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
#include "mem_pool.h"
#include <library.h>
-#include <hydra.h>
#include <utils/debug.h>
#include <collections/hashtable.h>
#include <collections/array.h>
* lock to safely access the pool
*/
mutex_t *mutex;
-
- /**
- * Do we reassign online leases to the same identity, if requested?
- */
- bool reassign_online;
};
+/**
+ * A unique lease address offset, with a hash of the peer host address
+ */
+typedef struct {
+ /** lease, as offset */
+ u_int offset;
+ /** hash of remote address, to allow duplicates */
+ u_int hash;
+} unique_lease_t;
+
/**
* Lease entry.
*/
typedef struct {
- /* identitiy reference */
+ /* identity reference */
identification_t *id;
- /* array of online leases, as u_int offset */
+ /* array of online leases, as unique_lease_t */
array_t *online;
/* array of offline leases, as u_int offset */
array_t *offline;
INIT(entry,
.id = id->clone(id),
- .online = array_create(sizeof(u_int), 0),
+ .online = array_create(sizeof(unique_lease_t), 0),
.offline = array_create(sizeof(u_int), 0),
);
return entry;
}
+/**
+ * Destroy an entry
+ */
+static void entry_destroy(entry_t *this)
+{
+ this->id->destroy(this->id);
+ array_destroy(this->online);
+ array_destroy(this->offline);
+ free(this);
+}
+
/**
* hashtable hash function for identities
*/
{
chunk_t addr;
host_t *host;
- u_int32_t *pos;
+ uint32_t *pos;
offset--;
if (offset > pool->size)
addr = chunk_clone(pool->base->get_address(pool->base));
if (pool->base->get_family(pool->base) == AF_INET6)
{
- pos = (u_int32_t*)(addr.ptr + 12);
+ pos = (uint32_t*)(addr.ptr + 12);
}
else
{
- pos = (u_int32_t*)addr.ptr;
+ pos = (uint32_t*)addr.ptr;
}
*pos = htonl(offset + ntohl(*pos));
host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
static int host2offset(private_mem_pool_t *pool, host_t *addr)
{
chunk_t host, base;
- u_int32_t hosti, basei;
+ uint32_t hosti, basei;
if (addr->get_family(addr) != pool->base->get_family(pool->base))
{
host = chunk_skip(host, 12);
base = chunk_skip(base, 12);
}
- hosti = ntohl(*(u_int32_t*)(host.ptr));
- basei = ntohl(*(u_int32_t*)(base.ptr));
+ hosti = ntohl(*(uint32_t*)(host.ptr));
+ basei = ntohl(*(uint32_t*)(base.ptr));
if (hosti > basei + pool->size)
{
return -1;
return count;
}
+/**
+ * Create a unique hash for a remote address
+ */
+static u_int hash_addr(host_t *addr)
+{
+ if (addr)
+ {
+ return chunk_hash_inc(addr->get_address(addr), addr->get_port(addr));
+ }
+ return 0;
+}
+
/**
* Get an existing lease for id
*/
static int get_existing(private_mem_pool_t *this, identification_t *id,
- host_t *requested)
+ host_t *requested, host_t *peer)
{
enumerator_t *enumerator;
+ unique_lease_t *lease, reassign;
u_int *current;
entry_t *entry;
int offset = 0;
enumerator = array_create_enumerator(entry->offline);
if (enumerator->enumerate(enumerator, ¤t))
{
- offset = *current;
- array_insert(entry->online, ARRAY_TAIL, current);
+ reassign.offset = offset = *current;
+ reassign.hash = hash_addr(peer);
+ array_insert(entry->online, ARRAY_TAIL, &reassign);
array_remove_at(entry->offline, enumerator);
}
enumerator->destroy(enumerator);
DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
return offset;
}
- if (!this->reassign_online)
+ if (!peer)
{
return 0;
}
/* check for a valid online lease to reassign */
enumerator = array_create_enumerator(entry->online);
- while (enumerator->enumerate(enumerator, ¤t))
+ while (enumerator->enumerate(enumerator, &lease))
{
- if (*current == host2offset(this, requested))
+ if (lease->offset == host2offset(this, requested) &&
+ lease->hash == hash_addr(peer))
{
- offset = *current;
+ offset = lease->offset;
/* add an additional "online" entry */
- array_insert(entry->online, ARRAY_TAIL, current);
+ array_insert(entry->online, ARRAY_TAIL, lease);
break;
}
}
/**
* Get a new lease for id
*/
-static int get_new(private_mem_pool_t *this, identification_t *id)
+static int get_new(private_mem_pool_t *this, identification_t *id, host_t *peer)
{
entry_t *entry;
- u_int offset = 0;
+ unique_lease_t lease = {};
if (this->unused < this->size)
{
this->leases->put(this->leases, entry->id, entry);
}
/* assigning offset, starting by 1 */
- offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
- array_insert(entry->online, ARRAY_TAIL, &offset);
+ lease.offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
+ lease.hash = hash_addr(peer);
+ array_insert(entry->online, ARRAY_TAIL, &lease);
DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
}
- return offset;
+ return lease.offset;
}
/**
* Get a reassigned lease for id in case the pool is full
*/
-static int get_reassigned(private_mem_pool_t *this, identification_t *id)
+static int get_reassigned(private_mem_pool_t *this, identification_t *id,
+ host_t *peer)
{
enumerator_t *enumerator;
entry_t *entry;
- u_int current, offset = 0;
+ u_int current;
+ unique_lease_t lease = {};
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
if (array_remove(entry->offline, ARRAY_HEAD, ¤t))
{
- offset = current;
- DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
- " to '%Y'", entry->id, id);
+ lease.offset = current;
+ DBG1(DBG_CFG, "reassigning existing offline lease by '%Y' "
+ "to '%Y'", entry->id, id);
+ }
+ if (!array_count(entry->online) && !array_count(entry->offline))
+ {
+ this->leases->remove_at(this->leases, enumerator);
+ entry_destroy(entry);
+ }
+ if (lease.offset)
+ {
break;
}
}
enumerator->destroy(enumerator);
- if (offset)
+ if (lease.offset)
{
entry = this->leases->get(this->leases, id);
if (!entry)
entry = entry_create(id);
this->leases->put(this->leases, entry->id, entry);
}
- array_insert(entry->online, ARRAY_TAIL, &offset);
+ lease.hash = hash_addr(peer);
+ array_insert(entry->online, ARRAY_TAIL, &lease);
}
- return offset;
+ return lease.offset;
}
METHOD(mem_pool_t, acquire_address, host_t*,
private_mem_pool_t *this, identification_t *id, host_t *requested,
- mem_pool_op_t operation)
+ mem_pool_op_t operation, host_t *peer)
{
int offset = 0;
switch (operation)
{
case MEM_POOL_EXISTING:
- offset = get_existing(this, id, requested);
+ offset = get_existing(this, id, requested, peer);
break;
case MEM_POOL_NEW:
- offset = get_new(this, id);
+ offset = get_new(this, id, peer);
break;
case MEM_POOL_REASSIGN:
- offset = get_reassigned(this, id);
+ offset = get_reassigned(this, id, peer);
if (!offset)
{
DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
enumerator_t *enumerator;
bool found = FALSE, more = FALSE;
entry_t *entry;
- u_int offset, *current;
+ u_int offset;
+ unique_lease_t *current;
if (this->size != 0)
{
enumerator = array_create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, ¤t))
{
- if (*current == offset)
+ if (current->offset == offset)
{
if (!found)
{ /* remove the first entry only */
} lease_enumerator_t;
METHOD(enumerator_t, lease_enumerate, bool,
- lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
+ lease_enumerator_t *this, va_list args)
{
+ identification_t **id;
+ unique_lease_t *lease;
+ host_t **addr;
u_int *offset;
+ bool *online;
+
+ VA_ARGS_VGET(args, id, addr, online);
DESTROY_IF(this->addr);
this->addr = NULL;
{
if (this->entry)
{
- if (this->online->enumerate(this->online, &offset))
+ if (this->online->enumerate(this->online, &lease))
{
*id = this->entry->id;
- *addr = this->addr = offset2host(this->pool, *offset);
+ *addr = this->addr = offset2host(this->pool, lease->offset);
*online = TRUE;
return TRUE;
}
this->mutex->lock(this->mutex);
INIT(enumerator,
.public = {
- .enumerate = (void*)_lease_enumerate,
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _lease_enumerate,
.destroy = _lease_enumerator_destroy,
},
.pool = this,
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
- entry->id->destroy(entry->id);
- array_destroy(entry->online);
- array_destroy(entry->offline);
- free(entry);
+ entry_destroy(entry);
}
enumerator->destroy(enumerator);
.leases = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
- .reassign_online = lib->settings->get_bool(lib->settings,
- "%s.mem-pool.reassign_online", FALSE, lib->ns),
);
return this;
*/
static u_int network_id_diff(host_t *host, int hostbits)
{
- u_int32_t last;
+ uint32_t last;
chunk_t addr;
if (!hostbits)
{
private_mem_pool_t *this;
chunk_t fromaddr, toaddr;
- u_int32_t diff;
+ uint32_t diff;
fromaddr = from->get_address(from);
toaddr = to->get_address(to);