6a72f4a9ae277e4887deed1003b486216469e0e4
[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 * Implementation of bus_t.get_sa
248 */
249 static ike_sa_t* get_sa(private_bus_t *this)
250 {
251 return pthread_getspecific(this->thread_sa);
252 }
253
254 /**
255 * data associated to a signal, passed to callback
256 */
257 typedef struct {
258 /** associated IKE_SA */
259 ike_sa_t *ike_sa;
260 /** invoking thread */
261 long thread;
262 /** debug group */
263 debug_t group;
264 /** debug level */
265 level_t level;
266 /** format string */
267 char *format;
268 /** argument list */
269 va_list args;
270 } log_data_t;
271
272 /**
273 * listener->log() invocation as a list remove callback
274 */
275 static bool log_cb(entry_t *entry, log_data_t *data)
276 {
277 va_list args;
278
279 if (entry->calling || !entry->listener->log)
280 { /* avoid recursive calls */
281 return FALSE;
282 }
283 entry->calling++;
284 va_copy(args, data->args);
285 if (!entry->listener->log(entry->listener, data->group, data->level,
286 data->thread, data->ike_sa, data->format, args))
287 {
288 if (entry->blocker)
289 {
290 entry->blocker = FALSE;
291 entry->condvar->signal(entry->condvar);
292 }
293 else
294 {
295 entry_destroy(entry);
296 }
297 va_end(args);
298 entry->calling--;
299 return TRUE;
300 }
301 va_end(args);
302 entry->calling--;
303 return FALSE;
304 }
305
306 /**
307 * Implementation of bus_t.vlog.
308 */
309 static void vlog(private_bus_t *this, debug_t group, level_t level,
310 char* format, va_list args)
311 {
312 log_data_t data;
313
314 data.ike_sa = pthread_getspecific(this->thread_sa);
315 data.thread = get_thread_number(this);
316 data.group = group;
317 data.level = level;
318 data.format = format;
319 va_copy(data.args, args);
320
321 this->mutex->lock(this->mutex);
322 /* We use the remove() method to invoke all listeners. This is cheap and
323 * does not require an allocation for this performance critical function. */
324 this->listeners->remove(this->listeners, &data, (void*)log_cb);
325 this->mutex->unlock(this->mutex);
326
327 va_end(data.args);
328 }
329
330 /**
331 * Implementation of bus_t.log.
332 */
333 static void log_(private_bus_t *this, debug_t group, level_t level,
334 char* format, ...)
335 {
336 va_list args;
337
338 va_start(args, format);
339 vlog(this, group, level, format, args);
340 va_end(args);
341 }
342
343 /**
344 * unregister a listener
345 */
346 static void unregister_listener(private_bus_t *this, entry_t *entry,
347 enumerator_t *enumerator)
348 {
349 if (entry->blocker)
350 {
351 entry->blocker = FALSE;
352 entry->condvar->signal(entry->condvar);
353 }
354 else
355 {
356 entry_destroy(entry);
357 }
358 this->listeners->remove_at(this->listeners, enumerator);
359 }
360
361 /**
362 * Implementation of bus_t.alert
363 */
364 static void alert(private_bus_t *this, alert_t alert, ...)
365 {
366 enumerator_t *enumerator;
367 ike_sa_t *ike_sa;
368 entry_t *entry;
369 va_list args;
370 bool keep;
371
372 ike_sa = pthread_getspecific(this->thread_sa);
373
374 this->mutex->lock(this->mutex);
375 enumerator = this->listeners->create_enumerator(this->listeners);
376 while (enumerator->enumerate(enumerator, &entry))
377 {
378 if (entry->calling || !entry->listener->alert)
379 {
380 continue;
381 }
382 entry->calling++;
383 va_start(args, alert);
384 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
385 va_end(args);
386 entry->calling--;
387 if (!keep)
388 {
389 unregister_listener(this, entry, enumerator);
390 }
391 }
392 enumerator->destroy(enumerator);
393 this->mutex->unlock(this->mutex);
394 }
395
396 /**
397 * Implementation of bus_t.ike_state_change
398 */
399 static void ike_state_change(private_bus_t *this, ike_sa_t *ike_sa,
400 ike_sa_state_t state)
401 {
402 enumerator_t *enumerator;
403 entry_t *entry;
404 bool keep;
405
406 this->mutex->lock(this->mutex);
407 enumerator = this->listeners->create_enumerator(this->listeners);
408 while (enumerator->enumerate(enumerator, &entry))
409 {
410 if (entry->calling || !entry->listener->ike_state_change)
411 {
412 continue;
413 }
414 entry->calling++;
415 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
416 entry->calling--;
417 if (!keep)
418 {
419 unregister_listener(this, entry, enumerator);
420 }
421 }
422 enumerator->destroy(enumerator);
423 this->mutex->unlock(this->mutex);
424 }
425
426 /**
427 * Implementation of bus_t.child_state_change
428 */
429 static void child_state_change(private_bus_t *this, child_sa_t *child_sa,
430 child_sa_state_t state)
431 {
432 enumerator_t *enumerator;
433 ike_sa_t *ike_sa;
434 entry_t *entry;
435 bool keep;
436
437 ike_sa = pthread_getspecific(this->thread_sa);
438
439 this->mutex->lock(this->mutex);
440 enumerator = this->listeners->create_enumerator(this->listeners);
441 while (enumerator->enumerate(enumerator, &entry))
442 {
443 if (entry->calling || !entry->listener->child_state_change)
444 {
445 continue;
446 }
447 entry->calling++;
448 keep = entry->listener->child_state_change(entry->listener, ike_sa,
449 child_sa, state);
450 entry->calling--;
451 if (!keep)
452 {
453 unregister_listener(this, entry, enumerator);
454 }
455 }
456 enumerator->destroy(enumerator);
457 this->mutex->unlock(this->mutex);
458 }
459
460 /**
461 * Implementation of bus_t.message
462 */
463 static void message(private_bus_t *this, message_t *message, bool incoming)
464 {
465 enumerator_t *enumerator;
466 ike_sa_t *ike_sa;
467 entry_t *entry;
468 bool keep;
469
470 ike_sa = pthread_getspecific(this->thread_sa);
471
472 this->mutex->lock(this->mutex);
473 enumerator = this->listeners->create_enumerator(this->listeners);
474 while (enumerator->enumerate(enumerator, &entry))
475 {
476 if (entry->calling || !entry->listener->message)
477 {
478 continue;
479 }
480 entry->calling++;
481 keep = entry->listener->message(entry->listener, ike_sa,
482 message, incoming);
483 entry->calling--;
484 if (!keep)
485 {
486 unregister_listener(this, entry, enumerator);
487 }
488 }
489 enumerator->destroy(enumerator);
490 this->mutex->unlock(this->mutex);
491 }
492
493 /**
494 * Implementation of bus_t.ike_keys
495 */
496 static void ike_keys(private_bus_t *this, ike_sa_t *ike_sa,
497 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
498 ike_sa_t *rekey)
499 {
500 enumerator_t *enumerator;
501 entry_t *entry;
502 bool keep;
503
504 this->mutex->lock(this->mutex);
505 enumerator = this->listeners->create_enumerator(this->listeners);
506 while (enumerator->enumerate(enumerator, &entry))
507 {
508 if (entry->calling || !entry->listener->ike_keys)
509 {
510 continue;
511 }
512 entry->calling++;
513 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
514 nonce_i, nonce_r, rekey);
515 entry->calling--;
516 if (!keep)
517 {
518 unregister_listener(this, entry, enumerator);
519 }
520 }
521 enumerator->destroy(enumerator);
522 this->mutex->unlock(this->mutex);
523 }
524
525 /**
526 * Implementation of bus_t.child_keys
527 */
528 static void child_keys(private_bus_t *this, child_sa_t *child_sa,
529 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
530 {
531 enumerator_t *enumerator;
532 ike_sa_t *ike_sa;
533 entry_t *entry;
534 bool keep;
535
536 ike_sa = pthread_getspecific(this->thread_sa);
537
538 this->mutex->lock(this->mutex);
539 enumerator = this->listeners->create_enumerator(this->listeners);
540 while (enumerator->enumerate(enumerator, &entry))
541 {
542 if (entry->calling || !entry->listener->child_keys)
543 {
544 continue;
545 }
546 entry->calling++;
547 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
548 dh, nonce_i, nonce_r);
549 entry->calling--;
550 if (!keep)
551 {
552 unregister_listener(this, entry, enumerator);
553 }
554 }
555 enumerator->destroy(enumerator);
556 this->mutex->unlock(this->mutex);
557 }
558
559 /**
560 * Implementation of bus_t.child_updown
561 */
562 static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
563 {
564 enumerator_t *enumerator;
565 ike_sa_t *ike_sa;
566 entry_t *entry;
567 bool keep;
568
569 ike_sa = pthread_getspecific(this->thread_sa);
570
571 this->mutex->lock(this->mutex);
572 enumerator = this->listeners->create_enumerator(this->listeners);
573 while (enumerator->enumerate(enumerator, &entry))
574 {
575 if (entry->calling || !entry->listener->child_updown)
576 {
577 continue;
578 }
579 entry->calling++;
580 keep = entry->listener->child_updown(entry->listener,
581 ike_sa, child_sa, up);
582 entry->calling--;
583 if (!keep)
584 {
585 unregister_listener(this, entry, enumerator);
586 }
587 }
588 enumerator->destroy(enumerator);
589 this->mutex->unlock(this->mutex);
590 }
591
592 /**
593 * Implementation of bus_t.child_rekey
594 */
595 static void child_rekey(private_bus_t *this, child_sa_t *old, child_sa_t *new)
596 {
597 enumerator_t *enumerator;
598 ike_sa_t *ike_sa;
599 entry_t *entry;
600 bool keep;
601
602 ike_sa = pthread_getspecific(this->thread_sa);
603
604 this->mutex->lock(this->mutex);
605 enumerator = this->listeners->create_enumerator(this->listeners);
606 while (enumerator->enumerate(enumerator, &entry))
607 {
608 if (entry->calling || !entry->listener->child_rekey)
609 {
610 continue;
611 }
612 entry->calling++;
613 keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
614 entry->calling--;
615 if (!keep)
616 {
617 unregister_listener(this, entry, enumerator);
618 }
619 }
620 enumerator->destroy(enumerator);
621 this->mutex->unlock(this->mutex);
622 }
623
624 /**
625 * Implementation of bus_t.ike_updown
626 */
627 static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
628 {
629 enumerator_t *enumerator;
630 entry_t *entry;
631 bool keep;
632
633 this->mutex->lock(this->mutex);
634 enumerator = this->listeners->create_enumerator(this->listeners);
635 while (enumerator->enumerate(enumerator, &entry))
636 {
637 if (entry->calling || !entry->listener->ike_updown)
638 {
639 continue;
640 }
641 entry->calling++;
642 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
643 entry->calling--;
644 if (!keep)
645 {
646 unregister_listener(this, entry, enumerator);
647 }
648 }
649 enumerator->destroy(enumerator);
650 this->mutex->unlock(this->mutex);
651
652 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
653 if (!up)
654 {
655 iterator_t *iterator;
656 child_sa_t *child_sa;
657
658 iterator = ike_sa->create_child_sa_iterator(ike_sa);
659 while (iterator->iterate(iterator, (void**)&child_sa))
660 {
661 child_updown(this, child_sa, FALSE);
662 }
663 iterator->destroy(iterator);
664 }
665 }
666
667 /**
668 * Implementation of bus_t.ike_rekey
669 */
670 static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
671 {
672 enumerator_t *enumerator;
673 entry_t *entry;
674 bool keep;
675
676 this->mutex->lock(this->mutex);
677 enumerator = this->listeners->create_enumerator(this->listeners);
678 while (enumerator->enumerate(enumerator, &entry))
679 {
680 if (entry->calling || !entry->listener->ike_rekey)
681 {
682 continue;
683 }
684 entry->calling++;
685 keep = entry->listener->ike_rekey(entry->listener, old, new);
686 entry->calling--;
687 if (!keep)
688 {
689 unregister_listener(this, entry, enumerator);
690 }
691 }
692 enumerator->destroy(enumerator);
693 this->mutex->unlock(this->mutex);
694 }
695
696 /**
697 * Implementation of bus_t.authorize
698 */
699 static bool authorize(private_bus_t *this, linked_list_t *auth, bool final)
700 {
701 enumerator_t *enumerator;
702 ike_sa_t *ike_sa;
703 entry_t *entry;
704 bool keep, success = TRUE;
705
706 ike_sa = pthread_getspecific(this->thread_sa);
707
708 this->mutex->lock(this->mutex);
709 enumerator = this->listeners->create_enumerator(this->listeners);
710 while (enumerator->enumerate(enumerator, &entry))
711 {
712 if (entry->calling || !entry->listener->authorize)
713 {
714 continue;
715 }
716 entry->calling++;
717 keep = entry->listener->authorize(entry->listener, ike_sa,
718 auth, final, &success);
719 entry->calling--;
720 if (!keep)
721 {
722 unregister_listener(this, entry, enumerator);
723 }
724 if (!success)
725 {
726 break;
727 }
728 }
729 enumerator->destroy(enumerator);
730 this->mutex->unlock(this->mutex);
731 return success;
732 }
733
734 /**
735 * Implementation of bus_t.destroy.
736 */
737 static void destroy(private_bus_t *this)
738 {
739 this->mutex->destroy(this->mutex);
740 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
741 free(this);
742 }
743
744 /*
745 * Described in header.
746 */
747 bus_t *bus_create()
748 {
749 private_bus_t *this = malloc_thing(private_bus_t);
750
751 this->public.add_listener = (void(*)(bus_t*,listener_t*))add_listener;
752 this->public.remove_listener = (void(*)(bus_t*,listener_t*))remove_listener;
753 this->public.listen = (void(*)(bus_t*, listener_t *listener, job_t *job))listen_;
754 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
755 this->public.get_sa = (ike_sa_t*(*)(bus_t*))get_sa;
756 this->public.log = (void(*)(bus_t*,debug_t,level_t,char*,...))log_;
757 this->public.vlog = (void(*)(bus_t*,debug_t,level_t,char*,va_list))vlog;
758 this->public.alert = (void(*)(bus_t*, alert_t alert, ...))alert;
759 this->public.ike_state_change = (void(*)(bus_t*,ike_sa_t*,ike_sa_state_t))ike_state_change;
760 this->public.child_state_change = (void(*)(bus_t*,child_sa_t*,child_sa_state_t))child_state_change;
761 this->public.message = (void(*)(bus_t*, message_t *message, bool incoming))message;
762 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;
763 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;
764 this->public.ike_updown = (void(*)(bus_t*, ike_sa_t *ike_sa, bool up))ike_updown;
765 this->public.ike_rekey = (void(*)(bus_t*, ike_sa_t *old, ike_sa_t *new))ike_rekey;
766 this->public.child_updown = (void(*)(bus_t*, child_sa_t *child_sa, bool up))child_updown;
767 this->public.child_rekey = (void(*)(bus_t*, child_sa_t *old, child_sa_t *new))child_rekey;
768 this->public.authorize = (bool(*)(bus_t*, linked_list_t *auth, bool final))authorize;
769 this->public.destroy = (void(*)(bus_t*)) destroy;
770
771 this->listeners = linked_list_create();
772 this->mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
773 pthread_key_create(&this->thread_id, NULL);
774 pthread_key_create(&this->thread_sa, NULL);
775
776 return &this->public;
777 }
778