e46559f9787642f11b22f990ab85382bbd107c9c
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011-2012 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 #include <threading/rwlock.h>
25
26 typedef struct private_bus_t private_bus_t;
27
28 /**
29 * Private data of a bus_t object.
30 */
31 struct private_bus_t {
32 /**
33 * Public part of a bus_t object.
34 */
35 bus_t public;
36
37 /**
38 * List of registered listeners as entry_t.
39 */
40 linked_list_t *listeners;
41
42 /**
43 * List of registered loggers for each log group as log_entry_t.
44 * Loggers are ordered by descending log level.
45 * The extra list stores all loggers so we can properly unregister them.
46 */
47 linked_list_t *loggers[DBG_MAX + 1];
48
49 /**
50 * Maximum log level of any registered logger for each log group.
51 * This allows to check quickly if a log message has to be logged at all.
52 */
53 level_t max_level[DBG_MAX + 1];
54
55 /**
56 * Mutex for the list of listeners, recursively.
57 */
58 mutex_t *mutex;
59
60 /**
61 * Read-write lock for the list of loggers.
62 */
63 rwlock_t *log_lock;
64
65 /**
66 * Thread local storage the threads IKE_SA
67 */
68 thread_value_t *thread_sa;
69 };
70
71 typedef struct entry_t entry_t;
72
73 /**
74 * a listener entry
75 */
76 struct entry_t {
77
78 /**
79 * registered listener interface
80 */
81 listener_t *listener;
82
83 /**
84 * are we currently calling this listener
85 */
86 int calling;
87
88 };
89
90 typedef struct log_entry_t log_entry_t;
91
92 /**
93 * a logger entry
94 */
95 struct log_entry_t {
96
97 /**
98 * registered logger interface
99 */
100 logger_t *logger;
101
102 /**
103 * registered log levels per group
104 */
105 level_t levels[DBG_MAX];
106
107 };
108
109 METHOD(bus_t, add_listener, void,
110 private_bus_t *this, listener_t *listener)
111 {
112 entry_t *entry;
113
114 INIT(entry,
115 .listener = listener,
116 );
117
118 this->mutex->lock(this->mutex);
119 this->listeners->insert_last(this->listeners, entry);
120 this->mutex->unlock(this->mutex);
121 }
122
123 METHOD(bus_t, remove_listener, void,
124 private_bus_t *this, listener_t *listener)
125 {
126 enumerator_t *enumerator;
127 entry_t *entry;
128
129 this->mutex->lock(this->mutex);
130 enumerator = this->listeners->create_enumerator(this->listeners);
131 while (enumerator->enumerate(enumerator, &entry))
132 {
133 if (entry->listener == listener)
134 {
135 this->listeners->remove_at(this->listeners, enumerator);
136 free(entry);
137 break;
138 }
139 }
140 enumerator->destroy(enumerator);
141 this->mutex->unlock(this->mutex);
142 }
143
144 /**
145 * Register a logger on the given log group according to the requested level
146 */
147 static inline void register_logger(private_bus_t *this, debug_t group,
148 log_entry_t *entry)
149 {
150 enumerator_t *enumerator;
151 linked_list_t *loggers;
152 log_entry_t *current;
153 level_t level;
154
155 loggers = this->loggers[group];
156 level = entry->levels[group];
157
158 enumerator = loggers->create_enumerator(loggers);
159 while (enumerator->enumerate(enumerator, (void**)&current))
160 {
161 if (current->levels[group] <= level)
162 {
163 break;
164 }
165 }
166 loggers->insert_before(loggers, enumerator, entry);
167 enumerator->destroy(enumerator);
168
169 this->max_level[group] = max(this->max_level[group], level);
170 }
171
172 /**
173 * Unregister a logger from all log groups (destroys the log_entry_t)
174 */
175 static inline void unregister_logger(private_bus_t *this, logger_t *logger)
176 {
177 enumerator_t *enumerator;
178 linked_list_t *loggers;
179 log_entry_t *entry, *found = NULL;
180
181 loggers = this->loggers[DBG_MAX];
182 enumerator = loggers->create_enumerator(loggers);
183 while (enumerator->enumerate(enumerator, &entry))
184 {
185 if (entry->logger == logger)
186 {
187 loggers->remove_at(loggers, enumerator);
188 found = entry;
189 break;
190 }
191 }
192 enumerator->destroy(enumerator);
193
194 if (found)
195 {
196 debug_t group;
197 for (group = 0; group < DBG_MAX; group++)
198 {
199 if (found->levels[group] > LEVEL_SILENT)
200 {
201 loggers = this->loggers[group];
202 loggers->remove(loggers, found, NULL);
203
204 this->max_level[group] = LEVEL_SILENT;
205 if (loggers->get_first(loggers, (void**)&entry) == SUCCESS)
206 {
207 this->max_level[group] = entry->levels[group];
208 }
209 }
210 }
211 free(found);
212 }
213 }
214
215 METHOD(bus_t, add_logger, void,
216 private_bus_t *this, logger_t *logger)
217 {
218 log_entry_t *entry;
219 debug_t group;
220
221 INIT(entry,
222 .logger = logger,
223 );
224
225 this->log_lock->write_lock(this->log_lock);
226 unregister_logger(this, logger);
227 for (group = 0; group < DBG_MAX; group++)
228 {
229 entry->levels[group] = logger->get_level(logger, group);
230 if (entry->levels[group] > LEVEL_SILENT)
231 {
232 register_logger(this, group, entry);
233 }
234 }
235 this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry);
236 this->log_lock->unlock(this->log_lock);
237 }
238
239 METHOD(bus_t, remove_logger, void,
240 private_bus_t *this, logger_t *logger)
241 {
242 this->log_lock->write_lock(this->log_lock);
243 unregister_logger(this, logger);
244 this->log_lock->unlock(this->log_lock);
245 }
246
247 METHOD(bus_t, set_sa, void,
248 private_bus_t *this, ike_sa_t *ike_sa)
249 {
250 this->thread_sa->set(this->thread_sa, ike_sa);
251 }
252
253 METHOD(bus_t, get_sa, ike_sa_t*,
254 private_bus_t *this)
255 {
256 return this->thread_sa->get(this->thread_sa);
257 }
258
259 /**
260 * data associated to a signal, passed to callback
261 */
262 typedef struct {
263 /** associated IKE_SA */
264 ike_sa_t *ike_sa;
265 /** invoking thread */
266 long thread;
267 /** debug group */
268 debug_t group;
269 /** debug level */
270 level_t level;
271 /** message */
272 char *message;
273 } log_data_t;
274
275 /**
276 * logger->log() invocation as a invoke_function callback
277 */
278 static void log_cb(log_entry_t *entry, log_data_t *data)
279 {
280 if (entry->levels[data->group] < data->level)
281 {
282 return;
283 }
284 entry->logger->log(entry->logger, data->group, data->level,
285 data->thread, data->ike_sa, data->message);
286 }
287
288 METHOD(bus_t, vlog, void,
289 private_bus_t *this, debug_t group, level_t level,
290 char* format, va_list args)
291 {
292 this->log_lock->read_lock(this->log_lock);
293 if (this->max_level[group] >= level)
294 {
295 linked_list_t *loggers = this->loggers[group];
296 log_data_t data;
297 va_list copy;
298 char buf[1024];
299 ssize_t len;
300
301 data.ike_sa = this->thread_sa->get(this->thread_sa);
302 data.thread = thread_current_id();
303 data.group = group;
304 data.level = level;
305 data.message = buf;
306
307 va_copy(copy, args);
308 len = vsnprintf(data.message, sizeof(buf), format, copy);
309 va_end(copy);
310 if (len >= sizeof(buf))
311 {
312 data.message = malloc(len);
313 len = vsnprintf(data.message, len, format, args);
314 }
315 if (len > 0)
316 {
317 loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb,
318 &data);
319 }
320 if (data.message != buf)
321 {
322 free(data.message);
323 }
324 }
325 this->log_lock->unlock(this->log_lock);
326 }
327
328 METHOD(bus_t, log_, void,
329 private_bus_t *this, debug_t group, level_t level, char* format, ...)
330 {
331 va_list args;
332
333 va_start(args, format);
334 vlog(this, group, level, format, args);
335 va_end(args);
336 }
337
338 /**
339 * unregister a listener
340 */
341 static inline void unregister_listener(private_bus_t *this, entry_t *entry,
342 enumerator_t *enumerator)
343 {
344 this->listeners->remove_at(this->listeners, enumerator);
345 free(entry);
346 }
347
348 METHOD(bus_t, alert, void,
349 private_bus_t *this, alert_t alert, ...)
350 {
351 enumerator_t *enumerator;
352 ike_sa_t *ike_sa;
353 entry_t *entry;
354 va_list args;
355 bool keep;
356
357 ike_sa = this->thread_sa->get(this->thread_sa);
358
359 this->mutex->lock(this->mutex);
360 enumerator = this->listeners->create_enumerator(this->listeners);
361 while (enumerator->enumerate(enumerator, &entry))
362 {
363 if (entry->calling || !entry->listener->alert)
364 {
365 continue;
366 }
367 entry->calling++;
368 va_start(args, alert);
369 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
370 va_end(args);
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, ike_state_change, void,
382 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
383 {
384 enumerator_t *enumerator;
385 entry_t *entry;
386 bool keep;
387
388 this->mutex->lock(this->mutex);
389 enumerator = this->listeners->create_enumerator(this->listeners);
390 while (enumerator->enumerate(enumerator, &entry))
391 {
392 if (entry->calling || !entry->listener->ike_state_change)
393 {
394 continue;
395 }
396 entry->calling++;
397 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
398 entry->calling--;
399 if (!keep)
400 {
401 unregister_listener(this, entry, enumerator);
402 }
403 }
404 enumerator->destroy(enumerator);
405 this->mutex->unlock(this->mutex);
406 }
407
408 METHOD(bus_t, child_state_change, void,
409 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
410 {
411 enumerator_t *enumerator;
412 ike_sa_t *ike_sa;
413 entry_t *entry;
414 bool keep;
415
416 ike_sa = this->thread_sa->get(this->thread_sa);
417
418 this->mutex->lock(this->mutex);
419 enumerator = this->listeners->create_enumerator(this->listeners);
420 while (enumerator->enumerate(enumerator, &entry))
421 {
422 if (entry->calling || !entry->listener->child_state_change)
423 {
424 continue;
425 }
426 entry->calling++;
427 keep = entry->listener->child_state_change(entry->listener, ike_sa,
428 child_sa, state);
429 entry->calling--;
430 if (!keep)
431 {
432 unregister_listener(this, entry, enumerator);
433 }
434 }
435 enumerator->destroy(enumerator);
436 this->mutex->unlock(this->mutex);
437 }
438
439 METHOD(bus_t, message, void,
440 private_bus_t *this, message_t *message, bool incoming, bool plain)
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->message)
454 {
455 continue;
456 }
457 entry->calling++;
458 keep = entry->listener->message(entry->listener, ike_sa,
459 message, incoming, plain);
460 entry->calling--;
461 if (!keep)
462 {
463 unregister_listener(this, entry, enumerator);
464 }
465 }
466 enumerator->destroy(enumerator);
467 this->mutex->unlock(this->mutex);
468 }
469
470 METHOD(bus_t, ike_keys, void,
471 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
472 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
473 ike_sa_t *rekey, shared_key_t *shared)
474 {
475 enumerator_t *enumerator;
476 entry_t *entry;
477 bool keep;
478
479 this->mutex->lock(this->mutex);
480 enumerator = this->listeners->create_enumerator(this->listeners);
481 while (enumerator->enumerate(enumerator, &entry))
482 {
483 if (entry->calling || !entry->listener->ike_keys)
484 {
485 continue;
486 }
487 entry->calling++;
488 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
489 nonce_i, nonce_r, rekey, shared);
490 entry->calling--;
491 if (!keep)
492 {
493 unregister_listener(this, entry, enumerator);
494 }
495 }
496 enumerator->destroy(enumerator);
497 this->mutex->unlock(this->mutex);
498 }
499
500 METHOD(bus_t, child_keys, void,
501 private_bus_t *this, child_sa_t *child_sa, bool initiator,
502 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
503 {
504 enumerator_t *enumerator;
505 ike_sa_t *ike_sa;
506 entry_t *entry;
507 bool keep;
508
509 ike_sa = this->thread_sa->get(this->thread_sa);
510
511 this->mutex->lock(this->mutex);
512 enumerator = this->listeners->create_enumerator(this->listeners);
513 while (enumerator->enumerate(enumerator, &entry))
514 {
515 if (entry->calling || !entry->listener->child_keys)
516 {
517 continue;
518 }
519 entry->calling++;
520 keep = entry->listener->child_keys(entry->listener, ike_sa,
521 child_sa, initiator, dh, nonce_i, nonce_r);
522 entry->calling--;
523 if (!keep)
524 {
525 unregister_listener(this, entry, enumerator);
526 }
527 }
528 enumerator->destroy(enumerator);
529 this->mutex->unlock(this->mutex);
530 }
531
532 METHOD(bus_t, child_updown, void,
533 private_bus_t *this, child_sa_t *child_sa, bool up)
534 {
535 enumerator_t *enumerator;
536 ike_sa_t *ike_sa;
537 entry_t *entry;
538 bool keep;
539
540 ike_sa = this->thread_sa->get(this->thread_sa);
541
542 this->mutex->lock(this->mutex);
543 enumerator = this->listeners->create_enumerator(this->listeners);
544 while (enumerator->enumerate(enumerator, &entry))
545 {
546 if (entry->calling || !entry->listener->child_updown)
547 {
548 continue;
549 }
550 entry->calling++;
551 keep = entry->listener->child_updown(entry->listener,
552 ike_sa, child_sa, up);
553 entry->calling--;
554 if (!keep)
555 {
556 unregister_listener(this, entry, enumerator);
557 }
558 }
559 enumerator->destroy(enumerator);
560 this->mutex->unlock(this->mutex);
561 }
562
563 METHOD(bus_t, child_rekey, void,
564 private_bus_t *this, child_sa_t *old, child_sa_t *new)
565 {
566 enumerator_t *enumerator;
567 ike_sa_t *ike_sa;
568 entry_t *entry;
569 bool keep;
570
571 ike_sa = this->thread_sa->get(this->thread_sa);
572
573 this->mutex->lock(this->mutex);
574 enumerator = this->listeners->create_enumerator(this->listeners);
575 while (enumerator->enumerate(enumerator, &entry))
576 {
577 if (entry->calling || !entry->listener->child_rekey)
578 {
579 continue;
580 }
581 entry->calling++;
582 keep = entry->listener->child_rekey(entry->listener, ike_sa,
583 old, new);
584 entry->calling--;
585 if (!keep)
586 {
587 unregister_listener(this, entry, enumerator);
588 }
589 }
590 enumerator->destroy(enumerator);
591 this->mutex->unlock(this->mutex);
592 }
593
594 METHOD(bus_t, ike_updown, void,
595 private_bus_t *this, ike_sa_t *ike_sa, bool up)
596 {
597 enumerator_t *enumerator;
598 entry_t *entry;
599 bool keep;
600
601 this->mutex->lock(this->mutex);
602 enumerator = this->listeners->create_enumerator(this->listeners);
603 while (enumerator->enumerate(enumerator, &entry))
604 {
605 if (entry->calling || !entry->listener->ike_updown)
606 {
607 continue;
608 }
609 entry->calling++;
610 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
611 entry->calling--;
612 if (!keep)
613 {
614 unregister_listener(this, entry, enumerator);
615 }
616 }
617 enumerator->destroy(enumerator);
618 this->mutex->unlock(this->mutex);
619
620 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
621 if (!up)
622 {
623 enumerator_t *enumerator;
624 child_sa_t *child_sa;
625
626 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
627 while (enumerator->enumerate(enumerator, (void**)&child_sa))
628 {
629 child_updown(this, child_sa, FALSE);
630 }
631 enumerator->destroy(enumerator);
632 }
633 }
634
635 METHOD(bus_t, ike_rekey, void,
636 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
637 {
638 enumerator_t *enumerator;
639 entry_t *entry;
640 bool keep;
641
642 this->mutex->lock(this->mutex);
643 enumerator = this->listeners->create_enumerator(this->listeners);
644 while (enumerator->enumerate(enumerator, &entry))
645 {
646 if (entry->calling || !entry->listener->ike_rekey)
647 {
648 continue;
649 }
650 entry->calling++;
651 keep = entry->listener->ike_rekey(entry->listener, old, new);
652 entry->calling--;
653 if (!keep)
654 {
655 unregister_listener(this, entry, enumerator);
656 }
657 }
658 enumerator->destroy(enumerator);
659 this->mutex->unlock(this->mutex);
660 }
661
662 METHOD(bus_t, authorize, bool,
663 private_bus_t *this, bool final)
664 {
665 enumerator_t *enumerator;
666 ike_sa_t *ike_sa;
667 entry_t *entry;
668 bool keep, success = TRUE;
669
670 ike_sa = this->thread_sa->get(this->thread_sa);
671
672 this->mutex->lock(this->mutex);
673 enumerator = this->listeners->create_enumerator(this->listeners);
674 while (enumerator->enumerate(enumerator, &entry))
675 {
676 if (entry->calling || !entry->listener->authorize)
677 {
678 continue;
679 }
680 entry->calling++;
681 keep = entry->listener->authorize(entry->listener, ike_sa,
682 final, &success);
683 entry->calling--;
684 if (!keep)
685 {
686 unregister_listener(this, entry, enumerator);
687 }
688 if (!success)
689 {
690 break;
691 }
692 }
693 enumerator->destroy(enumerator);
694 this->mutex->unlock(this->mutex);
695 return success;
696 }
697
698 METHOD(bus_t, narrow, void,
699 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
700 linked_list_t *local, linked_list_t *remote)
701 {
702 enumerator_t *enumerator;
703 ike_sa_t *ike_sa;
704 entry_t *entry;
705 bool keep;
706
707 ike_sa = this->thread_sa->get(this->thread_sa);
708
709 this->mutex->lock(this->mutex);
710 enumerator = this->listeners->create_enumerator(this->listeners);
711 while (enumerator->enumerate(enumerator, &entry))
712 {
713 if (entry->calling || !entry->listener->narrow)
714 {
715 continue;
716 }
717 entry->calling++;
718 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
719 type, local, remote);
720 entry->calling--;
721 if (!keep)
722 {
723 unregister_listener(this, entry, enumerator);
724 }
725 }
726 enumerator->destroy(enumerator);
727 this->mutex->unlock(this->mutex);
728 }
729
730 METHOD(bus_t, destroy, void,
731 private_bus_t *this)
732 {
733 debug_t group;
734 for (group = 0; group < DBG_MAX; group++)
735 {
736 this->loggers[group]->destroy(this->loggers[group]);
737 }
738 this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
739 (void*)free);
740 this->listeners->destroy_function(this->listeners, (void*)free);
741 this->thread_sa->destroy(this->thread_sa);
742 this->log_lock->destroy(this->log_lock);
743 this->mutex->destroy(this->mutex);
744 free(this);
745 }
746
747 /*
748 * Described in header.
749 */
750 bus_t *bus_create()
751 {
752 private_bus_t *this;
753 debug_t group;
754
755 INIT(this,
756 .public = {
757 .add_listener = _add_listener,
758 .remove_listener = _remove_listener,
759 .add_logger = _add_logger,
760 .remove_logger = _remove_logger,
761 .set_sa = _set_sa,
762 .get_sa = _get_sa,
763 .log = _log_,
764 .vlog = _vlog,
765 .alert = _alert,
766 .ike_state_change = _ike_state_change,
767 .child_state_change = _child_state_change,
768 .message = _message,
769 .ike_keys = _ike_keys,
770 .child_keys = _child_keys,
771 .ike_updown = _ike_updown,
772 .ike_rekey = _ike_rekey,
773 .child_updown = _child_updown,
774 .child_rekey = _child_rekey,
775 .authorize = _authorize,
776 .narrow = _narrow,
777 .destroy = _destroy,
778 },
779 .listeners = linked_list_create(),
780 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
781 .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
782 .thread_sa = thread_value_create(NULL),
783 );
784
785 for (group = 0; group <= DBG_MAX; group++)
786 {
787 this->loggers[group] = linked_list_create();
788 this->max_level[group] = LEVEL_SILENT;
789 }
790
791 return &this->public;
792 }
793