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
24 #include <utils/mutex.h>
26 ENUM(debug_names
, DBG_DMN
, DBG_LIB
,
39 ENUM(debug_lower_names
, DBG_DMN
, DBG_LIB
,
52 typedef struct private_bus_t private_bus_t
;
55 * Private data of a bus_t object.
57 struct private_bus_t
{
59 * Public part of a bus_t object.
64 * List of registered listeners as entry_t's
66 linked_list_t
*listeners
;
69 * mutex to synchronize active listeners, recursively
74 * Thread local storage for a unique, simple thread ID
76 pthread_key_t thread_id
;
79 * Thread local storage the threads IKE_SA
81 pthread_key_t thread_sa
;
84 typedef struct entry_t entry_t
;
87 * a listener entry, either active or passive
92 * registered listener interface
97 * is this a active listen() call with a blocking thread
102 * are we currently calling this listener
107 * condvar where active listeners wait
113 * create a listener entry
115 static entry_t
*entry_create(listener_t
*listener
, bool blocker
)
117 entry_t
*this = malloc_thing(entry_t
);
119 this->listener
= listener
;
120 this->blocker
= blocker
;
122 this->condvar
= condvar_create(CONDVAR_DEFAULT
);
130 static void entry_destroy(entry_t
*entry
)
132 entry
->condvar
->destroy(entry
->condvar
);
137 * Get a unique thread number for a calling thread. Since
138 * pthread_self returns large and ugly numbers, use this function
139 * for logging; these numbers are incremental starting at 1
141 static u_int
get_thread_number(private_bus_t
*this)
143 static uintptr_t current_num
= 0;
144 uintptr_t stored_num
;
146 stored_num
= (uintptr_t)pthread_getspecific(this->thread_id
);
148 { /* first call of current thread */
149 pthread_setspecific(this->thread_id
, (void*)++current_num
);
159 * Implementation of bus_t.add_listener.
161 static void add_listener(private_bus_t
*this, listener_t
*listener
)
163 this->mutex
->lock(this->mutex
);
164 this->listeners
->insert_last(this->listeners
, entry_create(listener
, FALSE
));
165 this->mutex
->unlock(this->mutex
);
169 * Implementation of bus_t.remove_listener.
171 static void remove_listener(private_bus_t
*this, listener_t
*listener
)
173 enumerator_t
*enumerator
;
176 this->mutex
->lock(this->mutex
);
177 enumerator
= this->listeners
->create_enumerator(this->listeners
);
178 while (enumerator
->enumerate(enumerator
, &entry
))
180 if (entry
->listener
== listener
)
182 this->listeners
->remove_at(this->listeners
, enumerator
);
183 entry_destroy(entry
);
187 enumerator
->destroy(enumerator
);
188 this->mutex
->unlock(this->mutex
);
191 typedef struct cleanup_data_t cleanup_data_t
;
194 * data to remove a listener using pthread_cleanup handler
196 struct cleanup_data_t
{
199 /** listener entry */
204 * pthread_cleanup handler to remove a listener
206 static void listener_cleanup(cleanup_data_t
*data
)
208 data
->this->listeners
->remove(data
->this->listeners
, data
->entry
, NULL
);
209 entry_destroy(data
->entry
);
213 * Implementation of bus_t.listen.
215 static void listen_(private_bus_t
*this, listener_t
*listener
, job_t
*job
)
221 data
.entry
= entry_create(listener
, TRUE
);
223 this->mutex
->lock(this->mutex
);
224 this->listeners
->insert_last(this->listeners
, data
.entry
);
225 charon
->processor
->queue_job(charon
->processor
, job
);
226 pthread_cleanup_push((void*)this->mutex
->unlock
, this->mutex
);
227 pthread_cleanup_push((void*)listener_cleanup
, &data
);
228 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &old
);
229 while (data
.entry
->blocker
)
231 data
.entry
->condvar
->wait(data
.entry
->condvar
, this->mutex
);
233 pthread_setcancelstate(old
, NULL
);
234 pthread_cleanup_pop(FALSE
);
236 pthread_cleanup_pop(TRUE
);
237 entry_destroy(data
.entry
);
241 * Implementation of bus_t.set_sa.
243 static void set_sa(private_bus_t
*this, ike_sa_t
*ike_sa
)
245 pthread_setspecific(this->thread_sa
, ike_sa
);
249 * data associated to a signal, passed to callback
252 /** associated IKE_SA */
254 /** invoking thread */
267 * listener->log() invocation as a list remove callback
269 static bool log_cb(entry_t
*entry
, log_data_t
*data
)
273 if (entry
->calling
|| !entry
->listener
->log
)
274 { /* avoid recursive calls */
278 va_copy(args
, data
->args
);
279 if (!entry
->listener
->log(entry
->listener
, data
->group
, data
->level
,
280 data
->thread
, data
->ike_sa
, data
->format
, args
))
284 entry
->blocker
= FALSE
;
285 entry
->condvar
->signal(entry
->condvar
);
289 entry_destroy(entry
);
301 * Implementation of bus_t.vlog.
303 static void vlog(private_bus_t
*this, debug_t group
, level_t level
,
304 char* format
, va_list args
)
308 data
.ike_sa
= pthread_getspecific(this->thread_sa
);
309 data
.thread
= get_thread_number(this);
312 data
.format
= format
;
313 va_copy(data
.args
, args
);
315 this->mutex
->lock(this->mutex
);
316 /* We use the remove() method to invoke all listeners. This is cheap and
317 * does not require an allocation for this performance critical function. */
318 this->listeners
->remove(this->listeners
, &data
, (void*)log_cb
);
319 this->mutex
->unlock(this->mutex
);
325 * Implementation of bus_t.log.
327 static void log_(private_bus_t
*this, debug_t group
, level_t level
,
332 va_start(args
, format
);
333 vlog(this, group
, level
, format
, args
);
338 * unregister a listener
340 static void unregister_listener(private_bus_t
*this, entry_t
*entry
,
341 enumerator_t
*enumerator
)
345 entry
->blocker
= FALSE
;
346 entry
->condvar
->signal(entry
->condvar
);
350 entry_destroy(entry
);
352 this->listeners
->remove_at(this->listeners
, enumerator
);
356 * Implementation of bus_t.ike_state_change
358 static void ike_state_change(private_bus_t
*this, ike_sa_t
*ike_sa
,
359 ike_sa_state_t state
)
361 enumerator_t
*enumerator
;
365 this->mutex
->lock(this->mutex
);
366 enumerator
= this->listeners
->create_enumerator(this->listeners
);
367 while (enumerator
->enumerate(enumerator
, &entry
))
369 if (entry
->calling
|| !entry
->listener
->ike_state_change
)
374 keep
= entry
->listener
->ike_state_change(entry
->listener
, ike_sa
, state
);
378 unregister_listener(this, entry
, enumerator
);
382 enumerator
->destroy(enumerator
);
383 this->mutex
->unlock(this->mutex
);
387 * Implementation of bus_t.child_state_change
389 static void child_state_change(private_bus_t
*this, child_sa_t
*child_sa
,
390 child_sa_state_t state
)
392 enumerator_t
*enumerator
;
397 ike_sa
= pthread_getspecific(this->thread_sa
);
399 this->mutex
->lock(this->mutex
);
400 enumerator
= this->listeners
->create_enumerator(this->listeners
);
401 while (enumerator
->enumerate(enumerator
, &entry
))
403 if (entry
->calling
|| !entry
->listener
->child_state_change
)
408 keep
= entry
->listener
->child_state_change(entry
->listener
, ike_sa
,
413 unregister_listener(this, entry
, enumerator
);
417 enumerator
->destroy(enumerator
);
418 this->mutex
->unlock(this->mutex
);
422 * Implementation of bus_t.message
424 static void message(private_bus_t
*this, message_t
*message
, bool incoming
)
426 enumerator_t
*enumerator
;
431 ike_sa
= pthread_getspecific(this->thread_sa
);
433 this->mutex
->lock(this->mutex
);
434 enumerator
= this->listeners
->create_enumerator(this->listeners
);
435 while (enumerator
->enumerate(enumerator
, &entry
))
437 if (entry
->calling
|| !entry
->listener
->message
)
442 keep
= entry
->listener
->message(entry
->listener
, ike_sa
,
447 unregister_listener(this, entry
, enumerator
);
451 enumerator
->destroy(enumerator
);
452 this->mutex
->unlock(this->mutex
);
456 * Implementation of bus_t.ike_keys
458 static void ike_keys(private_bus_t
*this, ike_sa_t
*ike_sa
,
459 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
,
462 enumerator_t
*enumerator
;
466 this->mutex
->lock(this->mutex
);
467 enumerator
= this->listeners
->create_enumerator(this->listeners
);
468 while (enumerator
->enumerate(enumerator
, &entry
))
470 if (entry
->calling
|| !entry
->listener
->ike_keys
)
475 keep
= entry
->listener
->ike_keys(entry
->listener
, ike_sa
, dh
,
476 nonce_i
, nonce_r
, rekey
);
480 unregister_listener(this, entry
, enumerator
);
484 enumerator
->destroy(enumerator
);
485 this->mutex
->unlock(this->mutex
);
489 * Implementation of bus_t.child_keys
491 static void child_keys(private_bus_t
*this, child_sa_t
*child_sa
,
492 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
)
494 enumerator_t
*enumerator
;
499 ike_sa
= pthread_getspecific(this->thread_sa
);
501 this->mutex
->lock(this->mutex
);
502 enumerator
= this->listeners
->create_enumerator(this->listeners
);
503 while (enumerator
->enumerate(enumerator
, &entry
))
505 if (entry
->calling
|| !entry
->listener
->child_keys
)
510 keep
= entry
->listener
->child_keys(entry
->listener
, ike_sa
, child_sa
,
511 dh
, nonce_i
, nonce_r
);
515 unregister_listener(this, entry
, enumerator
);
519 enumerator
->destroy(enumerator
);
520 this->mutex
->unlock(this->mutex
);
524 * Implementation of bus_t.destroy.
526 static void destroy(private_bus_t
*this)
528 this->mutex
->destroy(this->mutex
);
529 this->listeners
->destroy_function(this->listeners
, (void*)entry_destroy
);
534 * Described in header.
538 private_bus_t
*this = malloc_thing(private_bus_t
);
540 this->public.add_listener
= (void(*)(bus_t
*,listener_t
*))add_listener
;
541 this->public.remove_listener
= (void(*)(bus_t
*,listener_t
*))remove_listener
;
542 this->public.listen
= (void(*)(bus_t
*, listener_t
*listener
, job_t
*job
))listen_
;
543 this->public.set_sa
= (void(*)(bus_t
*,ike_sa_t
*))set_sa
;
544 this->public.log
= (void(*)(bus_t
*,debug_t
,level_t
,char*,...))log_
;
545 this->public.vlog
= (void(*)(bus_t
*,debug_t
,level_t
,char*,va_list))vlog
;
546 this->public.ike_state_change
= (void(*)(bus_t
*,ike_sa_t
*,ike_sa_state_t
))ike_state_change
;
547 this->public.child_state_change
= (void(*)(bus_t
*,child_sa_t
*,child_sa_state_t
))child_state_change
;
548 this->public.message
= (void(*)(bus_t
*, message_t
*message
, bool incoming
))message
;
549 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
;
550 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
;
551 this->public.destroy
= (void(*)(bus_t
*)) destroy
;
553 this->listeners
= linked_list_create();
554 this->mutex
= mutex_create(MUTEX_RECURSIVE
);
555 pthread_key_create(&this->thread_id
, NULL
);
556 pthread_key_create(&this->thread_sa
, NULL
);
558 return &this->public;