Reimplemented mem pool to support multiple leases for a single identity
[strongswan.git] / src / libhydra / attributes / attribute_manager.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 "attribute_manager.h"
17
18 #include <debug.h>
19 #include <utils/linked_list.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_attribute_manager_t private_attribute_manager_t;
23
24 /**
25 * private data of attribute_manager
26 */
27 struct private_attribute_manager_t {
28
29 /**
30 * public functions
31 */
32 attribute_manager_t public;
33
34 /**
35 * list of registered providers
36 */
37 linked_list_t *providers;
38
39 /**
40 * list of registered handlers
41 */
42 linked_list_t *handlers;
43
44 /**
45 * rwlock provider list
46 */
47 rwlock_t *lock;
48 };
49
50 /**
51 * Data to pass to enumerator filters
52 */
53 typedef struct {
54 /** attribute group pool */
55 char *pool;
56 /** server/peer identity */
57 identification_t *id;
58 /** requesting/assigned virtual IP */
59 host_t *vip;
60 } enum_data_t;
61
62 /**
63 * Implementation of attribute_manager_t.acquire_address.
64 */
65 static host_t* acquire_address(private_attribute_manager_t *this,
66 char *pool, identification_t *id,
67 host_t *requested)
68 {
69 enumerator_t *enumerator;
70 attribute_provider_t *current;
71 host_t *host = NULL;
72
73 this->lock->read_lock(this->lock);
74 enumerator = this->providers->create_enumerator(this->providers);
75 while (enumerator->enumerate(enumerator, &current))
76 {
77 host = current->acquire_address(current, pool, id, requested);
78 if (host)
79 {
80 break;
81 }
82 }
83 enumerator->destroy(enumerator);
84 this->lock->unlock(this->lock);
85
86 if (!host)
87 {
88 DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool);
89 }
90 return host;
91 }
92
93 /**
94 * Implementation of attribute_manager_t.release_address.
95 */
96 static void release_address(private_attribute_manager_t *this,
97 char *pool, host_t *address, identification_t *id)
98 {
99 enumerator_t *enumerator;
100 attribute_provider_t *current;
101 bool found = FALSE;
102
103 this->lock->read_lock(this->lock);
104 enumerator = this->providers->create_enumerator(this->providers);
105 while (enumerator->enumerate(enumerator, &current))
106 {
107 if (current->release_address(current, pool, address, id))
108 {
109 found = TRUE;
110 break;
111 }
112 }
113 enumerator->destroy(enumerator);
114 this->lock->unlock(this->lock);
115
116 if (!found)
117 {
118 DBG1(DBG_CFG, "releasing address to pool '%s' failed", pool);
119 }
120 }
121
122 /**
123 * inner enumerator constructor for responder attributes
124 */
125 static enumerator_t *responder_enum_create(attribute_provider_t *provider,
126 enum_data_t *data)
127 {
128 return provider->create_attribute_enumerator(provider, data->pool,
129 data->id, data->vip);
130 }
131
132 /**
133 * Implementation of attribute_manager_t.create_responder_enumerator
134 */
135 static enumerator_t* create_responder_enumerator(
136 private_attribute_manager_t *this, char *pool,
137 identification_t *id, host_t *vip)
138 {
139 enum_data_t *data = malloc_thing(enum_data_t);
140
141 data->pool = pool;
142 data->id = id;
143 data->vip = vip;
144 this->lock->read_lock(this->lock);
145 return enumerator_create_cleaner(
146 enumerator_create_nested(
147 this->providers->create_enumerator(this->providers),
148 (void*)responder_enum_create, data, free),
149 (void*)this->lock->unlock, this->lock);
150 }
151
152 /**
153 * Implementation of attribute_manager_t.add_provider.
154 */
155 static void add_provider(private_attribute_manager_t *this,
156 attribute_provider_t *provider)
157 {
158 this->lock->write_lock(this->lock);
159 this->providers->insert_last(this->providers, provider);
160 this->lock->unlock(this->lock);
161 }
162
163 /**
164 * Implementation of attribute_manager_t.remove_provider.
165 */
166 static void remove_provider(private_attribute_manager_t *this,
167 attribute_provider_t *provider)
168 {
169 this->lock->write_lock(this->lock);
170 this->providers->remove(this->providers, provider, NULL);
171 this->lock->unlock(this->lock);
172 }
173
174 /**
175 * Implementation of attribute_manager_t.handle
176 */
177 static attribute_handler_t* handle(private_attribute_manager_t *this,
178 identification_t *server, attribute_handler_t *handler,
179 configuration_attribute_type_t type, chunk_t data)
180 {
181 enumerator_t *enumerator;
182 attribute_handler_t *current, *handled = NULL;
183
184 this->lock->read_lock(this->lock);
185
186 /* try to find the passed handler */
187 enumerator = this->handlers->create_enumerator(this->handlers);
188 while (enumerator->enumerate(enumerator, &current))
189 {
190 if (current == handler && current->handle(current, server, type, data))
191 {
192 handled = current;
193 break;
194 }
195 }
196 enumerator->destroy(enumerator);
197 if (!handled)
198 { /* handler requesting this attribute not found, try any other */
199 enumerator = this->handlers->create_enumerator(this->handlers);
200 while (enumerator->enumerate(enumerator, &current))
201 {
202 if (current->handle(current, server, type, data))
203 {
204 handled = current;
205 break;
206 }
207 }
208 enumerator->destroy(enumerator);
209 }
210 this->lock->unlock(this->lock);
211
212 if (!handled)
213 {
214 DBG1(DBG_CFG, "handling %N attribute failed",
215 configuration_attribute_type_names, type);
216 }
217 return handled;
218 }
219
220 /**
221 * Implementation of attribute_manager_t.release
222 */
223 static void release(private_attribute_manager_t *this,
224 attribute_handler_t *handler,
225 identification_t *server,
226 configuration_attribute_type_t type, chunk_t data)
227 {
228 enumerator_t *enumerator;
229 attribute_handler_t *current;
230
231 this->lock->read_lock(this->lock);
232 enumerator = this->handlers->create_enumerator(this->handlers);
233 while (enumerator->enumerate(enumerator, &current))
234 {
235 if (current == handler)
236 {
237 current->release(current, server, type, data);
238 break;
239 }
240 }
241 enumerator->destroy(enumerator);
242 this->lock->unlock(this->lock);
243 }
244
245 /**
246 * Enumerator implementation to enumerate nested initiator attributes
247 */
248 typedef struct {
249 /** implements enumerator_t */
250 enumerator_t public;
251 /** back ref */
252 private_attribute_manager_t *this;
253 /** currently processing handler */
254 attribute_handler_t *handler;
255 /** outer enumerator over handlers */
256 enumerator_t *outer;
257 /** inner enumerator over current handlers attributes */
258 enumerator_t *inner;
259 /** server ID we want attributes for */
260 identification_t *id;
261 /** virtual IP we are requesting along with attriubutes */
262 host_t *vip;
263 } initiator_enumerator_t;
264
265 /**
266 * Enumerator implementation for initiator attributes
267 */
268 static bool initiator_enumerate(initiator_enumerator_t *this,
269 attribute_handler_t **handler,
270 configuration_attribute_type_t *type,
271 chunk_t *value)
272 {
273 /* enumerate inner attributes using outer handler enumerator */
274 while (!this->inner || !this->inner->enumerate(this->inner, type, value))
275 {
276 if (!this->outer->enumerate(this->outer, &this->handler))
277 {
278 return FALSE;
279 }
280 DESTROY_IF(this->inner);
281 this->inner = this->handler->create_attribute_enumerator(this->handler,
282 this->id, this->vip);
283 }
284 /* inject the handler as additional attribute */
285 *handler = this->handler;
286 return TRUE;
287 }
288
289 /**
290 * Cleanup function of initiator attribute enumerator
291 */
292 static void initiator_destroy(initiator_enumerator_t *this)
293 {
294 this->this->lock->unlock(this->this->lock);
295 this->outer->destroy(this->outer);
296 DESTROY_IF(this->inner);
297 free(this);
298 }
299
300 /**
301 * Implementation of attribute_manager_t.create_initiator_enumerator
302 */
303 static enumerator_t* create_initiator_enumerator(
304 private_attribute_manager_t *this, identification_t *id, host_t *vip)
305 {
306 initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t);
307
308 this->lock->read_lock(this->lock);
309 enumerator->public.enumerate = (void*)initiator_enumerate;
310 enumerator->public.destroy = (void*)initiator_destroy;
311 enumerator->this = this;
312 enumerator->id = id;
313 enumerator->vip = vip;
314 enumerator->outer = this->handlers->create_enumerator(this->handlers);
315 enumerator->inner = NULL;
316 enumerator->handler = NULL;
317
318 return &enumerator->public;
319 }
320
321 /**
322 * Implementation of attribute_manager_t.add_handler
323 */
324 static void add_handler(private_attribute_manager_t *this,
325 attribute_handler_t *handler)
326 {
327 this->lock->write_lock(this->lock);
328 this->handlers->insert_last(this->handlers, handler);
329 this->lock->unlock(this->lock);
330 }
331
332 /**
333 * Implementation of attribute_manager_t.remove_handler
334 */
335 static void remove_handler(private_attribute_manager_t *this,
336 attribute_handler_t *handler)
337 {
338 this->lock->write_lock(this->lock);
339 this->handlers->remove(this->handlers, handler, NULL);
340 this->lock->unlock(this->lock);
341 }
342
343 /**
344 * Implementation of attribute_manager_t.destroy
345 */
346 static void destroy(private_attribute_manager_t *this)
347 {
348 this->providers->destroy(this->providers);
349 this->handlers->destroy(this->handlers);
350 this->lock->destroy(this->lock);
351 free(this);
352 }
353
354 /*
355 * see header file
356 */
357 attribute_manager_t *attribute_manager_create()
358 {
359 private_attribute_manager_t *this = malloc_thing(private_attribute_manager_t);
360
361 this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,host_t*))acquire_address;
362 this->public.release_address = (void(*)(attribute_manager_t*, char *, host_t*, identification_t*))release_address;
363 this->public.create_responder_enumerator = (enumerator_t*(*)(attribute_manager_t*, char *name, identification_t*, host_t*))create_responder_enumerator;
364 this->public.add_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))add_provider;
365 this->public.remove_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))remove_provider;
366 this->public.handle = (attribute_handler_t*(*)(attribute_manager_t*,identification_t*, attribute_handler_t*, configuration_attribute_type_t, chunk_t))handle;
367 this->public.release = (void(*)(attribute_manager_t*, attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
368 this->public.create_initiator_enumerator = (enumerator_t*(*)(attribute_manager_t*, identification_t*, host_t*))create_initiator_enumerator;
369 this->public.add_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))add_handler;
370 this->public.remove_handler = (void(*)(attribute_manager_t*, attribute_handler_t*))remove_handler;
371 this->public.destroy = (void(*)(attribute_manager_t*))destroy;
372
373 this->providers = linked_list_create();
374 this->handlers = linked_list_create();
375 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
376
377 return &this->public;
378 }
379