Pass all configured pool names to attribute provider enumerator
[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 pools */
55 linked_list_t *pools;
56 /** server/peer identity */
57 identification_t *id;
58 /** requesting/assigned virtual IPs */
59 linked_list_t *vips;
60 } enum_data_t;
61
62 METHOD(attribute_manager_t, acquire_address, host_t*,
63 private_attribute_manager_t *this, char *pool, identification_t *id,
64 host_t *requested)
65 {
66 enumerator_t *enumerator;
67 attribute_provider_t *current;
68 host_t *host = NULL;
69
70 this->lock->read_lock(this->lock);
71 enumerator = this->providers->create_enumerator(this->providers);
72 while (enumerator->enumerate(enumerator, &current))
73 {
74 host = current->acquire_address(current, pool, id, requested);
75 if (host)
76 {
77 break;
78 }
79 }
80 enumerator->destroy(enumerator);
81 this->lock->unlock(this->lock);
82
83 if (!host)
84 {
85 DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool);
86 }
87 return host;
88 }
89
90 METHOD(attribute_manager_t, release_address, bool,
91 private_attribute_manager_t *this, char *pool, host_t *address,
92 identification_t *id)
93 {
94 enumerator_t *enumerator;
95 attribute_provider_t *current;
96 bool found = FALSE;
97
98 this->lock->read_lock(this->lock);
99 enumerator = this->providers->create_enumerator(this->providers);
100 while (enumerator->enumerate(enumerator, &current))
101 {
102 if (current->release_address(current, pool, address, id))
103 {
104 found = TRUE;
105 break;
106 }
107 }
108 enumerator->destroy(enumerator);
109 this->lock->unlock(this->lock);
110
111 return found;
112 }
113
114 /**
115 * inner enumerator constructor for responder attributes
116 */
117 static enumerator_t *responder_enum_create(attribute_provider_t *provider,
118 enum_data_t *data)
119 {
120 return provider->create_attribute_enumerator(provider, data->pools,
121 data->id, data->vips);
122 }
123
124 METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
125 private_attribute_manager_t *this, linked_list_t *pools,
126 identification_t *id, linked_list_t *vips)
127 {
128 enum_data_t *data;
129
130 INIT(data,
131 .pools = pools,
132 .id = id,
133 .vips = vips,
134 );
135 this->lock->read_lock(this->lock);
136 return enumerator_create_cleaner(
137 enumerator_create_nested(
138 this->providers->create_enumerator(this->providers),
139 (void*)responder_enum_create, data, free),
140 (void*)this->lock->unlock, this->lock);
141 }
142
143 METHOD(attribute_manager_t, add_provider, void,
144 private_attribute_manager_t *this, attribute_provider_t *provider)
145 {
146 this->lock->write_lock(this->lock);
147 this->providers->insert_last(this->providers, provider);
148 this->lock->unlock(this->lock);
149 }
150
151 METHOD(attribute_manager_t, remove_provider, void,
152 private_attribute_manager_t *this, attribute_provider_t *provider)
153 {
154 this->lock->write_lock(this->lock);
155 this->providers->remove(this->providers, provider, NULL);
156 this->lock->unlock(this->lock);
157 }
158
159 METHOD(attribute_manager_t, handle, attribute_handler_t*,
160 private_attribute_manager_t *this, identification_t *server,
161 attribute_handler_t *handler, configuration_attribute_type_t type,
162 chunk_t data)
163 {
164 enumerator_t *enumerator;
165 attribute_handler_t *current, *handled = NULL;
166
167 this->lock->read_lock(this->lock);
168
169 /* try to find the passed handler */
170 enumerator = this->handlers->create_enumerator(this->handlers);
171 while (enumerator->enumerate(enumerator, &current))
172 {
173 if (current == handler && current->handle(current, server, type, data))
174 {
175 handled = current;
176 break;
177 }
178 }
179 enumerator->destroy(enumerator);
180 if (!handled)
181 { /* handler requesting this attribute not found, try any other */
182 enumerator = this->handlers->create_enumerator(this->handlers);
183 while (enumerator->enumerate(enumerator, &current))
184 {
185 if (current->handle(current, server, type, data))
186 {
187 handled = current;
188 break;
189 }
190 }
191 enumerator->destroy(enumerator);
192 }
193 this->lock->unlock(this->lock);
194
195 if (!handled)
196 {
197 DBG1(DBG_CFG, "handling %N attribute failed",
198 configuration_attribute_type_names, type);
199 }
200 return handled;
201 }
202
203 METHOD(attribute_manager_t, release, void,
204 private_attribute_manager_t *this, attribute_handler_t *handler,
205 identification_t *server, configuration_attribute_type_t type, chunk_t data)
206 {
207 enumerator_t *enumerator;
208 attribute_handler_t *current;
209
210 this->lock->read_lock(this->lock);
211 enumerator = this->handlers->create_enumerator(this->handlers);
212 while (enumerator->enumerate(enumerator, &current))
213 {
214 if (current == handler)
215 {
216 current->release(current, server, type, data);
217 break;
218 }
219 }
220 enumerator->destroy(enumerator);
221 this->lock->unlock(this->lock);
222 }
223
224 /**
225 * Enumerator implementation to enumerate nested initiator attributes
226 */
227 typedef struct {
228 /** implements enumerator_t */
229 enumerator_t public;
230 /** back ref */
231 private_attribute_manager_t *this;
232 /** currently processing handler */
233 attribute_handler_t *handler;
234 /** outer enumerator over handlers */
235 enumerator_t *outer;
236 /** inner enumerator over current handlers attributes */
237 enumerator_t *inner;
238 /** server ID we want attributes for */
239 identification_t *id;
240 /** virtual IPs we are requesting along with attriubutes */
241 linked_list_t *vips;
242 } initiator_enumerator_t;
243
244 /**
245 * Enumerator implementation for initiator attributes
246 */
247 static bool initiator_enumerate(initiator_enumerator_t *this,
248 attribute_handler_t **handler,
249 configuration_attribute_type_t *type,
250 chunk_t *value)
251 {
252 /* enumerate inner attributes using outer handler enumerator */
253 while (!this->inner || !this->inner->enumerate(this->inner, type, value))
254 {
255 if (!this->outer->enumerate(this->outer, &this->handler))
256 {
257 return FALSE;
258 }
259 DESTROY_IF(this->inner);
260 this->inner = this->handler->create_attribute_enumerator(this->handler,
261 this->id, this->vips);
262 }
263 /* inject the handler as additional attribute */
264 *handler = this->handler;
265 return TRUE;
266 }
267
268 /**
269 * Cleanup function of initiator attribute enumerator
270 */
271 static void initiator_destroy(initiator_enumerator_t *this)
272 {
273 this->this->lock->unlock(this->this->lock);
274 this->outer->destroy(this->outer);
275 DESTROY_IF(this->inner);
276 free(this);
277 }
278
279 METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
280 private_attribute_manager_t *this, identification_t *id, linked_list_t *vips)
281 {
282 initiator_enumerator_t *enumerator;
283
284 this->lock->read_lock(this->lock);
285
286 INIT(enumerator,
287 .public = {
288 .enumerate = (void*)initiator_enumerate,
289 .destroy = (void*)initiator_destroy,
290 },
291 .this = this,
292 .id = id,
293 .vips = vips,
294 .outer = this->handlers->create_enumerator(this->handlers),
295 );
296 return &enumerator->public;
297 }
298
299 METHOD(attribute_manager_t, add_handler, void,
300 private_attribute_manager_t *this, attribute_handler_t *handler)
301 {
302 this->lock->write_lock(this->lock);
303 this->handlers->insert_last(this->handlers, handler);
304 this->lock->unlock(this->lock);
305 }
306
307 METHOD(attribute_manager_t, remove_handler, void,
308 private_attribute_manager_t *this, attribute_handler_t *handler)
309 {
310 this->lock->write_lock(this->lock);
311 this->handlers->remove(this->handlers, handler, NULL);
312 this->lock->unlock(this->lock);
313 }
314
315 METHOD(attribute_manager_t, destroy, void,
316 private_attribute_manager_t *this)
317 {
318 this->providers->destroy(this->providers);
319 this->handlers->destroy(this->handlers);
320 this->lock->destroy(this->lock);
321 free(this);
322 }
323
324 /*
325 * see header file
326 */
327 attribute_manager_t *attribute_manager_create()
328 {
329 private_attribute_manager_t *this;
330
331 INIT(this,
332 .public = {
333 .acquire_address = _acquire_address,
334 .release_address = _release_address,
335 .create_responder_enumerator = _create_responder_enumerator,
336 .add_provider = _add_provider,
337 .remove_provider = _remove_provider,
338 .handle = _handle,
339 .release = _release,
340 .create_initiator_enumerator = _create_initiator_enumerator,
341 .add_handler = _add_handler,
342 .remove_handler = _remove_handler,
343 .destroy = _destroy,
344 },
345 .providers = linked_list_create(),
346 .handlers = linked_list_create(),
347 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
348 );
349
350 return &this->public;
351 }
352