Use a separate interface for loggers.
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2011-2012 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "bus.h"
18
19 #include <stdint.h>
20
21 #include <threading/thread.h>
22 #include <threading/thread_value.h>
23 #include <threading/mutex.h>
24 #include <threading/rwlock.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.
39 */
40 linked_list_t *listeners;
41
42 /**
43 * List of registered loggers.
44 */
45 linked_list_t *loggers;
46
47 /**
48 * Mutex for the list of listeners, recursively.
49 */
50 mutex_t *mutex;
51
52 /**
53 * Read-write lock for the list of loggers.
54 */
55 rwlock_t *log_lock;
56
57 /**
58 * Thread local storage the threads IKE_SA
59 */
60 thread_value_t *thread_sa;
61 };
62
63 typedef struct entry_t entry_t;
64
65 /**
66 * a listener entry
67 */
68 struct entry_t {
69
70 /**
71 * registered listener interface
72 */
73 listener_t *listener;
74
75 /**
76 * are we currently calling this listener
77 */
78 int calling;
79
80 };
81
82 METHOD(bus_t, add_listener, void,
83 private_bus_t *this, listener_t *listener)
84 {
85 entry_t *entry;
86
87 INIT(entry,
88 .listener = listener,
89 );
90
91 this->mutex->lock(this->mutex);
92 this->listeners->insert_last(this->listeners, entry);
93 this->mutex->unlock(this->mutex);
94 }
95
96 METHOD(bus_t, remove_listener, void,
97 private_bus_t *this, listener_t *listener)
98 {
99 enumerator_t *enumerator;
100 entry_t *entry;
101
102 this->mutex->lock(this->mutex);
103 enumerator = this->listeners->create_enumerator(this->listeners);
104 while (enumerator->enumerate(enumerator, &entry))
105 {
106 if (entry->listener == listener)
107 {
108 this->listeners->remove_at(this->listeners, enumerator);
109 free(entry);
110 break;
111 }
112 }
113 enumerator->destroy(enumerator);
114 this->mutex->unlock(this->mutex);
115 }
116
117 METHOD(bus_t, add_logger, void,
118 private_bus_t *this, logger_t *logger)
119 {
120 this->log_lock->write_lock(this->log_lock);
121 this->loggers->insert_last(this->loggers, logger);
122 this->log_lock->unlock(this->log_lock);
123 }
124
125 METHOD(bus_t, remove_logger, void,
126 private_bus_t *this, logger_t *logger)
127 {
128 this->log_lock->write_lock(this->log_lock);
129 this->loggers->remove(this->loggers, logger, NULL);
130 this->log_lock->unlock(this->log_lock);
131 }
132
133 METHOD(bus_t, set_sa, void,
134 private_bus_t *this, ike_sa_t *ike_sa)
135 {
136 this->thread_sa->set(this->thread_sa, ike_sa);
137 }
138
139 METHOD(bus_t, get_sa, ike_sa_t*,
140 private_bus_t *this)
141 {
142 return this->thread_sa->get(this->thread_sa);
143 }
144
145 /**
146 * data associated to a signal, passed to callback
147 */
148 typedef struct {
149 /** associated IKE_SA */
150 ike_sa_t *ike_sa;
151 /** invoking thread */
152 long thread;
153 /** debug group */
154 debug_t group;
155 /** debug level */
156 level_t level;
157 /** format string */
158 char *format;
159 /** argument list */
160 va_list args;
161 } log_data_t;
162
163 /**
164 * logger->log() invocation as a invoke_function callback
165 */
166 static void log_cb(logger_t *logger, log_data_t *data)
167 {
168 va_list args;
169
170 va_copy(args, data->args);
171 logger->log(logger, data->group, data->level, data->thread, data->ike_sa,
172 data->format, args);
173 va_end(args);
174 }
175
176 METHOD(bus_t, vlog, void,
177 private_bus_t *this, debug_t group, level_t level,
178 char* format, va_list args)
179 {
180 log_data_t data;
181
182 data.ike_sa = this->thread_sa->get(this->thread_sa);
183 data.thread = thread_current_id();
184 data.group = group;
185 data.level = level;
186 data.format = format;
187 va_copy(data.args, args);
188
189 this->log_lock->read_lock(this->log_lock);
190 this->loggers->invoke_function(this->loggers, (void*)log_cb, &data);
191 this->log_lock->unlock(this->log_lock);
192
193 va_end(data.args);
194 }
195
196 METHOD(bus_t, log_, void,
197 private_bus_t *this, debug_t group, level_t level, char* format, ...)
198 {
199 va_list args;
200
201 va_start(args, format);
202 vlog(this, group, level, format, args);
203 va_end(args);
204 }
205
206 /**
207 * unregister a listener
208 */
209 static inline void unregister_listener(private_bus_t *this, entry_t *entry,
210 enumerator_t *enumerator)
211 {
212 this->listeners->remove_at(this->listeners, enumerator);
213 free(entry);
214 }
215
216 METHOD(bus_t, alert, void,
217 private_bus_t *this, alert_t alert, ...)
218 {
219 enumerator_t *enumerator;
220 ike_sa_t *ike_sa;
221 entry_t *entry;
222 va_list args;
223 bool keep;
224
225 ike_sa = this->thread_sa->get(this->thread_sa);
226
227 this->mutex->lock(this->mutex);
228 enumerator = this->listeners->create_enumerator(this->listeners);
229 while (enumerator->enumerate(enumerator, &entry))
230 {
231 if (entry->calling || !entry->listener->alert)
232 {
233 continue;
234 }
235 entry->calling++;
236 va_start(args, alert);
237 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
238 va_end(args);
239 entry->calling--;
240 if (!keep)
241 {
242 unregister_listener(this, entry, enumerator);
243 }
244 }
245 enumerator->destroy(enumerator);
246 this->mutex->unlock(this->mutex);
247 }
248
249 METHOD(bus_t, ike_state_change, void,
250 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
251 {
252 enumerator_t *enumerator;
253 entry_t *entry;
254 bool keep;
255
256 this->mutex->lock(this->mutex);
257 enumerator = this->listeners->create_enumerator(this->listeners);
258 while (enumerator->enumerate(enumerator, &entry))
259 {
260 if (entry->calling || !entry->listener->ike_state_change)
261 {
262 continue;
263 }
264 entry->calling++;
265 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
266 entry->calling--;
267 if (!keep)
268 {
269 unregister_listener(this, entry, enumerator);
270 }
271 }
272 enumerator->destroy(enumerator);
273 this->mutex->unlock(this->mutex);
274 }
275
276 METHOD(bus_t, child_state_change, void,
277 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
278 {
279 enumerator_t *enumerator;
280 ike_sa_t *ike_sa;
281 entry_t *entry;
282 bool keep;
283
284 ike_sa = this->thread_sa->get(this->thread_sa);
285
286 this->mutex->lock(this->mutex);
287 enumerator = this->listeners->create_enumerator(this->listeners);
288 while (enumerator->enumerate(enumerator, &entry))
289 {
290 if (entry->calling || !entry->listener->child_state_change)
291 {
292 continue;
293 }
294 entry->calling++;
295 keep = entry->listener->child_state_change(entry->listener, ike_sa,
296 child_sa, state);
297 entry->calling--;
298 if (!keep)
299 {
300 unregister_listener(this, entry, enumerator);
301 }
302 }
303 enumerator->destroy(enumerator);
304 this->mutex->unlock(this->mutex);
305 }
306
307 METHOD(bus_t, message, void,
308 private_bus_t *this, message_t *message, bool incoming, bool plain)
309 {
310 enumerator_t *enumerator;
311 ike_sa_t *ike_sa;
312 entry_t *entry;
313 bool keep;
314
315 ike_sa = this->thread_sa->get(this->thread_sa);
316
317 this->mutex->lock(this->mutex);
318 enumerator = this->listeners->create_enumerator(this->listeners);
319 while (enumerator->enumerate(enumerator, &entry))
320 {
321 if (entry->calling || !entry->listener->message)
322 {
323 continue;
324 }
325 entry->calling++;
326 keep = entry->listener->message(entry->listener, ike_sa,
327 message, incoming, plain);
328 entry->calling--;
329 if (!keep)
330 {
331 unregister_listener(this, entry, enumerator);
332 }
333 }
334 enumerator->destroy(enumerator);
335 this->mutex->unlock(this->mutex);
336 }
337
338 METHOD(bus_t, ike_keys, void,
339 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
340 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
341 ike_sa_t *rekey, shared_key_t *shared)
342 {
343 enumerator_t *enumerator;
344 entry_t *entry;
345 bool keep;
346
347 this->mutex->lock(this->mutex);
348 enumerator = this->listeners->create_enumerator(this->listeners);
349 while (enumerator->enumerate(enumerator, &entry))
350 {
351 if (entry->calling || !entry->listener->ike_keys)
352 {
353 continue;
354 }
355 entry->calling++;
356 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
357 nonce_i, nonce_r, rekey, shared);
358 entry->calling--;
359 if (!keep)
360 {
361 unregister_listener(this, entry, enumerator);
362 }
363 }
364 enumerator->destroy(enumerator);
365 this->mutex->unlock(this->mutex);
366 }
367
368 METHOD(bus_t, child_keys, void,
369 private_bus_t *this, child_sa_t *child_sa, bool initiator,
370 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
371 {
372 enumerator_t *enumerator;
373 ike_sa_t *ike_sa;
374 entry_t *entry;
375 bool keep;
376
377 ike_sa = this->thread_sa->get(this->thread_sa);
378
379 this->mutex->lock(this->mutex);
380 enumerator = this->listeners->create_enumerator(this->listeners);
381 while (enumerator->enumerate(enumerator, &entry))
382 {
383 if (entry->calling || !entry->listener->child_keys)
384 {
385 continue;
386 }
387 entry->calling++;
388 keep = entry->listener->child_keys(entry->listener, ike_sa,
389 child_sa, initiator, dh, nonce_i, nonce_r);
390 entry->calling--;
391 if (!keep)
392 {
393 unregister_listener(this, entry, enumerator);
394 }
395 }
396 enumerator->destroy(enumerator);
397 this->mutex->unlock(this->mutex);
398 }
399
400 METHOD(bus_t, child_updown, void,
401 private_bus_t *this, child_sa_t *child_sa, bool up)
402 {
403 enumerator_t *enumerator;
404 ike_sa_t *ike_sa;
405 entry_t *entry;
406 bool keep;
407
408 ike_sa = this->thread_sa->get(this->thread_sa);
409
410 this->mutex->lock(this->mutex);
411 enumerator = this->listeners->create_enumerator(this->listeners);
412 while (enumerator->enumerate(enumerator, &entry))
413 {
414 if (entry->calling || !entry->listener->child_updown)
415 {
416 continue;
417 }
418 entry->calling++;
419 keep = entry->listener->child_updown(entry->listener,
420 ike_sa, child_sa, up);
421 entry->calling--;
422 if (!keep)
423 {
424 unregister_listener(this, entry, enumerator);
425 }
426 }
427 enumerator->destroy(enumerator);
428 this->mutex->unlock(this->mutex);
429 }
430
431 METHOD(bus_t, child_rekey, void,
432 private_bus_t *this, child_sa_t *old, child_sa_t *new)
433 {
434 enumerator_t *enumerator;
435 ike_sa_t *ike_sa;
436 entry_t *entry;
437 bool keep;
438
439 ike_sa = this->thread_sa->get(this->thread_sa);
440
441 this->mutex->lock(this->mutex);
442 enumerator = this->listeners->create_enumerator(this->listeners);
443 while (enumerator->enumerate(enumerator, &entry))
444 {
445 if (entry->calling || !entry->listener->child_rekey)
446 {
447 continue;
448 }
449 entry->calling++;
450 keep = entry->listener->child_rekey(entry->listener, ike_sa,
451 old, new);
452 entry->calling--;
453 if (!keep)
454 {
455 unregister_listener(this, entry, enumerator);
456 }
457 }
458 enumerator->destroy(enumerator);
459 this->mutex->unlock(this->mutex);
460 }
461
462 METHOD(bus_t, ike_updown, void,
463 private_bus_t *this, ike_sa_t *ike_sa, bool up)
464 {
465 enumerator_t *enumerator;
466 entry_t *entry;
467 bool keep;
468
469 this->mutex->lock(this->mutex);
470 enumerator = this->listeners->create_enumerator(this->listeners);
471 while (enumerator->enumerate(enumerator, &entry))
472 {
473 if (entry->calling || !entry->listener->ike_updown)
474 {
475 continue;
476 }
477 entry->calling++;
478 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
479 entry->calling--;
480 if (!keep)
481 {
482 unregister_listener(this, entry, enumerator);
483 }
484 }
485 enumerator->destroy(enumerator);
486 this->mutex->unlock(this->mutex);
487
488 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
489 if (!up)
490 {
491 enumerator_t *enumerator;
492 child_sa_t *child_sa;
493
494 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
495 while (enumerator->enumerate(enumerator, (void**)&child_sa))
496 {
497 child_updown(this, child_sa, FALSE);
498 }
499 enumerator->destroy(enumerator);
500 }
501 }
502
503 METHOD(bus_t, ike_rekey, void,
504 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
505 {
506 enumerator_t *enumerator;
507 entry_t *entry;
508 bool keep;
509
510 this->mutex->lock(this->mutex);
511 enumerator = this->listeners->create_enumerator(this->listeners);
512 while (enumerator->enumerate(enumerator, &entry))
513 {
514 if (entry->calling || !entry->listener->ike_rekey)
515 {
516 continue;
517 }
518 entry->calling++;
519 keep = entry->listener->ike_rekey(entry->listener, old, new);
520 entry->calling--;
521 if (!keep)
522 {
523 unregister_listener(this, entry, enumerator);
524 }
525 }
526 enumerator->destroy(enumerator);
527 this->mutex->unlock(this->mutex);
528 }
529
530 METHOD(bus_t, authorize, bool,
531 private_bus_t *this, bool final)
532 {
533 enumerator_t *enumerator;
534 ike_sa_t *ike_sa;
535 entry_t *entry;
536 bool keep, success = TRUE;
537
538 ike_sa = this->thread_sa->get(this->thread_sa);
539
540 this->mutex->lock(this->mutex);
541 enumerator = this->listeners->create_enumerator(this->listeners);
542 while (enumerator->enumerate(enumerator, &entry))
543 {
544 if (entry->calling || !entry->listener->authorize)
545 {
546 continue;
547 }
548 entry->calling++;
549 keep = entry->listener->authorize(entry->listener, ike_sa,
550 final, &success);
551 entry->calling--;
552 if (!keep)
553 {
554 unregister_listener(this, entry, enumerator);
555 }
556 if (!success)
557 {
558 break;
559 }
560 }
561 enumerator->destroy(enumerator);
562 this->mutex->unlock(this->mutex);
563 return success;
564 }
565
566 METHOD(bus_t, narrow, void,
567 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
568 linked_list_t *local, linked_list_t *remote)
569 {
570 enumerator_t *enumerator;
571 ike_sa_t *ike_sa;
572 entry_t *entry;
573 bool keep;
574
575 ike_sa = this->thread_sa->get(this->thread_sa);
576
577 this->mutex->lock(this->mutex);
578 enumerator = this->listeners->create_enumerator(this->listeners);
579 while (enumerator->enumerate(enumerator, &entry))
580 {
581 if (entry->calling || !entry->listener->narrow)
582 {
583 continue;
584 }
585 entry->calling++;
586 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
587 type, local, remote);
588 entry->calling--;
589 if (!keep)
590 {
591 unregister_listener(this, entry, enumerator);
592 }
593 }
594 enumerator->destroy(enumerator);
595 this->mutex->unlock(this->mutex);
596 }
597
598 METHOD(bus_t, destroy, void,
599 private_bus_t *this)
600 {
601 this->listeners->destroy_function(this->listeners, (void*)free);
602 this->loggers->destroy(this->loggers);
603 this->thread_sa->destroy(this->thread_sa);
604 this->log_lock->destroy(this->log_lock);
605 this->mutex->destroy(this->mutex);
606 free(this);
607 }
608
609 /*
610 * Described in header.
611 */
612 bus_t *bus_create()
613 {
614 private_bus_t *this;
615
616 INIT(this,
617 .public = {
618 .add_listener = _add_listener,
619 .remove_listener = _remove_listener,
620 .add_logger = _add_logger,
621 .remove_logger = _remove_logger,
622 .set_sa = _set_sa,
623 .get_sa = _get_sa,
624 .log = _log_,
625 .vlog = _vlog,
626 .alert = _alert,
627 .ike_state_change = _ike_state_change,
628 .child_state_change = _child_state_change,
629 .message = _message,
630 .ike_keys = _ike_keys,
631 .child_keys = _child_keys,
632 .ike_updown = _ike_updown,
633 .ike_rekey = _ike_rekey,
634 .child_updown = _child_updown,
635 .child_rekey = _child_rekey,
636 .authorize = _authorize,
637 .narrow = _narrow,
638 .destroy = _destroy,
639 },
640 .listeners = linked_list_create(),
641 .loggers = linked_list_create(),
642 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
643 .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
644 .thread_sa = thread_value_create(NULL),
645 );
646
647 return &this->public;
648 }
649