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