df15afbe4dc12e24bad0de4c82b438c627d1ef17
[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 * List of registered listeners implementing listener_t.log() as entry_t
43 */
44 linked_list_t *loggers;
45
46 /**
47 * mutex for the list of listeners, recursively
48 */
49 mutex_t *mutex;
50
51 /**
52 * mutex for the list of loggers
53 */
54 mutex_t *log_mutex;
55
56 /**
57 * Thread local storage the threads IKE_SA
58 */
59 thread_value_t *thread_sa;
60 };
61
62 typedef struct entry_t entry_t;
63
64 /**
65 * a listener entry
66 */
67 struct entry_t {
68
69 /**
70 * registered listener interface
71 */
72 listener_t *listener;
73
74 /**
75 * are we currently calling this listener
76 */
77 int calling;
78
79 /**
80 * are we currently logging on this listener
81 */
82 int logging;
83
84 /**
85 * TRUE if this listener is active (we use this for the loggers)
86 */
87 bool enabled;
88 };
89
90 /**
91 * create a listener entry
92 */
93 static entry_t *entry_create(listener_t *listener)
94 {
95 entry_t *this;
96
97 INIT(this,
98 .listener = listener,
99 .enabled = TRUE,
100 );
101 return this;
102 }
103
104 /**
105 * destroy an entry_t
106 */
107 static void entry_destroy(entry_t *entry)
108 {
109 free(entry);
110 }
111
112 METHOD(bus_t, add_listener, void,
113 private_bus_t *this, listener_t *listener)
114 {
115 entry_t *entry = entry_create(listener);
116
117 this->mutex->lock(this->mutex);
118 this->listeners->insert_last(this->listeners, entry);
119 this->mutex->unlock(this->mutex);
120
121 if (listener->log)
122 {
123 this->log_mutex->lock(this->log_mutex);
124 this->loggers->insert_last(this->loggers, entry);
125 this->log_mutex->unlock(this->log_mutex);
126 }
127 }
128
129 METHOD(bus_t, remove_listener, void,
130 private_bus_t *this, listener_t *listener)
131 {
132 enumerator_t *enumerator;
133 entry_t *entry, *found = NULL;
134
135 this->mutex->lock(this->mutex);
136 enumerator = this->listeners->create_enumerator(this->listeners);
137 while (enumerator->enumerate(enumerator, &entry))
138 {
139 if (entry->listener == listener)
140 {
141 this->listeners->remove_at(this->listeners, enumerator);
142 found = entry;
143 break;
144 }
145 }
146 enumerator->destroy(enumerator);
147 this->mutex->unlock(this->mutex);
148
149 if (found)
150 {
151 this->log_mutex->lock(this->log_mutex);
152 this->loggers->remove(this->loggers, found, NULL);
153 this->log_mutex->unlock(this->log_mutex);
154 entry_destroy(found);
155 }
156 }
157
158 typedef struct cleanup_data_t cleanup_data_t;
159
160 /**
161 * data to remove a listener using thread_cleanup_t handler
162 */
163 struct cleanup_data_t {
164 /** bus instance */
165 private_bus_t *this;
166 /** listener entry */
167 entry_t *entry;
168 };
169
170 METHOD(bus_t, set_sa, void,
171 private_bus_t *this, ike_sa_t *ike_sa)
172 {
173 this->thread_sa->set(this->thread_sa, ike_sa);
174 }
175
176 METHOD(bus_t, get_sa, ike_sa_t*,
177 private_bus_t *this)
178 {
179 return this->thread_sa->get(this->thread_sa);
180 }
181
182 /**
183 * data associated to a signal, passed to callback
184 */
185 typedef struct {
186 /** associated IKE_SA */
187 ike_sa_t *ike_sa;
188 /** invoking thread */
189 long thread;
190 /** debug group */
191 debug_t group;
192 /** debug level */
193 level_t level;
194 /** format string */
195 char *format;
196 /** argument list */
197 va_list args;
198 } log_data_t;
199
200 /**
201 * listener->log() invocation as a list remove callback
202 */
203 static bool log_cb(entry_t *entry, log_data_t *data)
204 {
205 va_list args;
206
207 if (entry->logging)
208 { /* avoid recursive calls */
209 return FALSE;
210 }
211 entry->logging = TRUE;
212
213 va_copy(args, data->args);
214 if (!entry->listener->log(entry->listener, data->group, data->level,
215 data->thread, data->ike_sa, data->format, args))
216 {
217 entry->enabled = FALSE;
218 va_end(args);
219 return TRUE;
220 }
221 va_end(args);
222 entry->logging = FALSE;
223 return FALSE;
224 }
225
226 METHOD(bus_t, vlog, void,
227 private_bus_t *this, debug_t group, level_t level,
228 char* format, va_list args)
229 {
230 log_data_t data;
231
232 data.ike_sa = this->thread_sa->get(this->thread_sa);
233 data.thread = thread_current_id();
234 data.group = group;
235 data.level = level;
236 data.format = format;
237 va_copy(data.args, args);
238
239 this->log_mutex->lock(this->log_mutex);
240 /* We use the remove() method to invoke all listeners. This is cheap and
241 * does not require an allocation for this performance critical function. */
242 this->loggers->remove(this->loggers, &data, (void*)log_cb);
243 this->log_mutex->unlock(this->log_mutex);
244
245 va_end(data.args);
246 }
247
248 METHOD(bus_t, log_, void,
249 private_bus_t *this, debug_t group, level_t level, char* format, ...)
250 {
251 va_list args;
252
253 va_start(args, format);
254 vlog(this, group, level, format, args);
255 va_end(args);
256 }
257
258 /**
259 * unregister a listener
260 */
261 static void unregister_listener(private_bus_t *this, entry_t *entry,
262 enumerator_t *enumerator)
263 {
264 this->listeners->remove_at(this->listeners, enumerator);
265 this->log_mutex->lock(this->log_mutex);
266 this->loggers->remove(this->loggers, entry, NULL);
267 this->log_mutex->unlock(this->log_mutex);
268 entry_destroy(entry);
269 }
270
271 METHOD(bus_t, alert, void,
272 private_bus_t *this, alert_t alert, ...)
273 {
274 enumerator_t *enumerator;
275 ike_sa_t *ike_sa;
276 entry_t *entry;
277 va_list args;
278 bool keep;
279
280 ike_sa = this->thread_sa->get(this->thread_sa);
281
282 this->mutex->lock(this->mutex);
283 enumerator = this->listeners->create_enumerator(this->listeners);
284 while (enumerator->enumerate(enumerator, &entry))
285 {
286 if (entry->calling || !entry->listener->alert)
287 {
288 continue;
289 }
290 if (entry->enabled)
291 {
292 entry->calling++;
293 va_start(args, alert);
294 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
295 va_end(args);
296 entry->calling--;
297 }
298 if (!entry->enabled || !keep)
299 {
300 unregister_listener(this, entry, enumerator);
301 }
302 }
303 enumerator->destroy(enumerator);
304 this->mutex->unlock(this->mutex);
305 }
306
307 METHOD(bus_t, ike_state_change, void,
308 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
309 {
310 enumerator_t *enumerator;
311 entry_t *entry;
312 bool keep;
313
314 this->mutex->lock(this->mutex);
315 enumerator = this->listeners->create_enumerator(this->listeners);
316 while (enumerator->enumerate(enumerator, &entry))
317 {
318 if (entry->calling || !entry->listener->ike_state_change)
319 {
320 continue;
321 }
322 if (entry->enabled)
323 {
324 entry->calling++;
325 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
326 entry->calling--;
327 }
328 if (!entry->enabled || !keep)
329 {
330 unregister_listener(this, entry, enumerator);
331 }
332 }
333 enumerator->destroy(enumerator);
334 this->mutex->unlock(this->mutex);
335 }
336
337 METHOD(bus_t, child_state_change, void,
338 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
339 {
340 enumerator_t *enumerator;
341 ike_sa_t *ike_sa;
342 entry_t *entry;
343 bool keep;
344
345 ike_sa = this->thread_sa->get(this->thread_sa);
346
347 this->mutex->lock(this->mutex);
348 enumerator = this->listeners->create_enumerator(this->listeners);
349 while (enumerator->enumerate(enumerator, &entry))
350 {
351 if (entry->calling || !entry->listener->child_state_change)
352 {
353 continue;
354 }
355 if (entry->enabled)
356 {
357 entry->calling++;
358 keep = entry->listener->child_state_change(entry->listener, ike_sa,
359 child_sa, state);
360 entry->calling--;
361 }
362 if (!entry->enabled || !keep)
363 {
364 unregister_listener(this, entry, enumerator);
365 }
366 }
367 enumerator->destroy(enumerator);
368 this->mutex->unlock(this->mutex);
369 }
370
371 METHOD(bus_t, message, void,
372 private_bus_t *this, message_t *message, bool incoming, bool plain)
373 {
374 enumerator_t *enumerator;
375 ike_sa_t *ike_sa;
376 entry_t *entry;
377 bool keep;
378
379 ike_sa = this->thread_sa->get(this->thread_sa);
380
381 this->mutex->lock(this->mutex);
382 enumerator = this->listeners->create_enumerator(this->listeners);
383 while (enumerator->enumerate(enumerator, &entry))
384 {
385 if (entry->calling || !entry->listener->message)
386 {
387 continue;
388 }
389 if (entry->enabled)
390 {
391 entry->calling++;
392 keep = entry->listener->message(entry->listener, ike_sa,
393 message, incoming, plain);
394 entry->calling--;
395 }
396 if (!entry->enabled || !keep)
397 {
398 unregister_listener(this, entry, enumerator);
399 }
400 }
401 enumerator->destroy(enumerator);
402 this->mutex->unlock(this->mutex);
403 }
404
405 METHOD(bus_t, ike_keys, void,
406 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
407 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
408 ike_sa_t *rekey, shared_key_t *shared)
409 {
410 enumerator_t *enumerator;
411 entry_t *entry;
412 bool keep;
413
414 this->mutex->lock(this->mutex);
415 enumerator = this->listeners->create_enumerator(this->listeners);
416 while (enumerator->enumerate(enumerator, &entry))
417 {
418 if (entry->calling || !entry->listener->ike_keys)
419 {
420 continue;
421 }
422 if (entry->enabled)
423 {
424 entry->calling++;
425 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
426 nonce_i, nonce_r, rekey, shared);
427 entry->calling--;
428 }
429 if (!entry->enabled || !keep)
430 {
431 unregister_listener(this, entry, enumerator);
432 }
433 }
434 enumerator->destroy(enumerator);
435 this->mutex->unlock(this->mutex);
436 }
437
438 METHOD(bus_t, child_keys, void,
439 private_bus_t *this, child_sa_t *child_sa, bool initiator,
440 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
441 {
442 enumerator_t *enumerator;
443 ike_sa_t *ike_sa;
444 entry_t *entry;
445 bool keep;
446
447 ike_sa = this->thread_sa->get(this->thread_sa);
448
449 this->mutex->lock(this->mutex);
450 enumerator = this->listeners->create_enumerator(this->listeners);
451 while (enumerator->enumerate(enumerator, &entry))
452 {
453 if (entry->calling || !entry->listener->child_keys)
454 {
455 continue;
456 }
457 if (entry->enabled)
458 {
459 entry->calling++;
460 keep = entry->listener->child_keys(entry->listener, ike_sa,
461 child_sa, initiator, dh, nonce_i, nonce_r);
462 entry->calling--;
463 }
464 if (!entry->enabled || !keep)
465 {
466 unregister_listener(this, entry, enumerator);
467 }
468 }
469 enumerator->destroy(enumerator);
470 this->mutex->unlock(this->mutex);
471 }
472
473 METHOD(bus_t, child_updown, void,
474 private_bus_t *this, child_sa_t *child_sa, bool up)
475 {
476 enumerator_t *enumerator;
477 ike_sa_t *ike_sa;
478 entry_t *entry;
479 bool keep;
480
481 ike_sa = this->thread_sa->get(this->thread_sa);
482
483 this->mutex->lock(this->mutex);
484 enumerator = this->listeners->create_enumerator(this->listeners);
485 while (enumerator->enumerate(enumerator, &entry))
486 {
487 if (entry->calling || !entry->listener->child_updown)
488 {
489 continue;
490 }
491 if (entry->enabled)
492 {
493 entry->calling++;
494 keep = entry->listener->child_updown(entry->listener,
495 ike_sa, child_sa, up);
496 entry->calling--;
497 }
498 if (!entry->enabled || !keep)
499 {
500 unregister_listener(this, entry, enumerator);
501 }
502 }
503 enumerator->destroy(enumerator);
504 this->mutex->unlock(this->mutex);
505 }
506
507 METHOD(bus_t, child_rekey, void,
508 private_bus_t *this, child_sa_t *old, child_sa_t *new)
509 {
510 enumerator_t *enumerator;
511 ike_sa_t *ike_sa;
512 entry_t *entry;
513 bool keep;
514
515 ike_sa = this->thread_sa->get(this->thread_sa);
516
517 this->mutex->lock(this->mutex);
518 enumerator = this->listeners->create_enumerator(this->listeners);
519 while (enumerator->enumerate(enumerator, &entry))
520 {
521 if (entry->calling || !entry->listener->child_rekey)
522 {
523 continue;
524 }
525 if (entry->enabled)
526 {
527 entry->calling++;
528 keep = entry->listener->child_rekey(entry->listener, ike_sa,
529 old, new);
530 entry->calling--;
531 }
532 if (!entry->enabled || !keep)
533 {
534 unregister_listener(this, entry, enumerator);
535 }
536 }
537 enumerator->destroy(enumerator);
538 this->mutex->unlock(this->mutex);
539 }
540
541 METHOD(bus_t, ike_updown, void,
542 private_bus_t *this, ike_sa_t *ike_sa, bool up)
543 {
544 enumerator_t *enumerator;
545 entry_t *entry;
546 bool keep;
547
548 this->mutex->lock(this->mutex);
549 enumerator = this->listeners->create_enumerator(this->listeners);
550 while (enumerator->enumerate(enumerator, &entry))
551 {
552 if (entry->calling || !entry->listener->ike_updown)
553 {
554 continue;
555 }
556 if (entry->enabled)
557 {
558 entry->calling++;
559 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
560 entry->calling--;
561 }
562 if (!entry->enabled || !keep)
563 {
564 unregister_listener(this, entry, enumerator);
565 }
566 }
567 enumerator->destroy(enumerator);
568 this->mutex->unlock(this->mutex);
569
570 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
571 if (!up)
572 {
573 enumerator_t *enumerator;
574 child_sa_t *child_sa;
575
576 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
577 while (enumerator->enumerate(enumerator, (void**)&child_sa))
578 {
579 child_updown(this, child_sa, FALSE);
580 }
581 enumerator->destroy(enumerator);
582 }
583 }
584
585 METHOD(bus_t, ike_rekey, void,
586 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
587 {
588 enumerator_t *enumerator;
589 entry_t *entry;
590 bool keep;
591
592 this->mutex->lock(this->mutex);
593 enumerator = this->listeners->create_enumerator(this->listeners);
594 while (enumerator->enumerate(enumerator, &entry))
595 {
596 if (entry->calling || !entry->listener->ike_rekey)
597 {
598 continue;
599 }
600 if (entry->enabled)
601 {
602 entry->calling++;
603 keep = entry->listener->ike_rekey(entry->listener, old, new);
604 entry->calling--;
605 }
606 if (!entry->enabled || !keep)
607 {
608 unregister_listener(this, entry, enumerator);
609 }
610 }
611 enumerator->destroy(enumerator);
612 this->mutex->unlock(this->mutex);
613 }
614
615 METHOD(bus_t, authorize, bool,
616 private_bus_t *this, bool final)
617 {
618 enumerator_t *enumerator;
619 ike_sa_t *ike_sa;
620 entry_t *entry;
621 bool keep, success = TRUE;
622
623 ike_sa = this->thread_sa->get(this->thread_sa);
624
625 this->mutex->lock(this->mutex);
626 enumerator = this->listeners->create_enumerator(this->listeners);
627 while (enumerator->enumerate(enumerator, &entry))
628 {
629 if (entry->calling || !entry->listener->authorize)
630 {
631 continue;
632 }
633 if (entry->enabled)
634 {
635 entry->calling++;
636 keep = entry->listener->authorize(entry->listener, ike_sa,
637 final, &success);
638 entry->calling--;
639 }
640 if (!entry->enabled || !keep)
641 {
642 unregister_listener(this, entry, enumerator);
643 }
644 if (!success)
645 {
646 break;
647 }
648 }
649 enumerator->destroy(enumerator);
650 this->mutex->unlock(this->mutex);
651 return success;
652 }
653
654 METHOD(bus_t, narrow, void,
655 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
656 linked_list_t *local, linked_list_t *remote)
657 {
658 enumerator_t *enumerator;
659 ike_sa_t *ike_sa;
660 entry_t *entry;
661 bool keep;
662
663 ike_sa = this->thread_sa->get(this->thread_sa);
664
665 this->mutex->lock(this->mutex);
666 enumerator = this->listeners->create_enumerator(this->listeners);
667 while (enumerator->enumerate(enumerator, &entry))
668 {
669 if (entry->calling || !entry->listener->narrow)
670 {
671 continue;
672 }
673 if (entry->enabled)
674 {
675 entry->calling++;
676 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
677 type, local, remote);
678 entry->calling--;
679 }
680 if (!entry->enabled || !keep)
681 {
682 unregister_listener(this, entry, enumerator);
683 }
684 }
685 enumerator->destroy(enumerator);
686 this->mutex->unlock(this->mutex);
687 }
688
689 METHOD(bus_t, destroy, void,
690 private_bus_t *this)
691 {
692 this->thread_sa->destroy(this->thread_sa);
693 this->log_mutex->destroy(this->log_mutex);
694 this->mutex->destroy(this->mutex);
695 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
696 this->loggers->destroy(this->loggers);
697 free(this);
698 }
699
700 /*
701 * Described in header.
702 */
703 bus_t *bus_create()
704 {
705 private_bus_t *this;
706
707 INIT(this,
708 .public = {
709 .add_listener = _add_listener,
710 .remove_listener = _remove_listener,
711 .set_sa = _set_sa,
712 .get_sa = _get_sa,
713 .log = _log_,
714 .vlog = _vlog,
715 .alert = _alert,
716 .ike_state_change = _ike_state_change,
717 .child_state_change = _child_state_change,
718 .message = _message,
719 .ike_keys = _ike_keys,
720 .child_keys = _child_keys,
721 .ike_updown = _ike_updown,
722 .ike_rekey = _ike_rekey,
723 .child_updown = _child_updown,
724 .child_rekey = _child_rekey,
725 .authorize = _authorize,
726 .narrow = _narrow,
727 .destroy = _destroy,
728 },
729 .listeners = linked_list_create(),
730 .loggers = linked_list_create(),
731 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
732 .log_mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
733 .thread_sa = thread_value_create(NULL),
734 );
735
736 return &this->public;
737 }
738