183263f066dd88b521eaa90a28acf39b2d36e00e
[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 int current_num = 0, stored_num;
163
164 stored_num = (int)(intptr_t)pthread_getspecific(this->thread_id);
165 if (stored_num == 0)
166 { /* first call of current thread */
167 pthread_setspecific(this->thread_id, (void*)(intptr_t)++current_num);
168 return current_num;
169 }
170 else
171 {
172 return stored_num;
173 }
174 }
175
176 /**
177 * Implementation of bus_t.add_listener.
178 */
179 static void add_listener(private_bus_t *this, bus_listener_t *listener)
180 {
181 pthread_mutex_lock(&this->mutex);
182 this->listeners->insert_last(this->listeners, (void*)listener);
183 pthread_mutex_unlock(&this->mutex);
184 }
185
186 /**
187 * Get the listener object for the calling thread
188 */
189 static active_listener_t *get_active_listener(private_bus_t *this)
190 {
191 active_listener_t *current, *found = NULL;
192 iterator_t *iterator;
193
194 /* if the thread was here once before, we have a active_listener record */
195 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
196 while (iterator->iterate(iterator, (void**)&current))
197 {
198 if (current->id == pthread_self())
199 {
200 found = current;
201 break;
202 }
203 }
204 iterator->destroy(iterator);
205
206 if (found == NULL)
207 {
208 /* create a new object for a never-seen thread */
209 found = malloc_thing(active_listener_t);
210 found->id = pthread_self();
211 pthread_cond_init(&found->cond, NULL);
212 this->active_listeners->insert_last(this->active_listeners, found);
213 }
214
215 return found;
216 }
217
218 /**
219 * Implementation of bus_t.listen.
220 */
221 static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
222 ike_sa_t **ike_sa, char** format, va_list* args)
223 {
224 active_listener_t *listener;
225
226 pthread_mutex_lock(&this->mutex);
227 listener = get_active_listener(this);
228 /* go "listening", say hello to a thread which have a signal for us */
229 listener->state = LISTENING;
230 pthread_cond_broadcast(&listener->cond);
231 /* wait until it has us delivered a signal, and go back to "registered" */
232 pthread_cond_wait(&listener->cond, &this->mutex);
233 pthread_mutex_unlock(&this->mutex);
234
235 /* return signal values */
236 *level = listener->level;
237 *thread = listener->thread;
238 *ike_sa = listener->ike_sa;
239 *format = listener->format;
240 va_copy(*args, listener->args);
241 va_end(listener->args);
242
243 return listener->signal;
244 }
245
246 /**
247 * Implementation of bus_t.set_listen_state.
248 */
249 static void set_listen_state(private_bus_t *this, bool active)
250 {
251 active_listener_t *listener;
252
253 pthread_mutex_lock(&this->mutex);
254
255 listener = get_active_listener(this);
256 if (active)
257 {
258 listener->state = REGISTERED;
259 }
260 else
261 {
262 listener->state = UNREGISTERED;
263 /* say hello to signal emitter; we are finished processing the signal */
264 pthread_cond_signal(&listener->cond);
265 }
266
267 pthread_mutex_unlock(&this->mutex);
268 }
269
270
271 /**
272 * Implementation of bus_t.set_sa.
273 */
274 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
275 {
276 pthread_setspecific(this->thread_sa, ike_sa);
277 }
278
279 /**
280 * Implementation of bus_t.vsignal.
281 */
282 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
283 char* format, va_list args)
284 {
285 iterator_t *iterator;
286 bus_listener_t *listener;
287 active_listener_t *active_listener;
288 ike_sa_t *ike_sa;
289 long thread;
290
291 ike_sa = pthread_getspecific(this->thread_sa);
292 thread = get_thread_number(this);
293
294 pthread_mutex_lock(&this->mutex);
295
296 /* do the job for all passive bus_listeners */
297 iterator = this->listeners->create_iterator(this->listeners, TRUE);
298 while (iterator->iterate(iterator, (void**)&listener))
299 {
300 va_list args_copy;
301
302 va_copy(args_copy, args);
303 listener->signal(listener, signal, level, thread, ike_sa, format, args_copy);
304 va_end(args_copy);
305 }
306 iterator->destroy(iterator);
307
308 /* wake up all active listeners */
309 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
310 while (iterator->iterate(iterator, (void**)&active_listener))
311 {
312 /* wait until it is back */
313 while (active_listener->state == REGISTERED)
314 {
315 pthread_cond_wait(&active_listener->cond, &this->mutex);
316 }
317 /* if thread is listening now, give it the signal to process */
318 if (active_listener->state == LISTENING)
319 {
320 active_listener->level = level;
321 active_listener->thread = thread;
322 active_listener->ike_sa = ike_sa;
323 active_listener->signal = signal;
324 active_listener->format = format;
325 va_copy(active_listener->args, args);
326 active_listener->state = REGISTERED;
327 pthread_cond_signal(&active_listener->cond);
328 }
329 }
330
331 /* we must wait now until all are not in state REGISTERED,
332 * as they may still use our arguments */
333 iterator->reset(iterator);
334 while (iterator->iterate(iterator, (void**)&active_listener))
335 {
336 while (active_listener->state == REGISTERED)
337 {
338 pthread_cond_wait(&active_listener->cond, &this->mutex);
339 }
340 }
341 iterator->destroy(iterator);
342
343 pthread_mutex_unlock(&this->mutex);
344 }
345
346 /**
347 * Implementation of bus_t.signal.
348 */
349 static void signal_(private_bus_t *this, signal_t signal, level_t level,
350 char* format, ...)
351 {
352 va_list args;
353
354 va_start(args, format);
355 vsignal(this, signal, level, format, args);
356 va_end(args);
357 }
358
359 /**
360 * Implementation of bus_t.destroy.
361 */
362 static void destroy(private_bus_t *this)
363 {
364 this->active_listeners->destroy_function(this->active_listeners, free);
365 this->listeners->destroy(this->listeners);
366 free(this);
367 }
368
369 /*
370 * Described in header.
371 */
372 bus_t *bus_create()
373 {
374 private_bus_t *this = malloc_thing(private_bus_t);
375
376 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
377 this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
378 this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
379 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
380 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
381 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
382 this->public.destroy = (void(*)(bus_t*)) destroy;
383
384 this->listeners = linked_list_create();
385 this->active_listeners = linked_list_create();
386 pthread_mutex_init(&this->mutex, NULL);
387 pthread_key_create(&this->thread_id, NULL);
388 pthread_key_create(&this->thread_sa, NULL);
389
390 return &(this->public);
391 }