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