62e57ae3b477901502918811f7ac807663d9f5e3
[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 #include <daemon.h>
28
29 ENUM(signal_names, SIG_ANY, SIG_MAX,
30 /** should not get printed */
31 "SIG_ANY",
32 /** debugging message types */
33 "DMN",
34 "MGR",
35 "IKE",
36 "CHD",
37 "JOB",
38 "CFG",
39 "KNL",
40 "NET",
41 "ENC",
42 "LIB",
43 /** should not get printed */
44 "SIG_DBG_MAX",
45 /** all level0 signals are AUDIT signals */
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 "AUD", "AUD", "AUD",
53 "AUD", "AUD", "AUD",
54 /** should not get printed */
55 "SIG_MAX",
56 );
57
58 typedef struct private_bus_t private_bus_t;
59
60 /**
61 * Private data of a bus_t object.
62 */
63 struct private_bus_t {
64 /**
65 * Public part of a bus_t object.
66 */
67 bus_t public;
68
69 /**
70 * List of registered listeners as entry_t's
71 */
72 linked_list_t *listeners;
73
74 /**
75 * mutex to synchronize active listeners
76 */
77 pthread_mutex_t mutex;
78
79 /**
80 * Thread local storage for a unique, simple thread ID
81 */
82 pthread_key_t thread_id;
83
84 /**
85 * Thread local storage the threads IKE_SA
86 */
87 pthread_key_t thread_sa;
88 };
89
90 typedef struct entry_t entry_t;
91
92 /**
93 * a listener entry, either active or passive
94 */
95 struct entry_t {
96
97 /**
98 * registered listener interface
99 */
100 bus_listener_t *listener;
101
102 /**
103 * is this a active listen() call with a blocking thread
104 */
105 bool blocker;
106
107 /**
108 * condvar where active listeners wait
109 */
110 pthread_cond_t cond;
111 };
112
113 /**
114 * create a listener entry
115 */
116 static entry_t *entry_create(bus_listener_t *listener, bool blocker)
117 {
118 entry_t *this = malloc_thing(entry_t);
119
120 this->listener = listener;
121 this->blocker = blocker;
122 pthread_cond_init(&this->cond, NULL);
123
124 return this;
125 }
126
127 /**
128 * Get a unique thread number for a calling thread. Since
129 * pthread_self returns large and ugly numbers, use this function
130 * for logging; these numbers are incremental starting at 1
131 */
132 static int get_thread_number(private_bus_t *this)
133 {
134 static long current_num = 0;
135 long stored_num;
136
137 stored_num = (long)pthread_getspecific(this->thread_id);
138 if (stored_num == 0)
139 { /* first call of current thread */
140 pthread_setspecific(this->thread_id, (void*)++current_num);
141 return current_num;
142 }
143 else
144 {
145 return stored_num;
146 }
147 }
148
149 /**
150 * Implementation of bus_t.add_listener.
151 */
152 static void add_listener(private_bus_t *this, bus_listener_t *listener)
153 {
154 pthread_mutex_lock(&this->mutex);
155 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
156 pthread_mutex_unlock(&this->mutex);
157 }
158
159 /**
160 * Implementation of bus_t.remove_listener.
161 */
162 static void remove_listener(private_bus_t *this, bus_listener_t *listener)
163 {
164 iterator_t *iterator;
165 entry_t *entry;
166
167 pthread_mutex_lock(&this->mutex);
168 iterator = this->listeners->create_iterator(this->listeners, TRUE);
169 while (iterator->iterate(iterator, (void**)&entry))
170 {
171 if (entry->listener == listener)
172 {
173 iterator->remove(iterator);
174 free(entry);
175 break;
176 }
177 }
178 iterator->destroy(iterator);
179 pthread_mutex_unlock(&this->mutex);
180 }
181
182 /**
183 * Implementation of bus_t.listen.
184 */
185 static void listen_(private_bus_t *this, bus_listener_t *listener, job_t *job)
186 {
187 entry_t *entry;
188 int old;
189
190 entry = entry_create(listener, TRUE);
191
192 pthread_mutex_lock(&this->mutex);
193 this->listeners->insert_last(this->listeners, entry);
194 charon->processor->queue_job(charon->processor, job);
195 pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
196 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
197 while (entry->blocker)
198 {
199 pthread_cond_wait(&entry->cond, &this->mutex);
200 }
201 pthread_setcancelstate(old, NULL);
202 pthread_cleanup_pop(TRUE);
203 free(entry);
204 }
205
206 /**
207 * Implementation of bus_t.set_sa.
208 */
209 static void set_sa(private_bus_t *this, ike_sa_t *ike_sa)
210 {
211 pthread_setspecific(this->thread_sa, ike_sa);
212 }
213
214 /**
215 * Implementation of bus_t.vsignal.
216 */
217 static void vsignal(private_bus_t *this, signal_t signal, level_t level,
218 char* format, va_list args)
219 {
220 iterator_t *iterator;
221 entry_t *entry;
222 ike_sa_t *ike_sa;
223 long thread;
224
225 pthread_mutex_lock(&this->mutex);
226 ike_sa = pthread_getspecific(this->thread_sa);
227 thread = get_thread_number(this);
228
229 iterator = this->listeners->create_iterator(this->listeners, TRUE);
230 while (iterator->iterate(iterator, (void**)&entry))
231 {
232 va_list args_copy;
233 va_copy(args_copy, args);
234 if (!entry->listener->signal(entry->listener, signal, level, thread,
235 ike_sa, format, args_copy))
236 {
237 iterator->remove(iterator);
238 if (entry->blocker)
239 {
240 entry->blocker = FALSE;
241 pthread_cond_signal(&entry->cond);
242 }
243 else
244 {
245 free(entry);
246 }
247 }
248 va_end(args_copy);
249 }
250 iterator->destroy(iterator);
251
252 pthread_mutex_unlock(&this->mutex);
253 }
254
255 /**
256 * Implementation of bus_t.signal.
257 */
258 static void signal_(private_bus_t *this, signal_t signal, level_t level,
259 char* format, ...)
260 {
261 va_list args;
262
263 va_start(args, format);
264 vsignal(this, signal, level, format, args);
265 va_end(args);
266 }
267
268 /**
269 * Implementation of bus_t.destroy.
270 */
271 static void destroy(private_bus_t *this)
272 {
273 this->listeners->destroy_function(this->listeners, free);
274 free(this);
275 }
276
277 /*
278 * Described in header.
279 */
280 bus_t *bus_create()
281 {
282 private_bus_t *this = malloc_thing(private_bus_t);
283
284 this->public.add_listener = (void(*)(bus_t*,bus_listener_t*))add_listener;
285 this->public.remove_listener = (void(*)(bus_t*,bus_listener_t*))remove_listener;
286 this->public.listen = (void(*)(bus_t*, bus_listener_t *listener, job_t *job))listen_;
287 this->public.set_sa = (void(*)(bus_t*,ike_sa_t*))set_sa;
288 this->public.signal = (void(*)(bus_t*,signal_t,level_t,char*,...))signal_;
289 this->public.vsignal = (void(*)(bus_t*,signal_t,level_t,char*,va_list))vsignal;
290 this->public.destroy = (void(*)(bus_t*)) destroy;
291
292 this->listeners = linked_list_create();
293 pthread_mutex_init(&this->mutex, NULL);
294 pthread_key_create(&this->thread_id, NULL);
295 pthread_key_create(&this->thread_sa, NULL);
296
297 return &this->public;
298 }
299