introduced new logging subsystem using bus:
[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",
45 "AUD",
46 "AUD",
47 "AUD",
48 "AUD",
49 "AUD",
50 "AUD",
51 "AUD",
52 "AUD",
53 "AUD",
54 "AUD",
55 "AUD",
56 /** should not get printed */
57 "SIG_MAX",
58 );
59
60 typedef struct active_listener_t active_listener_t;
61
62 /**
63 * information for a active listener
64 */
65 struct active_listener_t {
66
67 /**
68 * associated thread
69 */
70 pthread_t id;
71
72 /**
73 * condvar to wait for a signal
74 */
75 pthread_cond_t cond;
76
77 /**
78 * state of the thread
79 */
80 enum {
81 /** not registered, do not wait for thread */
82 UNREGISTERED,
83 /** registered, if a signal occurs, wait until it is LISTENING */
84 REGISTERED,
85 /** listening, deliver signal */
86 LISTENING,
87 } state;
88
89 /**
90 * currently processed signals type
91 */
92 signal_t signal;
93
94 /**
95 * verbosity level of the signal
96 */
97 level_t level;
98
99 /**
100 * current processed signals thread number
101 */
102 int thread;
103
104 /**
105 * currently processed signals ike_sa
106 */
107 ike_sa_t *ike_sa;
108
109 /**
110 * currently processed signals format string
111 */
112 char *format;
113
114 /**
115 * currently processed signals format varargs
116 */
117 va_list args;
118
119 };
120
121 typedef struct private_bus_t private_bus_t;
122
123 /**
124 * Private data of a bus_t object.
125 */
126 struct private_bus_t {
127 /**
128 * Public part of a bus_t object.
129 */
130 bus_t public;
131
132 /**
133 * List of registered listeners implementing the bus_t interface
134 */
135 linked_list_t *listeners;
136
137 /**
138 * List of active listeners with listener_state TRUE
139 */
140 linked_list_t *active_listeners;
141
142 /**
143 * mutex to synchronize active listeners
144 */
145 pthread_mutex_t mutex;
146
147 /**
148 * Thread local storage for a unique, simple thread ID
149 */
150 pthread_key_t thread_id;
151
152 /**
153 * Thread local storage the threads IKE_SA
154 */
155 pthread_key_t thread_sa;
156
157 };
158
159 /**
160 * Get a unique thread number for a calling thread. Since
161 * pthread_self returns large and ugly numbers, use this function
162 * for logging; these numbers are incremental starting at 1
163 */
164 static int get_thread_number(private_bus_t *this)
165 {
166 static int current_num = 0, stored_num;
167
168 stored_num = (int)pthread_getspecific(this->thread_id);
169 if (stored_num == 0)
170 { /* first call of current thread */
171 pthread_setspecific(this->thread_id, (void*)++current_num);
172 return current_num;
173 }
174 else
175 {
176 return stored_num;
177 }
178 }
179
180 /**
181 * Implementation of bus_t.add_listener.
182 */
183 static void add_listener(private_bus_t *this, bus_listener_t *listener)
184 {
185 pthread_mutex_lock(&this->mutex);
186 this->listeners->insert_last(this->listeners, (void*)listener);
187 pthread_mutex_unlock(&this->mutex);
188 }
189
190 /**
191 * Get the listener object for the calling thread
192 */
193 static active_listener_t *get_active_listener(private_bus_t *this)
194 {
195 active_listener_t *current, *found = NULL;
196 iterator_t *iterator;
197
198 /* if the thread was here once before, we have a active_listener record */
199 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
200 while (iterator->iterate(iterator, (void**)&current))
201 {
202 if (current->id == pthread_self())
203 {
204 found = current;
205 break;
206 }
207 }
208 iterator->destroy(iterator);
209
210 if (found == NULL)
211 {
212 /* create a new object for a never-seen thread */
213 found = malloc_thing(active_listener_t);
214 found->id = pthread_self();
215 pthread_cond_init(&found->cond, NULL);
216 this->active_listeners->insert_last(this->active_listeners, found);
217 }
218
219 return found;
220 }
221
222 /**
223 * Implementation of bus_t.listen.
224 */
225 static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
226 ike_sa_t **ike_sa, char** format, va_list* args)
227 {
228 active_listener_t *listener;
229
230 pthread_mutex_lock(&this->mutex);
231 listener = get_active_listener(this);
232 /* go "listening", say hello to a thread which have a signal for us */
233 listener->state = LISTENING;
234 pthread_cond_broadcast(&listener->cond);
235 /* wait until it has us delivered a signal, and go back to "registered" */
236 pthread_cond_wait(&listener->cond, &this->mutex);
237 pthread_mutex_unlock(&this->mutex);
238
239 /* return signal values */
240 *level = listener->level;
241 *thread = listener->thread;
242 *ike_sa = listener->ike_sa;
243 *format = listener->format;
244 *args = listener->args;
245
246 return listener->signal;
247 }
248
249 /**
250 * Implementation of bus_t.set_listen_state.
251 */
252 static void set_listen_state(private_bus_t *this, bool active)
253 {
254 active_listener_t *listener;
255
256 pthread_mutex_lock(&this->mutex);
257
258 listener = get_active_listener(this);
259 if (active)
260 {
261 listener->state = REGISTERED;
262 }
263 else
264 {
265 listener->state = UNREGISTERED;
266 /* say hello to signal omitter; we are finished processing the signal */
267 pthread_cond_signal(&listener->cond);
268 }
269
270 pthread_mutex_unlock(&this->mutex);
271 }
272
273
274 /**
275 * Implementation of bus_t.set_sa.
276 */
277 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
278 {
279 pthread_setspecific(this->thread_sa, ike_sa);
280 }
281
282 /**
283 * Implementation of bus_t.vsignal.
284 */
285 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
286 char* format, va_list args)
287 {
288 iterator_t *iterator;
289 bus_listener_t *listener;
290 active_listener_t *active_listener;
291 ike_sa_t *ike_sa;
292 int thread;
293
294 ike_sa = pthread_getspecific(this->thread_sa);
295 thread = get_thread_number(this);
296
297 pthread_mutex_lock(&this->mutex);
298
299 /* do the job for all passive bus_listeners */
300 iterator = this->listeners->create_iterator(this->listeners, TRUE);
301 while (iterator->iterate(iterator, (void**)&listener))
302 {
303 va_list args_copy;
304
305 va_copy(args_copy, args);
306 listener->signal(listener, signal, level, thread, ike_sa, format, args_copy);
307 va_end(args_copy);
308 }
309 iterator->destroy(iterator);
310
311 /* wake up all active listeners */
312 iterator = this->active_listeners->create_iterator(this->active_listeners, TRUE);
313 while (iterator->iterate(iterator, (void**)&active_listener))
314 {
315 /* wait until it is back */
316 while (active_listener->state == REGISTERED)
317 {
318 pthread_cond_wait(&active_listener->cond, &this->mutex);
319 }
320 /* if thread is listening now, give it the signal to process */
321 if (active_listener->state == LISTENING)
322 {
323 active_listener->level = level;
324 active_listener->thread = thread;
325 active_listener->ike_sa = ike_sa;
326 active_listener->signal = signal;
327 active_listener->format = format;
328 va_copy(active_listener->args, args);
329 active_listener->state = REGISTERED;
330 pthread_cond_signal(&active_listener->cond);
331 }
332 }
333
334 /* we must wait now until all are not in state REGISTERED,
335 * as they may still use our arguments */
336 iterator->reset(iterator);
337 while (iterator->iterate(iterator, (void**)&active_listener))
338 {
339 while (active_listener->state == REGISTERED)
340 {
341 pthread_cond_wait(&active_listener->cond, &this->mutex);
342 }
343 va_end(active_listener->args);
344 }
345 iterator->destroy(iterator);
346
347 pthread_mutex_unlock(&this->mutex);
348 }
349
350 /**
351 * Implementation of bus_t.signal.
352 */
353 static void signal_(private_bus_t *this, signal_t signal, level_t level,
354 char* format, ...)
355 {
356 va_list args;
357
358 va_start(args, format);
359 vsignal(this, signal, level, format, args);
360 va_end(args);
361 }
362
363 /**
364 * Implementation of bus_t.destroy.
365 */
366 static void destroy(private_bus_t *this)
367 {
368 active_listener_t *listener;
369 while (this->active_listeners->remove_last(this->active_listeners,
370 (void**)&listener) == SUCCESS)
371 {
372 free(listener);
373 }
374
375 this->active_listeners->destroy(this->active_listeners);
376 this->listeners->destroy(this->listeners);
377 free(this);
378 }
379
380 /*
381 * Described in header.
382 */
383 bus_t *bus_create()
384 {
385 private_bus_t *this = malloc_thing(private_bus_t);
386
387 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
388 this->public.listen = (signal_t(*)(bus_t*,level_t*,int*,ike_sa_t**,char**,va_list*))listen_;
389 this->public.set_listen_state = (void(*)(bus_t*,bool))set_listen_state;
390 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
391 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
392 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
393 this->public.destroy = (void(*)(bus_t*)) destroy;
394
395 this->listeners = linked_list_create();
396 this->active_listeners = linked_list_create();
397 pthread_mutex_init(&this->mutex, NULL);
398 pthread_key_create(&this->thread_id, NULL);
399 pthread_key_create(&this->thread_sa, NULL);
400
401 return &(this->public);
402 }