dynamic logging configuration through strongswan.conf
[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 * $Id$
16 */
17
18 #include "bus.h"
19
20 #include <pthread.h>
21 #include <stdint.h>
22
23 #include <daemon.h>
24 #include <utils/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 for a unique, simple thread ID
75 */
76 pthread_key_t thread_id;
77
78 /**
79 * Thread local storage the threads IKE_SA
80 */
81 pthread_key_t thread_sa;
82 };
83
84 typedef struct entry_t entry_t;
85
86 /**
87 * a listener entry, either active or passive
88 */
89 struct entry_t {
90
91 /**
92 * registered listener interface
93 */
94 listener_t *listener;
95
96 /**
97 * is this a active listen() call with a blocking thread
98 */
99 bool blocker;
100
101 /**
102 * are we currently calling this listener
103 */
104 int calling;
105
106 /**
107 * condvar where active listeners wait
108 */
109 condvar_t *condvar;
110 };
111
112 /**
113 * create a listener entry
114 */
115 static entry_t *entry_create(listener_t *listener, bool blocker)
116 {
117 entry_t *this = malloc_thing(entry_t);
118
119 this->listener = listener;
120 this->blocker = blocker;
121 this->calling = 0;
122 this->condvar = condvar_create(CONDVAR_DEFAULT);
123
124 return this;
125 }
126
127 /**
128 * destroy an entry_t
129 */
130 static void entry_destroy(entry_t *entry)
131 {
132 entry->condvar->destroy(entry->condvar);
133 free(entry);
134 }
135
136 /**
137 * Get a unique thread number for a calling thread. Since
138 * pthread_self returns large and ugly numbers, use this function
139 * for logging; these numbers are incremental starting at 1
140 */
141 static u_int get_thread_number(private_bus_t *this)
142 {
143 static uintptr_t current_num = 0;
144 uintptr_t stored_num;
145
146 stored_num = (uintptr_t)pthread_getspecific(this->thread_id);
147 if (stored_num == 0)
148 { /* first call of current thread */
149 pthread_setspecific(this->thread_id, (void*)++current_num);
150 return current_num;
151 }
152 else
153 {
154 return stored_num;
155 }
156 }
157
158 /**
159 * Implementation of bus_t.add_listener.
160 */
161 static void add_listener(private_bus_t *this, listener_t *listener)
162 {
163 this->mutex->lock(this->mutex);
164 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
165 this->mutex->unlock(this->mutex);
166 }
167
168 /**
169 * Implementation of bus_t.remove_listener.
170 */
171 static void remove_listener(private_bus_t *this, listener_t *listener)
172 {
173 enumerator_t *enumerator;
174 entry_t *entry;
175
176 this->mutex->lock(this->mutex);
177 enumerator = this->listeners->create_enumerator(this->listeners);
178 while (enumerator->enumerate(enumerator, &entry))
179 {
180 if (entry->listener == listener)
181 {
182 this->listeners->remove_at(this->listeners, enumerator);
183 entry_destroy(entry);
184 break;
185 }
186 }
187 enumerator->destroy(enumerator);
188 this->mutex->unlock(this->mutex);
189 }
190
191 typedef struct cleanup_data_t cleanup_data_t;
192
193 /**
194 * data to remove a listener using pthread_cleanup handler
195 */
196 struct cleanup_data_t {
197 /** bus instance */
198 private_bus_t *this;
199 /** listener entry */
200 entry_t *entry;
201 };
202
203 /**
204 * pthread_cleanup handler to remove a listener
205 */
206 static void listener_cleanup(cleanup_data_t *data)
207 {
208 data->this->listeners->remove(data->this->listeners, data->entry, NULL);
209 entry_destroy(data->entry);
210 }
211
212 /**
213 * Implementation of bus_t.listen.
214 */
215 static void listen_(private_bus_t *this, listener_t *listener, job_t *job)
216 {
217 int old;
218 cleanup_data_t data;
219
220 data.this = this;
221 data.entry = entry_create(listener, TRUE);
222
223 this->mutex->lock(this->mutex);
224 this->listeners->insert_last(this->listeners, data.entry);
225 charon->processor->queue_job(charon->processor, job);
226 pthread_cleanup_push((void*)this->mutex->unlock, this->mutex);
227 pthread_cleanup_push((void*)listener_cleanup, &data);
228 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
229 while (data.entry->blocker)
230 {
231 data.entry->condvar->wait(data.entry->condvar, this->mutex);
232 }
233 pthread_setcancelstate(old, NULL);
234 pthread_cleanup_pop(FALSE);
235 /* unlock mutex */
236 pthread_cleanup_pop(TRUE);
237 entry_destroy(data.entry);
238 }
239
240 /**
241 * Implementation of bus_t.set_sa.
242 */
243 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
244 {
245 pthread_setspecific(this->thread_sa, ike_sa);
246 }
247
248 /**
249 * data associated to a signal, passed to callback
250 */
251 typedef struct {
252 /** associated IKE_SA */
253 ike_sa_t *ike_sa;
254 /** invoking thread */
255 long thread;
256 /** debug group */
257 debug_t group;
258 /** debug level */
259 level_t level;
260 /** format string */
261 char *format;
262 /** argument list */
263 va_list args;
264 } log_data_t;
265
266 /**
267 * listener->log() invocation as a list remove callback
268 */
269 static bool log_cb(entry_t *entry, log_data_t *data)
270 {
271 va_list args;
272
273 if (entry->calling || !entry->listener->log)
274 { /* avoid recursive calls */
275 return FALSE;
276 }
277 entry->calling++;
278 va_copy(args, data->args);
279 if (!entry->listener->log(entry->listener, data->group, data->level,
280 data->thread, data->ike_sa, data->format, args))
281 {
282 if (entry->blocker)
283 {
284 entry->blocker = FALSE;
285 entry->condvar->signal(entry->condvar);
286 }
287 else
288 {
289 entry_destroy(entry);
290 }
291 va_end(args);
292 entry->calling--;
293 return TRUE;
294 }
295 va_end(args);
296 entry->calling--;
297 return FALSE;
298 }
299
300 /**
301 * Implementation of bus_t.vlog.
302 */
303 static void vlog(private_bus_t *this, debug_t group, level_t level,
304 char* format, va_list args)
305 {
306 log_data_t data;
307
308 data.ike_sa = pthread_getspecific(this->thread_sa);
309 data.thread = get_thread_number(this);
310 data.group = group;
311 data.level = level;
312 data.format = format;
313 va_copy(data.args, args);
314
315 this->mutex->lock(this->mutex);
316 /* We use the remove() method to invoke all listeners. This is cheap and
317 * does not require an allocation for this performance critical function. */
318 this->listeners->remove(this->listeners, &data, (void*)log_cb);
319 this->mutex->unlock(this->mutex);
320
321 va_end(data.args);
322 }
323
324 /**
325 * Implementation of bus_t.log.
326 */
327 static void log_(private_bus_t *this, debug_t group, level_t level,
328 char* format, ...)
329 {
330 va_list args;
331
332 va_start(args, format);
333 vlog(this, group, level, format, args);
334 va_end(args);
335 }
336
337 /**
338 * unregister a listener
339 */
340 static void unregister_listener(private_bus_t *this, entry_t *entry,
341 enumerator_t *enumerator)
342 {
343 if (entry->blocker)
344 {
345 entry->blocker = FALSE;
346 entry->condvar->signal(entry->condvar);
347 }
348 else
349 {
350 entry_destroy(entry);
351 }
352 this->listeners->remove_at(this->listeners, enumerator);
353 }
354
355 /**
356 * Implementation of bus_t.ike_state_change
357 */
358 static void ike_state_change(private_bus_t *this, ike_sa_t *ike_sa,
359 ike_sa_state_t state)
360 {
361 enumerator_t *enumerator;
362 entry_t *entry;
363 bool keep;
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->ike_state_change)
370 {
371 continue;
372 }
373 entry->calling++;
374 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
375 entry->calling--;
376 if (!keep)
377 {
378 unregister_listener(this, entry, enumerator);
379 break;
380 }
381 }
382 enumerator->destroy(enumerator);
383 this->mutex->unlock(this->mutex);
384 }
385
386 /**
387 * Implementation of bus_t.child_state_change
388 */
389 static void child_state_change(private_bus_t *this, child_sa_t *child_sa,
390 child_sa_state_t state)
391 {
392 enumerator_t *enumerator;
393 ike_sa_t *ike_sa;
394 entry_t *entry;
395 bool keep;
396
397 ike_sa = pthread_getspecific(this->thread_sa);
398
399 this->mutex->lock(this->mutex);
400 enumerator = this->listeners->create_enumerator(this->listeners);
401 while (enumerator->enumerate(enumerator, &entry))
402 {
403 if (entry->calling || !entry->listener->child_state_change)
404 {
405 continue;
406 }
407 entry->calling++;
408 keep = entry->listener->child_state_change(entry->listener, ike_sa,
409 child_sa, state);
410 entry->calling--;
411 if (!keep)
412 {
413 unregister_listener(this, entry, enumerator);
414 break;
415 }
416 }
417 enumerator->destroy(enumerator);
418 this->mutex->unlock(this->mutex);
419 }
420
421 /**
422 * Implementation of bus_t.message
423 */
424 static void message(private_bus_t *this, message_t *message, bool incoming)
425 {
426 enumerator_t *enumerator;
427 ike_sa_t *ike_sa;
428 entry_t *entry;
429 bool keep;
430
431 ike_sa = pthread_getspecific(this->thread_sa);
432
433 this->mutex->lock(this->mutex);
434 enumerator = this->listeners->create_enumerator(this->listeners);
435 while (enumerator->enumerate(enumerator, &entry))
436 {
437 if (entry->calling || !entry->listener->message)
438 {
439 continue;
440 }
441 entry->calling++;
442 keep = entry->listener->message(entry->listener, ike_sa,
443 message, incoming);
444 entry->calling--;
445 if (!keep)
446 {
447 unregister_listener(this, entry, enumerator);
448 break;
449 }
450 }
451 enumerator->destroy(enumerator);
452 this->mutex->unlock(this->mutex);
453 }
454
455 /**
456 * Implementation of bus_t.ike_keys
457 */
458 static void ike_keys(private_bus_t *this, ike_sa_t *ike_sa,
459 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
460 ike_sa_t *rekey)
461 {
462 enumerator_t *enumerator;
463 entry_t *entry;
464 bool keep;
465
466 this->mutex->lock(this->mutex);
467 enumerator = this->listeners->create_enumerator(this->listeners);
468 while (enumerator->enumerate(enumerator, &entry))
469 {
470 if (entry->calling || !entry->listener->ike_keys)
471 {
472 continue;
473 }
474 entry->calling++;
475 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
476 nonce_i, nonce_r, rekey);
477 entry->calling--;
478 if (!keep)
479 {
480 unregister_listener(this, entry, enumerator);
481 break;
482 }
483 }
484 enumerator->destroy(enumerator);
485 this->mutex->unlock(this->mutex);
486 }
487
488 /**
489 * Implementation of bus_t.child_keys
490 */
491 static void child_keys(private_bus_t *this, child_sa_t *child_sa,
492 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
493 {
494 enumerator_t *enumerator;
495 ike_sa_t *ike_sa;
496 entry_t *entry;
497 bool keep;
498
499 ike_sa = pthread_getspecific(this->thread_sa);
500
501 this->mutex->lock(this->mutex);
502 enumerator = this->listeners->create_enumerator(this->listeners);
503 while (enumerator->enumerate(enumerator, &entry))
504 {
505 if (entry->calling || !entry->listener->child_keys)
506 {
507 continue;
508 }
509 entry->calling++;
510 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
511 dh, nonce_i, nonce_r);
512 entry->calling--;
513 if (!keep)
514 {
515 unregister_listener(this, entry, enumerator);
516 break;
517 }
518 }
519 enumerator->destroy(enumerator);
520 this->mutex->unlock(this->mutex);
521 }
522
523 /**
524 * Implementation of bus_t.destroy.
525 */
526 static void destroy(private_bus_t *this)
527 {
528 this->mutex->destroy(this->mutex);
529 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
530 free(this);
531 }
532
533 /*
534 * Described in header.
535 */
536 bus_t *bus_create()
537 {
538 private_bus_t *this = malloc_thing(private_bus_t);
539
540 this->public.add_listener = (void(*)(bus_t*,listener_t*))add_listener;
541 this->public.remove_listener = (void(*)(bus_t*,listener_t*))remove_listener;
542 this->public.listen = (void(*)(bus_t*, listener_t *listener, job_t *job))listen_;
543 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
544 this->public.log = (void(*)(bus_t*,debug_t,level_t,char*,...))log_;
545 this->public.vlog = (void(*)(bus_t*,debug_t,level_t,char*,va_list))vlog;
546 this->public.ike_state_change = (void(*)(bus_t*,ike_sa_t*,ike_sa_state_t))ike_state_change;
547 this->public.child_state_change = (void(*)(bus_t*,child_sa_t*,child_sa_state_t))child_state_change;
548 this->public.message = (void(*)(bus_t*, message_t *message, bool incoming))message;
549 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;
550 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;
551 this->public.destroy = (void(*)(bus_t*)) destroy;
552
553 this->listeners = linked_list_create();
554 this->mutex = mutex_create(MUTEX_RECURSIVE);
555 pthread_key_create(&this->thread_id, NULL);
556 pthread_key_create(&this->thread_sa, NULL);
557
558 return &this->public;
559 }
560