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_
, void,
155 private_bus_t
*this, listener_t
*listener
, job_t
*job
)
161 data
.entry
= entry_create(listener
, TRUE
);
163 this->mutex
->lock(this->mutex
);
164 this->listeners
->insert_last(this->listeners
, data
.entry
);
165 lib
->processor
->queue_job(lib
->processor
, job
);
166 thread_cleanup_push((thread_cleanup_t
)this->mutex
->unlock
, this->mutex
);
167 thread_cleanup_push((thread_cleanup_t
)listener_cleanup
, &data
);
168 old
= thread_cancelability(TRUE
);
169 while (data
.entry
->blocker
)
171 data
.entry
->condvar
->wait(data
.entry
->condvar
, this->mutex
);
173 thread_cancelability(old
);
174 thread_cleanup_pop(FALSE
);
176 thread_cleanup_pop(TRUE
);
177 entry_destroy(data
.entry
);
180 METHOD(bus_t
, set_sa
, void,
181 private_bus_t
*this, ike_sa_t
*ike_sa
)
183 this->thread_sa
->set(this->thread_sa
, ike_sa
);
186 METHOD(bus_t
, get_sa
, ike_sa_t
*,
189 return this->thread_sa
->get(this->thread_sa
);
193 * data associated to a signal, passed to callback
196 /** associated IKE_SA */
198 /** invoking thread */
211 * listener->log() invocation as a list remove callback
213 static bool log_cb(entry_t
*entry
, log_data_t
*data
)
217 if (entry
->calling
|| !entry
->listener
->log
)
218 { /* avoid recursive calls */
222 va_copy(args
, data
->args
);
223 if (!entry
->listener
->log(entry
->listener
, data
->group
, data
->level
,
224 data
->thread
, data
->ike_sa
, data
->format
, args
))
228 entry
->blocker
= FALSE
;
229 entry
->condvar
->signal(entry
->condvar
);
234 entry_destroy(entry
);
244 METHOD(bus_t
, vlog
, void,
245 private_bus_t
*this, debug_t group
, level_t level
,
246 char* format
, va_list args
)
250 data
.ike_sa
= this->thread_sa
->get(this->thread_sa
);
251 data
.thread
= thread_current_id();
254 data
.format
= format
;
255 va_copy(data
.args
, args
);
257 this->mutex
->lock(this->mutex
);
258 /* We use the remove() method to invoke all listeners. This is cheap and
259 * does not require an allocation for this performance critical function. */
260 this->listeners
->remove(this->listeners
, &data
, (void*)log_cb
);
261 this->mutex
->unlock(this->mutex
);
266 METHOD(bus_t
, log_
, void,
267 private_bus_t
*this, debug_t group
, level_t level
, char* format
, ...)
271 va_start(args
, format
);
272 vlog(this, group
, level
, format
, args
);
277 * unregister a listener
279 static void unregister_listener(private_bus_t
*this, entry_t
*entry
,
280 enumerator_t
*enumerator
)
284 entry
->blocker
= FALSE
;
285 entry
->condvar
->signal(entry
->condvar
);
289 entry_destroy(entry
);
291 this->listeners
->remove_at(this->listeners
, enumerator
);
294 METHOD(bus_t
, alert
, void,
295 private_bus_t
*this, alert_t alert
, ...)
297 enumerator_t
*enumerator
;
303 ike_sa
= this->thread_sa
->get(this->thread_sa
);
305 this->mutex
->lock(this->mutex
);
306 enumerator
= this->listeners
->create_enumerator(this->listeners
);
307 while (enumerator
->enumerate(enumerator
, &entry
))
309 if (entry
->calling
|| !entry
->listener
->alert
)
314 va_start(args
, alert
);
315 keep
= entry
->listener
->alert(entry
->listener
, ike_sa
, alert
, args
);
320 unregister_listener(this, entry
, enumerator
);
323 enumerator
->destroy(enumerator
);
324 this->mutex
->unlock(this->mutex
);
327 METHOD(bus_t
, ike_state_change
, void,
328 private_bus_t
*this, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
330 enumerator_t
*enumerator
;
334 this->mutex
->lock(this->mutex
);
335 enumerator
= this->listeners
->create_enumerator(this->listeners
);
336 while (enumerator
->enumerate(enumerator
, &entry
))
338 if (entry
->calling
|| !entry
->listener
->ike_state_change
)
343 keep
= entry
->listener
->ike_state_change(entry
->listener
, ike_sa
, state
);
347 unregister_listener(this, entry
, enumerator
);
350 enumerator
->destroy(enumerator
);
351 this->mutex
->unlock(this->mutex
);
354 METHOD(bus_t
, child_state_change
, void,
355 private_bus_t
*this, child_sa_t
*child_sa
, child_sa_state_t state
)
357 enumerator_t
*enumerator
;
362 ike_sa
= this->thread_sa
->get(this->thread_sa
);
364 this->mutex
->lock(this->mutex
);
365 enumerator
= this->listeners
->create_enumerator(this->listeners
);
366 while (enumerator
->enumerate(enumerator
, &entry
))
368 if (entry
->calling
|| !entry
->listener
->child_state_change
)
373 keep
= entry
->listener
->child_state_change(entry
->listener
, ike_sa
,
378 unregister_listener(this, entry
, enumerator
);
381 enumerator
->destroy(enumerator
);
382 this->mutex
->unlock(this->mutex
);
385 METHOD(bus_t
, message
, void,
386 private_bus_t
*this, message_t
*message
, bool incoming
)
388 enumerator_t
*enumerator
;
393 ike_sa
= this->thread_sa
->get(this->thread_sa
);
395 this->mutex
->lock(this->mutex
);
396 enumerator
= this->listeners
->create_enumerator(this->listeners
);
397 while (enumerator
->enumerate(enumerator
, &entry
))
399 if (entry
->calling
|| !entry
->listener
->message
)
404 keep
= entry
->listener
->message(entry
->listener
, ike_sa
,
409 unregister_listener(this, entry
, enumerator
);
412 enumerator
->destroy(enumerator
);
413 this->mutex
->unlock(this->mutex
);
416 METHOD(bus_t
, ike_keys
, void,
417 private_bus_t
*this, ike_sa_t
*ike_sa
, diffie_hellman_t
*dh
,
418 chunk_t nonce_i
, chunk_t nonce_r
, ike_sa_t
*rekey
)
420 enumerator_t
*enumerator
;
424 this->mutex
->lock(this->mutex
);
425 enumerator
= this->listeners
->create_enumerator(this->listeners
);
426 while (enumerator
->enumerate(enumerator
, &entry
))
428 if (entry
->calling
|| !entry
->listener
->ike_keys
)
433 keep
= entry
->listener
->ike_keys(entry
->listener
, ike_sa
, dh
,
434 nonce_i
, nonce_r
, rekey
);
438 unregister_listener(this, entry
, enumerator
);
441 enumerator
->destroy(enumerator
);
442 this->mutex
->unlock(this->mutex
);
445 METHOD(bus_t
, child_keys
, void,
446 private_bus_t
*this, child_sa_t
*child_sa
, bool initiator
,
447 diffie_hellman_t
*dh
, chunk_t nonce_i
, chunk_t nonce_r
)
449 enumerator_t
*enumerator
;
454 ike_sa
= this->thread_sa
->get(this->thread_sa
);
456 this->mutex
->lock(this->mutex
);
457 enumerator
= this->listeners
->create_enumerator(this->listeners
);
458 while (enumerator
->enumerate(enumerator
, &entry
))
460 if (entry
->calling
|| !entry
->listener
->child_keys
)
465 keep
= entry
->listener
->child_keys(entry
->listener
, ike_sa
, child_sa
,
466 initiator
, dh
, nonce_i
, nonce_r
);
470 unregister_listener(this, entry
, enumerator
);
473 enumerator
->destroy(enumerator
);
474 this->mutex
->unlock(this->mutex
);
477 METHOD(bus_t
, child_updown
, void,
478 private_bus_t
*this, child_sa_t
*child_sa
, bool up
)
480 enumerator_t
*enumerator
;
485 ike_sa
= this->thread_sa
->get(this->thread_sa
);
487 this->mutex
->lock(this->mutex
);
488 enumerator
= this->listeners
->create_enumerator(this->listeners
);
489 while (enumerator
->enumerate(enumerator
, &entry
))
491 if (entry
->calling
|| !entry
->listener
->child_updown
)
496 keep
= entry
->listener
->child_updown(entry
->listener
,
497 ike_sa
, child_sa
, up
);
501 unregister_listener(this, entry
, enumerator
);
504 enumerator
->destroy(enumerator
);
505 this->mutex
->unlock(this->mutex
);
508 METHOD(bus_t
, child_rekey
, void,
509 private_bus_t
*this, child_sa_t
*old
, child_sa_t
*new)
511 enumerator_t
*enumerator
;
516 ike_sa
= this->thread_sa
->get(this->thread_sa
);
518 this->mutex
->lock(this->mutex
);
519 enumerator
= this->listeners
->create_enumerator(this->listeners
);
520 while (enumerator
->enumerate(enumerator
, &entry
))
522 if (entry
->calling
|| !entry
->listener
->child_rekey
)
527 keep
= entry
->listener
->child_rekey(entry
->listener
, ike_sa
, old
, new);
531 unregister_listener(this, entry
, enumerator
);
534 enumerator
->destroy(enumerator
);
535 this->mutex
->unlock(this->mutex
);
538 METHOD(bus_t
, ike_updown
, void,
539 private_bus_t
*this, ike_sa_t
*ike_sa
, bool up
)
541 enumerator_t
*enumerator
;
545 this->mutex
->lock(this->mutex
);
546 enumerator
= this->listeners
->create_enumerator(this->listeners
);
547 while (enumerator
->enumerate(enumerator
, &entry
))
549 if (entry
->calling
|| !entry
->listener
->ike_updown
)
554 keep
= entry
->listener
->ike_updown(entry
->listener
, ike_sa
, up
);
558 unregister_listener(this, entry
, enumerator
);
561 enumerator
->destroy(enumerator
);
562 this->mutex
->unlock(this->mutex
);
564 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
567 enumerator_t
*enumerator
;
568 child_sa_t
*child_sa
;
570 enumerator
= ike_sa
->create_child_sa_enumerator(ike_sa
);
571 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
573 child_updown(this, child_sa
, FALSE
);
575 enumerator
->destroy(enumerator
);
579 METHOD(bus_t
, ike_rekey
, void,
580 private_bus_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
582 enumerator_t
*enumerator
;
586 this->mutex
->lock(this->mutex
);
587 enumerator
= this->listeners
->create_enumerator(this->listeners
);
588 while (enumerator
->enumerate(enumerator
, &entry
))
590 if (entry
->calling
|| !entry
->listener
->ike_rekey
)
595 keep
= entry
->listener
->ike_rekey(entry
->listener
, old
, new);
599 unregister_listener(this, entry
, enumerator
);
602 enumerator
->destroy(enumerator
);
603 this->mutex
->unlock(this->mutex
);
606 METHOD(bus_t
, authorize
, bool,
607 private_bus_t
*this, bool final
)
609 enumerator_t
*enumerator
;
612 bool keep
, success
= TRUE
;
614 ike_sa
= this->thread_sa
->get(this->thread_sa
);
616 this->mutex
->lock(this->mutex
);
617 enumerator
= this->listeners
->create_enumerator(this->listeners
);
618 while (enumerator
->enumerate(enumerator
, &entry
))
620 if (entry
->calling
|| !entry
->listener
->authorize
)
625 keep
= entry
->listener
->authorize(entry
->listener
, ike_sa
,
630 unregister_listener(this, entry
, enumerator
);
637 enumerator
->destroy(enumerator
);
638 this->mutex
->unlock(this->mutex
);
642 METHOD(bus_t
, narrow
, void,
643 private_bus_t
*this, child_sa_t
*child_sa
, narrow_hook_t type
,
644 linked_list_t
*local
, linked_list_t
*remote
)
646 enumerator_t
*enumerator
;
651 ike_sa
= this->thread_sa
->get(this->thread_sa
);
653 this->mutex
->lock(this->mutex
);
654 enumerator
= this->listeners
->create_enumerator(this->listeners
);
655 while (enumerator
->enumerate(enumerator
, &entry
))
657 if (entry
->calling
|| !entry
->listener
->narrow
)
662 keep
= entry
->listener
->narrow(entry
->listener
, ike_sa
, child_sa
,
663 type
, local
, remote
);
667 unregister_listener(this, entry
, enumerator
);
670 enumerator
->destroy(enumerator
);
671 this->mutex
->unlock(this->mutex
);
674 METHOD(bus_t
, destroy
, void,
677 this->thread_sa
->destroy(this->thread_sa
);
678 this->mutex
->destroy(this->mutex
);
679 this->listeners
->destroy_function(this->listeners
, (void*)entry_destroy
);
684 * Described in header.
692 .add_listener
= _add_listener
,
693 .remove_listener
= _remove_listener
,
700 .ike_state_change
= _ike_state_change
,
701 .child_state_change
= _child_state_change
,
703 .ike_keys
= _ike_keys
,
704 .child_keys
= _child_keys
,
705 .ike_updown
= _ike_updown
,
706 .ike_rekey
= _ike_rekey
,
707 .child_updown
= _child_updown
,
708 .child_rekey
= _child_rekey
,
709 .authorize
= _authorize
,
713 .listeners
= linked_list_create(),
714 .mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
),
715 .thread_sa
= thread_value_create(NULL
),
718 return &this->public;