]> git.ipfire.org Git - thirdparty/strongswan.git/blobdiff - src/libcharon/attributes/mem_pool.c
Spelling fixes
[thirdparty/strongswan.git] / src / libcharon / attributes / mem_pool.c
index f35ffaa9c244c691b49c86e9d65ab59693421de6..9fca4645c8b7469fb3f09367c27e0db38b8446fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -17,7 +17,6 @@
 #include "mem_pool.h"
 
 #include <library.h>
-#include <hydra.h>
 #include <utils/debug.h>
 #include <collections/hashtable.h>
 #include <collections/array.h>
@@ -70,20 +69,25 @@ struct private_mem_pool_t {
         * 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;
@@ -98,12 +102,23 @@ static entry_t* entry_create(identification_t *id)
 
        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
  */
@@ -127,7 +142,7 @@ static host_t* offset2host(private_mem_pool_t *pool, int offset)
 {
        chunk_t addr;
        host_t *host;
-       u_int32_t *pos;
+       uint32_t *pos;
 
        offset--;
        if (offset > pool->size)
@@ -138,11 +153,11 @@ static host_t* offset2host(private_mem_pool_t *pool, int offset)
        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);
@@ -156,7 +171,7 @@ static host_t* offset2host(private_mem_pool_t *pool, int offset)
 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))
        {
@@ -174,8 +189,8 @@ static int host2offset(private_mem_pool_t *pool, host_t *addr)
                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;
@@ -239,13 +254,26 @@ METHOD(mem_pool_t, get_offline, u_int,
        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;
@@ -260,8 +288,9 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
        enumerator = array_create_enumerator(entry->offline);
        if (enumerator->enumerate(enumerator, &current))
        {
-               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);
@@ -270,19 +299,20 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
                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, &current))
+       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;
                }
        }
@@ -297,10 +327,10 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
 /**
  * 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)
        {
@@ -311,36 +341,47 @@ static int get_new(private_mem_pool_t *this, identification_t *id)
                        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, &current))
                {
-                       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)
@@ -348,14 +389,15 @@ static int get_reassigned(private_mem_pool_t *this, identification_t *id)
                        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;
 
@@ -376,13 +418,13 @@ METHOD(mem_pool_t, acquire_address, host_t*,
        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",
@@ -407,7 +449,8 @@ METHOD(mem_pool_t, release_address, bool,
        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)
        {
@@ -420,7 +463,7 @@ METHOD(mem_pool_t, release_address, bool,
                        enumerator = array_create_enumerator(entry->online);
                        while (enumerator->enumerate(enumerator, &current))
                        {
-                               if (*current == offset)
+                               if (current->offset == offset)
                                {
                                        if (!found)
                                        {       /* remove the first entry only */
@@ -469,9 +512,15 @@ typedef struct {
 } 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;
@@ -480,10 +529,10 @@ METHOD(enumerator_t, lease_enumerate, bool,
        {
                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;
                        }
@@ -526,7 +575,8 @@ METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
        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,
@@ -544,10 +594,7 @@ METHOD(mem_pool_t, destroy, void,
        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);
 
@@ -581,8 +628,6 @@ static private_mem_pool_t *create_generic(char *name)
                .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;
@@ -595,7 +640,7 @@ static private_mem_pool_t *create_generic(char *name)
  */
 static u_int network_id_diff(host_t *host, int hostbits)
 {
-       u_int32_t last;
+       uint32_t last;
        chunk_t addr;
 
        if (!hostbits)
@@ -666,7 +711,7 @@ mem_pool_t *mem_pool_create_range(char *name, host_t *from, host_t *to)
 {
        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);