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