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