bus: Fix maximum log levels when mixing log/vlog implementing loggers
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011-2015 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 /**
27 * These operations allow us to speed up the log level checks on some platforms.
28 * In particular if acquiring the read lock is expensive even in the absence of
29 * any writers.
30 *
31 * Note that while holding the read/write lock the read does not have to be
32 * atomic as the write lock must be held to set the level.
33 */
34 #ifdef HAVE_GCC_ATOMIC_OPERATIONS
35
36 #define skip_level(ptr, level) (__atomic_load_n(ptr, __ATOMIC_RELAXED) < level)
37 #define set_level(ptr, val) __atomic_store_n(ptr, val, __ATOMIC_RELAXED)
38
39 #elif defined(HAVE_GCC_SYNC_OPERATIONS)
40
41 #define skip_level(ptr, level) (__sync_fetch_and_add(ptr, 0) < level)
42 #define set_level(ptr, val) __sync_bool_compare_and_swap(ptr, *ptr, val)
43
44 #else
45
46 #define skip_level(ptr, level) FALSE
47 #define set_level(ptr, val) ({ *ptr = val; })
48
49 #endif
50
51 typedef struct private_bus_t private_bus_t;
52
53 /**
54 * Private data of a bus_t object.
55 */
56 struct private_bus_t {
57 /**
58 * Public part of a bus_t object.
59 */
60 bus_t public;
61
62 /**
63 * List of registered listeners as entry_t.
64 */
65 linked_list_t *listeners;
66
67 /**
68 * List of registered loggers for each log group as log_entry_t.
69 * Loggers are ordered by descending log level.
70 * The extra list stores all loggers so we can properly unregister them.
71 */
72 linked_list_t *loggers[DBG_MAX + 1];
73
74 /**
75 * Maximum log level of any registered logger for each log group.
76 * This allows to check quickly if a log message has to be logged at all.
77 */
78 level_t max_level[DBG_MAX + 1];
79
80 /**
81 * Same as max level, but for loggers using the vlog() method.
82 */
83 level_t max_vlevel[DBG_MAX + 1];
84
85 /**
86 * Mutex for the list of listeners, recursively.
87 */
88 mutex_t *mutex;
89
90 /**
91 * Read-write lock for the list of loggers.
92 */
93 rwlock_t *log_lock;
94
95 /**
96 * Thread local storage the threads IKE_SA
97 */
98 thread_value_t *thread_sa;
99 };
100
101 typedef struct entry_t entry_t;
102
103 /**
104 * a listener entry
105 */
106 struct entry_t {
107
108 /**
109 * registered listener interface
110 */
111 listener_t *listener;
112
113 /**
114 * are we currently calling this listener
115 */
116 int calling;
117
118 };
119
120 typedef struct log_entry_t log_entry_t;
121
122 /**
123 * a logger entry
124 */
125 struct log_entry_t {
126
127 /**
128 * registered logger interface
129 */
130 logger_t *logger;
131
132 /**
133 * registered log levels per group
134 */
135 level_t levels[DBG_MAX];
136
137 };
138
139 METHOD(bus_t, add_listener, void,
140 private_bus_t *this, listener_t *listener)
141 {
142 entry_t *entry;
143
144 INIT(entry,
145 .listener = listener,
146 );
147
148 this->mutex->lock(this->mutex);
149 this->listeners->insert_last(this->listeners, entry);
150 this->mutex->unlock(this->mutex);
151 }
152
153 METHOD(bus_t, remove_listener, void,
154 private_bus_t *this, listener_t *listener)
155 {
156 enumerator_t *enumerator;
157 entry_t *entry;
158
159 this->mutex->lock(this->mutex);
160 enumerator = this->listeners->create_enumerator(this->listeners);
161 while (enumerator->enumerate(enumerator, &entry))
162 {
163 if (entry->listener == listener)
164 {
165 this->listeners->remove_at(this->listeners, enumerator);
166 free(entry);
167 break;
168 }
169 }
170 enumerator->destroy(enumerator);
171 this->mutex->unlock(this->mutex);
172 }
173
174 /**
175 * Register a logger on the given log group according to the requested level
176 */
177 static inline void register_logger(private_bus_t *this, debug_t group,
178 log_entry_t *entry)
179 {
180 enumerator_t *enumerator;
181 linked_list_t *loggers;
182 log_entry_t *current;
183 level_t level;
184
185 loggers = this->loggers[group];
186 level = entry->levels[group];
187
188 enumerator = loggers->create_enumerator(loggers);
189 while (enumerator->enumerate(enumerator, (void**)&current))
190 {
191 if (current->levels[group] <= level)
192 {
193 break;
194 }
195 }
196 loggers->insert_before(loggers, enumerator, entry);
197 enumerator->destroy(enumerator);
198
199 if (entry->logger->log)
200 {
201 set_level(&this->max_level[group], max(this->max_level[group], level));
202 }
203 if (entry->logger->vlog)
204 {
205 set_level(&this->max_vlevel[group],
206 max(this->max_vlevel[group], level));
207 }
208 }
209
210 /**
211 * Find the log level of the first registered logger that implements log or
212 * vlog (or both).
213 */
214 static bool find_max_levels(log_entry_t *entry, debug_t *group, level_t *level,
215 level_t *vlevel)
216 {
217 if (entry->logger->log && *level == LEVEL_SILENT)
218 {
219 *level = entry->levels[*group];
220 }
221 if (entry->logger->vlog && *vlevel == LEVEL_SILENT)
222 {
223 *vlevel = entry->levels[*group];
224 }
225 return *level > LEVEL_SILENT && *vlevel > LEVEL_SILENT;
226 }
227
228 /**
229 * Unregister a logger from all log groups (destroys the log_entry_t)
230 */
231 static inline void unregister_logger(private_bus_t *this, logger_t *logger)
232 {
233 enumerator_t *enumerator;
234 linked_list_t *loggers;
235 log_entry_t *entry, *found = NULL;
236
237 loggers = this->loggers[DBG_MAX];
238 enumerator = loggers->create_enumerator(loggers);
239 while (enumerator->enumerate(enumerator, &entry))
240 {
241 if (entry->logger == logger)
242 {
243 loggers->remove_at(loggers, enumerator);
244 found = entry;
245 break;
246 }
247 }
248 enumerator->destroy(enumerator);
249
250 if (found)
251 {
252 level_t level = LEVEL_SILENT, vlevel = LEVEL_SILENT;
253 debug_t group;
254
255 for (group = 0; group < DBG_MAX; group++)
256 {
257 if (found->levels[group] > LEVEL_SILENT)
258 {
259 loggers = this->loggers[group];
260 loggers->remove(loggers, found, NULL);
261 loggers->find_first(loggers, (linked_list_match_t)find_max_levels, NULL,
262 &group, &level, &vlevel);
263 set_level(&this->max_level[group], level);
264 set_level(&this->max_vlevel[group], vlevel);
265 }
266 }
267 free(found);
268 }
269 }
270
271 METHOD(bus_t, add_logger, void,
272 private_bus_t *this, logger_t *logger)
273 {
274 log_entry_t *entry;
275 debug_t group;
276
277 INIT(entry,
278 .logger = logger,
279 );
280
281 this->log_lock->write_lock(this->log_lock);
282 unregister_logger(this, logger);
283 for (group = 0; group < DBG_MAX; group++)
284 {
285 entry->levels[group] = logger->get_level(logger, group);
286 if (entry->levels[group] > LEVEL_SILENT)
287 {
288 register_logger(this, group, entry);
289 }
290 }
291 this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry);
292 this->log_lock->unlock(this->log_lock);
293 }
294
295 METHOD(bus_t, remove_logger, void,
296 private_bus_t *this, logger_t *logger)
297 {
298 this->log_lock->write_lock(this->log_lock);
299 unregister_logger(this, logger);
300 this->log_lock->unlock(this->log_lock);
301 }
302
303 METHOD(bus_t, set_sa, void,
304 private_bus_t *this, ike_sa_t *ike_sa)
305 {
306 this->thread_sa->set(this->thread_sa, ike_sa);
307 }
308
309 METHOD(bus_t, get_sa, ike_sa_t*,
310 private_bus_t *this)
311 {
312 return this->thread_sa->get(this->thread_sa);
313 }
314
315 /**
316 * data associated to a signal, passed to callback
317 */
318 typedef struct {
319 /** associated IKE_SA */
320 ike_sa_t *ike_sa;
321 /** invoking thread */
322 long thread;
323 /** debug group */
324 debug_t group;
325 /** debug level */
326 level_t level;
327 /** message/fmt */
328 char *message;
329 /** argument list if message is a format string for vlog() */
330 va_list args;
331 } log_data_t;
332
333 /**
334 * logger->log() invocation as a invoke_function callback
335 */
336 static void log_cb(log_entry_t *entry, log_data_t *data)
337 {
338 if (entry->logger->log && entry->levels[data->group] >= data->level)
339 {
340 entry->logger->log(entry->logger, data->group, data->level,
341 data->thread, data->ike_sa, data->message);
342 }
343 }
344
345 /**
346 * logger->vlog() invocation as a invoke_function callback
347 */
348 static void vlog_cb(log_entry_t *entry, log_data_t *data)
349 {
350 if (entry->logger->vlog && entry->levels[data->group] >= data->level)
351 {
352 va_list copy;
353
354 va_copy(copy, data->args);
355 entry->logger->vlog(entry->logger, data->group, data->level,
356 data->thread, data->ike_sa, data->message, copy);
357 va_end(copy);
358 }
359 }
360
361 METHOD(bus_t, vlog, void,
362 private_bus_t *this, debug_t group, level_t level,
363 char* format, va_list args)
364 {
365 linked_list_t *loggers;
366 log_data_t data;
367
368 /* NOTE: This is not 100% thread-safe and done here only because it is
369 * performance critical. We therefore ignore the following two issues for
370 * this particular case: 1) We might miss some log messages if another
371 * thread concurrently increases the log level or registers a new logger.
372 * 2) We might have to acquire the read lock below even if it wouldn't be
373 * necessary anymore due to another thread concurrently unregistering a
374 * logger or reducing the level. */
375 if (skip_level(&this->max_level[group], level) &&
376 skip_level(&this->max_vlevel[group], level))
377 {
378 return;
379 }
380
381 this->log_lock->read_lock(this->log_lock);
382 loggers = this->loggers[group];
383
384 if (this->max_level[group] >= level)
385 {
386 char buf[1024];
387 ssize_t len;
388
389 data.ike_sa = this->thread_sa->get(this->thread_sa);
390 data.thread = thread_current_id();
391 data.group = group;
392 data.level = level;
393 data.message = buf;
394
395 va_copy(data.args, args);
396 len = vsnprintf(data.message, sizeof(buf), format, data.args);
397 va_end(data.args);
398 if (len >= sizeof(buf))
399 {
400 len++;
401 data.message = malloc(len);
402 va_copy(data.args, args);
403 len = vsnprintf(data.message, len, format, data.args);
404 va_end(data.args);
405 }
406 if (len > 0)
407 {
408 loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb,
409 &data);
410 }
411 if (data.message != buf)
412 {
413 free(data.message);
414 }
415 }
416 if (this->max_vlevel[group] >= level)
417 {
418 data.ike_sa = this->thread_sa->get(this->thread_sa);
419 data.thread = thread_current_id();
420 data.group = group;
421 data.level = level;
422 data.message = format;
423
424 va_copy(data.args, args);
425 loggers->invoke_function(loggers, (linked_list_invoke_t)vlog_cb, &data);
426 va_end(data.args);
427 }
428
429 this->log_lock->unlock(this->log_lock);
430 }
431
432 METHOD(bus_t, log_, void,
433 private_bus_t *this, debug_t group, level_t level, char* format, ...)
434 {
435 va_list args;
436
437 va_start(args, format);
438 vlog(this, group, level, format, args);
439 va_end(args);
440 }
441
442 /**
443 * unregister a listener
444 */
445 static inline void unregister_listener(private_bus_t *this, entry_t *entry,
446 enumerator_t *enumerator)
447 {
448 this->listeners->remove_at(this->listeners, enumerator);
449 free(entry);
450 }
451
452 METHOD(bus_t, alert, void,
453 private_bus_t *this, alert_t alert, ...)
454 {
455 enumerator_t *enumerator;
456 ike_sa_t *ike_sa;
457 entry_t *entry;
458 va_list args;
459 bool keep;
460
461 ike_sa = this->thread_sa->get(this->thread_sa);
462
463 this->mutex->lock(this->mutex);
464 enumerator = this->listeners->create_enumerator(this->listeners);
465 while (enumerator->enumerate(enumerator, &entry))
466 {
467 if (entry->calling || !entry->listener->alert)
468 {
469 continue;
470 }
471 entry->calling++;
472 va_start(args, alert);
473 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
474 va_end(args);
475 entry->calling--;
476 if (!keep)
477 {
478 unregister_listener(this, entry, enumerator);
479 }
480 }
481 enumerator->destroy(enumerator);
482 this->mutex->unlock(this->mutex);
483 }
484
485 METHOD(bus_t, ike_state_change, void,
486 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
487 {
488 enumerator_t *enumerator;
489 entry_t *entry;
490 bool keep;
491
492 this->mutex->lock(this->mutex);
493 enumerator = this->listeners->create_enumerator(this->listeners);
494 while (enumerator->enumerate(enumerator, &entry))
495 {
496 if (entry->calling || !entry->listener->ike_state_change)
497 {
498 continue;
499 }
500 entry->calling++;
501 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
502 entry->calling--;
503 if (!keep)
504 {
505 unregister_listener(this, entry, enumerator);
506 }
507 }
508 enumerator->destroy(enumerator);
509 this->mutex->unlock(this->mutex);
510 }
511
512 METHOD(bus_t, child_state_change, void,
513 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
514 {
515 enumerator_t *enumerator;
516 ike_sa_t *ike_sa;
517 entry_t *entry;
518 bool keep;
519
520 ike_sa = this->thread_sa->get(this->thread_sa);
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->child_state_change)
527 {
528 continue;
529 }
530 entry->calling++;
531 keep = entry->listener->child_state_change(entry->listener, ike_sa,
532 child_sa, state);
533 entry->calling--;
534 if (!keep)
535 {
536 unregister_listener(this, entry, enumerator);
537 }
538 }
539 enumerator->destroy(enumerator);
540 this->mutex->unlock(this->mutex);
541 }
542
543 METHOD(bus_t, message, void,
544 private_bus_t *this, message_t *message, bool incoming, bool plain)
545 {
546 enumerator_t *enumerator;
547 ike_sa_t *ike_sa;
548 entry_t *entry;
549 bool keep;
550
551 ike_sa = this->thread_sa->get(this->thread_sa);
552
553 this->mutex->lock(this->mutex);
554 enumerator = this->listeners->create_enumerator(this->listeners);
555 while (enumerator->enumerate(enumerator, &entry))
556 {
557 if (entry->calling || !entry->listener->message)
558 {
559 continue;
560 }
561 entry->calling++;
562 keep = entry->listener->message(entry->listener, ike_sa,
563 message, incoming, plain);
564 entry->calling--;
565 if (!keep)
566 {
567 unregister_listener(this, entry, enumerator);
568 }
569 }
570 enumerator->destroy(enumerator);
571 this->mutex->unlock(this->mutex);
572 }
573
574 METHOD(bus_t, ike_keys, void,
575 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
576 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
577 ike_sa_t *rekey, shared_key_t *shared)
578 {
579 enumerator_t *enumerator;
580 entry_t *entry;
581 bool keep;
582
583 this->mutex->lock(this->mutex);
584 enumerator = this->listeners->create_enumerator(this->listeners);
585 while (enumerator->enumerate(enumerator, &entry))
586 {
587 if (entry->calling || !entry->listener->ike_keys)
588 {
589 continue;
590 }
591 entry->calling++;
592 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
593 nonce_i, nonce_r, rekey, shared);
594 entry->calling--;
595 if (!keep)
596 {
597 unregister_listener(this, entry, enumerator);
598 }
599 }
600 enumerator->destroy(enumerator);
601 this->mutex->unlock(this->mutex);
602 }
603
604 METHOD(bus_t, child_keys, void,
605 private_bus_t *this, child_sa_t *child_sa, bool initiator,
606 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
607 {
608 enumerator_t *enumerator;
609 ike_sa_t *ike_sa;
610 entry_t *entry;
611 bool keep;
612
613 ike_sa = this->thread_sa->get(this->thread_sa);
614
615 this->mutex->lock(this->mutex);
616 enumerator = this->listeners->create_enumerator(this->listeners);
617 while (enumerator->enumerate(enumerator, &entry))
618 {
619 if (entry->calling || !entry->listener->child_keys)
620 {
621 continue;
622 }
623 entry->calling++;
624 keep = entry->listener->child_keys(entry->listener, ike_sa,
625 child_sa, initiator, dh, nonce_i, nonce_r);
626 entry->calling--;
627 if (!keep)
628 {
629 unregister_listener(this, entry, enumerator);
630 }
631 }
632 enumerator->destroy(enumerator);
633 this->mutex->unlock(this->mutex);
634 }
635
636 METHOD(bus_t, child_updown, void,
637 private_bus_t *this, child_sa_t *child_sa, bool up)
638 {
639 enumerator_t *enumerator;
640 ike_sa_t *ike_sa;
641 entry_t *entry;
642 bool keep;
643
644 ike_sa = this->thread_sa->get(this->thread_sa);
645
646 this->mutex->lock(this->mutex);
647 enumerator = this->listeners->create_enumerator(this->listeners);
648 while (enumerator->enumerate(enumerator, &entry))
649 {
650 if (entry->calling || !entry->listener->child_updown)
651 {
652 continue;
653 }
654 entry->calling++;
655 keep = entry->listener->child_updown(entry->listener,
656 ike_sa, child_sa, up);
657 entry->calling--;
658 if (!keep)
659 {
660 unregister_listener(this, entry, enumerator);
661 }
662 }
663 enumerator->destroy(enumerator);
664 this->mutex->unlock(this->mutex);
665 }
666
667 METHOD(bus_t, child_rekey, void,
668 private_bus_t *this, child_sa_t *old, child_sa_t *new)
669 {
670 enumerator_t *enumerator;
671 ike_sa_t *ike_sa;
672 entry_t *entry;
673 bool keep;
674
675 ike_sa = this->thread_sa->get(this->thread_sa);
676
677 this->mutex->lock(this->mutex);
678 enumerator = this->listeners->create_enumerator(this->listeners);
679 while (enumerator->enumerate(enumerator, &entry))
680 {
681 if (entry->calling || !entry->listener->child_rekey)
682 {
683 continue;
684 }
685 entry->calling++;
686 keep = entry->listener->child_rekey(entry->listener, ike_sa,
687 old, new);
688 entry->calling--;
689 if (!keep)
690 {
691 unregister_listener(this, entry, enumerator);
692 }
693 }
694 enumerator->destroy(enumerator);
695 this->mutex->unlock(this->mutex);
696 }
697
698 METHOD(bus_t, children_migrate, void,
699 private_bus_t *this, ike_sa_id_t *new, uint32_t unique)
700 {
701 enumerator_t *enumerator;
702 ike_sa_t *ike_sa;
703 entry_t *entry;
704 bool keep;
705
706 ike_sa = this->thread_sa->get(this->thread_sa);
707
708 this->mutex->lock(this->mutex);
709 enumerator = this->listeners->create_enumerator(this->listeners);
710 while (enumerator->enumerate(enumerator, &entry))
711 {
712 if (entry->calling || !entry->listener->children_migrate)
713 {
714 continue;
715 }
716 entry->calling++;
717 keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
718 unique);
719 entry->calling--;
720 if (!keep)
721 {
722 unregister_listener(this, entry, enumerator);
723 }
724 }
725 enumerator->destroy(enumerator);
726 this->mutex->unlock(this->mutex);
727 }
728
729 METHOD(bus_t, ike_updown, void,
730 private_bus_t *this, ike_sa_t *ike_sa, bool up)
731 {
732 enumerator_t *enumerator;
733 entry_t *entry;
734 bool keep;
735
736 this->mutex->lock(this->mutex);
737 enumerator = this->listeners->create_enumerator(this->listeners);
738 while (enumerator->enumerate(enumerator, &entry))
739 {
740 if (entry->calling || !entry->listener->ike_updown)
741 {
742 continue;
743 }
744 entry->calling++;
745 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
746 entry->calling--;
747 if (!keep)
748 {
749 unregister_listener(this, entry, enumerator);
750 }
751 }
752 enumerator->destroy(enumerator);
753 this->mutex->unlock(this->mutex);
754
755 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
756 if (!up)
757 {
758 enumerator_t *enumerator;
759 child_sa_t *child_sa;
760
761 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
762 while (enumerator->enumerate(enumerator, (void**)&child_sa))
763 {
764 child_updown(this, child_sa, FALSE);
765 }
766 enumerator->destroy(enumerator);
767 }
768 }
769
770 METHOD(bus_t, ike_rekey, void,
771 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
772 {
773 enumerator_t *enumerator;
774 entry_t *entry;
775 bool keep;
776
777 this->mutex->lock(this->mutex);
778 enumerator = this->listeners->create_enumerator(this->listeners);
779 while (enumerator->enumerate(enumerator, &entry))
780 {
781 if (entry->calling || !entry->listener->ike_rekey)
782 {
783 continue;
784 }
785 entry->calling++;
786 keep = entry->listener->ike_rekey(entry->listener, old, new);
787 entry->calling--;
788 if (!keep)
789 {
790 unregister_listener(this, entry, enumerator);
791 }
792 }
793 enumerator->destroy(enumerator);
794 this->mutex->unlock(this->mutex);
795 }
796
797 METHOD(bus_t, ike_update, void,
798 private_bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new)
799 {
800 enumerator_t *enumerator;
801 entry_t *entry;
802 bool keep;
803
804 this->mutex->lock(this->mutex);
805 enumerator = this->listeners->create_enumerator(this->listeners);
806 while (enumerator->enumerate(enumerator, &entry))
807 {
808 if (entry->calling || !entry->listener->ike_update)
809 {
810 continue;
811 }
812 entry->calling++;
813 keep = entry->listener->ike_update(entry->listener, ike_sa, local, new);
814 entry->calling--;
815 if (!keep)
816 {
817 unregister_listener(this, entry, enumerator);
818 }
819 }
820 enumerator->destroy(enumerator);
821 this->mutex->unlock(this->mutex);
822 }
823
824 METHOD(bus_t, ike_reestablish_pre, void,
825 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
826 {
827 enumerator_t *enumerator;
828 entry_t *entry;
829 bool keep;
830
831 this->mutex->lock(this->mutex);
832 enumerator = this->listeners->create_enumerator(this->listeners);
833 while (enumerator->enumerate(enumerator, &entry))
834 {
835 if (entry->calling || !entry->listener->ike_reestablish_pre)
836 {
837 continue;
838 }
839 entry->calling++;
840 keep = entry->listener->ike_reestablish_pre(entry->listener, old, new);
841 entry->calling--;
842 if (!keep)
843 {
844 unregister_listener(this, entry, enumerator);
845 }
846 }
847 enumerator->destroy(enumerator);
848 this->mutex->unlock(this->mutex);
849 }
850
851 METHOD(bus_t, ike_reestablish_post, void,
852 private_bus_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated)
853 {
854 enumerator_t *enumerator;
855 entry_t *entry;
856 bool keep;
857
858 this->mutex->lock(this->mutex);
859 enumerator = this->listeners->create_enumerator(this->listeners);
860 while (enumerator->enumerate(enumerator, &entry))
861 {
862 if (entry->calling || !entry->listener->ike_reestablish_post)
863 {
864 continue;
865 }
866 entry->calling++;
867 keep = entry->listener->ike_reestablish_post(entry->listener, old, new,
868 initiated);
869 entry->calling--;
870 if (!keep)
871 {
872 unregister_listener(this, entry, enumerator);
873 }
874 }
875 enumerator->destroy(enumerator);
876 this->mutex->unlock(this->mutex);
877 }
878
879 METHOD(bus_t, authorize, bool,
880 private_bus_t *this, bool final)
881 {
882 enumerator_t *enumerator;
883 ike_sa_t *ike_sa;
884 entry_t *entry;
885 bool keep, success = TRUE;
886
887 ike_sa = this->thread_sa->get(this->thread_sa);
888
889 this->mutex->lock(this->mutex);
890 enumerator = this->listeners->create_enumerator(this->listeners);
891 while (enumerator->enumerate(enumerator, &entry))
892 {
893 if (entry->calling || !entry->listener->authorize)
894 {
895 continue;
896 }
897 entry->calling++;
898 keep = entry->listener->authorize(entry->listener, ike_sa,
899 final, &success);
900 entry->calling--;
901 if (!keep)
902 {
903 unregister_listener(this, entry, enumerator);
904 }
905 if (!success)
906 {
907 break;
908 }
909 }
910 enumerator->destroy(enumerator);
911 this->mutex->unlock(this->mutex);
912 if (!success)
913 {
914 alert(this, ALERT_AUTHORIZATION_FAILED);
915 }
916 return success;
917 }
918
919 METHOD(bus_t, narrow, void,
920 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
921 linked_list_t *local, linked_list_t *remote)
922 {
923 enumerator_t *enumerator;
924 ike_sa_t *ike_sa;
925 entry_t *entry;
926 bool keep;
927
928 ike_sa = this->thread_sa->get(this->thread_sa);
929
930 this->mutex->lock(this->mutex);
931 enumerator = this->listeners->create_enumerator(this->listeners);
932 while (enumerator->enumerate(enumerator, &entry))
933 {
934 if (entry->calling || !entry->listener->narrow)
935 {
936 continue;
937 }
938 entry->calling++;
939 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
940 type, local, remote);
941 entry->calling--;
942 if (!keep)
943 {
944 unregister_listener(this, entry, enumerator);
945 }
946 }
947 enumerator->destroy(enumerator);
948 this->mutex->unlock(this->mutex);
949 }
950
951 METHOD(bus_t, assign_vips, void,
952 private_bus_t *this, ike_sa_t *ike_sa, bool assign)
953 {
954 enumerator_t *enumerator;
955 entry_t *entry;
956 bool keep;
957
958 this->mutex->lock(this->mutex);
959 enumerator = this->listeners->create_enumerator(this->listeners);
960 while (enumerator->enumerate(enumerator, &entry))
961 {
962 if (entry->calling || !entry->listener->assign_vips)
963 {
964 continue;
965 }
966 entry->calling++;
967 keep = entry->listener->assign_vips(entry->listener, ike_sa, assign);
968 entry->calling--;
969 if (!keep)
970 {
971 unregister_listener(this, entry, enumerator);
972 }
973 }
974 enumerator->destroy(enumerator);
975 this->mutex->unlock(this->mutex);
976 }
977
978 METHOD(bus_t, handle_vips, void,
979 private_bus_t *this, ike_sa_t *ike_sa, bool handle)
980 {
981 enumerator_t *enumerator;
982 entry_t *entry;
983 bool keep;
984
985 this->mutex->lock(this->mutex);
986 enumerator = this->listeners->create_enumerator(this->listeners);
987 while (enumerator->enumerate(enumerator, &entry))
988 {
989 if (entry->calling || !entry->listener->handle_vips)
990 {
991 continue;
992 }
993 entry->calling++;
994 keep = entry->listener->handle_vips(entry->listener, ike_sa, handle);
995 entry->calling--;
996 if (!keep)
997 {
998 unregister_listener(this, entry, enumerator);
999 }
1000 }
1001 enumerator->destroy(enumerator);
1002 this->mutex->unlock(this->mutex);
1003 }
1004
1005 /**
1006 * Credential manager hook function to forward bus alerts
1007 */
1008 static void hook_creds(private_bus_t *this, credential_hook_type_t type,
1009 certificate_t *cert)
1010 {
1011 switch (type)
1012 {
1013 case CRED_HOOK_EXPIRED:
1014 return alert(this, ALERT_CERT_EXPIRED, cert);
1015 case CRED_HOOK_REVOKED:
1016 return alert(this, ALERT_CERT_REVOKED, cert);
1017 case CRED_HOOK_VALIDATION_FAILED:
1018 return alert(this, ALERT_CERT_VALIDATION_FAILED, cert);
1019 case CRED_HOOK_NO_ISSUER:
1020 return alert(this, ALERT_CERT_NO_ISSUER, cert);
1021 case CRED_HOOK_UNTRUSTED_ROOT:
1022 return alert(this, ALERT_CERT_UNTRUSTED_ROOT, cert);
1023 case CRED_HOOK_EXCEEDED_PATH_LEN:
1024 return alert(this, ALERT_CERT_EXCEEDED_PATH_LEN, cert);
1025 case CRED_HOOK_POLICY_VIOLATION:
1026 return alert(this, ALERT_CERT_POLICY_VIOLATION, cert);
1027 }
1028 }
1029
1030 METHOD(bus_t, destroy, void,
1031 private_bus_t *this)
1032 {
1033 debug_t group;
1034
1035 lib->credmgr->set_hook(lib->credmgr, NULL, NULL);
1036 for (group = 0; group < DBG_MAX; group++)
1037 {
1038 this->loggers[group]->destroy(this->loggers[group]);
1039 }
1040 this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
1041 (void*)free);
1042 this->listeners->destroy_function(this->listeners, (void*)free);
1043 this->thread_sa->destroy(this->thread_sa);
1044 this->log_lock->destroy(this->log_lock);
1045 this->mutex->destroy(this->mutex);
1046 free(this);
1047 }
1048
1049 /*
1050 * Described in header.
1051 */
1052 bus_t *bus_create()
1053 {
1054 private_bus_t *this;
1055 debug_t group;
1056
1057 INIT(this,
1058 .public = {
1059 .add_listener = _add_listener,
1060 .remove_listener = _remove_listener,
1061 .add_logger = _add_logger,
1062 .remove_logger = _remove_logger,
1063 .set_sa = _set_sa,
1064 .get_sa = _get_sa,
1065 .log = _log_,
1066 .vlog = _vlog,
1067 .alert = _alert,
1068 .ike_state_change = _ike_state_change,
1069 .child_state_change = _child_state_change,
1070 .message = _message,
1071 .ike_keys = _ike_keys,
1072 .child_keys = _child_keys,
1073 .ike_updown = _ike_updown,
1074 .ike_rekey = _ike_rekey,
1075 .ike_update = _ike_update,
1076 .ike_reestablish_pre = _ike_reestablish_pre,
1077 .ike_reestablish_post = _ike_reestablish_post,
1078 .child_updown = _child_updown,
1079 .child_rekey = _child_rekey,
1080 .children_migrate = _children_migrate,
1081 .authorize = _authorize,
1082 .narrow = _narrow,
1083 .assign_vips = _assign_vips,
1084 .handle_vips = _handle_vips,
1085 .destroy = _destroy,
1086 },
1087 .listeners = linked_list_create(),
1088 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1089 .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1090 .thread_sa = thread_value_create(NULL),
1091 );
1092
1093 for (group = 0; group <= DBG_MAX; group++)
1094 {
1095 this->loggers[group] = linked_list_create();
1096 this->max_level[group] = LEVEL_SILENT;
1097 this->max_vlevel[group] = LEVEL_SILENT;
1098 }
1099
1100 lib->credmgr->set_hook(lib->credmgr, (credential_hook_t)hook_creds, this);
1101
1102 return &this->public;
1103 }