further mobike improvements, regarding to NAT-T
[strongswan.git] / src / charon / bus / bus.c
1 /**
2 * @file bus.c
3 *
4 * @brief Implementation of bus_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "bus.h"
24
25 #include <pthread.h>
26
27 ENUM(signal_names, SIG_ANY, SIG_MAX,
28 /** should not get printed */
29 "SIG_ANY",
30 /** debugging message types */
31 "DMN",
32 "MGR",
33 "IKE",
34 "CHD",
35 "JOB",
36 "CFG",
37 "KNL",
38 "NET",
39 "ENC",
40 "LIB",
41 /** should not get printed */
42 "SIG_DBG_MAX",
43 /** all level0 signals are AUDIT signals */
44 "AUD", "AUD", "AUD",
45 "AUD", "AUD", "AUD",
46 "AUD", "AUD", "AUD",
47 "AUD", "AUD", "AUD",
48 "AUD", "AUD", "AUD",
49 "AUD", "AUD", "AUD",
50 "AUD", "AUD", "AUD",
51 "AUD", "AUD", "AUD",
52 /** should not get printed */
53 "SIG_MAX",
54 );
55
56 typedef struct active_listener_t active_listener_t;
57
58 /**
59 * information for a active listener
60 */
61 struct active_listener_t {
62
63 /**
64 * associated thread
65 */
66 pthread_t id;
67
68 /**
69 * condvar to wait for a signal
70 */
71 pthread_cond_t cond;
72
73 /**
74 * state of the thread
75 */
76 enum {
77 /** not registered, do not wait for thread */
78 UNREGISTERED,
79 /** registered, if a signal occurs, wait until it is LISTENING */
80 REGISTERED,
81 /** listening, deliver signal */
82 LISTENING,
83 } state;
84
85 /**
86 * currently processed signals type
87 */
88 signal_t signal;
89
90 /**
91 * verbosity level of the signal
92 */
93 level_t level;
94
95 /**
96 * current processed signals thread number
97 */
98 int thread;
99
100 /**
101 * currently processed signals ike_sa
102 */
103 ike_sa_t *ike_sa;
104
105 /**
106 * currently processed signals format string
107 */
108 char *format;
109
110 /**
111 * currently processed signals format varargs
112 */
113 va_list args;
114
115 };
116
117 typedef struct private_bus_t private_bus_t;
118
119 /**
120 * Private data of a bus_t object.
121 */
122 struct private_bus_t {
123 /**
124 * Public part of a bus_t object.
125 */
126 bus_t public;
127
128 /**
129 * List of registered listeners implementing the bus_t interface
130 */
131 linked_list_t *listeners;
132
133 /**
134 * List of active listeners with listener_state TRUE
135 */
136 linked_list_t *active_listeners;
137
138 /**
139 * mutex to synchronize active listeners
140 */
141 pthread_mutex_t mutex;
142
143 /**
144 * Thread local storage for a unique, simple thread ID
145 */
146 pthread_key_t thread_id;
147
148 /**
149 * Thread local storage the threads IKE_SA
150 */
151 pthread_key_t thread_sa;
152
153 };
154
155 /**
156 * Get a unique thread number for a calling thread. Since
157 * pthread_self returns large and ugly numbers, use this function
158 * for logging; these numbers are incremental starting at 1
159 */
160 static int get_thread_number(private_bus_t *this)
161 {
162 static long current_num = 0;
163 static long stored_num;
164
165 stored_num = (long)pthread_getspecific(this->thread_id);
166 if (stored_num == 0)
167 { /* first call of current thread */
168 pthread_setspecific(this->thread_id, (void*)++current_num);
169 return current_num;
170 }
171 else
172 {
173 return stored_num;
174 }
175 }
176
177 /**
178 * Implementation of bus_t.add_listener.
179 */
180 static void add_listener(private_bus_t *this, bus_listener_t *listener)
181 {
182 pthread_mutex_lock(&this->mutex);
183 this->listeners->insert_last(this->listeners, listener);
184 pthread_mutex_unlock(&this->mutex);
185 }
186
187 /**
188 * Implementation of bus_t.remove_listener.
189 */
190 static void remove_listener(private_bus_t *this, bus_listener_t *listener)
191 {
192 iterator_t *iterator;
193 bus_listener_t *current;
194
195 pthread_mutex_lock(&this->mutex);
196 iterator = this->listeners->create_iterator(this->listeners, TRUE);
197 while (iterator->iterate(iterator, (void**)&current))
198 {
199 if (current == listener)
200 {
201 iterator->remove(iterator);
202 break;
203 }
204 }
205 iterator->destroy(iterator);
206 pthread_mutex_unlock(&this->mutex);
207 }
208
209 /**
210 * Get the listener object for the calling thread
211 */
212 static active_listener_t *get_active_listener(private_bus_t *this)
213 {
214 active_listener_t *current, *found = NULL;
215 iterator_t *iterator;
216
217 /* if the thread was here once before, we have a active_listener record */
218 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
219 while (iterator->iterate(iterator, (void**)&current))
220 {
221 if (current->id == pthread_self())
222 {
223 found = current;
224 break;
225 }
226 }
227 iterator->destroy(iterator);
228
229 if (found == NULL)
230 {
231 /* create a new object for a never-seen thread */
232 found = malloc_thing(active_listener_t);
233 found->id = pthread_self();
234 pthread_cond_init(&found->cond, NULL);
235 this->active_listeners->insert_last(this->active_listeners, found);
236 }
237
238 return found;
239 }
240
241 /**
242 * disable a listener to cleanly clean up
243 */
244 static void unregister(active_listener_t *listener)
245 {
246 listener->state = UNREGISTERED;
247 pthread_cond_broadcast(&listener->cond);
248 }
249
250 /**
251 * Implementation of bus_t.listen.
252 */
253 static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
254 ike_sa_t **ike_sa, char** format, va_list* args)
255 {
256 active_listener_t *listener;
257 int oldstate;
258
259 pthread_mutex_lock(&this->mutex);
260 listener = get_active_listener(this);
261 /* go "listening", say hello to a thread which have a signal for us */
262 listener->state = LISTENING;
263 pthread_cond_broadcast(&listener->cond);
264 /* wait until it has us delivered a signal, and go back to "registered".
265 * we allow cancellation here, but must cleanly disable the listener. */
266 pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
267 pthread_cleanup_push((void*)unregister, listener);
268 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
269 pthread_cond_wait(&listener->cond, &this->mutex);
270 pthread_setcancelstate(oldstate, NULL);
271 pthread_cleanup_pop(0);
272 pthread_cleanup_pop(0);
273
274 pthread_mutex_unlock(&this->mutex);
275
276 /* return signal values */
277 *level = listener->level;
278 *thread = listener->thread;
279 *ike_sa = listener->ike_sa;
280 *format = listener->format;
281 va_copy(*args, listener->args);
282 va_end(listener->args);
283
284 return listener->signal;
285 }
286
287 /**
288 * Implementation of bus_t.set_listen_state.
289 */
290 static void set_listen_state(private_bus_t *this, bool active)
291 {
292 active_listener_t *listener;
293
294 pthread_mutex_lock(&this->mutex);
295
296 listener = get_active_listener(this);
297 if (active)
298 {
299 listener->state = REGISTERED;
300 }
301 else
302 {
303 listener->state = UNREGISTERED;
304 /* say hello to signal emitter; we are finished processing the signal */
305 pthread_cond_broadcast(&listener->cond);
306 }
307
308 pthread_mutex_unlock(&this->mutex);
309 }
310
311
312 /**
313 * Implementation of bus_t.set_sa.
314 */
315 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
316 {
317 pthread_setspecific(this->thread_sa, ike_sa);
318 }
319
320 /**
321 * Implementation of bus_t.vsignal.
322 */
323 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
324 char* format, va_list args)
325 {
326 iterator_t *iterator;
327 bus_listener_t *listener;
328 active_listener_t *active_listener;
329 ike_sa_t *ike_sa;
330 long thread;
331
332 ike_sa = pthread_getspecific(this->thread_sa);
333 thread = get_thread_number(this);
334
335 pthread_mutex_lock(&this->mutex);
336
337 /* do the job for all passive bus_listeners */
338 iterator = this->listeners->create_iterator(this->listeners, TRUE);
339 while (iterator->iterate(iterator, (void**)&listener))
340 {
341 va_list args_copy;
342 va_copy(args_copy, args);
343 if (!listener->signal(listener, signal, level, thread,
344 ike_sa, format, args_copy))
345 {
346 /* unregister listener if requested */
347 iterator->remove(iterator);
348 }
349 va_end(args_copy);
350 }
351 iterator->destroy(iterator);
352
353 /* wake up all active listeners */
354 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
355 while (iterator->iterate(iterator, (void**)&active_listener))
356 {
357 /* wait until all threads are registered. But if the thread raising
358 * the signal is the same as the one that listens, we skip it.
359 * Otherwise we would deadlock. */
360 while (active_listener->id != pthread_self() &&
361 active_listener->state == REGISTERED)
362 {
363 pthread_cond_wait(&active_listener->cond, &this->mutex);
364 }
365 /* if thread is listening now, give it the signal to process */
366 if (active_listener->state == LISTENING)
367 {
368 active_listener->level = level;
369 active_listener->thread = thread;
370 active_listener->ike_sa = ike_sa;
371 active_listener->signal = signal;
372 active_listener->format = format;
373 va_copy(active_listener->args, args);
374 active_listener->state = REGISTERED;
375 pthread_cond_broadcast(&active_listener->cond);
376 }
377 }
378
379 /* we must wait now until all are not in state REGISTERED,
380 * as they may still use our arguments */
381 iterator->reset(iterator);
382 while (iterator->iterate(iterator, (void**)&active_listener))
383 {
384 /* do not wait for ourself, it won't happen (see above) */
385 while (active_listener->id != pthread_self() &&
386 active_listener->state == REGISTERED)
387 {
388 pthread_cond_wait(&active_listener->cond, &this->mutex);
389 }
390 }
391 iterator->destroy(iterator);
392
393 pthread_mutex_unlock(&this->mutex);
394 }
395
396 /**
397 * Implementation of bus_t.signal.
398 */
399 static void signal_(private_bus_t *this, signal_t signal, level_t level,
400 char* format, ...)
401 {
402 va_list args;
403
404 va_start(args, format);
405 vsignal(this, signal, level, format, args);
406 va_end(args);
407 }
408
409 /**
410 * Implementation of bus_t.destroy.
411 */
412 static void destroy(private_bus_t *this)
413 {
414 this->active_listeners->destroy_function(this->active_listeners, free);
415 this->listeners->destroy(this->listeners);
416 free(this);
417 }
418
419 /*
420 * Described in header.
421 */
422 bus_t *bus_create()
423 {
424 private_bus_t *this = malloc_thing(private_bus_t);
425
426 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
427 this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
428 this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
429 this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
430 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
431 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
432 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
433 this->public.destroy = (void(*)(bus_t*)) destroy;
434
435 this->listeners = linked_list_create();
436 this->active_listeners = linked_list_create();
437 pthread_mutex_init(&this->mutex, NULL);
438 pthread_key_create(&this->thread_id, NULL);
439 pthread_key_create(&this->thread_sa, NULL);
440
441 return &(this->public);
442 }