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