Pass the full list of pools to acquire_address, enumerate in providers
authorMartin Willi <martin@revosec.ch>
Tue, 11 Sep 2012 08:41:11 +0000 (10:41 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 11 Sep 2012 14:18:28 +0000 (16:18 +0200)
If the provider has access to the full pool list, it can enumerate
them twice, for example to search for existing leases first, and
only search for new leases in a second step.

Fixes lease enumeration in attr-sql using multiple pools.

src/libcharon/plugins/dhcp/dhcp_provider.c
src/libcharon/plugins/ha/ha_attribute.c
src/libcharon/plugins/stroke/stroke_attribute.c
src/libcharon/plugins/unit_tester/tests/test_pool.c
src/libcharon/sa/ikev1/tasks/mode_config.c
src/libcharon/sa/ikev2/tasks/ike_config.c
src/libhydra/attributes/attribute_manager.c
src/libhydra/attributes/attribute_manager.h
src/libhydra/attributes/attribute_provider.h
src/libhydra/plugins/attr_sql/sql_attribute.c

index e46cc4d..eaaad45 100644 (file)
@@ -81,18 +81,29 @@ static uintptr_t hash_transaction(dhcp_transaction_t *transaction)
 }
 
 METHOD(attribute_provider_t, acquire_address, host_t*,
-       private_dhcp_provider_t *this, char *pool,
+       private_dhcp_provider_t *this, linked_list_t *pools,
        identification_t *id, host_t *requested)
 {
-       if (streq(pool, "dhcp") && requested->get_family(requested) == AF_INET)
-       {
-               dhcp_transaction_t *transaction, *old;
-               host_t *vip;
+       dhcp_transaction_t *transaction, *old;
+       enumerator_t *enumerator;
+       char *pool;
+       host_t *vip = NULL;
 
+       if (requested->get_family(requested) != AF_INET)
+       {
+               return NULL;
+       }
+       enumerator = pools->create_enumerator(pools);
+       while (enumerator->enumerate(enumerator, &pool))
+       {
+               if (!streq(pool, "dhcp"))
+               {
+                       continue;
+               }
                transaction = this->socket->enroll(this->socket, id);
                if (!transaction)
                {
-                       return NULL;
+                       continue;
                }
                vip = transaction->get_address(transaction);
                vip = vip->clone(vip);
@@ -101,9 +112,10 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
                                                        (void*)hash_transaction(transaction), transaction);
                this->mutex->unlock(this->mutex);
                DESTROY_IF(old);
-               return vip;
+               break;
        }
-       return NULL;
+       enumerator->destroy(enumerator);
+       return vip;
 }
 
 METHOD(attribute_provider_t, release_address, bool,
index f18c58b..d9f460a 100644 (file)
@@ -170,22 +170,28 @@ static bool responsible_for(private_ha_attribute_t *this, int bit)
 }
 
 METHOD(attribute_provider_t, acquire_address, host_t*,
-       private_ha_attribute_t *this, char *name, identification_t *id,
+       private_ha_attribute_t *this, linked_list_t *pools, identification_t *id,
        host_t *requested)
 {
+       enumerator_t *enumerator;
        pool_t *pool;
        int offset = -1, byte, bit;
        host_t *address;
+       char *name;
 
+       enumerator = pools->create_enumerator(pools);
        this->mutex->lock(this->mutex);
-       pool = get_pool(this, name);
-       if (pool)
+       while (enumerator->enumerate(enumerator, &name))
        {
+               pool = get_pool(this, name);
+               if (!pool)
+               {
+                       continue;
+               }
                if (pool->base->get_family(pool->base) !=
                        requested->get_family(requested))
                {
-                       this->mutex->unlock(this->mutex);
-                       return NULL;
+                       continue;
                }
                for (byte = 0; byte < pool->size / 8; byte++)
                {
@@ -214,6 +220,8 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
                }
        }
        this->mutex->unlock(this->mutex);
+       enumerator->destroy(enumerator);
+
        if (offset != -1)
        {
                address = offset2host(pool, offset);
index fa58a24..99392bf 100644 (file)
@@ -90,19 +90,31 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
 }
 
 METHOD(attribute_provider_t, acquire_address, host_t*,
-       private_stroke_attribute_t *this, char *name, identification_t *id,
+       private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
        host_t *requested)
 {
+       enumerator_t *enumerator;
        mem_pool_t *pool;
        host_t *addr = NULL;
+       char *name;
 
+       enumerator = pools->create_enumerator(pools);
        this->lock->read_lock(this->lock);
-       pool = find_pool(this, name);
-       if (pool)
+       while (enumerator->enumerate(enumerator, &name))
        {
-               addr = pool->acquire_address(pool, id, requested);
+               pool = find_pool(this, name);
+               if (pool)
+               {
+                       addr = pool->acquire_address(pool, id, requested);
+                       if (addr)
+                       {
+                               break;
+                       }
+               }
        }
        this->lock->unlock(this->lock);
+       enumerator->destroy(enumerator);
+
        return addr;
 }
 
index a68246f..f67353d 100644 (file)
@@ -27,6 +27,7 @@ static void* testing(void *thread)
        int i;
        host_t *addr[ALLOCS];
        identification_t *id[ALLOCS];
+       linked_list_t *pools;
 
        /* prepare identities */
        for (i = 0; i < ALLOCS; i++)
@@ -37,17 +38,23 @@ static void* testing(void *thread)
                id[i] = identification_create_from_string(buf);
        }
 
+       pools = linked_list_create();
+       pools->insert_last(pools, "test");
+
        /* allocate addresses */
        for (i = 0; i < ALLOCS; i++)
        {
                addr[i] = hydra->attributes->acquire_address(hydra->attributes,
-                                                                                                        "test", id[i], NULL);
+                                                                                                        pools, id[i], NULL);
                if (!addr[i])
                {
+                       pools->destroy(pools);
                        return (void*)FALSE;
                }
        }
 
+       pools->destroy(pools);
+
        /* release addresses */
        for (i = 0; i < ALLOCS; i++)
        {
index a134ad5..6a5bac9 100644 (file)
@@ -330,29 +330,23 @@ METHOD(task_t, build_r, status_t,
        id = this->ike_sa->get_other_eap_id(this->ike_sa);
        config = this->ike_sa->get_peer_cfg(this->ike_sa);
        vips = linked_list_create();
-       pools = linked_list_create();
+       pools = linked_list_create_from_enumerator(
+                                                                       config->create_pool_enumerator(config));
 
        this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
 
        enumerator = this->vips->create_enumerator(this->vips);
        while (enumerator->enumerate(enumerator, &requested))
        {
-               enumerator_t *poolenum;
-               char *pool;
                host_t *found = NULL;
 
                /* query all pools until we get an address */
                DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
 
-               poolenum = config->create_pool_enumerator(config);
-               while (poolenum->enumerate(poolenum, &pool))
+               found = hydra->attributes->acquire_address(hydra->attributes,
+                                                                                                  pools, id, requested);
+               if (found)
                {
-                       found = hydra->attributes->acquire_address(hydra->attributes,
-                                                                                                          pool, id, requested);
-                       if (!found)
-                       {
-                               continue;
-                       }
                        DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
                        this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
                        if (!cp)
@@ -360,17 +354,9 @@ METHOD(task_t, build_r, status_t,
                                cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
                        }
                        cp->add_attribute(cp, build_vip(found));
-                       /* use pool to request other attributes */
-                       if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
-                       {
-                               pools->insert_last(pools, pool);
-                       }
                        vips->insert_last(vips, found);
-                       break;
                }
-               poolenum->destroy(poolenum);
-
-               if (!found)
+               else
                {
                        DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
                                 requested, id);
index fbfcb0e..d624fd1 100644 (file)
@@ -342,29 +342,23 @@ METHOD(task_t, build_r, status_t,
                id = this->ike_sa->get_other_eap_id(this->ike_sa);
                config = this->ike_sa->get_peer_cfg(this->ike_sa);
                vips = linked_list_create();
-               pools = linked_list_create();
+               pools = linked_list_create_from_enumerator(
+                                                                       config->create_pool_enumerator(config));
 
                this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
 
                enumerator = this->vips->create_enumerator(this->vips);
                while (enumerator->enumerate(enumerator, &requested))
                {
-                       enumerator_t *poolenum;
-                       char *pool;
                        host_t *found = NULL;
 
                        /* query all pools until we get an address */
                        DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
 
-                       poolenum = config->create_pool_enumerator(config);
-                       while (poolenum->enumerate(poolenum, &pool))
+                       found = hydra->attributes->acquire_address(hydra->attributes,
+                                                                                                          pools, id, requested);
+                       if (found)
                        {
-                               found = hydra->attributes->acquire_address(hydra->attributes,
-                                                                                                                  pool, id, requested);
-                               if (!found)
-                               {
-                                       continue;
-                               }
                                DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
                                this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
                                if (!cp)
@@ -372,17 +366,9 @@ METHOD(task_t, build_r, status_t,
                                        cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
                                }
                                cp->add_attribute(cp, build_vip(found));
-                               /* use pool to request other attributes */
-                               if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
-                               {
-                                       pools->insert_last(pools, pool);
-                               }
                                vips->insert_last(vips, found);
-                               break;
                        }
-                       poolenum->destroy(poolenum);
-
-                       if (!found)
+                       else
                        {
                                DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
                                         requested, id);
index 64dc9c7..e7a687a 100644 (file)
@@ -60,8 +60,8 @@ typedef struct {
 } enum_data_t;
 
 METHOD(attribute_manager_t, acquire_address, host_t*,
-       private_attribute_manager_t *this, char *pool, identification_t *id,
-       host_t *requested)
+       private_attribute_manager_t *this, linked_list_t *pools,
+       identification_t *id, host_t *requested)
 {
        enumerator_t *enumerator;
        attribute_provider_t *current;
@@ -71,7 +71,7 @@ METHOD(attribute_manager_t, acquire_address, host_t*,
        enumerator = this->providers->create_enumerator(this->providers);
        while (enumerator->enumerate(enumerator, &current))
        {
-               host = current->acquire_address(current, pool, id, requested);
+               host = current->acquire_address(current, pools, id, requested);
                if (host)
                {
                        break;
index 8bc80ca..45e5a40 100644 (file)
@@ -39,13 +39,13 @@ struct attribute_manager_t {
        /**
         * Acquire a virtual IP address to assign to a peer.
         *
-        * @param pool                  pool name to acquire address from
+        * @param pools                 list of pool names (char*) to acquire from
         * @param id                    peer identity to get address forua
         * @param requested             IP in configuration request
         * @return                              allocated address, NULL to serve none
         */
        host_t* (*acquire_address)(attribute_manager_t *this,
-                                                          char *pool, identification_t *id,
+                                                          linked_list_t *pool, identification_t *id,
                                                           host_t *requested);
 
        /**
index 327135f..7d0acdb 100644 (file)
@@ -35,13 +35,13 @@ struct attribute_provider_t {
        /**
         * Acquire a virtual IP address to assign to a peer.
         *
-        * @param pool                  name of the pool to acquire address from
+        * @param pools                 list of pool names (char*) to acquire from
         * @param id                    peer ID
         * @param requested             IP in configuration request
         * @return                              allocated address, NULL to serve none
         */
        host_t* (*acquire_address)(attribute_provider_t *this,
-                                                          char *pool, identification_t *id,
+                                                          linked_list_t *pools, identification_t *id,
                                                           host_t *requested);
        /**
         * Release a previously acquired address.
index 8055be7..28e5985 100644 (file)
@@ -233,25 +233,50 @@ static host_t* get_lease(private_sql_attribute_t *this, char *name,
 }
 
 METHOD(attribute_provider_t, acquire_address, host_t*,
-       private_sql_attribute_t *this, char *name, identification_t *id,
+       private_sql_attribute_t *this, linked_list_t *pools, identification_t *id,
        host_t *requested)
 {
+       enumerator_t *enumerator;
        host_t *address = NULL;
        u_int identity, pool, timeout;
+       char *name;
 
        identity = get_identity(this, id);
        if (identity)
        {
-               pool = get_pool(this, name, &timeout);
-               if (pool)
+               /* check for an existing lease in all pools */
+               enumerator = pools->create_enumerator(pools);
+               while (enumerator->enumerate(enumerator, &name))
                {
-                       /* check for an existing lease */
-                       address = check_lease(this, name, pool, identity);
-                       if (address == NULL)
+                       pool = get_pool(this, name, &timeout);
+                       if (pool)
                        {
-                               /* get an unallocated address or expired lease */
-                               address = get_lease(this, name, pool, timeout, identity);
+                               address = check_lease(this, name, pool, identity);
+                               if (address)
+                               {
+                                       break;
+                               }
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               if (!address)
+               {
+                       /* get an unallocated address or expired lease */
+                       enumerator = pools->create_enumerator(pools);
+                       while (enumerator->enumerate(enumerator, &name))
+                       {
+                               pool = get_pool(this, name, &timeout);
+                               if (pool)
+                               {
+                                       address = get_lease(this, name, pool, timeout, identity);
+                                       if (address)
+                                       {
+                                               break;
+                                       }
+                               }
                        }
+                       enumerator->destroy(enumerator);
                }
        }
        return address;