bus: Fix maximum log level for different groups after removal of a logger
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011-2016 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 debug_t group;
237
238 loggers = this->loggers[DBG_MAX];
239 enumerator = loggers->create_enumerator(loggers);
240 while (enumerator->enumerate(enumerator, &entry))
241 {
242 if (entry->logger == logger)
243 {
244 loggers->remove_at(loggers, enumerator);
245 found = entry;
246 break;
247 }
248 }
249 enumerator->destroy(enumerator);
250
251 if (found)
252 {
253 for (group = 0; group < DBG_MAX; group++)
254 {
255 if (found->levels[group] > LEVEL_SILENT)
256 {
257 level_t level = LEVEL_SILENT, vlevel = 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,
262 NULL, 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, ike_derived_keys, void,
605 private_bus_t *this, chunk_t sk_ei, chunk_t sk_er, chunk_t sk_ai,
606 chunk_t sk_ar)
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->ike_derived_keys)
620 {
621 continue;
622 }
623 entry->calling++;
624 keep = entry->listener->ike_derived_keys(entry->listener, ike_sa, sk_ei,
625 sk_er, sk_ai, sk_ar);
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_keys, void,
637 private_bus_t *this, child_sa_t *child_sa, bool initiator,
638 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
639 {
640 enumerator_t *enumerator;
641 ike_sa_t *ike_sa;
642 entry_t *entry;
643 bool keep;
644
645 ike_sa = this->thread_sa->get(this->thread_sa);
646
647 this->mutex->lock(this->mutex);
648 enumerator = this->listeners->create_enumerator(this->listeners);
649 while (enumerator->enumerate(enumerator, &entry))
650 {
651 if (entry->calling || !entry->listener->child_keys)
652 {
653 continue;
654 }
655 entry->calling++;
656 keep = entry->listener->child_keys(entry->listener, ike_sa,
657 child_sa, initiator, dh, nonce_i, nonce_r);
658 entry->calling--;
659 if (!keep)
660 {
661 unregister_listener(this, entry, enumerator);
662 }
663 }
664 enumerator->destroy(enumerator);
665 this->mutex->unlock(this->mutex);
666 }
667
668 METHOD(bus_t, child_derived_keys, void,
669 private_bus_t *this, child_sa_t *child_sa, bool initiator,
670 chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, chunk_t integ_r)
671 {
672 enumerator_t *enumerator;
673 ike_sa_t *ike_sa;
674 entry_t *entry;
675 bool keep;
676
677 ike_sa = this->thread_sa->get(this->thread_sa);
678
679 this->mutex->lock(this->mutex);
680 enumerator = this->listeners->create_enumerator(this->listeners);
681 while (enumerator->enumerate(enumerator, &entry))
682 {
683 if (entry->calling || !entry->listener->child_derived_keys)
684 {
685 continue;
686 }
687 entry->calling++;
688 keep = entry->listener->child_derived_keys(entry->listener, ike_sa,
689 child_sa, initiator, encr_i, encr_r,
690 integ_i, integ_r);
691 entry->calling--;
692 if (!keep)
693 {
694 unregister_listener(this, entry, enumerator);
695 }
696 }
697 enumerator->destroy(enumerator);
698 this->mutex->unlock(this->mutex);
699 }
700
701 METHOD(bus_t, child_updown, void,
702 private_bus_t *this, child_sa_t *child_sa, bool up)
703 {
704 enumerator_t *enumerator;
705 ike_sa_t *ike_sa;
706 entry_t *entry;
707 bool keep;
708
709 ike_sa = this->thread_sa->get(this->thread_sa);
710
711 this->mutex->lock(this->mutex);
712 enumerator = this->listeners->create_enumerator(this->listeners);
713 while (enumerator->enumerate(enumerator, &entry))
714 {
715 if (entry->calling || !entry->listener->child_updown)
716 {
717 continue;
718 }
719 entry->calling++;
720 keep = entry->listener->child_updown(entry->listener,
721 ike_sa, child_sa, up);
722 entry->calling--;
723 if (!keep)
724 {
725 unregister_listener(this, entry, enumerator);
726 }
727 }
728 enumerator->destroy(enumerator);
729 this->mutex->unlock(this->mutex);
730 }
731
732 METHOD(bus_t, child_rekey, void,
733 private_bus_t *this, child_sa_t *old, child_sa_t *new)
734 {
735 enumerator_t *enumerator;
736 ike_sa_t *ike_sa;
737 entry_t *entry;
738 bool keep;
739
740 ike_sa = this->thread_sa->get(this->thread_sa);
741
742 this->mutex->lock(this->mutex);
743 enumerator = this->listeners->create_enumerator(this->listeners);
744 while (enumerator->enumerate(enumerator, &entry))
745 {
746 if (entry->calling || !entry->listener->child_rekey)
747 {
748 continue;
749 }
750 entry->calling++;
751 keep = entry->listener->child_rekey(entry->listener, ike_sa,
752 old, new);
753 entry->calling--;
754 if (!keep)
755 {
756 unregister_listener(this, entry, enumerator);
757 }
758 }
759 enumerator->destroy(enumerator);
760 this->mutex->unlock(this->mutex);
761 }
762
763 METHOD(bus_t, children_migrate, void,
764 private_bus_t *this, ike_sa_id_t *new, uint32_t unique)
765 {
766 enumerator_t *enumerator;
767 ike_sa_t *ike_sa;
768 entry_t *entry;
769 bool keep;
770
771 ike_sa = this->thread_sa->get(this->thread_sa);
772
773 this->mutex->lock(this->mutex);
774 enumerator = this->listeners->create_enumerator(this->listeners);
775 while (enumerator->enumerate(enumerator, &entry))
776 {
777 if (entry->calling || !entry->listener->children_migrate)
778 {
779 continue;
780 }
781 entry->calling++;
782 keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
783 unique);
784 entry->calling--;
785 if (!keep)
786 {
787 unregister_listener(this, entry, enumerator);
788 }
789 }
790 enumerator->destroy(enumerator);
791 this->mutex->unlock(this->mutex);
792 }
793
794 METHOD(bus_t, ike_updown, void,
795 private_bus_t *this, ike_sa_t *ike_sa, bool up)
796 {
797 enumerator_t *enumerator;
798 entry_t *entry;
799 bool keep;
800
801 this->mutex->lock(this->mutex);
802 enumerator = this->listeners->create_enumerator(this->listeners);
803 while (enumerator->enumerate(enumerator, &entry))
804 {
805 if (entry->calling || !entry->listener->ike_updown)
806 {
807 continue;
808 }
809 entry->calling++;
810 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
811 entry->calling--;
812 if (!keep)
813 {
814 unregister_listener(this, entry, enumerator);
815 }
816 }
817 enumerator->destroy(enumerator);
818 this->mutex->unlock(this->mutex);
819
820 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
821 if (!up)
822 {
823 enumerator_t *enumerator;
824 child_sa_t *child_sa;
825
826 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
827 while (enumerator->enumerate(enumerator, (void**)&child_sa))
828 {
829 child_updown(this, child_sa, FALSE);
830 }
831 enumerator->destroy(enumerator);
832 }
833 }
834
835 METHOD(bus_t, ike_rekey, void,
836 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
837 {
838 enumerator_t *enumerator;
839 entry_t *entry;
840 bool keep;
841
842 this->mutex->lock(this->mutex);
843 enumerator = this->listeners->create_enumerator(this->listeners);
844 while (enumerator->enumerate(enumerator, &entry))
845 {
846 if (entry->calling || !entry->listener->ike_rekey)
847 {
848 continue;
849 }
850 entry->calling++;
851 keep = entry->listener->ike_rekey(entry->listener, old, new);
852 entry->calling--;
853 if (!keep)
854 {
855 unregister_listener(this, entry, enumerator);
856 }
857 }
858 enumerator->destroy(enumerator);
859 this->mutex->unlock(this->mutex);
860 }
861
862 METHOD(bus_t, ike_update, void,
863 private_bus_t *this, ike_sa_t *ike_sa, bool local, host_t *new)
864 {
865 enumerator_t *enumerator;
866 entry_t *entry;
867 bool keep;
868
869 this->mutex->lock(this->mutex);
870 enumerator = this->listeners->create_enumerator(this->listeners);
871 while (enumerator->enumerate(enumerator, &entry))
872 {
873 if (entry->calling || !entry->listener->ike_update)
874 {
875 continue;
876 }
877 entry->calling++;
878 keep = entry->listener->ike_update(entry->listener, ike_sa, local, new);
879 entry->calling--;
880 if (!keep)
881 {
882 unregister_listener(this, entry, enumerator);
883 }
884 }
885 enumerator->destroy(enumerator);
886 this->mutex->unlock(this->mutex);
887 }
888
889 METHOD(bus_t, ike_reestablish_pre, void,
890 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
891 {
892 enumerator_t *enumerator;
893 entry_t *entry;
894 bool keep;
895
896 this->mutex->lock(this->mutex);
897 enumerator = this->listeners->create_enumerator(this->listeners);
898 while (enumerator->enumerate(enumerator, &entry))
899 {
900 if (entry->calling || !entry->listener->ike_reestablish_pre)
901 {
902 continue;
903 }
904 entry->calling++;
905 keep = entry->listener->ike_reestablish_pre(entry->listener, old, new);
906 entry->calling--;
907 if (!keep)
908 {
909 unregister_listener(this, entry, enumerator);
910 }
911 }
912 enumerator->destroy(enumerator);
913 this->mutex->unlock(this->mutex);
914 }
915
916 METHOD(bus_t, ike_reestablish_post, void,
917 private_bus_t *this, ike_sa_t *old, ike_sa_t *new, bool initiated)
918 {
919 enumerator_t *enumerator;
920 entry_t *entry;
921 bool keep;
922
923 this->mutex->lock(this->mutex);
924 enumerator = this->listeners->create_enumerator(this->listeners);
925 while (enumerator->enumerate(enumerator, &entry))
926 {
927 if (entry->calling || !entry->listener->ike_reestablish_post)
928 {
929 continue;
930 }
931 entry->calling++;
932 keep = entry->listener->ike_reestablish_post(entry->listener, old, new,
933 initiated);
934 entry->calling--;
935 if (!keep)
936 {
937 unregister_listener(this, entry, enumerator);
938 }
939 }
940 enumerator->destroy(enumerator);
941 this->mutex->unlock(this->mutex);
942 }
943
944 METHOD(bus_t, authorize, bool,
945 private_bus_t *this, bool final)
946 {
947 enumerator_t *enumerator;
948 ike_sa_t *ike_sa;
949 entry_t *entry;
950 bool keep, success = TRUE;
951
952 ike_sa = this->thread_sa->get(this->thread_sa);
953
954 this->mutex->lock(this->mutex);
955 enumerator = this->listeners->create_enumerator(this->listeners);
956 while (enumerator->enumerate(enumerator, &entry))
957 {
958 if (entry->calling || !entry->listener->authorize)
959 {
960 continue;
961 }
962 entry->calling++;
963 keep = entry->listener->authorize(entry->listener, ike_sa,
964 final, &success);
965 entry->calling--;
966 if (!keep)
967 {
968 unregister_listener(this, entry, enumerator);
969 }
970 if (!success)
971 {
972 break;
973 }
974 }
975 enumerator->destroy(enumerator);
976 this->mutex->unlock(this->mutex);
977 if (!success)
978 {
979 alert(this, ALERT_AUTHORIZATION_FAILED);
980 }
981 return success;
982 }
983
984 METHOD(bus_t, narrow, void,
985 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
986 linked_list_t *local, linked_list_t *remote)
987 {
988 enumerator_t *enumerator;
989 ike_sa_t *ike_sa;
990 entry_t *entry;
991 bool keep;
992
993 ike_sa = this->thread_sa->get(this->thread_sa);
994
995 this->mutex->lock(this->mutex);
996 enumerator = this->listeners->create_enumerator(this->listeners);
997 while (enumerator->enumerate(enumerator, &entry))
998 {
999 if (entry->calling || !entry->listener->narrow)
1000 {
1001 continue;
1002 }
1003 entry->calling++;
1004 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
1005 type, local, remote);
1006 entry->calling--;
1007 if (!keep)
1008 {
1009 unregister_listener(this, entry, enumerator);
1010 }
1011 }
1012 enumerator->destroy(enumerator);
1013 this->mutex->unlock(this->mutex);
1014 }
1015
1016 METHOD(bus_t, assign_vips, void,
1017 private_bus_t *this, ike_sa_t *ike_sa, bool assign)
1018 {
1019 enumerator_t *enumerator;
1020 entry_t *entry;
1021 bool keep;
1022
1023 this->mutex->lock(this->mutex);
1024 enumerator = this->listeners->create_enumerator(this->listeners);
1025 while (enumerator->enumerate(enumerator, &entry))
1026 {
1027 if (entry->calling || !entry->listener->assign_vips)
1028 {
1029 continue;
1030 }
1031 entry->calling++;
1032 keep = entry->listener->assign_vips(entry->listener, ike_sa, assign);
1033 entry->calling--;
1034 if (!keep)
1035 {
1036 unregister_listener(this, entry, enumerator);
1037 }
1038 }
1039 enumerator->destroy(enumerator);
1040 this->mutex->unlock(this->mutex);
1041 }
1042
1043 METHOD(bus_t, handle_vips, void,
1044 private_bus_t *this, ike_sa_t *ike_sa, bool handle)
1045 {
1046 enumerator_t *enumerator;
1047 entry_t *entry;
1048 bool keep;
1049
1050 this->mutex->lock(this->mutex);
1051 enumerator = this->listeners->create_enumerator(this->listeners);
1052 while (enumerator->enumerate(enumerator, &entry))
1053 {
1054 if (entry->calling || !entry->listener->handle_vips)
1055 {
1056 continue;
1057 }
1058 entry->calling++;
1059 keep = entry->listener->handle_vips(entry->listener, ike_sa, handle);
1060 entry->calling--;
1061 if (!keep)
1062 {
1063 unregister_listener(this, entry, enumerator);
1064 }
1065 }
1066 enumerator->destroy(enumerator);
1067 this->mutex->unlock(this->mutex);
1068 }
1069
1070 /**
1071 * Credential manager hook function to forward bus alerts
1072 */
1073 static void hook_creds(private_bus_t *this, credential_hook_type_t type,
1074 certificate_t *cert)
1075 {
1076 switch (type)
1077 {
1078 case CRED_HOOK_EXPIRED:
1079 return alert(this, ALERT_CERT_EXPIRED, cert);
1080 case CRED_HOOK_REVOKED:
1081 return alert(this, ALERT_CERT_REVOKED, cert);
1082 case CRED_HOOK_VALIDATION_FAILED:
1083 return alert(this, ALERT_CERT_VALIDATION_FAILED, cert);
1084 case CRED_HOOK_NO_ISSUER:
1085 return alert(this, ALERT_CERT_NO_ISSUER, cert);
1086 case CRED_HOOK_UNTRUSTED_ROOT:
1087 return alert(this, ALERT_CERT_UNTRUSTED_ROOT, cert);
1088 case CRED_HOOK_EXCEEDED_PATH_LEN:
1089 return alert(this, ALERT_CERT_EXCEEDED_PATH_LEN, cert);
1090 case CRED_HOOK_POLICY_VIOLATION:
1091 return alert(this, ALERT_CERT_POLICY_VIOLATION, cert);
1092 }
1093 }
1094
1095 METHOD(bus_t, destroy, void,
1096 private_bus_t *this)
1097 {
1098 debug_t group;
1099
1100 lib->credmgr->set_hook(lib->credmgr, NULL, NULL);
1101 for (group = 0; group < DBG_MAX; group++)
1102 {
1103 this->loggers[group]->destroy(this->loggers[group]);
1104 }
1105 this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
1106 (void*)free);
1107 this->listeners->destroy_function(this->listeners, (void*)free);
1108 this->thread_sa->destroy(this->thread_sa);
1109 this->log_lock->destroy(this->log_lock);
1110 this->mutex->destroy(this->mutex);
1111 free(this);
1112 }
1113
1114 /*
1115 * Described in header.
1116 */
1117 bus_t *bus_create()
1118 {
1119 private_bus_t *this;
1120 debug_t group;
1121
1122 INIT(this,
1123 .public = {
1124 .add_listener = _add_listener,
1125 .remove_listener = _remove_listener,
1126 .add_logger = _add_logger,
1127 .remove_logger = _remove_logger,
1128 .set_sa = _set_sa,
1129 .get_sa = _get_sa,
1130 .log = _log_,
1131 .vlog = _vlog,
1132 .alert = _alert,
1133 .ike_state_change = _ike_state_change,
1134 .child_state_change = _child_state_change,
1135 .message = _message,
1136 .ike_keys = _ike_keys,
1137 .ike_derived_keys = _ike_derived_keys,
1138 .child_keys = _child_keys,
1139 .child_derived_keys = _child_derived_keys,
1140 .ike_updown = _ike_updown,
1141 .ike_rekey = _ike_rekey,
1142 .ike_update = _ike_update,
1143 .ike_reestablish_pre = _ike_reestablish_pre,
1144 .ike_reestablish_post = _ike_reestablish_post,
1145 .child_updown = _child_updown,
1146 .child_rekey = _child_rekey,
1147 .children_migrate = _children_migrate,
1148 .authorize = _authorize,
1149 .narrow = _narrow,
1150 .assign_vips = _assign_vips,
1151 .handle_vips = _handle_vips,
1152 .destroy = _destroy,
1153 },
1154 .listeners = linked_list_create(),
1155 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
1156 .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1157 .thread_sa = thread_value_create(NULL),
1158 );
1159
1160 for (group = 0; group <= DBG_MAX; group++)
1161 {
1162 this->loggers[group] = linked_list_create();
1163 this->max_level[group] = LEVEL_SILENT;
1164 this->max_vlevel[group] = LEVEL_SILENT;
1165 }
1166
1167 lib->credmgr->set_hook(lib->credmgr, (credential_hook_t)hook_creds, this);
1168
1169 return &this->public;
1170 }