Move debug groups from charon's bus.h to libstrongswan's debug.h.
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2006 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "bus.h"
17
18 #include <stdint.h>
19
20 #include <daemon.h>
21 #include <threading/thread.h>
22 #include <threading/thread_value.h>
23 #include <threading/condvar.h>
24 #include <threading/mutex.h>
25
26 typedef struct private_bus_t private_bus_t;
27
28 /**
29 * Private data of a bus_t object.
30 */
31 struct private_bus_t {
32 /**
33 * Public part of a bus_t object.
34 */
35 bus_t public;
36
37 /**
38 * List of registered listeners as entry_t's
39 */
40 linked_list_t *listeners;
41
42 /**
43 * mutex to synchronize active listeners, recursively
44 */
45 mutex_t *mutex;
46
47 /**
48 * Thread local storage the threads IKE_SA
49 */
50 thread_value_t *thread_sa;
51 };
52
53 typedef struct entry_t entry_t;
54
55 /**
56 * a listener entry, either active or passive
57 */
58 struct entry_t {
59
60 /**
61 * registered listener interface
62 */
63 listener_t *listener;
64
65 /**
66 * is this a active listen() call with a blocking thread
67 */
68 bool blocker;
69
70 /**
71 * are we currently calling this listener
72 */
73 int calling;
74
75 /**
76 * condvar where active listeners wait
77 */
78 condvar_t *condvar;
79 };
80
81 /**
82 * create a listener entry
83 */
84 static entry_t *entry_create(listener_t *listener, bool blocker)
85 {
86 entry_t *this = malloc_thing(entry_t);
87
88 this->listener = listener;
89 this->blocker = blocker;
90 this->calling = 0;
91 this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
92
93 return this;
94 }
95
96 /**
97 * destroy an entry_t
98 */
99 static void entry_destroy(entry_t *entry)
100 {
101 entry->condvar->destroy(entry->condvar);
102 free(entry);
103 }
104
105 /**
106 * Implementation of bus_t.add_listener.
107 */
108 static void add_listener(private_bus_t *this, listener_t *listener)
109 {
110 this->mutex->lock(this->mutex);
111 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
112 this->mutex->unlock(this->mutex);
113 }
114
115 /**
116 * Implementation of bus_t.remove_listener.
117 */
118 static void remove_listener(private_bus_t *this, listener_t *listener)
119 {
120 enumerator_t *enumerator;
121 entry_t *entry;
122
123 this->mutex->lock(this->mutex);
124 enumerator = this->listeners->create_enumerator(this->listeners);
125 while (enumerator->enumerate(enumerator, &entry))
126 {
127 if (entry->listener == listener)
128 {
129 this->listeners->remove_at(this->listeners, enumerator);
130 entry_destroy(entry);
131 break;
132 }
133 }
134 enumerator->destroy(enumerator);
135 this->mutex->unlock(this->mutex);
136 }
137
138 typedef struct cleanup_data_t cleanup_data_t;
139
140 /**
141 * data to remove a listener using thread_cleanup_t handler
142 */
143 struct cleanup_data_t {
144 /** bus instance */
145 private_bus_t *this;
146 /** listener entry */
147 entry_t *entry;
148 };
149
150 /**
151 * thread_cleanup_t handler to remove a listener
152 */
153 static void listener_cleanup(cleanup_data_t *data)
154 {
155 data->this->listeners->remove(data->this->listeners, data->entry, NULL);
156 entry_destroy(data->entry);
157 }
158
159 /**
160 * Implementation of bus_t.listen.
161 */
162 static void listen_(private_bus_t *this, listener_t *listener, job_t *job)
163 {
164 bool old;
165 cleanup_data_t data;
166
167 data.this = this;
168 data.entry = entry_create(listener, TRUE);
169
170 this->mutex->lock(this->mutex);
171 this->listeners->insert_last(this->listeners, data.entry);
172 charon->processor->queue_job(charon->processor, job);
173 thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
174 thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data);
175 old = thread_cancelability(TRUE);
176 while (data.entry->blocker)
177 {
178 data.entry->condvar->wait(data.entry->condvar, this->mutex);
179 }
180 thread_cancelability(old);
181 thread_cleanup_pop(FALSE);
182 /* unlock mutex */
183 thread_cleanup_pop(TRUE);
184 entry_destroy(data.entry);
185 }
186
187 /**
188 * Implementation of bus_t.set_sa.
189 */
190 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
191 {
192 this->thread_sa->set(this->thread_sa, ike_sa);
193 }
194
195 /**
196 * Implementation of bus_t.get_sa
197 */
198 static ike_sa_t* get_sa(private_bus_t *this)
199 {
200 return this->thread_sa->get(this->thread_sa);
201 }
202
203 /**
204 * data associated to a signal, passed to callback
205 */
206 typedef struct {
207 /** associated IKE_SA */
208 ike_sa_t *ike_sa;
209 /** invoking thread */
210 long thread;
211 /** debug group */
212 debug_t group;
213 /** debug level */
214 level_t level;
215 /** format string */
216 char *format;
217 /** argument list */
218 va_list args;
219 } log_data_t;
220
221 /**
222 * listener->log() invocation as a list remove callback
223 */
224 static bool log_cb(entry_t *entry, log_data_t *data)
225 {
226 va_list args;
227
228 if (entry->calling || !entry->listener->log)
229 { /* avoid recursive calls */
230 return FALSE;
231 }
232 entry->calling++;
233 va_copy(args, data->args);
234 if (!entry->listener->log(entry->listener, data->group, data->level,
235 data->thread, data->ike_sa, data->format, args))
236 {
237 if (entry->blocker)
238 {
239 entry->blocker = FALSE;
240 entry->condvar->signal(entry->condvar);
241 }
242 else
243 {
244 entry_destroy(entry);
245 }
246 va_end(args);
247 entry->calling--;
248 return TRUE;
249 }
250 va_end(args);
251 entry->calling--;
252 return FALSE;
253 }
254
255 /**
256 * Implementation of bus_t.vlog.
257 */
258 static void vlog(private_bus_t *this, debug_t group, level_t level,
259 char* format, va_list args)
260 {
261 log_data_t data;
262
263 data.ike_sa = this->thread_sa->get(this->thread_sa);
264 data.thread = thread_current_id();
265 data.group = group;
266 data.level = level;
267 data.format = format;
268 va_copy(data.args, args);
269
270 this->mutex->lock(this->mutex);
271 /* We use the remove() method to invoke all listeners. This is cheap and
272 * does not require an allocation for this performance critical function. */
273 this->listeners->remove(this->listeners, &data, (void*)log_cb);
274 this->mutex->unlock(this->mutex);
275
276 va_end(data.args);
277 }
278
279 /**
280 * Implementation of bus_t.log.
281 */
282 static void log_(private_bus_t *this, debug_t group, level_t level,
283 char* format, ...)
284 {
285 va_list args;
286
287 va_start(args, format);
288 vlog(this, group, level, format, args);
289 va_end(args);
290 }
291
292 /**
293 * unregister a listener
294 */
295 static void unregister_listener(private_bus_t *this, entry_t *entry,
296 enumerator_t *enumerator)
297 {
298 if (entry->blocker)
299 {
300 entry->blocker = FALSE;
301 entry->condvar->signal(entry->condvar);
302 }
303 else
304 {
305 entry_destroy(entry);
306 }
307 this->listeners->remove_at(this->listeners, enumerator);
308 }
309
310 /**
311 * Implementation of bus_t.alert
312 */
313 static void alert(private_bus_t *this, alert_t alert, ...)
314 {
315 enumerator_t *enumerator;
316 ike_sa_t *ike_sa;
317 entry_t *entry;
318 va_list args;
319 bool keep;
320
321 ike_sa = this->thread_sa->get(this->thread_sa);
322
323 this->mutex->lock(this->mutex);
324 enumerator = this->listeners->create_enumerator(this->listeners);
325 while (enumerator->enumerate(enumerator, &entry))
326 {
327 if (entry->calling || !entry->listener->alert)
328 {
329 continue;
330 }
331 entry->calling++;
332 va_start(args, alert);
333 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
334 va_end(args);
335 entry->calling--;
336 if (!keep)
337 {
338 unregister_listener(this, entry, enumerator);
339 }
340 }
341 enumerator->destroy(enumerator);
342 this->mutex->unlock(this->mutex);
343 }
344
345 /**
346 * Implementation of bus_t.ike_state_change
347 */
348 static void ike_state_change(private_bus_t *this, ike_sa_t *ike_sa,
349 ike_sa_state_t state)
350 {
351 enumerator_t *enumerator;
352 entry_t *entry;
353 bool keep;
354
355 this->mutex->lock(this->mutex);
356 enumerator = this->listeners->create_enumerator(this->listeners);
357 while (enumerator->enumerate(enumerator, &entry))
358 {
359 if (entry->calling || !entry->listener->ike_state_change)
360 {
361 continue;
362 }
363 entry->calling++;
364 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
365 entry->calling--;
366 if (!keep)
367 {
368 unregister_listener(this, entry, enumerator);
369 }
370 }
371 enumerator->destroy(enumerator);
372 this->mutex->unlock(this->mutex);
373 }
374
375 /**
376 * Implementation of bus_t.child_state_change
377 */
378 static void child_state_change(private_bus_t *this, child_sa_t *child_sa,
379 child_sa_state_t state)
380 {
381 enumerator_t *enumerator;
382 ike_sa_t *ike_sa;
383 entry_t *entry;
384 bool keep;
385
386 ike_sa = this->thread_sa->get(this->thread_sa);
387
388 this->mutex->lock(this->mutex);
389 enumerator = this->listeners->create_enumerator(this->listeners);
390 while (enumerator->enumerate(enumerator, &entry))
391 {
392 if (entry->calling || !entry->listener->child_state_change)
393 {
394 continue;
395 }
396 entry->calling++;
397 keep = entry->listener->child_state_change(entry->listener, ike_sa,
398 child_sa, state);
399 entry->calling--;
400 if (!keep)
401 {
402 unregister_listener(this, entry, enumerator);
403 }
404 }
405 enumerator->destroy(enumerator);
406 this->mutex->unlock(this->mutex);
407 }
408
409 /**
410 * Implementation of bus_t.message
411 */
412 static void message(private_bus_t *this, message_t *message, bool incoming)
413 {
414 enumerator_t *enumerator;
415 ike_sa_t *ike_sa;
416 entry_t *entry;
417 bool keep;
418
419 ike_sa = this->thread_sa->get(this->thread_sa);
420
421 this->mutex->lock(this->mutex);
422 enumerator = this->listeners->create_enumerator(this->listeners);
423 while (enumerator->enumerate(enumerator, &entry))
424 {
425 if (entry->calling || !entry->listener->message)
426 {
427 continue;
428 }
429 entry->calling++;
430 keep = entry->listener->message(entry->listener, ike_sa,
431 message, incoming);
432 entry->calling--;
433 if (!keep)
434 {
435 unregister_listener(this, entry, enumerator);
436 }
437 }
438 enumerator->destroy(enumerator);
439 this->mutex->unlock(this->mutex);
440 }
441
442 /**
443 * Implementation of bus_t.ike_keys
444 */
445 static void ike_keys(private_bus_t *this, ike_sa_t *ike_sa,
446 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
447 ike_sa_t *rekey)
448 {
449 enumerator_t *enumerator;
450 entry_t *entry;
451 bool keep;
452
453 this->mutex->lock(this->mutex);
454 enumerator = this->listeners->create_enumerator(this->listeners);
455 while (enumerator->enumerate(enumerator, &entry))
456 {
457 if (entry->calling || !entry->listener->ike_keys)
458 {
459 continue;
460 }
461 entry->calling++;
462 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
463 nonce_i, nonce_r, rekey);
464 entry->calling--;
465 if (!keep)
466 {
467 unregister_listener(this, entry, enumerator);
468 }
469 }
470 enumerator->destroy(enumerator);
471 this->mutex->unlock(this->mutex);
472 }
473
474 /**
475 * Implementation of bus_t.child_keys
476 */
477 static void child_keys(private_bus_t *this, child_sa_t *child_sa,
478 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
479 {
480 enumerator_t *enumerator;
481 ike_sa_t *ike_sa;
482 entry_t *entry;
483 bool keep;
484
485 ike_sa = this->thread_sa->get(this->thread_sa);
486
487 this->mutex->lock(this->mutex);
488 enumerator = this->listeners->create_enumerator(this->listeners);
489 while (enumerator->enumerate(enumerator, &entry))
490 {
491 if (entry->calling || !entry->listener->child_keys)
492 {
493 continue;
494 }
495 entry->calling++;
496 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
497 dh, nonce_i, nonce_r);
498 entry->calling--;
499 if (!keep)
500 {
501 unregister_listener(this, entry, enumerator);
502 }
503 }
504 enumerator->destroy(enumerator);
505 this->mutex->unlock(this->mutex);
506 }
507
508 /**
509 * Implementation of bus_t.child_updown
510 */
511 static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
512 {
513 enumerator_t *enumerator;
514 ike_sa_t *ike_sa;
515 entry_t *entry;
516 bool keep;
517
518 ike_sa = this->thread_sa->get(this->thread_sa);
519
520 this->mutex->lock(this->mutex);
521 enumerator = this->listeners->create_enumerator(this->listeners);
522 while (enumerator->enumerate(enumerator, &entry))
523 {
524 if (entry->calling || !entry->listener->child_updown)
525 {
526 continue;
527 }
528 entry->calling++;
529 keep = entry->listener->child_updown(entry->listener,
530 ike_sa, child_sa, up);
531 entry->calling--;
532 if (!keep)
533 {
534 unregister_listener(this, entry, enumerator);
535 }
536 }
537 enumerator->destroy(enumerator);
538 this->mutex->unlock(this->mutex);
539 }
540
541 /**
542 * Implementation of bus_t.child_rekey
543 */
544 static void child_rekey(private_bus_t *this, child_sa_t *old, child_sa_t *new)
545 {
546 enumerator_t *enumerator;
547 ike_sa_t *ike_sa;
548 entry_t *entry;
549 bool keep;
550
551 ike_sa = this->thread_sa->get(this->thread_sa);
552
553 this->mutex->lock(this->mutex);
554 enumerator = this->listeners->create_enumerator(this->listeners);
555 while (enumerator->enumerate(enumerator, &entry))
556 {
557 if (entry->calling || !entry->listener->child_rekey)
558 {
559 continue;
560 }
561 entry->calling++;
562 keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
563 entry->calling--;
564 if (!keep)
565 {
566 unregister_listener(this, entry, enumerator);
567 }
568 }
569 enumerator->destroy(enumerator);
570 this->mutex->unlock(this->mutex);
571 }
572
573 /**
574 * Implementation of bus_t.ike_updown
575 */
576 static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
577 {
578 enumerator_t *enumerator;
579 entry_t *entry;
580 bool keep;
581
582 this->mutex->lock(this->mutex);
583 enumerator = this->listeners->create_enumerator(this->listeners);
584 while (enumerator->enumerate(enumerator, &entry))
585 {
586 if (entry->calling || !entry->listener->ike_updown)
587 {
588 continue;
589 }
590 entry->calling++;
591 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
592 entry->calling--;
593 if (!keep)
594 {
595 unregister_listener(this, entry, enumerator);
596 }
597 }
598 enumerator->destroy(enumerator);
599 this->mutex->unlock(this->mutex);
600
601 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
602 if (!up)
603 {
604 iterator_t *iterator;
605 child_sa_t *child_sa;
606
607 iterator = ike_sa->create_child_sa_iterator(ike_sa);
608 while (iterator->iterate(iterator, (void**)&child_sa))
609 {
610 child_updown(this, child_sa, FALSE);
611 }
612 iterator->destroy(iterator);
613 }
614 }
615
616 /**
617 * Implementation of bus_t.ike_rekey
618 */
619 static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
620 {
621 enumerator_t *enumerator;
622 entry_t *entry;
623 bool keep;
624
625 this->mutex->lock(this->mutex);
626 enumerator = this->listeners->create_enumerator(this->listeners);
627 while (enumerator->enumerate(enumerator, &entry))
628 {
629 if (entry->calling || !entry->listener->ike_rekey)
630 {
631 continue;
632 }
633 entry->calling++;
634 keep = entry->listener->ike_rekey(entry->listener, old, new);
635 entry->calling--;
636 if (!keep)
637 {
638 unregister_listener(this, entry, enumerator);
639 }
640 }
641 enumerator->destroy(enumerator);
642 this->mutex->unlock(this->mutex);
643 }
644
645 /**
646 * Implementation of bus_t.authorize
647 */
648 static bool authorize(private_bus_t *this, bool final)
649 {
650 enumerator_t *enumerator;
651 ike_sa_t *ike_sa;
652 entry_t *entry;
653 bool keep, success = TRUE;
654
655 ike_sa = this->thread_sa->get(this->thread_sa);
656
657 this->mutex->lock(this->mutex);
658 enumerator = this->listeners->create_enumerator(this->listeners);
659 while (enumerator->enumerate(enumerator, &entry))
660 {
661 if (entry->calling || !entry->listener->authorize)
662 {
663 continue;
664 }
665 entry->calling++;
666 keep = entry->listener->authorize(entry->listener, ike_sa,
667 final, &success);
668 entry->calling--;
669 if (!keep)
670 {
671 unregister_listener(this, entry, enumerator);
672 }
673 if (!success)
674 {
675 break;
676 }
677 }
678 enumerator->destroy(enumerator);
679 this->mutex->unlock(this->mutex);
680 return success;
681 }
682
683 /**
684 * Implementation of bus_t.destroy.
685 */
686 static void destroy(private_bus_t *this)
687 {
688 this->thread_sa->destroy(this->thread_sa);
689 this->mutex->destroy(this->mutex);
690 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
691 free(this);
692 }
693
694 /*
695 * Described in header.
696 */
697 bus_t *bus_create()
698 {
699 private_bus_t *this = malloc_thing(private_bus_t);
700
701 this->public.add_listener = (void(*)(bus_t*,listener_t*))add_listener;
702 this->public.remove_listener = (void(*)(bus_t*,listener_t*))remove_listener;
703 this->public.listen = (void(*)(bus_t*, listener_t *listener, job_t *job))listen_;
704 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
705 this->public.get_sa = (ike_sa_t*(*)(bus_t*))get_sa;
706 this->public.log = (void(*)(bus_t*,debug_t,level_t,char*,...))log_;
707 this->public.vlog = (void(*)(bus_t*,debug_t,level_t,char*,va_list))vlog;
708 this->public.alert = (void(*)(bus_t*, alert_t alert, ...))alert;
709 this->public.ike_state_change = (void(*)(bus_t*,ike_sa_t*,ike_sa_state_t))ike_state_change;
710 this->public.child_state_change = (void(*)(bus_t*,child_sa_t*,child_sa_state_t))child_state_change;
711 this->public.message = (void(*)(bus_t*, message_t *message, bool incoming))message;
712 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;
713 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;
714 this->public.ike_updown = (void(*)(bus_t*, ike_sa_t *ike_sa, bool up))ike_updown;
715 this->public.ike_rekey = (void(*)(bus_t*, ike_sa_t *old, ike_sa_t *new))ike_rekey;
716 this->public.child_updown = (void(*)(bus_t*, child_sa_t *child_sa, bool up))child_updown;
717 this->public.child_rekey = (void(*)(bus_t*, child_sa_t *old, child_sa_t *new))child_rekey;
718 this->public.authorize = (bool(*)(bus_t*, bool final))authorize;
719 this->public.destroy = (void(*)(bus_t*)) destroy;
720
721 this->listeners = linked_list_create();
722 this->mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
723 this->thread_sa = thread_value_create(NULL);
724
725 return &this->public;
726 }
727