2 * Copyright (C) 2011-2012 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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>.
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
21 #include <threading/thread.h>
22 #include <threading/thread_value.h>
23 #include <threading/mutex.h>
24 #include <threading/rwlock.h>
26 typedef struct private_bus_t private_bus_t
;
29 * Private data of a bus_t object.
31 struct private_bus_t
{
33 * Public part of a bus_t object.
38 * List of registered listeners as entry_t.
40 linked_list_t
*listeners
;
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.
47 linked_list_t
*loggers
[DBG_MAX
+ 1];
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.
53 level_t max_level
[DBG_MAX
+ 1];
56 * Mutex for the list of listeners, recursively.
61 * Read-write lock for the list of loggers.
66 * Thread local storage the threads IKE_SA
68 thread_value_t
*thread_sa
;
71 typedef struct entry_t entry_t
;
79 * registered listener interface
84 * are we currently calling this listener
90 typedef struct log_entry_t log_entry_t
;
98 * registered logger interface
103 * registered log levels per group
105 level_t levels
[DBG_MAX
];
109 METHOD(bus_t
, add_listener
, void,
110 private_bus_t
*this, listener_t
*listener
)
115 .listener
= listener
,
118 this->mutex
->lock(this->mutex
);
119 this->listeners
->insert_last(this->listeners
, entry
);
120 this->mutex
->unlock(this->mutex
);
123 METHOD(bus_t
, remove_listener
, void,
124 private_bus_t
*this, listener_t
*listener
)
126 enumerator_t
*enumerator
;
129 this->mutex
->lock(this->mutex
);
130 enumerator
= this->listeners
->create_enumerator(this->listeners
);
131 while (enumerator
->enumerate(enumerator
, &entry
))
133 if (entry
->listener
== listener
)
135 this->listeners
->remove_at(this->listeners
, enumerator
);
140 enumerator
->destroy(enumerator
);
141 this->mutex
->unlock(this->mutex
);
145 * Register a logger on the given log group according to the requested level
147 static inline void register_logger(private_bus_t
*this, debug_t group
,
150 enumerator_t
*enumerator
;
151 linked_list_t
*loggers
;
152 log_entry_t
*current
;
155 loggers
= this->loggers
[group
];
156 level
= entry
->levels
[group
];
158 enumerator
= loggers
->create_enumerator(loggers
);
159 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
161 if (current
->levels
[group
] <= level
)
166 loggers
->insert_before(loggers
, enumerator
, entry
);
167 enumerator
->destroy(enumerator
);
169 this->max_level
[group
] = max(this->max_level
[group
], level
);
173 * Unregister a logger from all log groups (destroys the log_entry_t)
175 static inline void unregister_logger(private_bus_t
*this, logger_t
*logger
)
177 enumerator_t
*enumerator
;
178 linked_list_t
*loggers
;
179 log_entry_t
*entry
, *found
= NULL
;
181 loggers
= this->loggers
[DBG_MAX
];
182 enumerator
= loggers
->create_enumerator(loggers
);
183 while (enumerator
->enumerate(enumerator
, &entry
))
185 if (entry
->logger
== logger
)
187 loggers
->remove_at(loggers
, enumerator
);
192 enumerator
->destroy(enumerator
);
197 for (group
= 0; group
< DBG_MAX
; group
++)
199 if (found
->levels
[group
] > LEVEL_SILENT
)
201 loggers
= this->loggers
[group
];
202 loggers
->remove(loggers
, found
, NULL
);
204 this->max_level
[group
] = LEVEL_SILENT
;
205 if (loggers
->get_first(loggers
, (void**)&entry
) == SUCCESS
)
207 this->max_level
[group
] = entry
->levels
[group
];
215 METHOD(bus_t
, add_logger
, void,
216 private_bus_t
*this, logger_t
*logger
)
225 this->log_lock
->write_lock(this->log_lock
);
226 unregister_logger(this, logger
);
227 for (group
= 0; group
< DBG_MAX
; group
++)
229 entry
->levels
[group
] = logger
->get_level(logger
, group
);
230 if (entry
->levels
[group
] > LEVEL_SILENT
)
232 register_logger(this, group
, entry
);
235 this->loggers
[DBG_MAX
]->insert_last(this->loggers
[DBG_MAX
], entry
);
236 this->log_lock
->unlock(this->log_lock
);
239 METHOD(bus_t
, remove_logger
, void,
240 private_bus_t
*this, logger_t
*logger
)
242 this->log_lock
->write_lock(this->log_lock
);
243 unregister_logger(this, logger
);
244 this->log_lock
->unlock(this->log_lock
);
247 METHOD(bus_t
, set_sa
, void,
248 private_bus_t
*this, ike_sa_t
*ike_sa
)
250 this->thread_sa
->set(this->thread_sa
, ike_sa
);
253 METHOD(bus_t
, get_sa
, ike_sa_t
*,
256 return this->thread_sa
->get(this->thread_sa
);
260 * data associated to a signal, passed to callback
263 /** associated IKE_SA */
265 /** invoking thread */
276 * logger->log() invocation as a invoke_function callback
278 static void log_cb(log_entry_t
*entry
, log_data_t
*data
)
280 if (entry
->levels
[data
->group
] < data
->level
)
284 entry
->logger
->log(entry
->logger
, data
->group
, data
->level
,
285 data
->thread
, data
->ike_sa
, data
->message
);
288 METHOD(bus_t
, vlog
, void,
289 private_bus_t
*this, debug_t group
, level_t level
,
290 char* format
, va_list args
)
292 this->log_lock
->read_lock(this->log_lock
);
293 if (this->max_level
[group
] >= level
)
295 linked_list_t
*loggers
= this->loggers
[group
];
301 data
.ike_sa
= this->thread_sa
->get(this->thread_sa
);
302 data
.thread
= thread_current_id();
308 len
= vsnprintf(data
.message
, sizeof(buf
), format
, copy
);
310 if (len
>= sizeof(buf
))
312 data
.message
= malloc(len
);
313 len
= vsnprintf(data
.message
, len
, format
, args
);
317 loggers
->invoke_function(loggers
, (linked_list_invoke_t
)log_cb
,
320 if (data
.message
!= buf
)
325 this->log_lock
->unlock(this->log_lock
);
328 METHOD(bus_t
, log_
, void,
329 private_bus_t
*this, debug_t group
, level_t level
, char* format
, ...)
333 va_start(args
, format
);
334 vlog(this, group
, level
, format
, args
);
339 * unregister a listener
341 static inline void unregister_listener(private_bus_t
*this, entry_t
*entry
,
342 enumerator_t
*enumerator
)
344 this->listeners
->remove_at(this->listeners
, enumerator
);
348 METHOD(bus_t
, alert
, void,
349 private_bus_t
*this, alert_t alert
, ...)
351 enumerator_t
*enumerator
;
357 ike_sa
= this->thread_sa
->get(this->thread_sa
);
359 this->mutex
->lock(this->mutex
);
360 enumerator
= this->listeners
->create_enumerator(this->listeners
);
361 while (enumerator
->enumerate(enumerator
, &entry
))
363 if (entry
->calling
|| !entry
->listener
->alert
)
368 va_start(args
, alert
);
369 keep
= entry
->listener
->alert(entry
->listener
, ike_sa
, alert
, args
);
374 unregister_listener(this, entry
, enumerator
);
377 enumerator
->destroy(enumerator
);
378 this->mutex
->unlock(this->mutex
);
381 METHOD(bus_t
, ike_state_change
, void,
382 private_bus_t
*this, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
384 enumerator_t
*enumerator
;
388 this->mutex
->lock(this->mutex
);
389 enumerator
= this->listeners
->create_enumerator(this->listeners
);
390 while (enumerator
->enumerate(enumerator
, &entry
))
392 if (entry
->calling
|| !entry
->listener
->ike_state_change
)
397 keep
= entry
->listener
->ike_state_change(entry
->listener
, ike_sa
, state
);
401 unregister_listener(this, entry
, enumerator
);
404 enumerator
->destroy(enumerator
);
405 this->mutex
->unlock(this->mutex
);
408 METHOD(bus_t
, child_state_change
, void,
409 private_bus_t
*this, child_sa_t
*child_sa
, child_sa_state_t state
)
411 enumerator_t
*enumerator
;
416 ike_sa
= this->thread_sa
->get(this->thread_sa
);
418 this->mutex
->lock(this->mutex
);
419 enumerator
= this->listeners
->create_enumerator(this->listeners
);
420 while (enumerator
->enumerate(enumerator
, &entry
))
422 if (entry
->calling
|| !entry
->listener
->child_state_change
)
427 keep
= entry
->listener
->child_state_change(entry
->listener
, ike_sa
,
432 unregister_listener(this, entry
, enumerator
);
435 enumerator
->destroy(enumerator
);
436 this->mutex
->unlock(this->mutex
);
439 METHOD(bus_t
, message
, void,
440 private_bus_t
*this, message_t
*message
, bool incoming
, bool plain
)
442 enumerator_t
*enumerator
;
447 ike_sa
= this->thread_sa
->get(this->thread_sa
);
449 this->mutex
->lock(this->mutex
);
450 enumerator
= this->listeners
->create_enumerator(this->listeners
);
451 while (enumerator
->enumerate(enumerator
, &entry
))
453 if (entry
->calling
|| !entry
->listener
->message
)
458 keep
= entry
->listener
->message(entry
->listener
, ike_sa
,
459 message
, incoming
, plain
);
463 unregister_listener(this, entry
, enumerator
);
466 enumerator
->destroy(enumerator
);
467 this->mutex
->unlock(this->mutex
);
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
)
475 enumerator_t
*enumerator
;
479 this->mutex
->lock(this->mutex
);
480 enumerator
= this->listeners
->create_enumerator(this->listeners
);
481 while (enumerator
->enumerate(enumerator
, &entry
))
483 if (entry
->calling
|| !entry
->listener
->ike_keys
)
488 keep
= entry
->listener
->ike_keys(entry
->listener
, ike_sa
, dh
, dh_other
,
489 nonce_i
, nonce_r
, rekey
, shared
);
493 unregister_listener(this, entry
, enumerator
);
496 enumerator
->destroy(enumerator
);
497 this->mutex
->unlock(this->mutex
);
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
)
504 enumerator_t
*enumerator
;
509 ike_sa
= this->thread_sa
->get(this->thread_sa
);
511 this->mutex
->lock(this->mutex
);
512 enumerator
= this->listeners
->create_enumerator(this->listeners
);
513 while (enumerator
->enumerate(enumerator
, &entry
))
515 if (entry
->calling
|| !entry
->listener
->child_keys
)
520 keep
= entry
->listener
->child_keys(entry
->listener
, ike_sa
,
521 child_sa
, initiator
, dh
, nonce_i
, nonce_r
);
525 unregister_listener(this, entry
, enumerator
);
528 enumerator
->destroy(enumerator
);
529 this->mutex
->unlock(this->mutex
);
532 METHOD(bus_t
, child_updown
, void,
533 private_bus_t
*this, child_sa_t
*child_sa
, bool up
)
535 enumerator_t
*enumerator
;
540 ike_sa
= this->thread_sa
->get(this->thread_sa
);
542 this->mutex
->lock(this->mutex
);
543 enumerator
= this->listeners
->create_enumerator(this->listeners
);
544 while (enumerator
->enumerate(enumerator
, &entry
))
546 if (entry
->calling
|| !entry
->listener
->child_updown
)
551 keep
= entry
->listener
->child_updown(entry
->listener
,
552 ike_sa
, child_sa
, up
);
556 unregister_listener(this, entry
, enumerator
);
559 enumerator
->destroy(enumerator
);
560 this->mutex
->unlock(this->mutex
);
563 METHOD(bus_t
, child_rekey
, void,
564 private_bus_t
*this, child_sa_t
*old
, child_sa_t
*new)
566 enumerator_t
*enumerator
;
571 ike_sa
= this->thread_sa
->get(this->thread_sa
);
573 this->mutex
->lock(this->mutex
);
574 enumerator
= this->listeners
->create_enumerator(this->listeners
);
575 while (enumerator
->enumerate(enumerator
, &entry
))
577 if (entry
->calling
|| !entry
->listener
->child_rekey
)
582 keep
= entry
->listener
->child_rekey(entry
->listener
, ike_sa
,
587 unregister_listener(this, entry
, enumerator
);
590 enumerator
->destroy(enumerator
);
591 this->mutex
->unlock(this->mutex
);
594 METHOD(bus_t
, ike_updown
, void,
595 private_bus_t
*this, ike_sa_t
*ike_sa
, bool up
)
597 enumerator_t
*enumerator
;
601 this->mutex
->lock(this->mutex
);
602 enumerator
= this->listeners
->create_enumerator(this->listeners
);
603 while (enumerator
->enumerate(enumerator
, &entry
))
605 if (entry
->calling
|| !entry
->listener
->ike_updown
)
610 keep
= entry
->listener
->ike_updown(entry
->listener
, ike_sa
, up
);
614 unregister_listener(this, entry
, enumerator
);
617 enumerator
->destroy(enumerator
);
618 this->mutex
->unlock(this->mutex
);
620 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
623 enumerator_t
*enumerator
;
624 child_sa_t
*child_sa
;
626 enumerator
= ike_sa
->create_child_sa_enumerator(ike_sa
);
627 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
629 child_updown(this, child_sa
, FALSE
);
631 enumerator
->destroy(enumerator
);
635 METHOD(bus_t
, ike_rekey
, void,
636 private_bus_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
638 enumerator_t
*enumerator
;
642 this->mutex
->lock(this->mutex
);
643 enumerator
= this->listeners
->create_enumerator(this->listeners
);
644 while (enumerator
->enumerate(enumerator
, &entry
))
646 if (entry
->calling
|| !entry
->listener
->ike_rekey
)
651 keep
= entry
->listener
->ike_rekey(entry
->listener
, old
, new);
655 unregister_listener(this, entry
, enumerator
);
658 enumerator
->destroy(enumerator
);
659 this->mutex
->unlock(this->mutex
);
662 METHOD(bus_t
, ike_reestablish
, void,
663 private_bus_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
665 enumerator_t
*enumerator
;
669 this->mutex
->lock(this->mutex
);
670 enumerator
= this->listeners
->create_enumerator(this->listeners
);
671 while (enumerator
->enumerate(enumerator
, &entry
))
673 if (entry
->calling
|| !entry
->listener
->ike_reestablish
)
678 keep
= entry
->listener
->ike_reestablish(entry
->listener
, old
, new);
682 unregister_listener(this, entry
, enumerator
);
685 enumerator
->destroy(enumerator
);
686 this->mutex
->unlock(this->mutex
);
689 METHOD(bus_t
, authorize
, bool,
690 private_bus_t
*this, bool final
)
692 enumerator_t
*enumerator
;
695 bool keep
, success
= TRUE
;
697 ike_sa
= this->thread_sa
->get(this->thread_sa
);
699 this->mutex
->lock(this->mutex
);
700 enumerator
= this->listeners
->create_enumerator(this->listeners
);
701 while (enumerator
->enumerate(enumerator
, &entry
))
703 if (entry
->calling
|| !entry
->listener
->authorize
)
708 keep
= entry
->listener
->authorize(entry
->listener
, ike_sa
,
713 unregister_listener(this, entry
, enumerator
);
720 enumerator
->destroy(enumerator
);
721 this->mutex
->unlock(this->mutex
);
725 METHOD(bus_t
, narrow
, void,
726 private_bus_t
*this, child_sa_t
*child_sa
, narrow_hook_t type
,
727 linked_list_t
*local
, linked_list_t
*remote
)
729 enumerator_t
*enumerator
;
734 ike_sa
= this->thread_sa
->get(this->thread_sa
);
736 this->mutex
->lock(this->mutex
);
737 enumerator
= this->listeners
->create_enumerator(this->listeners
);
738 while (enumerator
->enumerate(enumerator
, &entry
))
740 if (entry
->calling
|| !entry
->listener
->narrow
)
745 keep
= entry
->listener
->narrow(entry
->listener
, ike_sa
, child_sa
,
746 type
, local
, remote
);
750 unregister_listener(this, entry
, enumerator
);
753 enumerator
->destroy(enumerator
);
754 this->mutex
->unlock(this->mutex
);
757 METHOD(bus_t
, destroy
, void,
761 for (group
= 0; group
< DBG_MAX
; group
++)
763 this->loggers
[group
]->destroy(this->loggers
[group
]);
765 this->loggers
[DBG_MAX
]->destroy_function(this->loggers
[DBG_MAX
],
767 this->listeners
->destroy_function(this->listeners
, (void*)free
);
768 this->thread_sa
->destroy(this->thread_sa
);
769 this->log_lock
->destroy(this->log_lock
);
770 this->mutex
->destroy(this->mutex
);
775 * Described in header.
784 .add_listener
= _add_listener
,
785 .remove_listener
= _remove_listener
,
786 .add_logger
= _add_logger
,
787 .remove_logger
= _remove_logger
,
793 .ike_state_change
= _ike_state_change
,
794 .child_state_change
= _child_state_change
,
796 .ike_keys
= _ike_keys
,
797 .child_keys
= _child_keys
,
798 .ike_updown
= _ike_updown
,
799 .ike_rekey
= _ike_rekey
,
800 .ike_reestablish
= _ike_reestablish
,
801 .child_updown
= _child_updown
,
802 .child_rekey
= _child_rekey
,
803 .authorize
= _authorize
,
807 .listeners
= linked_list_create(),
808 .mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
),
809 .log_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
810 .thread_sa
= thread_value_create(NULL
),
813 for (group
= 0; group
<= DBG_MAX
; group
++)
815 this->loggers
[group
] = linked_list_create();
816 this->max_level
[group
] = LEVEL_SILENT
;
819 return &this->public;