Removed remaining parts of controller_t.listen() implementation.
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "bus.h"
18
19 #include <stdint.h>
20
21 #include <threading/thread.h>
22 #include <threading/thread_value.h>
23 #include <threading/mutex.h>
24
25 typedef struct private_bus_t private_bus_t;
26
27 /**
28 * Private data of a bus_t object.
29 */
30 struct private_bus_t {
31 /**
32 * Public part of a bus_t object.
33 */
34 bus_t public;
35
36 /**
37 * List of registered listeners as entry_t's
38 */
39 linked_list_t *listeners;
40
41 /**
42 * mutex to synchronize active listeners, recursively
43 */
44 mutex_t *mutex;
45
46 /**
47 * Thread local storage the threads IKE_SA
48 */
49 thread_value_t *thread_sa;
50 };
51
52 typedef struct entry_t entry_t;
53
54 /**
55 * a listener entry, either active or passive
56 */
57 struct entry_t {
58
59 /**
60 * registered listener interface
61 */
62 listener_t *listener;
63
64 /**
65 * are we currently calling this listener
66 */
67 int calling;
68 };
69
70 /**
71 * create a listener entry
72 */
73 static entry_t *entry_create(listener_t *listener)
74 {
75 entry_t *this;
76
77 INIT(this,
78 .listener = listener,
79 );
80 return this;
81 }
82
83 /**
84 * destroy an entry_t
85 */
86 static void entry_destroy(entry_t *entry)
87 {
88 free(entry);
89 }
90
91 METHOD(bus_t, add_listener, void,
92 private_bus_t *this, listener_t *listener)
93 {
94 this->mutex->lock(this->mutex);
95 this->listeners->insert_last(this->listeners, entry_create(listener));
96 this->mutex->unlock(this->mutex);
97 }
98
99 METHOD(bus_t, remove_listener, void,
100 private_bus_t *this, listener_t *listener)
101 {
102 enumerator_t *enumerator;
103 entry_t *entry;
104
105 this->mutex->lock(this->mutex);
106 enumerator = this->listeners->create_enumerator(this->listeners);
107 while (enumerator->enumerate(enumerator, &entry))
108 {
109 if (entry->listener == listener)
110 {
111 this->listeners->remove_at(this->listeners, enumerator);
112 entry_destroy(entry);
113 break;
114 }
115 }
116 enumerator->destroy(enumerator);
117 this->mutex->unlock(this->mutex);
118 }
119
120 typedef struct cleanup_data_t cleanup_data_t;
121
122 /**
123 * data to remove a listener using thread_cleanup_t handler
124 */
125 struct cleanup_data_t {
126 /** bus instance */
127 private_bus_t *this;
128 /** listener entry */
129 entry_t *entry;
130 };
131
132 METHOD(bus_t, set_sa, void,
133 private_bus_t *this, ike_sa_t *ike_sa)
134 {
135 this->thread_sa->set(this->thread_sa, ike_sa);
136 }
137
138 METHOD(bus_t, get_sa, ike_sa_t*,
139 private_bus_t *this)
140 {
141 return this->thread_sa->get(this->thread_sa);
142 }
143
144 /**
145 * data associated to a signal, passed to callback
146 */
147 typedef struct {
148 /** associated IKE_SA */
149 ike_sa_t *ike_sa;
150 /** invoking thread */
151 long thread;
152 /** debug group */
153 debug_t group;
154 /** debug level */
155 level_t level;
156 /** format string */
157 char *format;
158 /** argument list */
159 va_list args;
160 } log_data_t;
161
162 /**
163 * listener->log() invocation as a list remove callback
164 */
165 static bool log_cb(entry_t *entry, log_data_t *data)
166 {
167 va_list args;
168
169 if (entry->calling || !entry->listener->log)
170 { /* avoid recursive calls */
171 return FALSE;
172 }
173 entry->calling++;
174 va_copy(args, data->args);
175 if (!entry->listener->log(entry->listener, data->group, data->level,
176 data->thread, data->ike_sa, data->format, args))
177 {
178 entry_destroy(entry);
179 va_end(args);
180 return TRUE;
181 }
182 va_end(args);
183 entry->calling--;
184 return FALSE;
185 }
186
187 METHOD(bus_t, vlog, void,
188 private_bus_t *this, debug_t group, level_t level,
189 char* format, va_list args)
190 {
191 log_data_t data;
192
193 data.ike_sa = this->thread_sa->get(this->thread_sa);
194 data.thread = thread_current_id();
195 data.group = group;
196 data.level = level;
197 data.format = format;
198 va_copy(data.args, args);
199
200 this->mutex->lock(this->mutex);
201 /* We use the remove() method to invoke all listeners. This is cheap and
202 * does not require an allocation for this performance critical function. */
203 this->listeners->remove(this->listeners, &data, (void*)log_cb);
204 this->mutex->unlock(this->mutex);
205
206 va_end(data.args);
207 }
208
209 METHOD(bus_t, log_, void,
210 private_bus_t *this, debug_t group, level_t level, char* format, ...)
211 {
212 va_list args;
213
214 va_start(args, format);
215 vlog(this, group, level, format, args);
216 va_end(args);
217 }
218
219 /**
220 * unregister a listener
221 */
222 static void unregister_listener(private_bus_t *this, entry_t *entry,
223 enumerator_t *enumerator)
224 {
225 this->listeners->remove_at(this->listeners, enumerator);
226 entry_destroy(entry);
227 }
228
229 METHOD(bus_t, alert, void,
230 private_bus_t *this, alert_t alert, ...)
231 {
232 enumerator_t *enumerator;
233 ike_sa_t *ike_sa;
234 entry_t *entry;
235 va_list args;
236 bool keep;
237
238 ike_sa = this->thread_sa->get(this->thread_sa);
239
240 this->mutex->lock(this->mutex);
241 enumerator = this->listeners->create_enumerator(this->listeners);
242 while (enumerator->enumerate(enumerator, &entry))
243 {
244 if (entry->calling || !entry->listener->alert)
245 {
246 continue;
247 }
248 entry->calling++;
249 va_start(args, alert);
250 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
251 va_end(args);
252 entry->calling--;
253 if (!keep)
254 {
255 unregister_listener(this, entry, enumerator);
256 }
257 }
258 enumerator->destroy(enumerator);
259 this->mutex->unlock(this->mutex);
260 }
261
262 METHOD(bus_t, ike_state_change, void,
263 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
264 {
265 enumerator_t *enumerator;
266 entry_t *entry;
267 bool keep;
268
269 this->mutex->lock(this->mutex);
270 enumerator = this->listeners->create_enumerator(this->listeners);
271 while (enumerator->enumerate(enumerator, &entry))
272 {
273 if (entry->calling || !entry->listener->ike_state_change)
274 {
275 continue;
276 }
277 entry->calling++;
278 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
279 entry->calling--;
280 if (!keep)
281 {
282 unregister_listener(this, entry, enumerator);
283 }
284 }
285 enumerator->destroy(enumerator);
286 this->mutex->unlock(this->mutex);
287 }
288
289 METHOD(bus_t, child_state_change, void,
290 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
291 {
292 enumerator_t *enumerator;
293 ike_sa_t *ike_sa;
294 entry_t *entry;
295 bool keep;
296
297 ike_sa = this->thread_sa->get(this->thread_sa);
298
299 this->mutex->lock(this->mutex);
300 enumerator = this->listeners->create_enumerator(this->listeners);
301 while (enumerator->enumerate(enumerator, &entry))
302 {
303 if (entry->calling || !entry->listener->child_state_change)
304 {
305 continue;
306 }
307 entry->calling++;
308 keep = entry->listener->child_state_change(entry->listener, ike_sa,
309 child_sa, state);
310 entry->calling--;
311 if (!keep)
312 {
313 unregister_listener(this, entry, enumerator);
314 }
315 }
316 enumerator->destroy(enumerator);
317 this->mutex->unlock(this->mutex);
318 }
319
320 METHOD(bus_t, message, void,
321 private_bus_t *this, message_t *message, bool incoming, bool plain)
322 {
323 enumerator_t *enumerator;
324 ike_sa_t *ike_sa;
325 entry_t *entry;
326 bool keep;
327
328 ike_sa = this->thread_sa->get(this->thread_sa);
329
330 this->mutex->lock(this->mutex);
331 enumerator = this->listeners->create_enumerator(this->listeners);
332 while (enumerator->enumerate(enumerator, &entry))
333 {
334 if (entry->calling || !entry->listener->message)
335 {
336 continue;
337 }
338 entry->calling++;
339 keep = entry->listener->message(entry->listener, ike_sa,
340 message, incoming, plain);
341 entry->calling--;
342 if (!keep)
343 {
344 unregister_listener(this, entry, enumerator);
345 }
346 }
347 enumerator->destroy(enumerator);
348 this->mutex->unlock(this->mutex);
349 }
350
351 METHOD(bus_t, ike_keys, void,
352 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
353 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
354 ike_sa_t *rekey, shared_key_t *shared)
355 {
356 enumerator_t *enumerator;
357 entry_t *entry;
358 bool keep;
359
360 this->mutex->lock(this->mutex);
361 enumerator = this->listeners->create_enumerator(this->listeners);
362 while (enumerator->enumerate(enumerator, &entry))
363 {
364 if (entry->calling || !entry->listener->ike_keys)
365 {
366 continue;
367 }
368 entry->calling++;
369 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
370 nonce_i, nonce_r, rekey, shared);
371 entry->calling--;
372 if (!keep)
373 {
374 unregister_listener(this, entry, enumerator);
375 }
376 }
377 enumerator->destroy(enumerator);
378 this->mutex->unlock(this->mutex);
379 }
380
381 METHOD(bus_t, child_keys, void,
382 private_bus_t *this, child_sa_t *child_sa, bool initiator,
383 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
384 {
385 enumerator_t *enumerator;
386 ike_sa_t *ike_sa;
387 entry_t *entry;
388 bool keep;
389
390 ike_sa = this->thread_sa->get(this->thread_sa);
391
392 this->mutex->lock(this->mutex);
393 enumerator = this->listeners->create_enumerator(this->listeners);
394 while (enumerator->enumerate(enumerator, &entry))
395 {
396 if (entry->calling || !entry->listener->child_keys)
397 {
398 continue;
399 }
400 entry->calling++;
401 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
402 initiator, dh, nonce_i, nonce_r);
403 entry->calling--;
404 if (!keep)
405 {
406 unregister_listener(this, entry, enumerator);
407 }
408 }
409 enumerator->destroy(enumerator);
410 this->mutex->unlock(this->mutex);
411 }
412
413 METHOD(bus_t, child_updown, void,
414 private_bus_t *this, child_sa_t *child_sa, bool up)
415 {
416 enumerator_t *enumerator;
417 ike_sa_t *ike_sa;
418 entry_t *entry;
419 bool keep;
420
421 ike_sa = this->thread_sa->get(this->thread_sa);
422
423 this->mutex->lock(this->mutex);
424 enumerator = this->listeners->create_enumerator(this->listeners);
425 while (enumerator->enumerate(enumerator, &entry))
426 {
427 if (entry->calling || !entry->listener->child_updown)
428 {
429 continue;
430 }
431 entry->calling++;
432 keep = entry->listener->child_updown(entry->listener,
433 ike_sa, child_sa, up);
434 entry->calling--;
435 if (!keep)
436 {
437 unregister_listener(this, entry, enumerator);
438 }
439 }
440 enumerator->destroy(enumerator);
441 this->mutex->unlock(this->mutex);
442 }
443
444 METHOD(bus_t, child_rekey, void,
445 private_bus_t *this, child_sa_t *old, child_sa_t *new)
446 {
447 enumerator_t *enumerator;
448 ike_sa_t *ike_sa;
449 entry_t *entry;
450 bool keep;
451
452 ike_sa = this->thread_sa->get(this->thread_sa);
453
454 this->mutex->lock(this->mutex);
455 enumerator = this->listeners->create_enumerator(this->listeners);
456 while (enumerator->enumerate(enumerator, &entry))
457 {
458 if (entry->calling || !entry->listener->child_rekey)
459 {
460 continue;
461 }
462 entry->calling++;
463 keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
464 entry->calling--;
465 if (!keep)
466 {
467 unregister_listener(this, entry, enumerator);
468 }
469 }
470 enumerator->destroy(enumerator);
471 this->mutex->unlock(this->mutex);
472 }
473
474 METHOD(bus_t, ike_updown, void,
475 private_bus_t *this, ike_sa_t *ike_sa, bool up)
476 {
477 enumerator_t *enumerator;
478 entry_t *entry;
479 bool keep;
480
481 this->mutex->lock(this->mutex);
482 enumerator = this->listeners->create_enumerator(this->listeners);
483 while (enumerator->enumerate(enumerator, &entry))
484 {
485 if (entry->calling || !entry->listener->ike_updown)
486 {
487 continue;
488 }
489 entry->calling++;
490 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
491 entry->calling--;
492 if (!keep)
493 {
494 unregister_listener(this, entry, enumerator);
495 }
496 }
497 enumerator->destroy(enumerator);
498 this->mutex->unlock(this->mutex);
499
500 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
501 if (!up)
502 {
503 enumerator_t *enumerator;
504 child_sa_t *child_sa;
505
506 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
507 while (enumerator->enumerate(enumerator, (void**)&child_sa))
508 {
509 child_updown(this, child_sa, FALSE);
510 }
511 enumerator->destroy(enumerator);
512 }
513 }
514
515 METHOD(bus_t, ike_rekey, void,
516 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
517 {
518 enumerator_t *enumerator;
519 entry_t *entry;
520 bool keep;
521
522 this->mutex->lock(this->mutex);
523 enumerator = this->listeners->create_enumerator(this->listeners);
524 while (enumerator->enumerate(enumerator, &entry))
525 {
526 if (entry->calling || !entry->listener->ike_rekey)
527 {
528 continue;
529 }
530 entry->calling++;
531 keep = entry->listener->ike_rekey(entry->listener, old, new);
532 entry->calling--;
533 if (!keep)
534 {
535 unregister_listener(this, entry, enumerator);
536 }
537 }
538 enumerator->destroy(enumerator);
539 this->mutex->unlock(this->mutex);
540 }
541
542 METHOD(bus_t, authorize, bool,
543 private_bus_t *this, bool final)
544 {
545 enumerator_t *enumerator;
546 ike_sa_t *ike_sa;
547 entry_t *entry;
548 bool keep, success = TRUE;
549
550 ike_sa = this->thread_sa->get(this->thread_sa);
551
552 this->mutex->lock(this->mutex);
553 enumerator = this->listeners->create_enumerator(this->listeners);
554 while (enumerator->enumerate(enumerator, &entry))
555 {
556 if (entry->calling || !entry->listener->authorize)
557 {
558 continue;
559 }
560 entry->calling++;
561 keep = entry->listener->authorize(entry->listener, ike_sa,
562 final, &success);
563 entry->calling--;
564 if (!keep)
565 {
566 unregister_listener(this, entry, enumerator);
567 }
568 if (!success)
569 {
570 break;
571 }
572 }
573 enumerator->destroy(enumerator);
574 this->mutex->unlock(this->mutex);
575 return success;
576 }
577
578 METHOD(bus_t, narrow, void,
579 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
580 linked_list_t *local, linked_list_t *remote)
581 {
582 enumerator_t *enumerator;
583 ike_sa_t *ike_sa;
584 entry_t *entry;
585 bool keep;
586
587 ike_sa = this->thread_sa->get(this->thread_sa);
588
589 this->mutex->lock(this->mutex);
590 enumerator = this->listeners->create_enumerator(this->listeners);
591 while (enumerator->enumerate(enumerator, &entry))
592 {
593 if (entry->calling || !entry->listener->narrow)
594 {
595 continue;
596 }
597 entry->calling++;
598 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
599 type, local, remote);
600 entry->calling--;
601 if (!keep)
602 {
603 unregister_listener(this, entry, enumerator);
604 }
605 }
606 enumerator->destroy(enumerator);
607 this->mutex->unlock(this->mutex);
608 }
609
610 METHOD(bus_t, destroy, void,
611 private_bus_t *this)
612 {
613 this->thread_sa->destroy(this->thread_sa);
614 this->mutex->destroy(this->mutex);
615 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
616 free(this);
617 }
618
619 /*
620 * Described in header.
621 */
622 bus_t *bus_create()
623 {
624 private_bus_t *this;
625
626 INIT(this,
627 .public = {
628 .add_listener = _add_listener,
629 .remove_listener = _remove_listener,
630 .set_sa = _set_sa,
631 .get_sa = _get_sa,
632 .log = _log_,
633 .vlog = _vlog,
634 .alert = _alert,
635 .ike_state_change = _ike_state_change,
636 .child_state_change = _child_state_change,
637 .message = _message,
638 .ike_keys = _ike_keys,
639 .child_keys = _child_keys,
640 .ike_updown = _ike_updown,
641 .ike_rekey = _ike_rekey,
642 .child_updown = _child_updown,
643 .child_rekey = _child_rekey,
644 .authorize = _authorize,
645 .narrow = _narrow,
646 .destroy = _destroy,
647 },
648 .listeners = linked_list_create(),
649 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
650 .thread_sa = thread_value_create(NULL),
651 );
652
653 return &this->public;
654 }
655