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
20 #include <threading/thread.h>
21 #include <threading/thread_value.h>
22 #include <threading/condvar.h>
23 #include <threading/mutex.h>
25 typedef struct private_bus_t private_bus_t
;
28 * Private data of a bus_t object.
30 struct private_bus_t
{
32 * Public part of a bus_t object.
37 * List of registered listeners as entry_t's
39 linked_list_t
*listeners
;
42 * mutex to synchronize active listeners, recursively
47 * Thread local storage the threads IKE_SA
49 thread_value_t
*thread_sa
;
52 typedef struct entry_t entry_t
;
55 * a listener entry, either active or passive
60 * registered listener interface
65 * is this a active listen() call with a blocking thread
70 * are we currently calling this listener
75 * condvar where active listeners wait
81 * create a listener entry
83 static entry_t
*entry_create(listener_t
*listener
, bool blocker
)
85 entry_t
*this = malloc_thing(entry_t
);
87 this->listener
= listener
;
88 this->blocker
= blocker
;
90 this->condvar
= condvar_create(CONDVAR_TYPE_DEFAULT
);
98 static void entry_destroy(entry_t
*entry
)
100 entry
->condvar
->destroy(entry
->condvar
);
104 METHOD(bus_t
, add_listener
, void,
105 private_bus_t
*this, listener_t
*listener
)
107 this->mutex
->lock(this->mutex
);
108 this->listeners
->insert_last(this->listeners
, entry_create(listener
, FALSE
));
109 this->mutex
->unlock(this->mutex
);
112 METHOD(bus_t
, remove_listener
, void,
113 private_bus_t
*this, listener_t
*listener
)
115 enumerator_t
*enumerator
;
118 this->mutex
->lock(this->mutex
);
119 enumerator
= this->listeners
->create_enumerator(this->listeners
);
120 while (enumerator
->enumerate(enumerator
, &entry
))
122 if (entry
->listener
== listener
)
124 this->listeners
->remove_at(this->listeners
, enumerator
);
125 entry_destroy(entry
);
129 enumerator
->destroy(enumerator
);
130 this->mutex
->unlock(this->mutex
);
133 typedef struct cleanup_data_t cleanup_data_t
;
136 * data to remove a listener using thread_cleanup_t handler
138 struct cleanup_data_t
{
141 /** listener entry */
146 * thread_cleanup_t handler to remove a listener
148 static void listener_cleanup(cleanup_data_t
*data
)
150 data
->this->listeners
->remove(data
->this->listeners
, data
->entry
, NULL
);
151 entry_destroy(data
->entry
);
154 METHOD(bus_t
, listen_
, bool,
155 private_bus_t
*this, listener_t
*listener
, job_t
*job
, u_int timeout
)
157 bool old
, timed_out
= FALSE
;
163 add
.tv_sec
= timeout
/ 1000;
164 add
.tv_usec
= (timeout
- (add
.tv_sec
* 1000)) * 1000;
166 timeradd(&tv
, &add
, &tv
);
170 data
.entry
= entry_create(listener
, TRUE
);
172 this->mutex
->lock(this->mutex
);
173 this->listeners
->insert_last(this->listeners
, data
.entry
);
174 lib
->processor
->queue_job(lib
->processor
, job
);
175 thread_cleanup_push((thread_cleanup_t
)this->mutex
->unlock
, this->mutex
);
176 thread_cleanup_push((thread_cleanup_t
)listener_cleanup
, &data
);
177 old
= thread_cancelability(TRUE
);
178 while (data
.entry
->blocker
)
182 if (data
.entry
->condvar
->timed_wait_abs(data
.entry
->condvar
,
185 this->listeners
->remove(this->listeners
, data
.entry
, NULL
);
192 data
.entry
->condvar
->wait(data
.entry
->condvar
, this->mutex
);
195 thread_cancelability(old
);
196 thread_cleanup_pop(FALSE
);
198 thread_cleanup_pop(TRUE
);
199 entry_destroy(data
.entry
);
203 METHOD(bus_t
, set_sa
, void,
204 private_bus_t
*this, ike_sa_t
*ike_sa
)
206 this->thread_sa
->set(this->thread_sa
, ike_sa
);
209 METHOD(bus_t
, get_sa
, ike_sa_t
*,
212 return this->thread_sa
->get(this->thread_sa
);
216 * data associated to a signal, passed to callback
219 /** associated IKE_SA */
221 /** invoking thread */
234 * listener->log() invocation as a list remove callback
236 static bool log_cb(entry_t
*entry
, log_data_t
*data
)
240 if (entry
->calling
|| !entry
->listener
->log
)
241 { /* avoid recursive calls */
245 va_copy(args
, data
->args
);
246 if (!entry
->listener
->log(entry
->listener
, data
->group
, data
->level
,
247 data
->thread
, data
->ike_sa
, data
->format
, args
))
251 entry
->blocker
= FALSE
;
252 entry
->condvar
->signal(entry
->condvar
);
257 entry_destroy(entry
);
267 METHOD(bus_t
, vlog
, void,
268 private_bus_t
*this, debug_t group
, level_t level
,
269 char* format
, va_list args
)
273 data
.ike_sa
= this->thread_sa
->get(this->thread_sa
);
274 data
.thread
= thread_current_id();
277 data
.format
= format
;
278 va_copy(data
.args
, args
);
280 this->mutex
->lock(this->mutex
);
281 /* We use the remove() method to invoke all listeners. This is cheap and
282 * does not require an allocation for this performance critical function. */
283 this->listeners
->remove(this->listeners
, &data
, (void*)log_cb
);
284 this->mutex
->unlock(this->mutex
);
289 METHOD(bus_t
, log_
, void,
290 private_bus_t
*this, debug_t group
, level_t level
, char* format
, ...)
294 va_start(args
, format
);
295 vlog(this, group
, level
, format
, args
);
300 * unregister a listener
302 static void unregister_listener(private_bus_t
*this, entry_t
*entry
,
303 enumerator_t
*enumerator
)
307 entry
->blocker
= FALSE
;
308 entry
->condvar
->signal(entry
->condvar
);
312 entry_destroy(entry
);
314 this->listeners
->remove_at(this->listeners
, enumerator
);
317 METHOD(bus_t
, alert
, void,
318 private_bus_t
*this, alert_t alert
, ...)
320 enumerator_t
*enumerator
;
326 ike_sa
= this->thread_sa
->get(this->thread_sa
);
328 this->mutex
->lock(this->mutex
);
329 enumerator
= this->listeners
->create_enumerator(this->listeners
);
330 while (enumerator
->enumerate(enumerator
, &entry
))
332 if (entry
->calling
|| !entry
->listener
->alert
)
337 va_start(args
, alert
);
338 keep
= entry
->listener
->alert(entry
->listener
, ike_sa
, alert
, args
);
343 unregister_listener(this, entry
, enumerator
);
346 enumerator
->destroy(enumerator
);
347 this->mutex
->unlock(this->mutex
);
350 METHOD(bus_t
, ike_state_change
, void,
351 private_bus_t
*this, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
353 enumerator_t
*enumerator
;
357 this->mutex
->lock(this->mutex
);
358 enumerator
= this->listeners
->create_enumerator(this->listeners
);
359 while (enumerator
->enumerate(enumerator
, &entry
))
361 if (entry
->calling
|| !entry
->listener
->ike_state_change
)
366 keep
= entry
->listener
->ike_state_change(entry
->listener
, ike_sa
, state
);
370 unregister_listener(this, entry
, enumerator
);
373 enumerator
->destroy(enumerator
);
374 this->mutex
->unlock(this->mutex
);
377 METHOD(bus_t
, child_state_change
, void,
378 private_bus_t
*this, child_sa_t
*child_sa
, child_sa_state_t state
)
380 enumerator_t
*enumerator
;
385 ike_sa
= this->thread_sa
->get(this->thread_sa
);
387 this->mutex
->lock(this->mutex
);
388 enumerator
= this->listeners
->create_enumerator(this->listeners
);
389 while (enumerator
->enumerate(enumerator
, &entry
))
391 if (entry
->calling
|| !entry
->listener
->child_state_change
)
396 keep
= entry
->listener
->child_state_change(entry
->listener
, ike_sa
,
401 unregister_listener(this, entry
, enumerator
);
404 enumerator
->destroy(enumerator
);
405 this->mutex
->unlock(this->mutex
);
408 METHOD(bus_t
, message
, void,
409 private_bus_t
*this, message_t
*message
, bool incoming
)
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
->message
)
427 keep
= entry
->listener
->message(entry
->listener
, ike_sa
,
432 unregister_listener(this, entry
, enumerator
);
435 enumerator
->destroy(enumerator
);
436 this->mutex
->unlock(this->mutex
);
439 METHOD(bus_t
, ike_keys
, void,
440 private_bus_t
*this, ike_sa_t
*ike_sa
, diffie_hellman_t
*dh
,
441 chunk_t nonce_i
, chunk_t nonce_r
, ike_sa_t
*rekey
)
443 enumerator_t
*enumerator
;
447 this->mutex
->lock(this->mutex
);
448 enumerator
= this->listeners
->create_enumerator(this->listeners
);
449 while (enumerator
->enumerate(enumerator
, &entry
))
451 if (entry
->calling
|| !entry
->listener
->ike_keys
)
456 keep
= entry
->listener
->ike_keys(entry
->listener
, ike_sa
, dh
,
457 nonce_i
, nonce_r
, rekey
);
461 unregister_listener(this, entry
, enumerator
);
464 enumerator
->destroy(enumerator
);
465 this->mutex
->unlock(this->mutex
);
468 METHOD(bus_t
, child_keys
, void,
469 private_bus_t
*this, child_sa_t
*child_sa
, bool initiator
,
470 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
)
472 enumerator_t
*enumerator
;
477 ike_sa
= this->thread_sa
->get(this->thread_sa
);
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
->child_keys
)
488 keep
= entry
->listener
->child_keys(entry
->listener
, ike_sa
, child_sa
,
489 initiator
, dh
, nonce_i
, nonce_r
);
493 unregister_listener(this, entry
, enumerator
);
496 enumerator
->destroy(enumerator
);
497 this->mutex
->unlock(this->mutex
);
500 METHOD(bus_t
, child_updown
, void,
501 private_bus_t
*this, child_sa_t
*child_sa
, bool up
)
503 enumerator_t
*enumerator
;
508 ike_sa
= this->thread_sa
->get(this->thread_sa
);
510 this->mutex
->lock(this->mutex
);
511 enumerator
= this->listeners
->create_enumerator(this->listeners
);
512 while (enumerator
->enumerate(enumerator
, &entry
))
514 if (entry
->calling
|| !entry
->listener
->child_updown
)
519 keep
= entry
->listener
->child_updown(entry
->listener
,
520 ike_sa
, child_sa
, up
);
524 unregister_listener(this, entry
, enumerator
);
527 enumerator
->destroy(enumerator
);
528 this->mutex
->unlock(this->mutex
);
531 METHOD(bus_t
, child_rekey
, void,
532 private_bus_t
*this, child_sa_t
*old
, child_sa_t
*new)
534 enumerator_t
*enumerator
;
539 ike_sa
= this->thread_sa
->get(this->thread_sa
);
541 this->mutex
->lock(this->mutex
);
542 enumerator
= this->listeners
->create_enumerator(this->listeners
);
543 while (enumerator
->enumerate(enumerator
, &entry
))
545 if (entry
->calling
|| !entry
->listener
->child_rekey
)
550 keep
= entry
->listener
->child_rekey(entry
->listener
, ike_sa
, old
, new);
554 unregister_listener(this, entry
, enumerator
);
557 enumerator
->destroy(enumerator
);
558 this->mutex
->unlock(this->mutex
);
561 METHOD(bus_t
, ike_updown
, void,
562 private_bus_t
*this, ike_sa_t
*ike_sa
, bool up
)
564 enumerator_t
*enumerator
;
568 this->mutex
->lock(this->mutex
);
569 enumerator
= this->listeners
->create_enumerator(this->listeners
);
570 while (enumerator
->enumerate(enumerator
, &entry
))
572 if (entry
->calling
|| !entry
->listener
->ike_updown
)
577 keep
= entry
->listener
->ike_updown(entry
->listener
, ike_sa
, up
);
581 unregister_listener(this, entry
, enumerator
);
584 enumerator
->destroy(enumerator
);
585 this->mutex
->unlock(this->mutex
);
587 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
590 enumerator_t
*enumerator
;
591 child_sa_t
*child_sa
;
593 enumerator
= ike_sa
->create_child_sa_enumerator(ike_sa
);
594 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
596 child_updown(this, child_sa
, FALSE
);
598 enumerator
->destroy(enumerator
);
602 METHOD(bus_t
, ike_rekey
, void,
603 private_bus_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
605 enumerator_t
*enumerator
;
609 this->mutex
->lock(this->mutex
);
610 enumerator
= this->listeners
->create_enumerator(this->listeners
);
611 while (enumerator
->enumerate(enumerator
, &entry
))
613 if (entry
->calling
|| !entry
->listener
->ike_rekey
)
618 keep
= entry
->listener
->ike_rekey(entry
->listener
, old
, new);
622 unregister_listener(this, entry
, enumerator
);
625 enumerator
->destroy(enumerator
);
626 this->mutex
->unlock(this->mutex
);
629 METHOD(bus_t
, authorize
, bool,
630 private_bus_t
*this, bool final
)
632 enumerator_t
*enumerator
;
635 bool keep
, success
= TRUE
;
637 ike_sa
= this->thread_sa
->get(this->thread_sa
);
639 this->mutex
->lock(this->mutex
);
640 enumerator
= this->listeners
->create_enumerator(this->listeners
);
641 while (enumerator
->enumerate(enumerator
, &entry
))
643 if (entry
->calling
|| !entry
->listener
->authorize
)
648 keep
= entry
->listener
->authorize(entry
->listener
, ike_sa
,
653 unregister_listener(this, entry
, enumerator
);
660 enumerator
->destroy(enumerator
);
661 this->mutex
->unlock(this->mutex
);
665 METHOD(bus_t
, narrow
, void,
666 private_bus_t
*this, child_sa_t
*child_sa
, narrow_hook_t type
,
667 linked_list_t
*local
, linked_list_t
*remote
)
669 enumerator_t
*enumerator
;
674 ike_sa
= this->thread_sa
->get(this->thread_sa
);
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
->narrow
)
685 keep
= entry
->listener
->narrow(entry
->listener
, ike_sa
, child_sa
,
686 type
, local
, remote
);
690 unregister_listener(this, entry
, enumerator
);
693 enumerator
->destroy(enumerator
);
694 this->mutex
->unlock(this->mutex
);
697 METHOD(bus_t
, destroy
, void,
700 this->thread_sa
->destroy(this->thread_sa
);
701 this->mutex
->destroy(this->mutex
);
702 this->listeners
->destroy_function(this->listeners
, (void*)entry_destroy
);
707 * Described in header.
715 .add_listener
= _add_listener
,
716 .remove_listener
= _remove_listener
,
723 .ike_state_change
= _ike_state_change
,
724 .child_state_change
= _child_state_change
,
726 .ike_keys
= _ike_keys
,
727 .child_keys
= _child_keys
,
728 .ike_updown
= _ike_updown
,
729 .ike_rekey
= _ike_rekey
,
730 .child_updown
= _child_updown
,
731 .child_rekey
= _child_rekey
,
732 .authorize
= _authorize
,
736 .listeners
= linked_list_create(),
737 .mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
),
738 .thread_sa
= thread_value_create(NULL
),
741 return &this->public;