Pass the CREATE_CHILD_SA initiator flag to the child_keys parameter
[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 METHOD(bus_t, add_listener, void,
106 private_bus_t *this, listener_t *listener)
107 {
108 this->mutex->lock(this->mutex);
109 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
110 this->mutex->unlock(this->mutex);
111 }
112
113 METHOD(bus_t, remove_listener, void,
114 private_bus_t *this, listener_t *listener)
115 {
116 enumerator_t *enumerator;
117 entry_t *entry;
118
119 this->mutex->lock(this->mutex);
120 enumerator = this->listeners->create_enumerator(this->listeners);
121 while (enumerator->enumerate(enumerator, &entry))
122 {
123 if (entry->listener == listener)
124 {
125 this->listeners->remove_at(this->listeners, enumerator);
126 entry_destroy(entry);
127 break;
128 }
129 }
130 enumerator->destroy(enumerator);
131 this->mutex->unlock(this->mutex);
132 }
133
134 typedef struct cleanup_data_t cleanup_data_t;
135
136 /**
137 * data to remove a listener using thread_cleanup_t handler
138 */
139 struct cleanup_data_t {
140 /** bus instance */
141 private_bus_t *this;
142 /** listener entry */
143 entry_t *entry;
144 };
145
146 /**
147 * thread_cleanup_t handler to remove a listener
148 */
149 static void listener_cleanup(cleanup_data_t *data)
150 {
151 data->this->listeners->remove(data->this->listeners, data->entry, NULL);
152 entry_destroy(data->entry);
153 }
154
155 METHOD(bus_t, listen_, void,
156 private_bus_t *this, listener_t *listener, job_t *job)
157 {
158 bool old;
159 cleanup_data_t data;
160
161 data.this = this;
162 data.entry = entry_create(listener, TRUE);
163
164 this->mutex->lock(this->mutex);
165 this->listeners->insert_last(this->listeners, data.entry);
166 charon->processor->queue_job(charon->processor, job);
167 thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
168 thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data);
169 old = thread_cancelability(TRUE);
170 while (data.entry->blocker)
171 {
172 data.entry->condvar->wait(data.entry->condvar, this->mutex);
173 }
174 thread_cancelability(old);
175 thread_cleanup_pop(FALSE);
176 /* unlock mutex */
177 thread_cleanup_pop(TRUE);
178 entry_destroy(data.entry);
179 }
180
181 METHOD(bus_t, set_sa, void,
182 private_bus_t *this, ike_sa_t *ike_sa)
183 {
184 this->thread_sa->set(this->thread_sa, ike_sa);
185 }
186
187 METHOD(bus_t, get_sa, ike_sa_t*,
188 private_bus_t *this)
189 {
190 return this->thread_sa->get(this->thread_sa);
191 }
192
193 /**
194 * data associated to a signal, passed to callback
195 */
196 typedef struct {
197 /** associated IKE_SA */
198 ike_sa_t *ike_sa;
199 /** invoking thread */
200 long thread;
201 /** debug group */
202 debug_t group;
203 /** debug level */
204 level_t level;
205 /** format string */
206 char *format;
207 /** argument list */
208 va_list args;
209 } log_data_t;
210
211 /**
212 * listener->log() invocation as a list remove callback
213 */
214 static bool log_cb(entry_t *entry, log_data_t *data)
215 {
216 va_list args;
217
218 if (entry->calling || !entry->listener->log)
219 { /* avoid recursive calls */
220 return FALSE;
221 }
222 entry->calling++;
223 va_copy(args, data->args);
224 if (!entry->listener->log(entry->listener, data->group, data->level,
225 data->thread, data->ike_sa, data->format, args))
226 {
227 if (entry->blocker)
228 {
229 entry->blocker = FALSE;
230 entry->condvar->signal(entry->condvar);
231 }
232 else
233 {
234 entry_destroy(entry);
235 }
236 va_end(args);
237 entry->calling--;
238 return TRUE;
239 }
240 va_end(args);
241 entry->calling--;
242 return FALSE;
243 }
244
245 METHOD(bus_t, vlog, void,
246 private_bus_t *this, debug_t group, level_t level,
247 char* format, va_list args)
248 {
249 log_data_t data;
250
251 data.ike_sa = this->thread_sa->get(this->thread_sa);
252 data.thread = thread_current_id();
253 data.group = group;
254 data.level = level;
255 data.format = format;
256 va_copy(data.args, args);
257
258 this->mutex->lock(this->mutex);
259 /* We use the remove() method to invoke all listeners. This is cheap and
260 * does not require an allocation for this performance critical function. */
261 this->listeners->remove(this->listeners, &data, (void*)log_cb);
262 this->mutex->unlock(this->mutex);
263
264 va_end(data.args);
265 }
266
267 METHOD(bus_t, log_, void,
268 private_bus_t *this, debug_t group, level_t level, char* format, ...)
269 {
270 va_list args;
271
272 va_start(args, format);
273 vlog(this, group, level, format, args);
274 va_end(args);
275 }
276
277 /**
278 * unregister a listener
279 */
280 static void unregister_listener(private_bus_t *this, entry_t *entry,
281 enumerator_t *enumerator)
282 {
283 if (entry->blocker)
284 {
285 entry->blocker = FALSE;
286 entry->condvar->signal(entry->condvar);
287 }
288 else
289 {
290 entry_destroy(entry);
291 }
292 this->listeners->remove_at(this->listeners, enumerator);
293 }
294
295 METHOD(bus_t, alert, void,
296 private_bus_t *this, alert_t alert, ...)
297 {
298 enumerator_t *enumerator;
299 ike_sa_t *ike_sa;
300 entry_t *entry;
301 va_list args;
302 bool keep;
303
304 ike_sa = this->thread_sa->get(this->thread_sa);
305
306 this->mutex->lock(this->mutex);
307 enumerator = this->listeners->create_enumerator(this->listeners);
308 while (enumerator->enumerate(enumerator, &entry))
309 {
310 if (entry->calling || !entry->listener->alert)
311 {
312 continue;
313 }
314 entry->calling++;
315 va_start(args, alert);
316 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
317 va_end(args);
318 entry->calling--;
319 if (!keep)
320 {
321 unregister_listener(this, entry, enumerator);
322 }
323 }
324 enumerator->destroy(enumerator);
325 this->mutex->unlock(this->mutex);
326 }
327
328 METHOD(bus_t, ike_state_change, void,
329 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
330 {
331 enumerator_t *enumerator;
332 entry_t *entry;
333 bool keep;
334
335 this->mutex->lock(this->mutex);
336 enumerator = this->listeners->create_enumerator(this->listeners);
337 while (enumerator->enumerate(enumerator, &entry))
338 {
339 if (entry->calling || !entry->listener->ike_state_change)
340 {
341 continue;
342 }
343 entry->calling++;
344 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
345 entry->calling--;
346 if (!keep)
347 {
348 unregister_listener(this, entry, enumerator);
349 }
350 }
351 enumerator->destroy(enumerator);
352 this->mutex->unlock(this->mutex);
353 }
354
355 METHOD(bus_t, child_state_change, void,
356 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
357 {
358 enumerator_t *enumerator;
359 ike_sa_t *ike_sa;
360 entry_t *entry;
361 bool keep;
362
363 ike_sa = this->thread_sa->get(this->thread_sa);
364
365 this->mutex->lock(this->mutex);
366 enumerator = this->listeners->create_enumerator(this->listeners);
367 while (enumerator->enumerate(enumerator, &entry))
368 {
369 if (entry->calling || !entry->listener->child_state_change)
370 {
371 continue;
372 }
373 entry->calling++;
374 keep = entry->listener->child_state_change(entry->listener, ike_sa,
375 child_sa, state);
376 entry->calling--;
377 if (!keep)
378 {
379 unregister_listener(this, entry, enumerator);
380 }
381 }
382 enumerator->destroy(enumerator);
383 this->mutex->unlock(this->mutex);
384 }
385
386 METHOD(bus_t, message, void,
387 private_bus_t *this, message_t *message, bool incoming)
388 {
389 enumerator_t *enumerator;
390 ike_sa_t *ike_sa;
391 entry_t *entry;
392 bool keep;
393
394 ike_sa = this->thread_sa->get(this->thread_sa);
395
396 this->mutex->lock(this->mutex);
397 enumerator = this->listeners->create_enumerator(this->listeners);
398 while (enumerator->enumerate(enumerator, &entry))
399 {
400 if (entry->calling || !entry->listener->message)
401 {
402 continue;
403 }
404 entry->calling++;
405 keep = entry->listener->message(entry->listener, ike_sa,
406 message, incoming);
407 entry->calling--;
408 if (!keep)
409 {
410 unregister_listener(this, entry, enumerator);
411 }
412 }
413 enumerator->destroy(enumerator);
414 this->mutex->unlock(this->mutex);
415 }
416
417 METHOD(bus_t, ike_keys, void,
418 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
419 chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey)
420 {
421 enumerator_t *enumerator;
422 entry_t *entry;
423 bool keep;
424
425 this->mutex->lock(this->mutex);
426 enumerator = this->listeners->create_enumerator(this->listeners);
427 while (enumerator->enumerate(enumerator, &entry))
428 {
429 if (entry->calling || !entry->listener->ike_keys)
430 {
431 continue;
432 }
433 entry->calling++;
434 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
435 nonce_i, nonce_r, rekey);
436 entry->calling--;
437 if (!keep)
438 {
439 unregister_listener(this, entry, enumerator);
440 }
441 }
442 enumerator->destroy(enumerator);
443 this->mutex->unlock(this->mutex);
444 }
445
446 METHOD(bus_t, child_keys, void,
447 private_bus_t *this, child_sa_t *child_sa, bool initiator,
448 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
449 {
450 enumerator_t *enumerator;
451 ike_sa_t *ike_sa;
452 entry_t *entry;
453 bool keep;
454
455 ike_sa = this->thread_sa->get(this->thread_sa);
456
457 this->mutex->lock(this->mutex);
458 enumerator = this->listeners->create_enumerator(this->listeners);
459 while (enumerator->enumerate(enumerator, &entry))
460 {
461 if (entry->calling || !entry->listener->child_keys)
462 {
463 continue;
464 }
465 entry->calling++;
466 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
467 initiator, dh, nonce_i, nonce_r);
468 entry->calling--;
469 if (!keep)
470 {
471 unregister_listener(this, entry, enumerator);
472 }
473 }
474 enumerator->destroy(enumerator);
475 this->mutex->unlock(this->mutex);
476 }
477
478 METHOD(bus_t, child_updown, void,
479 private_bus_t *this, child_sa_t *child_sa, bool up)
480 {
481 enumerator_t *enumerator;
482 ike_sa_t *ike_sa;
483 entry_t *entry;
484 bool keep;
485
486 ike_sa = this->thread_sa->get(this->thread_sa);
487
488 this->mutex->lock(this->mutex);
489 enumerator = this->listeners->create_enumerator(this->listeners);
490 while (enumerator->enumerate(enumerator, &entry))
491 {
492 if (entry->calling || !entry->listener->child_updown)
493 {
494 continue;
495 }
496 entry->calling++;
497 keep = entry->listener->child_updown(entry->listener,
498 ike_sa, child_sa, up);
499 entry->calling--;
500 if (!keep)
501 {
502 unregister_listener(this, entry, enumerator);
503 }
504 }
505 enumerator->destroy(enumerator);
506 this->mutex->unlock(this->mutex);
507 }
508
509 METHOD(bus_t, child_rekey, void,
510 private_bus_t *this, child_sa_t *old, child_sa_t *new)
511 {
512 enumerator_t *enumerator;
513 ike_sa_t *ike_sa;
514 entry_t *entry;
515 bool keep;
516
517 ike_sa = this->thread_sa->get(this->thread_sa);
518
519 this->mutex->lock(this->mutex);
520 enumerator = this->listeners->create_enumerator(this->listeners);
521 while (enumerator->enumerate(enumerator, &entry))
522 {
523 if (entry->calling || !entry->listener->child_rekey)
524 {
525 continue;
526 }
527 entry->calling++;
528 keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
529 entry->calling--;
530 if (!keep)
531 {
532 unregister_listener(this, entry, enumerator);
533 }
534 }
535 enumerator->destroy(enumerator);
536 this->mutex->unlock(this->mutex);
537 }
538
539 METHOD(bus_t, ike_updown, void,
540 private_bus_t *this, ike_sa_t *ike_sa, bool up)
541 {
542 enumerator_t *enumerator;
543 entry_t *entry;
544 bool keep;
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->ike_updown)
551 {
552 continue;
553 }
554 entry->calling++;
555 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
556 entry->calling--;
557 if (!keep)
558 {
559 unregister_listener(this, entry, enumerator);
560 }
561 }
562 enumerator->destroy(enumerator);
563 this->mutex->unlock(this->mutex);
564
565 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
566 if (!up)
567 {
568 iterator_t *iterator;
569 child_sa_t *child_sa;
570
571 iterator = ike_sa->create_child_sa_iterator(ike_sa);
572 while (iterator->iterate(iterator, (void**)&child_sa))
573 {
574 child_updown(this, child_sa, FALSE);
575 }
576 iterator->destroy(iterator);
577 }
578 }
579
580 METHOD(bus_t, ike_rekey, void,
581 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
582 {
583 enumerator_t *enumerator;
584 entry_t *entry;
585 bool keep;
586
587 this->mutex->lock(this->mutex);
588 enumerator = this->listeners->create_enumerator(this->listeners);
589 while (enumerator->enumerate(enumerator, &entry))
590 {
591 if (entry->calling || !entry->listener->ike_rekey)
592 {
593 continue;
594 }
595 entry->calling++;
596 keep = entry->listener->ike_rekey(entry->listener, old, new);
597 entry->calling--;
598 if (!keep)
599 {
600 unregister_listener(this, entry, enumerator);
601 }
602 }
603 enumerator->destroy(enumerator);
604 this->mutex->unlock(this->mutex);
605 }
606
607 METHOD(bus_t, authorize, bool,
608 private_bus_t *this, bool final)
609 {
610 enumerator_t *enumerator;
611 ike_sa_t *ike_sa;
612 entry_t *entry;
613 bool keep, success = TRUE;
614
615 ike_sa = this->thread_sa->get(this->thread_sa);
616
617 this->mutex->lock(this->mutex);
618 enumerator = this->listeners->create_enumerator(this->listeners);
619 while (enumerator->enumerate(enumerator, &entry))
620 {
621 if (entry->calling || !entry->listener->authorize)
622 {
623 continue;
624 }
625 entry->calling++;
626 keep = entry->listener->authorize(entry->listener, ike_sa,
627 final, &success);
628 entry->calling--;
629 if (!keep)
630 {
631 unregister_listener(this, entry, enumerator);
632 }
633 if (!success)
634 {
635 break;
636 }
637 }
638 enumerator->destroy(enumerator);
639 this->mutex->unlock(this->mutex);
640 return success;
641 }
642
643 METHOD(bus_t, narrow, void,
644 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
645 linked_list_t *local, linked_list_t *remote)
646 {
647 enumerator_t *enumerator;
648 ike_sa_t *ike_sa;
649 entry_t *entry;
650 bool keep;
651
652 ike_sa = this->thread_sa->get(this->thread_sa);
653
654 this->mutex->lock(this->mutex);
655 enumerator = this->listeners->create_enumerator(this->listeners);
656 while (enumerator->enumerate(enumerator, &entry))
657 {
658 if (entry->calling || !entry->listener->narrow)
659 {
660 continue;
661 }
662 entry->calling++;
663 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
664 type, local, remote);
665 entry->calling--;
666 if (!keep)
667 {
668 unregister_listener(this, entry, enumerator);
669 }
670 }
671 enumerator->destroy(enumerator);
672 this->mutex->unlock(this->mutex);
673 }
674
675 METHOD(bus_t, destroy, void,
676 private_bus_t *this)
677 {
678 this->thread_sa->destroy(this->thread_sa);
679 this->mutex->destroy(this->mutex);
680 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
681 free(this);
682 }
683
684 /*
685 * Described in header.
686 */
687 bus_t *bus_create()
688 {
689 private_bus_t *this;
690
691 INIT(this,
692 .public = {
693 .add_listener = _add_listener,
694 .remove_listener = _remove_listener,
695 .listen = _listen_,
696 .set_sa = _set_sa,
697 .get_sa = _get_sa,
698 .log = _log_,
699 .vlog = _vlog,
700 .alert = _alert,
701 .ike_state_change = _ike_state_change,
702 .child_state_change = _child_state_change,
703 .message = _message,
704 .ike_keys = _ike_keys,
705 .child_keys = _child_keys,
706 .ike_updown = _ike_updown,
707 .ike_rekey = _ike_rekey,
708 .child_updown = _child_updown,
709 .child_rekey = _child_rekey,
710 .authorize = _authorize,
711 .narrow = _narrow,
712 .destroy = _destroy,
713 },
714 .listeners = linked_list_create(),
715 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
716 .thread_sa = thread_value_create(NULL),
717 );
718
719 return &this->public;
720 }
721