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