Pass the full list of pools to acquire_address, enumerate in providers
[strongswan.git] / src / libcharon / plugins / dhcp / dhcp_provider.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "dhcp_provider.h"
17
18 #include <utils/hashtable.h>
19 #include <threading/mutex.h>
20
21 typedef struct private_dhcp_provider_t private_dhcp_provider_t;
22
23 /**
24 * Private data of an dhcp_provider_t object.
25 */
26 struct private_dhcp_provider_t {
27
28 /**
29 * Public dhcp_provider_t interface.
30 */
31 dhcp_provider_t public;
32
33 /**
34 * Completed DHCP transactions
35 */
36 hashtable_t *transactions;
37
38 /**
39 * Lock for transactions
40 */
41 mutex_t *mutex;
42
43 /**
44 * DHCP communication socket
45 */
46 dhcp_socket_t *socket;
47 };
48
49 /**
50 * Hashtable hash function
51 */
52 static u_int hash(void *key)
53 {
54 return (uintptr_t)key;
55 }
56
57 /**
58 * Hashtable equals function
59 */
60 static bool equals(void *a, void *b)
61 {
62 return a == b;
63 }
64
65 /**
66 * Hash ID and host to a key
67 */
68 static uintptr_t hash_id_host(identification_t *id, host_t *host)
69 {
70 return chunk_hash_inc(id->get_encoding(id),
71 chunk_hash(host->get_address(host)));
72 }
73
74 /**
75 * Hash a DHCP transaction to a key, using address and id
76 */
77 static uintptr_t hash_transaction(dhcp_transaction_t *transaction)
78 {
79 return hash_id_host(transaction->get_identity(transaction),
80 transaction->get_address(transaction));
81 }
82
83 METHOD(attribute_provider_t, acquire_address, host_t*,
84 private_dhcp_provider_t *this, linked_list_t *pools,
85 identification_t *id, host_t *requested)
86 {
87 dhcp_transaction_t *transaction, *old;
88 enumerator_t *enumerator;
89 char *pool;
90 host_t *vip = NULL;
91
92 if (requested->get_family(requested) != AF_INET)
93 {
94 return NULL;
95 }
96 enumerator = pools->create_enumerator(pools);
97 while (enumerator->enumerate(enumerator, &pool))
98 {
99 if (!streq(pool, "dhcp"))
100 {
101 continue;
102 }
103 transaction = this->socket->enroll(this->socket, id);
104 if (!transaction)
105 {
106 continue;
107 }
108 vip = transaction->get_address(transaction);
109 vip = vip->clone(vip);
110 this->mutex->lock(this->mutex);
111 old = this->transactions->put(this->transactions,
112 (void*)hash_transaction(transaction), transaction);
113 this->mutex->unlock(this->mutex);
114 DESTROY_IF(old);
115 break;
116 }
117 enumerator->destroy(enumerator);
118 return vip;
119 }
120
121 METHOD(attribute_provider_t, release_address, bool,
122 private_dhcp_provider_t *this, char *pool,
123 host_t *address, identification_t *id)
124 {
125 if (streq(pool, "dhcp") && address->get_family(address) == AF_INET)
126 {
127 dhcp_transaction_t *transaction;
128
129 this->mutex->lock(this->mutex);
130 transaction = this->transactions->remove(this->transactions,
131 (void*)hash_id_host(id, address));
132 this->mutex->unlock(this->mutex);
133 if (transaction)
134 {
135 this->socket->release(this->socket, transaction);
136 transaction->destroy(transaction);
137 return TRUE;
138 }
139 }
140 return FALSE;
141 }
142
143 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
144 private_dhcp_provider_t *this, linked_list_t *pools, identification_t *id,
145 linked_list_t *vips)
146 {
147 dhcp_transaction_t *transaction = NULL;
148 enumerator_t *enumerator;
149 host_t *vip;
150
151 this->mutex->lock(this->mutex);
152 enumerator = vips->create_enumerator(vips);
153 while (enumerator->enumerate(enumerator, &vip))
154 {
155 transaction = this->transactions->get(this->transactions,
156 (void*)hash_id_host(id, vip));
157 if (transaction)
158 {
159 break;
160 }
161 }
162 enumerator->destroy(enumerator);
163 if (!transaction)
164 {
165 this->mutex->unlock(this->mutex);
166 return NULL;
167 }
168 return enumerator_create_cleaner(
169 transaction->create_attribute_enumerator(transaction),
170 (void*)this->mutex->unlock, this->mutex);
171 }
172
173 METHOD(dhcp_provider_t, destroy, void,
174 private_dhcp_provider_t *this)
175 {
176 enumerator_t *enumerator;
177 dhcp_transaction_t *value;
178 void *key;
179
180 enumerator = this->transactions->create_enumerator(this->transactions);
181 while (enumerator->enumerate(enumerator, &key, &value))
182 {
183 value->destroy(value);
184 }
185 enumerator->destroy(enumerator);
186 this->transactions->destroy(this->transactions);
187 this->mutex->destroy(this->mutex);
188 free(this);
189 }
190
191 /**
192 * See header
193 */
194 dhcp_provider_t *dhcp_provider_create(dhcp_socket_t *socket)
195 {
196 private_dhcp_provider_t *this;
197
198 INIT(this,
199 .public = {
200 .provider = {
201 .acquire_address = _acquire_address,
202 .release_address = _release_address,
203 .create_attribute_enumerator = _create_attribute_enumerator,
204 },
205 .destroy = _destroy,
206 },
207 .socket = socket,
208 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
209 .transactions = hashtable_create(hash, equals, 8),
210 );
211
212 return &this->public;
213 }
214