Added member fields for reserved bits and bytes in all payloads
[strongswan.git] / src / libcharon / bus / bus.c
1 /*
2 * Copyright (C) 2006 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "bus.h"
17
18 #include <stdint.h>
19
20 #include <threading/thread.h>
21 #include <threading/thread_value.h>
22 #include <threading/condvar.h>
23 #include <threading/mutex.h>
24
25 typedef struct private_bus_t private_bus_t;
26
27 /**
28 * Private data of a bus_t object.
29 */
30 struct private_bus_t {
31 /**
32 * Public part of a bus_t object.
33 */
34 bus_t public;
35
36 /**
37 * List of registered listeners as entry_t's
38 */
39 linked_list_t *listeners;
40
41 /**
42 * mutex to synchronize active listeners, recursively
43 */
44 mutex_t *mutex;
45
46 /**
47 * Thread local storage the threads IKE_SA
48 */
49 thread_value_t *thread_sa;
50 };
51
52 typedef struct entry_t entry_t;
53
54 /**
55 * a listener entry, either active or passive
56 */
57 struct entry_t {
58
59 /**
60 * registered listener interface
61 */
62 listener_t *listener;
63
64 /**
65 * is this a active listen() call with a blocking thread
66 */
67 bool blocker;
68
69 /**
70 * are we currently calling this listener
71 */
72 int calling;
73
74 /**
75 * condvar where active listeners wait
76 */
77 condvar_t *condvar;
78 };
79
80 /**
81 * create a listener entry
82 */
83 static entry_t *entry_create(listener_t *listener, bool blocker)
84 {
85 entry_t *this = malloc_thing(entry_t);
86
87 this->listener = listener;
88 this->blocker = blocker;
89 this->calling = 0;
90 this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
91
92 return this;
93 }
94
95 /**
96 * destroy an entry_t
97 */
98 static void entry_destroy(entry_t *entry)
99 {
100 entry->condvar->destroy(entry->condvar);
101 free(entry);
102 }
103
104 METHOD(bus_t, add_listener, void,
105 private_bus_t *this, listener_t *listener)
106 {
107 this->mutex->lock(this->mutex);
108 this->listeners->insert_last(this->listeners, entry_create(listener, FALSE));
109 this->mutex->unlock(this->mutex);
110 }
111
112 METHOD(bus_t, remove_listener, void,
113 private_bus_t *this, listener_t *listener)
114 {
115 enumerator_t *enumerator;
116 entry_t *entry;
117
118 this->mutex->lock(this->mutex);
119 enumerator = this->listeners->create_enumerator(this->listeners);
120 while (enumerator->enumerate(enumerator, &entry))
121 {
122 if (entry->listener == listener)
123 {
124 this->listeners->remove_at(this->listeners, enumerator);
125 entry_destroy(entry);
126 break;
127 }
128 }
129 enumerator->destroy(enumerator);
130 this->mutex->unlock(this->mutex);
131 }
132
133 typedef struct cleanup_data_t cleanup_data_t;
134
135 /**
136 * data to remove a listener using thread_cleanup_t handler
137 */
138 struct cleanup_data_t {
139 /** bus instance */
140 private_bus_t *this;
141 /** listener entry */
142 entry_t *entry;
143 };
144
145 /**
146 * thread_cleanup_t handler to remove a listener
147 */
148 static void listener_cleanup(cleanup_data_t *data)
149 {
150 data->this->listeners->remove(data->this->listeners, data->entry, NULL);
151 entry_destroy(data->entry);
152 }
153
154 METHOD(bus_t, listen_, void,
155 private_bus_t *this, listener_t *listener, job_t *job)
156 {
157 bool old;
158 cleanup_data_t data;
159
160 data.this = this;
161 data.entry = entry_create(listener, TRUE);
162
163 this->mutex->lock(this->mutex);
164 this->listeners->insert_last(this->listeners, data.entry);
165 lib->processor->queue_job(lib->processor, job);
166 thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
167 thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data);
168 old = thread_cancelability(TRUE);
169 while (data.entry->blocker)
170 {
171 data.entry->condvar->wait(data.entry->condvar, this->mutex);
172 }
173 thread_cancelability(old);
174 thread_cleanup_pop(FALSE);
175 /* unlock mutex */
176 thread_cleanup_pop(TRUE);
177 entry_destroy(data.entry);
178 }
179
180 METHOD(bus_t, set_sa, void,
181 private_bus_t *this, ike_sa_t *ike_sa)
182 {
183 this->thread_sa->set(this->thread_sa, ike_sa);
184 }
185
186 METHOD(bus_t, get_sa, ike_sa_t*,
187 private_bus_t *this)
188 {
189 return this->thread_sa->get(this->thread_sa);
190 }
191
192 /**
193 * data associated to a signal, passed to callback
194 */
195 typedef struct {
196 /** associated IKE_SA */
197 ike_sa_t *ike_sa;
198 /** invoking thread */
199 long thread;
200 /** debug group */
201 debug_t group;
202 /** debug level */
203 level_t level;
204 /** format string */
205 char *format;
206 /** argument list */
207 va_list args;
208 } log_data_t;
209
210 /**
211 * listener->log() invocation as a list remove callback
212 */
213 static bool log_cb(entry_t *entry, log_data_t *data)
214 {
215 va_list args;
216
217 if (entry->calling || !entry->listener->log)
218 { /* avoid recursive calls */
219 return FALSE;
220 }
221 entry->calling++;
222 va_copy(args, data->args);
223 if (!entry->listener->log(entry->listener, data->group, data->level,
224 data->thread, data->ike_sa, data->format, args))
225 {
226 if (entry->blocker)
227 {
228 entry->blocker = FALSE;
229 entry->condvar->signal(entry->condvar);
230 }
231 else
232 {
233 entry_destroy(entry);
234 }
235 va_end(args);
236 entry->calling--;
237 return TRUE;
238 }
239 va_end(args);
240 entry->calling--;
241 return FALSE;
242 }
243
244 METHOD(bus_t, vlog, void,
245 private_bus_t *this, debug_t group, level_t level,
246 char* format, va_list args)
247 {
248 log_data_t data;
249
250 data.ike_sa = this->thread_sa->get(this->thread_sa);
251 data.thread = thread_current_id();
252 data.group = group;
253 data.level = level;
254 data.format = format;
255 va_copy(data.args, args);
256
257 this->mutex->lock(this->mutex);
258 /* We use the remove() method to invoke all listeners. This is cheap and
259 * does not require an allocation for this performance critical function. */
260 this->listeners->remove(this->listeners, &data, (void*)log_cb);
261 this->mutex->unlock(this->mutex);
262
263 va_end(data.args);
264 }
265
266 METHOD(bus_t, log_, void,
267 private_bus_t *this, debug_t group, level_t level, char* format, ...)
268 {
269 va_list args;
270
271 va_start(args, format);
272 vlog(this, group, level, format, args);
273 va_end(args);
274 }
275
276 /**
277 * unregister a listener
278 */
279 static void unregister_listener(private_bus_t *this, entry_t *entry,
280 enumerator_t *enumerator)
281 {
282 if (entry->blocker)
283 {
284 entry->blocker = FALSE;
285 entry->condvar->signal(entry->condvar);
286 }
287 else
288 {
289 entry_destroy(entry);
290 }
291 this->listeners->remove_at(this->listeners, enumerator);
292 }
293
294 METHOD(bus_t, alert, void,
295 private_bus_t *this, alert_t alert, ...)
296 {
297 enumerator_t *enumerator;
298 ike_sa_t *ike_sa;
299 entry_t *entry;
300 va_list args;
301 bool keep;
302
303 ike_sa = this->thread_sa->get(this->thread_sa);
304
305 this->mutex->lock(this->mutex);
306 enumerator = this->listeners->create_enumerator(this->listeners);
307 while (enumerator->enumerate(enumerator, &entry))
308 {
309 if (entry->calling || !entry->listener->alert)
310 {
311 continue;
312 }
313 entry->calling++;
314 va_start(args, alert);
315 keep = entry->listener->alert(entry->listener, ike_sa, alert, args);
316 va_end(args);
317 entry->calling--;
318 if (!keep)
319 {
320 unregister_listener(this, entry, enumerator);
321 }
322 }
323 enumerator->destroy(enumerator);
324 this->mutex->unlock(this->mutex);
325 }
326
327 METHOD(bus_t, ike_state_change, void,
328 private_bus_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
329 {
330 enumerator_t *enumerator;
331 entry_t *entry;
332 bool keep;
333
334 this->mutex->lock(this->mutex);
335 enumerator = this->listeners->create_enumerator(this->listeners);
336 while (enumerator->enumerate(enumerator, &entry))
337 {
338 if (entry->calling || !entry->listener->ike_state_change)
339 {
340 continue;
341 }
342 entry->calling++;
343 keep = entry->listener->ike_state_change(entry->listener, ike_sa, state);
344 entry->calling--;
345 if (!keep)
346 {
347 unregister_listener(this, entry, enumerator);
348 }
349 }
350 enumerator->destroy(enumerator);
351 this->mutex->unlock(this->mutex);
352 }
353
354 METHOD(bus_t, child_state_change, void,
355 private_bus_t *this, child_sa_t *child_sa, child_sa_state_t state)
356 {
357 enumerator_t *enumerator;
358 ike_sa_t *ike_sa;
359 entry_t *entry;
360 bool keep;
361
362 ike_sa = this->thread_sa->get(this->thread_sa);
363
364 this->mutex->lock(this->mutex);
365 enumerator = this->listeners->create_enumerator(this->listeners);
366 while (enumerator->enumerate(enumerator, &entry))
367 {
368 if (entry->calling || !entry->listener->child_state_change)
369 {
370 continue;
371 }
372 entry->calling++;
373 keep = entry->listener->child_state_change(entry->listener, ike_sa,
374 child_sa, state);
375 entry->calling--;
376 if (!keep)
377 {
378 unregister_listener(this, entry, enumerator);
379 }
380 }
381 enumerator->destroy(enumerator);
382 this->mutex->unlock(this->mutex);
383 }
384
385 METHOD(bus_t, message, void,
386 private_bus_t *this, message_t *message, bool incoming)
387 {
388 enumerator_t *enumerator;
389 ike_sa_t *ike_sa;
390 entry_t *entry;
391 bool keep;
392
393 ike_sa = this->thread_sa->get(this->thread_sa);
394
395 this->mutex->lock(this->mutex);
396 enumerator = this->listeners->create_enumerator(this->listeners);
397 while (enumerator->enumerate(enumerator, &entry))
398 {
399 if (entry->calling || !entry->listener->message)
400 {
401 continue;
402 }
403 entry->calling++;
404 keep = entry->listener->message(entry->listener, ike_sa,
405 message, incoming);
406 entry->calling--;
407 if (!keep)
408 {
409 unregister_listener(this, entry, enumerator);
410 }
411 }
412 enumerator->destroy(enumerator);
413 this->mutex->unlock(this->mutex);
414 }
415
416 METHOD(bus_t, ike_keys, void,
417 private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
418 chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey)
419 {
420 enumerator_t *enumerator;
421 entry_t *entry;
422 bool keep;
423
424 this->mutex->lock(this->mutex);
425 enumerator = this->listeners->create_enumerator(this->listeners);
426 while (enumerator->enumerate(enumerator, &entry))
427 {
428 if (entry->calling || !entry->listener->ike_keys)
429 {
430 continue;
431 }
432 entry->calling++;
433 keep = entry->listener->ike_keys(entry->listener, ike_sa, dh,
434 nonce_i, nonce_r, rekey);
435 entry->calling--;
436 if (!keep)
437 {
438 unregister_listener(this, entry, enumerator);
439 }
440 }
441 enumerator->destroy(enumerator);
442 this->mutex->unlock(this->mutex);
443 }
444
445 METHOD(bus_t, child_keys, void,
446 private_bus_t *this, child_sa_t *child_sa, bool initiator,
447 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
448 {
449 enumerator_t *enumerator;
450 ike_sa_t *ike_sa;
451 entry_t *entry;
452 bool keep;
453
454 ike_sa = this->thread_sa->get(this->thread_sa);
455
456 this->mutex->lock(this->mutex);
457 enumerator = this->listeners->create_enumerator(this->listeners);
458 while (enumerator->enumerate(enumerator, &entry))
459 {
460 if (entry->calling || !entry->listener->child_keys)
461 {
462 continue;
463 }
464 entry->calling++;
465 keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa,
466 initiator, dh, nonce_i, nonce_r);
467 entry->calling--;
468 if (!keep)
469 {
470 unregister_listener(this, entry, enumerator);
471 }
472 }
473 enumerator->destroy(enumerator);
474 this->mutex->unlock(this->mutex);
475 }
476
477 METHOD(bus_t, child_updown, void,
478 private_bus_t *this, child_sa_t *child_sa, bool up)
479 {
480 enumerator_t *enumerator;
481 ike_sa_t *ike_sa;
482 entry_t *entry;
483 bool keep;
484
485 ike_sa = this->thread_sa->get(this->thread_sa);
486
487 this->mutex->lock(this->mutex);
488 enumerator = this->listeners->create_enumerator(this->listeners);
489 while (enumerator->enumerate(enumerator, &entry))
490 {
491 if (entry->calling || !entry->listener->child_updown)
492 {
493 continue;
494 }
495 entry->calling++;
496 keep = entry->listener->child_updown(entry->listener,
497 ike_sa, child_sa, up);
498 entry->calling--;
499 if (!keep)
500 {
501 unregister_listener(this, entry, enumerator);
502 }
503 }
504 enumerator->destroy(enumerator);
505 this->mutex->unlock(this->mutex);
506 }
507
508 METHOD(bus_t, child_rekey, void,
509 private_bus_t *this, child_sa_t *old, child_sa_t *new)
510 {
511 enumerator_t *enumerator;
512 ike_sa_t *ike_sa;
513 entry_t *entry;
514 bool keep;
515
516 ike_sa = this->thread_sa->get(this->thread_sa);
517
518 this->mutex->lock(this->mutex);
519 enumerator = this->listeners->create_enumerator(this->listeners);
520 while (enumerator->enumerate(enumerator, &entry))
521 {
522 if (entry->calling || !entry->listener->child_rekey)
523 {
524 continue;
525 }
526 entry->calling++;
527 keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
528 entry->calling--;
529 if (!keep)
530 {
531 unregister_listener(this, entry, enumerator);
532 }
533 }
534 enumerator->destroy(enumerator);
535 this->mutex->unlock(this->mutex);
536 }
537
538 METHOD(bus_t, ike_updown, void,
539 private_bus_t *this, ike_sa_t *ike_sa, bool up)
540 {
541 enumerator_t *enumerator;
542 entry_t *entry;
543 bool keep;
544
545 this->mutex->lock(this->mutex);
546 enumerator = this->listeners->create_enumerator(this->listeners);
547 while (enumerator->enumerate(enumerator, &entry))
548 {
549 if (entry->calling || !entry->listener->ike_updown)
550 {
551 continue;
552 }
553 entry->calling++;
554 keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
555 entry->calling--;
556 if (!keep)
557 {
558 unregister_listener(this, entry, enumerator);
559 }
560 }
561 enumerator->destroy(enumerator);
562 this->mutex->unlock(this->mutex);
563
564 /* a down event for IKE_SA implicitly downs all CHILD_SAs */
565 if (!up)
566 {
567 iterator_t *iterator;
568 child_sa_t *child_sa;
569
570 iterator = ike_sa->create_child_sa_iterator(ike_sa);
571 while (iterator->iterate(iterator, (void**)&child_sa))
572 {
573 child_updown(this, child_sa, FALSE);
574 }
575 iterator->destroy(iterator);
576 }
577 }
578
579 METHOD(bus_t, ike_rekey, void,
580 private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
581 {
582 enumerator_t *enumerator;
583 entry_t *entry;
584 bool keep;
585
586 this->mutex->lock(this->mutex);
587 enumerator = this->listeners->create_enumerator(this->listeners);
588 while (enumerator->enumerate(enumerator, &entry))
589 {
590 if (entry->calling || !entry->listener->ike_rekey)
591 {
592 continue;
593 }
594 entry->calling++;
595 keep = entry->listener->ike_rekey(entry->listener, old, new);
596 entry->calling--;
597 if (!keep)
598 {
599 unregister_listener(this, entry, enumerator);
600 }
601 }
602 enumerator->destroy(enumerator);
603 this->mutex->unlock(this->mutex);
604 }
605
606 METHOD(bus_t, authorize, bool,
607 private_bus_t *this, bool final)
608 {
609 enumerator_t *enumerator;
610 ike_sa_t *ike_sa;
611 entry_t *entry;
612 bool keep, success = TRUE;
613
614 ike_sa = this->thread_sa->get(this->thread_sa);
615
616 this->mutex->lock(this->mutex);
617 enumerator = this->listeners->create_enumerator(this->listeners);
618 while (enumerator->enumerate(enumerator, &entry))
619 {
620 if (entry->calling || !entry->listener->authorize)
621 {
622 continue;
623 }
624 entry->calling++;
625 keep = entry->listener->authorize(entry->listener, ike_sa,
626 final, &success);
627 entry->calling--;
628 if (!keep)
629 {
630 unregister_listener(this, entry, enumerator);
631 }
632 if (!success)
633 {
634 break;
635 }
636 }
637 enumerator->destroy(enumerator);
638 this->mutex->unlock(this->mutex);
639 return success;
640 }
641
642 METHOD(bus_t, narrow, void,
643 private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
644 linked_list_t *local, linked_list_t *remote)
645 {
646 enumerator_t *enumerator;
647 ike_sa_t *ike_sa;
648 entry_t *entry;
649 bool keep;
650
651 ike_sa = this->thread_sa->get(this->thread_sa);
652
653 this->mutex->lock(this->mutex);
654 enumerator = this->listeners->create_enumerator(this->listeners);
655 while (enumerator->enumerate(enumerator, &entry))
656 {
657 if (entry->calling || !entry->listener->narrow)
658 {
659 continue;
660 }
661 entry->calling++;
662 keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
663 type, local, remote);
664 entry->calling--;
665 if (!keep)
666 {
667 unregister_listener(this, entry, enumerator);
668 }
669 }
670 enumerator->destroy(enumerator);
671 this->mutex->unlock(this->mutex);
672 }
673
674 METHOD(bus_t, destroy, void,
675 private_bus_t *this)
676 {
677 this->thread_sa->destroy(this->thread_sa);
678 this->mutex->destroy(this->mutex);
679 this->listeners->destroy_function(this->listeners, (void*)entry_destroy);
680 free(this);
681 }
682
683 /*
684 * Described in header.
685 */
686 bus_t *bus_create()
687 {
688 private_bus_t *this;
689
690 INIT(this,
691 .public = {
692 .add_listener = _add_listener,
693 .remove_listener = _remove_listener,
694 .listen = _listen_,
695 .set_sa = _set_sa,
696 .get_sa = _get_sa,
697 .log = _log_,
698 .vlog = _vlog,
699 .alert = _alert,
700 .ike_state_change = _ike_state_change,
701 .child_state_change = _child_state_change,
702 .message = _message,
703 .ike_keys = _ike_keys,
704 .child_keys = _child_keys,
705 .ike_updown = _ike_updown,
706 .ike_rekey = _ike_rekey,
707 .child_updown = _child_updown,
708 .child_rekey = _child_rekey,
709 .authorize = _authorize,
710 .narrow = _narrow,
711 .destroy = _destroy,
712 },
713 .listeners = linked_list_create(),
714 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
715 .thread_sa = thread_value_create(NULL),
716 );
717
718 return &this->public;
719 }
720