2 * Copyright (C) 2006 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include <utils/mutex.h>
24 ENUM(debug_names
, DBG_DMN
, DBG_LIB
,
37 ENUM(debug_lower_names
, DBG_DMN
, DBG_LIB
,
50 typedef struct private_bus_t private_bus_t
;
53 * Private data of a bus_t object.
55 struct private_bus_t
{
57 * Public part of a bus_t object.
62 * List of registered listeners as entry_t's
64 linked_list_t
*listeners
;
67 * mutex to synchronize active listeners, recursively
72 * Thread local storage for a unique, simple thread ID
74 pthread_key_t thread_id
;
77 * Thread local storage the threads IKE_SA
79 pthread_key_t thread_sa
;
82 typedef struct entry_t entry_t
;
85 * a listener entry, either active or passive
90 * registered listener interface
95 * is this a active listen() call with a blocking thread
100 * are we currently calling this listener
105 * condvar where active listeners wait
111 * create a listener entry
113 static entry_t
*entry_create(listener_t
*listener
, bool blocker
)
115 entry_t
*this = malloc_thing(entry_t
);
117 this->listener
= listener
;
118 this->blocker
= blocker
;
120 this->condvar
= condvar_create(CONDVAR_TYPE_DEFAULT
);
128 static void entry_destroy(entry_t
*entry
)
130 entry
->condvar
->destroy(entry
->condvar
);
135 * Get a unique thread number for a calling thread. Since
136 * pthread_self returns large and ugly numbers, use this function
137 * for logging; these numbers are incremental starting at 1
139 static u_int
get_thread_number(private_bus_t
*this)
141 static uintptr_t current_num
= 0;
142 uintptr_t stored_num
;
144 stored_num
= (uintptr_t)pthread_getspecific(this->thread_id
);
146 { /* first call of current thread */
147 pthread_setspecific(this->thread_id
, (void*)++current_num
);
157 * Implementation of bus_t.add_listener.
159 static void add_listener(private_bus_t
*this, listener_t
*listener
)
161 this->mutex
->lock(this->mutex
);
162 this->listeners
->insert_last(this->listeners
, entry_create(listener
, FALSE
));
163 this->mutex
->unlock(this->mutex
);
167 * Implementation of bus_t.remove_listener.
169 static void remove_listener(private_bus_t
*this, listener_t
*listener
)
171 enumerator_t
*enumerator
;
174 this->mutex
->lock(this->mutex
);
175 enumerator
= this->listeners
->create_enumerator(this->listeners
);
176 while (enumerator
->enumerate(enumerator
, &entry
))
178 if (entry
->listener
== listener
)
180 this->listeners
->remove_at(this->listeners
, enumerator
);
181 entry_destroy(entry
);
185 enumerator
->destroy(enumerator
);
186 this->mutex
->unlock(this->mutex
);
189 typedef struct cleanup_data_t cleanup_data_t
;
192 * data to remove a listener using pthread_cleanup handler
194 struct cleanup_data_t
{
197 /** listener entry */
202 * pthread_cleanup handler to remove a listener
204 static void listener_cleanup(cleanup_data_t
*data
)
206 data
->this->listeners
->remove(data
->this->listeners
, data
->entry
, NULL
);
207 entry_destroy(data
->entry
);
211 * Implementation of bus_t.listen.
213 static void listen_(private_bus_t
*this, listener_t
*listener
, job_t
*job
)
219 data
.entry
= entry_create(listener
, TRUE
);
221 this->mutex
->lock(this->mutex
);
222 this->listeners
->insert_last(this->listeners
, data
.entry
);
223 charon
->processor
->queue_job(charon
->processor
, job
);
224 pthread_cleanup_push((void*)this->mutex
->unlock
, this->mutex
);
225 pthread_cleanup_push((void*)listener_cleanup
, &data
);
226 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &old
);
227 while (data
.entry
->blocker
)
229 data
.entry
->condvar
->wait(data
.entry
->condvar
, this->mutex
);
231 pthread_setcancelstate(old
, NULL
);
232 pthread_cleanup_pop(FALSE
);
234 pthread_cleanup_pop(TRUE
);
235 entry_destroy(data
.entry
);
239 * Implementation of bus_t.set_sa.
241 static void set_sa(private_bus_t
*this, ike_sa_t
*ike_sa
)
243 pthread_setspecific(this->thread_sa
, ike_sa
);
247 * Implementation of bus_t.get_sa
249 static ike_sa_t
* get_sa(private_bus_t
*this)
251 return pthread_getspecific(this->thread_sa
);
255 * data associated to a signal, passed to callback
258 /** associated IKE_SA */
260 /** invoking thread */
273 * listener->log() invocation as a list remove callback
275 static bool log_cb(entry_t
*entry
, log_data_t
*data
)
279 if (entry
->calling
|| !entry
->listener
->log
)
280 { /* avoid recursive calls */
284 va_copy(args
, data
->args
);
285 if (!entry
->listener
->log(entry
->listener
, data
->group
, data
->level
,
286 data
->thread
, data
->ike_sa
, data
->format
, args
))
290 entry
->blocker
= FALSE
;
291 entry
->condvar
->signal(entry
->condvar
);
295 entry_destroy(entry
);
307 * Implementation of bus_t.vlog.
309 static void vlog(private_bus_t
*this, debug_t group
, level_t level
,
310 char* format
, va_list args
)
314 data
.ike_sa
= pthread_getspecific(this->thread_sa
);
315 data
.thread
= get_thread_number(this);
318 data
.format
= format
;
319 va_copy(data
.args
, args
);
321 this->mutex
->lock(this->mutex
);
322 /* We use the remove() method to invoke all listeners. This is cheap and
323 * does not require an allocation for this performance critical function. */
324 this->listeners
->remove(this->listeners
, &data
, (void*)log_cb
);
325 this->mutex
->unlock(this->mutex
);
331 * Implementation of bus_t.log.
333 static void log_(private_bus_t
*this, debug_t group
, level_t level
,
338 va_start(args
, format
);
339 vlog(this, group
, level
, format
, args
);
344 * unregister a listener
346 static void unregister_listener(private_bus_t
*this, entry_t
*entry
,
347 enumerator_t
*enumerator
)
351 entry
->blocker
= FALSE
;
352 entry
->condvar
->signal(entry
->condvar
);
356 entry_destroy(entry
);
358 this->listeners
->remove_at(this->listeners
, enumerator
);
362 * Implementation of bus_t.alert
364 static void alert(private_bus_t
*this, alert_t alert
, ...)
366 enumerator_t
*enumerator
;
372 ike_sa
= pthread_getspecific(this->thread_sa
);
374 this->mutex
->lock(this->mutex
);
375 enumerator
= this->listeners
->create_enumerator(this->listeners
);
376 while (enumerator
->enumerate(enumerator
, &entry
))
378 if (entry
->calling
|| !entry
->listener
->alert
)
383 va_start(args
, alert
);
384 keep
= entry
->listener
->alert(entry
->listener
, ike_sa
, alert
, args
);
389 unregister_listener(this, entry
, enumerator
);
392 enumerator
->destroy(enumerator
);
393 this->mutex
->unlock(this->mutex
);
397 * Implementation of bus_t.ike_state_change
399 static void ike_state_change(private_bus_t
*this, ike_sa_t
*ike_sa
,
400 ike_sa_state_t state
)
402 enumerator_t
*enumerator
;
406 this->mutex
->lock(this->mutex
);
407 enumerator
= this->listeners
->create_enumerator(this->listeners
);
408 while (enumerator
->enumerate(enumerator
, &entry
))
410 if (entry
->calling
|| !entry
->listener
->ike_state_change
)
415 keep
= entry
->listener
->ike_state_change(entry
->listener
, ike_sa
, state
);
419 unregister_listener(this, entry
, enumerator
);
422 enumerator
->destroy(enumerator
);
423 this->mutex
->unlock(this->mutex
);
427 * Implementation of bus_t.child_state_change
429 static void child_state_change(private_bus_t
*this, child_sa_t
*child_sa
,
430 child_sa_state_t state
)
432 enumerator_t
*enumerator
;
437 ike_sa
= pthread_getspecific(this->thread_sa
);
439 this->mutex
->lock(this->mutex
);
440 enumerator
= this->listeners
->create_enumerator(this->listeners
);
441 while (enumerator
->enumerate(enumerator
, &entry
))
443 if (entry
->calling
|| !entry
->listener
->child_state_change
)
448 keep
= entry
->listener
->child_state_change(entry
->listener
, ike_sa
,
453 unregister_listener(this, entry
, enumerator
);
456 enumerator
->destroy(enumerator
);
457 this->mutex
->unlock(this->mutex
);
461 * Implementation of bus_t.message
463 static void message(private_bus_t
*this, message_t
*message
, bool incoming
)
465 enumerator_t
*enumerator
;
470 ike_sa
= pthread_getspecific(this->thread_sa
);
472 this->mutex
->lock(this->mutex
);
473 enumerator
= this->listeners
->create_enumerator(this->listeners
);
474 while (enumerator
->enumerate(enumerator
, &entry
))
476 if (entry
->calling
|| !entry
->listener
->message
)
481 keep
= entry
->listener
->message(entry
->listener
, ike_sa
,
486 unregister_listener(this, entry
, enumerator
);
489 enumerator
->destroy(enumerator
);
490 this->mutex
->unlock(this->mutex
);
494 * Implementation of bus_t.ike_keys
496 static void ike_keys(private_bus_t
*this, ike_sa_t
*ike_sa
,
497 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
,
500 enumerator_t
*enumerator
;
504 this->mutex
->lock(this->mutex
);
505 enumerator
= this->listeners
->create_enumerator(this->listeners
);
506 while (enumerator
->enumerate(enumerator
, &entry
))
508 if (entry
->calling
|| !entry
->listener
->ike_keys
)
513 keep
= entry
->listener
->ike_keys(entry
->listener
, ike_sa
, dh
,
514 nonce_i
, nonce_r
, rekey
);
518 unregister_listener(this, entry
, enumerator
);
521 enumerator
->destroy(enumerator
);
522 this->mutex
->unlock(this->mutex
);
526 * Implementation of bus_t.child_keys
528 static void child_keys(private_bus_t
*this, child_sa_t
*child_sa
,
529 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
)
531 enumerator_t
*enumerator
;
536 ike_sa
= pthread_getspecific(this->thread_sa
);
538 this->mutex
->lock(this->mutex
);
539 enumerator
= this->listeners
->create_enumerator(this->listeners
);
540 while (enumerator
->enumerate(enumerator
, &entry
))
542 if (entry
->calling
|| !entry
->listener
->child_keys
)
547 keep
= entry
->listener
->child_keys(entry
->listener
, ike_sa
, child_sa
,
548 dh
, nonce_i
, nonce_r
);
552 unregister_listener(this, entry
, enumerator
);
555 enumerator
->destroy(enumerator
);
556 this->mutex
->unlock(this->mutex
);
560 * Implementation of bus_t.child_updown
562 static void child_updown(private_bus_t
*this, child_sa_t
*child_sa
, bool up
)
564 enumerator_t
*enumerator
;
569 ike_sa
= pthread_getspecific(this->thread_sa
);
571 this->mutex
->lock(this->mutex
);
572 enumerator
= this->listeners
->create_enumerator(this->listeners
);
573 while (enumerator
->enumerate(enumerator
, &entry
))
575 if (entry
->calling
|| !entry
->listener
->child_updown
)
580 keep
= entry
->listener
->child_updown(entry
->listener
,
581 ike_sa
, child_sa
, up
);
585 unregister_listener(this, entry
, enumerator
);
588 enumerator
->destroy(enumerator
);
589 this->mutex
->unlock(this->mutex
);
593 * Implementation of bus_t.child_rekey
595 static void child_rekey(private_bus_t
*this, child_sa_t
*old
, child_sa_t
*new)
597 enumerator_t
*enumerator
;
602 ike_sa
= pthread_getspecific(this->thread_sa
);
604 this->mutex
->lock(this->mutex
);
605 enumerator
= this->listeners
->create_enumerator(this->listeners
);
606 while (enumerator
->enumerate(enumerator
, &entry
))
608 if (entry
->calling
|| !entry
->listener
->child_rekey
)
613 keep
= entry
->listener
->child_rekey(entry
->listener
, ike_sa
, old
, new);
617 unregister_listener(this, entry
, enumerator
);
620 enumerator
->destroy(enumerator
);
621 this->mutex
->unlock(this->mutex
);
625 * Implementation of bus_t.ike_updown
627 static void ike_updown(private_bus_t
*this, ike_sa_t
*ike_sa
, bool up
)
629 enumerator_t
*enumerator
;
633 this->mutex
->lock(this->mutex
);
634 enumerator
= this->listeners
->create_enumerator(this->listeners
);
635 while (enumerator
->enumerate(enumerator
, &entry
))
637 if (entry
->calling
|| !entry
->listener
->ike_updown
)
642 keep
= entry
->listener
->ike_updown(entry
->listener
, ike_sa
, up
);
646 unregister_listener(this, entry
, enumerator
);
649 enumerator
->destroy(enumerator
);
650 this->mutex
->unlock(this->mutex
);
652 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
655 iterator_t
*iterator
;
656 child_sa_t
*child_sa
;
658 iterator
= ike_sa
->create_child_sa_iterator(ike_sa
);
659 while (iterator
->iterate(iterator
, (void**)&child_sa
))
661 child_updown(this, child_sa
, FALSE
);
663 iterator
->destroy(iterator
);
668 * Implementation of bus_t.ike_rekey
670 static void ike_rekey(private_bus_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
672 enumerator_t
*enumerator
;
676 this->mutex
->lock(this->mutex
);
677 enumerator
= this->listeners
->create_enumerator(this->listeners
);
678 while (enumerator
->enumerate(enumerator
, &entry
))
680 if (entry
->calling
|| !entry
->listener
->ike_rekey
)
685 keep
= entry
->listener
->ike_rekey(entry
->listener
, old
, new);
689 unregister_listener(this, entry
, enumerator
);
692 enumerator
->destroy(enumerator
);
693 this->mutex
->unlock(this->mutex
);
697 * Implementation of bus_t.authorize
699 static bool authorize(private_bus_t
*this, bool final
)
701 enumerator_t
*enumerator
;
704 bool keep
, success
= TRUE
;
706 ike_sa
= pthread_getspecific(this->thread_sa
);
708 this->mutex
->lock(this->mutex
);
709 enumerator
= this->listeners
->create_enumerator(this->listeners
);
710 while (enumerator
->enumerate(enumerator
, &entry
))
712 if (entry
->calling
|| !entry
->listener
->authorize
)
717 keep
= entry
->listener
->authorize(entry
->listener
, ike_sa
,
722 unregister_listener(this, entry
, enumerator
);
729 enumerator
->destroy(enumerator
);
730 this->mutex
->unlock(this->mutex
);
735 * Implementation of bus_t.destroy.
737 static void destroy(private_bus_t
*this)
739 this->mutex
->destroy(this->mutex
);
740 this->listeners
->destroy_function(this->listeners
, (void*)entry_destroy
);
745 * Described in header.
749 private_bus_t
*this = malloc_thing(private_bus_t
);
751 this->public.add_listener
= (void(*)(bus_t
*,listener_t
*))add_listener
;
752 this->public.remove_listener
= (void(*)(bus_t
*,listener_t
*))remove_listener
;
753 this->public.listen
= (void(*)(bus_t
*, listener_t
*listener
, job_t
*job
))listen_
;
754 this->public.set_sa
= (void(*)(bus_t
*,ike_sa_t
*))set_sa
;
755 this->public.get_sa
= (ike_sa_t
*(*)(bus_t
*))get_sa
;
756 this->public.log
= (void(*)(bus_t
*,debug_t
,level_t
,char*,...))log_
;
757 this->public.vlog
= (void(*)(bus_t
*,debug_t
,level_t
,char*,va_list))vlog
;
758 this->public.alert
= (void(*)(bus_t
*, alert_t alert
, ...))alert
;
759 this->public.ike_state_change
= (void(*)(bus_t
*,ike_sa_t
*,ike_sa_state_t
))ike_state_change
;
760 this->public.child_state_change
= (void(*)(bus_t
*,child_sa_t
*,child_sa_state_t
))child_state_change
;
761 this->public.message
= (void(*)(bus_t
*, message_t
*message
, bool incoming
))message
;
762 this->public.ike_keys
= (void(*)(bus_t
*, ike_sa_t
*ike_sa
, diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
, ike_sa_t
*rekey
))ike_keys
;
763 this->public.child_keys
= (void(*)(bus_t
*, child_sa_t
*child_sa
, diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
))child_keys
;
764 this->public.ike_updown
= (void(*)(bus_t
*, ike_sa_t
*ike_sa
, bool up
))ike_updown
;
765 this->public.ike_rekey
= (void(*)(bus_t
*, ike_sa_t
*old
, ike_sa_t
*new))ike_rekey
;
766 this->public.child_updown
= (void(*)(bus_t
*, child_sa_t
*child_sa
, bool up
))child_updown
;
767 this->public.child_rekey
= (void(*)(bus_t
*, child_sa_t
*old
, child_sa_t
*new))child_rekey
;
768 this->public.authorize
= (bool(*)(bus_t
*, bool final
))authorize
;
769 this->public.destroy
= (void(*)(bus_t
*)) destroy
;
771 this->listeners
= linked_list_create();
772 this->mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
);
773 pthread_key_create(&this->thread_id
, NULL
);
774 pthread_key_create(&this->thread_sa
, NULL
);
776 return &this->public;