some cleanups
[strongswan.git] / src / charon / sa / ike_sa_manager.c
1 /**
2 * @file ike_sa_manager.c
3 *
4 * @brief Implementation of ike_sa_mananger_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <pthread.h>
25 #include <string.h>
26
27 #include "ike_sa_manager.h"
28
29 #include <daemon.h>
30 #include <sa/ike_sa_id.h>
31 #include <bus/bus.h>
32 #include <utils/linked_list.h>
33
34 typedef struct entry_t entry_t;
35
36 /**
37 * An entry in the linked list, contains IKE_SA, locking and lookup data.
38 */
39 struct entry_t {
40
41 /**
42 * Number of threads waiting for this ike_sa_t object.
43 */
44 int waiting_threads;
45
46 /**
47 * Condvar where threads can wait until ike_sa_t object is free for use again.
48 */
49 pthread_cond_t condvar;
50
51 /**
52 * Is this ike_sa currently checked out?
53 */
54 bool checked_out;
55
56 /**
57 * Does this SA drives out new threads?
58 */
59 bool driveout_new_threads;
60
61 /**
62 * Does this SA drives out waiting threads?
63 */
64 bool driveout_waiting_threads;
65
66 /**
67 * Identifiaction of an IKE_SA (SPIs).
68 */
69 ike_sa_id_t *ike_sa_id;
70
71 /**
72 * The contained ike_sa_t object.
73 */
74 ike_sa_t *ike_sa;
75 };
76
77 /**
78 * Implementation of entry_t.destroy.
79 */
80 static status_t entry_destroy(entry_t *this)
81 {
82 /* also destroy IKE SA */
83 this->ike_sa->destroy(this->ike_sa);
84 this->ike_sa_id->destroy(this->ike_sa_id);
85 free(this);
86 return SUCCESS;
87 }
88
89 /**
90 * Creates a new entry for the ike_sa_t list.
91 */
92 static entry_t *entry_create(ike_sa_id_t *ike_sa_id)
93 {
94 entry_t *this = malloc_thing(entry_t);
95
96 this->waiting_threads = 0;
97 pthread_cond_init(&(this->condvar), NULL);
98
99 /* we set checkout flag when we really give it out */
100 this->checked_out = FALSE;
101 this->driveout_new_threads = FALSE;
102 this->driveout_waiting_threads = FALSE;
103
104 /* ike_sa_id is always cloned */
105 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
106
107 /* create new ike_sa */
108 this->ike_sa = ike_sa_create(ike_sa_id);
109
110 return this;
111 }
112
113
114 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
115
116 /**
117 * Additional private members of ike_sa_manager_t.
118 */
119 struct private_ike_sa_manager_t {
120 /**
121 * Public interface of ike_sa_manager_t.
122 */
123 ike_sa_manager_t public;
124
125 /**
126 * Lock for exclusivly accessing the manager.
127 */
128 pthread_mutex_t mutex;
129
130 /**
131 * Linked list with entries for the ike_sa_t objects.
132 */
133 linked_list_t *ike_sa_list;
134
135 /**
136 * A randomizer, to get random SPIs for our side
137 */
138 randomizer_t *randomizer;
139 };
140
141 /**
142 * Implementation of private_ike_sa_manager_t.get_entry_by_id.
143 */
144 static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry)
145 {
146 linked_list_t *list = this->ike_sa_list;
147 iterator_t *iterator;
148 entry_t *current;
149 status_t status;
150
151 /* create iterator over list of ike_sa's */
152 iterator = list->create_iterator(list, TRUE);
153
154 /* default status */
155 status = NOT_FOUND;
156
157 while (iterator->iterate(iterator, (void**)&current))
158 {
159 if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id))
160 {
161 DBG2(DBG_MGR, "found entry by both SPIs");
162 *entry = current;
163 status = SUCCESS;
164 break;
165 }
166 if (ike_sa_id->get_responder_spi(ike_sa_id) == 0 ||
167 current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0)
168 {
169 /* seems to be a half ready ike_sa */
170 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) ==
171 ike_sa_id->get_initiator_spi(ike_sa_id)) &&
172 (current->ike_sa_id->is_initiator(ike_sa_id) ==
173 ike_sa_id->is_initiator(current->ike_sa_id)))
174 {
175 DBG2(DBG_MGR, "found entry by initiator SPI");
176 *entry = current;
177 status = SUCCESS;
178 break;
179 }
180 }
181 }
182
183 iterator->destroy(iterator);
184 return status;
185 }
186
187 /**
188 * Implementation of private_ike_sa_manager_t.get_entry_by_sa.
189 */
190 static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, entry_t **entry)
191 {
192 linked_list_t *list = this->ike_sa_list;
193 iterator_t *iterator;
194 entry_t *current;
195 status_t status;
196
197 iterator = list->create_iterator(list, TRUE);
198
199 /* default status */
200 status = NOT_FOUND;
201
202 while (iterator->iterate(iterator, (void**)&current))
203 {
204 /* only pointers are compared */
205 if (current->ike_sa == ike_sa)
206 {
207 DBG2(DBG_MGR, "found entry by pointer");
208 *entry = current;
209 status = SUCCESS;
210 break;
211 }
212 }
213 iterator->destroy(iterator);
214
215 return status;
216 }
217
218 /**
219 * Implementation of private_ike_sa_manager_s.delete_entry.
220 */
221 static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry)
222 {
223 linked_list_t *list = this->ike_sa_list;
224 iterator_t *iterator;
225 entry_t *current;
226 status_t status;
227
228 iterator = list->create_iterator(list, TRUE);
229
230 status = NOT_FOUND;
231
232 while (iterator->iterate(iterator, (void**)&current))
233 {
234 if (current == entry)
235 {
236 /* mark it, so now new threads can get this entry */
237 entry->driveout_new_threads = TRUE;
238 /* wait until all workers have done their work */
239 while (entry->waiting_threads)
240 {
241 /* wake up all */
242 pthread_cond_broadcast(&(entry->condvar));
243 /* they will wake us again when their work is done */
244 pthread_cond_wait(&(entry->condvar), &(this->mutex));
245 }
246
247 DBG2(DBG_MGR, "found entry by pointer, deleting it");
248 iterator->remove(iterator);
249 entry_destroy(entry);
250 status = SUCCESS;
251 break;
252 }
253 }
254 iterator->destroy(iterator);
255 return status;
256 }
257
258 /**
259 * Wait until no other thread is using an IKE_SA, return FALSE if entry not
260 * acquireable
261 */
262 static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry)
263 {
264 if (entry->driveout_new_threads)
265 {
266 /* we are not allowed to get this */
267 return FALSE;
268 }
269 while (entry->checked_out && !entry->driveout_waiting_threads)
270 {
271 /* so wait until we can get it for us.
272 * we register us as waiting. */
273 entry->waiting_threads++;
274 pthread_cond_wait(&(entry->condvar), &(this->mutex));
275 entry->waiting_threads--;
276 }
277 /* hm, a deletion request forbids us to get this SA, get next one */
278 if (entry->driveout_waiting_threads)
279 {
280 /* we must signal here, others may be waiting on it, too */
281 pthread_cond_signal(&(entry->condvar));
282 return FALSE;
283 }
284 return TRUE;
285 }
286
287 /**
288 * Implementation of private_ike_sa_manager_t.get_next_spi.
289 */
290 static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
291 {
292 u_int64_t spi;
293
294 this->randomizer->get_pseudo_random_bytes(this->randomizer, 8, (u_int8_t*)&spi);
295
296 return spi;
297 }
298
299 /**
300 * Implementation of of ike_sa_manager.checkout.
301 */
302 static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
303 {
304 bool responder_spi_set;
305 bool initiator_spi_set;
306 bool original_initiator;
307 ike_sa_t *ike_sa = NULL;
308
309 DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
310
311 DBG2(DBG_MGR, "%d IKE_SAs in manager",
312 this->ike_sa_list->get_count(this->ike_sa_list));
313
314 /* each access is locked */
315 pthread_mutex_lock(&(this->mutex));
316
317 responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
318 initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
319 original_initiator = ike_sa_id->is_initiator(ike_sa_id);
320
321 if ((initiator_spi_set && responder_spi_set) ||
322 ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
323 {
324 /* we SHOULD have an IKE_SA for these SPIs in the list,
325 * if not, we can't handle the request...
326 */
327 entry_t *entry;
328 /* look for the entry */
329 if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
330 {
331 if (wait_for_entry(this, entry))
332 {
333 DBG2(DBG_MGR, "IKE_SA successfully checked out");
334 /* ok, this IKE_SA is finally ours */
335 entry->checked_out = TRUE;
336 ike_sa = entry->ike_sa;
337 /* update responder SPI when it's not set */
338 if (entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0)
339 {
340 ike_sa_id_t *ike_sa_ike_sa_id = ike_sa->get_id(ike_sa);
341 u_int64_t spi = ike_sa_id->get_responder_spi(ike_sa_id);
342
343 ike_sa_ike_sa_id->set_responder_spi(ike_sa_ike_sa_id, spi);
344 entry->ike_sa_id->set_responder_spi(entry->ike_sa_id, spi);
345 }
346 }
347 else
348 {
349 DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
350 }
351 }
352 else
353 {
354 DBG2(DBG_MGR, "IKE_SA not stored in list");
355 /* looks like there is no such IKE_SA, better luck next time... */
356 }
357 }
358 else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
359 {
360 /* an IKE_SA_INIT from an another endpoint,
361 * he is the initiator.
362 * For simplicity, we do NOT check for retransmitted
363 * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
364 * Request (even a retransmitted one) will result in a
365 * IKE_SA. This could be improved...
366 */
367 u_int64_t responder_spi;
368 entry_t *new_entry;
369
370 /* set SPIs, we are the responder */
371 responder_spi = get_next_spi(this);
372
373 /* we also set arguments spi, so its still valid */
374 ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
375
376 /* create entry */
377 new_entry = entry_create(ike_sa_id);
378
379 this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
380
381 /* check ike_sa out */
382 DBG2(DBG_MGR, "IKE_SA added to list of known IKE_SAs");
383 new_entry->checked_out = TRUE;
384 ike_sa = new_entry->ike_sa;
385 }
386 else if (!initiator_spi_set && !responder_spi_set)
387 {
388 /* checkout of a new and unused IKE_SA, used for rekeying */
389 entry_t *new_entry;
390
391 if (original_initiator)
392 {
393 ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
394 }
395 else
396 {
397 ike_sa_id->set_responder_spi(ike_sa_id, get_next_spi(this));
398 }
399 /* create entry */
400 new_entry = entry_create(ike_sa_id);
401 DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
402
403 this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
404
405 /* check ike_sa out */
406 new_entry->checked_out = TRUE;
407 ike_sa = new_entry->ike_sa;
408 }
409 else
410 {
411 /* responder set, initiator not: here is something seriously wrong! */
412 DBG2(DBG_MGR, "invalid IKE_SA SPIs");
413 }
414
415 pthread_mutex_unlock(&(this->mutex));
416
417 charon->bus->set_sa(charon->bus, ike_sa);
418 return ike_sa;
419 }
420
421 /**
422 * Implementation of of ike_sa_manager.checkout_by_id.
423 */
424 static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
425 host_t *my_host, host_t *other_host,
426 identification_t *my_id,
427 identification_t *other_id)
428 {
429 iterator_t *iterator;
430 entry_t *entry;
431 ike_sa_t *ike_sa = NULL;
432
433 pthread_mutex_lock(&(this->mutex));
434
435 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
436 while (iterator->iterate(iterator, (void**)&entry))
437 {
438 identification_t *found_my_id, *found_other_id;
439 host_t *found_my_host, *found_other_host;
440 int wc;
441
442 if (!wait_for_entry(this, entry))
443 {
444 continue;
445 }
446
447 if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
448 {
449 /* skip IKE_SA which are not useable */
450 continue;
451 }
452
453 found_my_id = entry->ike_sa->get_my_id(entry->ike_sa);
454 found_other_id = entry->ike_sa->get_other_id(entry->ike_sa);
455 found_my_host = entry->ike_sa->get_my_host(entry->ike_sa);
456 found_other_host = entry->ike_sa->get_other_host(entry->ike_sa);
457
458 if (found_my_id->get_type(found_my_id) == ID_ANY &&
459 found_other_id->get_type(found_other_id) == ID_ANY)
460 {
461 /* IKE_SA has no IDs yet, so we can't use it */
462 continue;
463 }
464
465 /* compare ID and hosts. Supplied ID may contain wildcards, and IP
466 * may be %any. */
467 if ((found_my_host->is_anyaddr(found_my_host) ||
468 my_host->ip_equals(my_host, found_my_host)) &&
469 (found_other_host->is_anyaddr(found_other_host) ||
470 other_host->ip_equals(other_host, found_other_host)) &&
471 found_my_id->matches(found_my_id, my_id, &wc) &&
472 found_other_id->matches(found_other_id, other_id, &wc))
473 {
474 /* looks good, we take this one */
475 DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
476 my_host, other_host, my_id, other_id);
477 entry->checked_out = TRUE;
478 ike_sa = entry->ike_sa;
479 }
480 }
481 iterator->destroy(iterator);
482
483 if (!ike_sa)
484 {
485 u_int64_t initiator_spi;
486 entry_t *new_entry;
487 ike_sa_id_t *new_ike_sa_id;
488
489 initiator_spi = get_next_spi(this);
490 new_ike_sa_id = ike_sa_id_create(0, 0, TRUE);
491 new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi);
492
493 /* create entry */
494 new_entry = entry_create(new_ike_sa_id);
495 DBG2(DBG_MGR, "created IKE_SA: %J", new_ike_sa_id);
496 new_ike_sa_id->destroy(new_ike_sa_id);
497
498 this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
499
500 /* check ike_sa out */
501 DBG2(DBG_MGR, "new IKE_SA created for IDs [%D]...[%D]", my_id, other_id);
502 new_entry->checked_out = TRUE;
503 ike_sa = new_entry->ike_sa;
504 }
505 pthread_mutex_unlock(&(this->mutex));
506 charon->bus->set_sa(charon->bus, ike_sa);
507 return ike_sa;
508 }
509
510 /**
511 * Implementation of of ike_sa_manager.checkout_by_id.
512 */
513 static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
514 bool child)
515 {
516 iterator_t *iterator, *children;
517 entry_t *entry;
518 ike_sa_t *ike_sa = NULL;
519 child_sa_t *child_sa;
520
521 pthread_mutex_lock(&(this->mutex));
522
523 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
524 while (iterator->iterate(iterator, (void**)&entry))
525 {
526 if (wait_for_entry(this, entry))
527 {
528 /* look for a child with such a reqid ... */
529 if (child)
530 {
531 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
532 while (children->iterate(children, (void**)&child_sa))
533 {
534 if (child_sa->get_reqid(child_sa) == id)
535 {
536 ike_sa = entry->ike_sa;
537 break;
538 }
539 }
540 children->destroy(children);
541 }
542 else /* ... or for a IKE_SA with such a unique id */
543 {
544 if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
545 {
546 ike_sa = entry->ike_sa;
547 }
548 }
549 /* got one, return */
550 if (ike_sa)
551 {
552 entry->checked_out = TRUE;
553 break;
554 }
555 }
556 }
557 iterator->destroy(iterator);
558 pthread_mutex_unlock(&(this->mutex));
559
560 charon->bus->set_sa(charon->bus, ike_sa);
561 return ike_sa;
562 }
563
564 /**
565 * Implementation of of ike_sa_manager.checkout_by_name.
566 */
567 static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
568 bool child)
569 {
570 iterator_t *iterator, *children;
571 entry_t *entry;
572 ike_sa_t *ike_sa = NULL;
573 child_sa_t *child_sa;
574
575 pthread_mutex_lock(&(this->mutex));
576
577 iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
578 while (iterator->iterate(iterator, (void**)&entry))
579 {
580 if (wait_for_entry(this, entry))
581 {
582 /* look for a child with such a policy name ... */
583 if (child)
584 {
585 children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
586 while (children->iterate(children, (void**)&child_sa))
587 {
588 if (streq(child_sa->get_name(child_sa), name))
589 {
590 ike_sa = entry->ike_sa;
591 break;
592 }
593 }
594 children->destroy(children);
595 }
596 else /* ... or for a IKE_SA with such a connection name */
597 {
598 if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
599 {
600 ike_sa = entry->ike_sa;
601 }
602 }
603 /* got one, return */
604 if (ike_sa)
605 {
606 entry->checked_out = TRUE;
607 break;
608 }
609 }
610 }
611 iterator->destroy(iterator);
612 pthread_mutex_unlock(&(this->mutex));
613
614 charon->bus->set_sa(charon->bus, ike_sa);
615 return ike_sa;
616 }
617
618 /**
619 * Iterator hook for iterate, gets ike_sas instead of entries
620 */
621 static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
622 ike_sa_t **out)
623 {
624 /* check out entry */
625 if (wait_for_entry(this, in))
626 {
627 *out = in->ike_sa;
628 return TRUE;
629 }
630 return FALSE;
631 }
632
633 /**
634 * Implementation of ike_sa_manager_t.create_iterator.
635 */
636 static iterator_t *create_iterator(private_ike_sa_manager_t* this)
637 {
638 iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
639 this->ike_sa_list, &this->mutex);
640 /* register hook to iterator over ike_sas, not entries */
641 iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
642 return iterator;
643 }
644
645 /**
646 * Implementation of ike_sa_manager_t.checkin.
647 */
648 static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
649 {
650 /* to check the SA back in, we look for the pointer of the ike_sa
651 * in all entries.
652 * We can't search by SPI's since the MAY have changed (e.g. on reception
653 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
654 */
655 status_t retval;
656 entry_t *entry;
657 ike_sa_id_t *ike_sa_id;
658
659 ike_sa_id = ike_sa->get_id(ike_sa);
660
661 DBG2(DBG_MGR, "checkin IKE_SA: %J", ike_sa_id);
662
663 pthread_mutex_lock(&(this->mutex));
664
665 /* look for the entry */
666 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
667 {
668 /* ike_sa_id must be updated */
669 entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
670 /* signal waiting threads */
671 entry->checked_out = FALSE;
672 DBG2(DBG_MGR, "check-in of IKE_SA successful.");
673 pthread_cond_signal(&(entry->condvar));
674 retval = SUCCESS;
675 }
676 else
677 {
678 DBG2(DBG_MGR, "tried to check in nonexisting IKE_SA");
679 /* this SA is no more, this REALLY should not happen */
680 retval = NOT_FOUND;
681 }
682
683 DBG2(DBG_MGR, "%d IKE_SAs in manager now",
684 this->ike_sa_list->get_count(this->ike_sa_list));
685 pthread_mutex_unlock(&(this->mutex));
686
687 charon->bus->set_sa(charon->bus, NULL);
688 return retval;
689 }
690
691
692 /**
693 * Implementation of ike_sa_manager_t.checkin_and_destroy.
694 */
695 static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
696 {
697 /* deletion is a bit complex, we must garant that no thread is waiting for
698 * this SA.
699 * We take this SA from the list, and start signaling while threads
700 * are in the condvar.
701 */
702 entry_t *entry;
703 status_t retval;
704 ike_sa_id_t *ike_sa_id;
705
706 ike_sa_id = ike_sa->get_id(ike_sa);
707 DBG2(DBG_MGR, "checkin and destroy IKE_SA: %J", ike_sa_id);
708
709 pthread_mutex_lock(&(this->mutex));
710
711 if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
712 {
713 /* drive out waiting threads, as we are in hurry */
714 entry->driveout_waiting_threads = TRUE;
715
716 delete_entry(this, entry);
717
718 DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful");
719 retval = SUCCESS;
720 }
721 else
722 {
723 DBG2(DBG_MGR, "tried to check-in and delete nonexisting IKE_SA");
724 retval = NOT_FOUND;
725 }
726
727 pthread_mutex_unlock(&(this->mutex));
728 charon->bus->set_sa(charon->bus, ike_sa);
729 return retval;
730 }
731
732 /**
733 * Implementation of ike_sa_manager_t.destroy.
734 */
735 static void destroy(private_ike_sa_manager_t *this)
736 {
737 /* destroy all list entries */
738 linked_list_t *list = this->ike_sa_list;
739 iterator_t *iterator;
740 entry_t *entry;
741
742 pthread_mutex_lock(&(this->mutex));
743 DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
744 /* Step 1: drive out all waiting threads */
745 DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
746 iterator = list->create_iterator(list, TRUE);
747 while (iterator->iterate(iterator, (void**)&entry))
748 {
749 /* do not accept new threads, drive out waiting threads */
750 entry->driveout_new_threads = TRUE;
751 entry->driveout_waiting_threads = TRUE;
752 }
753 DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
754 /* Step 2: wait until all are gone */
755 iterator->reset(iterator);
756 while (iterator->iterate(iterator, (void**)&entry))
757 {
758 while (entry->waiting_threads)
759 {
760 /* wake up all */
761 pthread_cond_broadcast(&(entry->condvar));
762 /* go sleeping until they are gone */
763 pthread_cond_wait(&(entry->condvar), &(this->mutex));
764 }
765 }
766 DBG2(DBG_MGR, "delete all IKE_SA's");
767 /* Step 3: initiate deletion of all IKE_SAs */
768 iterator->reset(iterator);
769 while (iterator->iterate(iterator, (void**)&entry))
770 {
771 entry->ike_sa->delete(entry->ike_sa);
772 }
773 iterator->destroy(iterator);
774
775 DBG2(DBG_MGR, "destroy all entries");
776 /* Step 4: destroy all entries */
777 list->destroy_function(list, (void*)entry_destroy);
778 pthread_mutex_unlock(&(this->mutex));
779
780 this->randomizer->destroy(this->randomizer);
781
782 free(this);
783 }
784
785 /*
786 * Described in header.
787 */
788 ike_sa_manager_t *ike_sa_manager_create()
789 {
790 private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t);
791
792 /* assign public functions */
793 this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
794 this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
795 this->public.checkout_by_peer = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_peer;
796 this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
797 this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
798 this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
799 this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
800 this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
801
802 /* initialize private variables */
803 this->ike_sa_list = linked_list_create();
804 pthread_mutex_init(&this->mutex, NULL);
805 this->randomizer = randomizer_create();
806
807 return &this->public;
808 }