55fd0fcd633d3ad3b823a3c39f5e13a618e5456a
[strongswan.git] / Source / charon / sa / ike_sa_manager.c
1 /**
2 * @file ike_sa_manager.c
3 *
4 * @brief Central point for managing IKE-SAs (creation, locking, deleting...)
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, 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 <pthread.h>
24 #include <string.h>
25
26 #include "ike_sa_manager.h"
27
28 #include <globals.h>
29 #include <sa/ike_sa_id.h>
30 #include <utils/allocator.h>
31 #include <utils/logger.h>
32 #include <utils/logger_manager.h>
33 #include <utils/linked_list.h>
34
35 typedef struct ike_sa_entry_t ike_sa_entry_t;
36
37 /**
38 * @brief An entry in the linked list, contains IKE_SA, locking and lookup data.
39 */
40 struct ike_sa_entry_t {
41 /**
42 * destructor, also destroys ike_sa
43 */
44 status_t (*destroy) (ike_sa_entry_t *this);
45 /**
46 * Number of threads waiting for this ike_sa
47 */
48 int waiting_threads;
49 /**
50 * condvar where threads can wait until it's free again
51 */
52 pthread_cond_t condvar;
53 /**
54 * is this ike_sa currently checked out?
55 */
56 bool checked_out;
57 /**
58 * Does this SA drives out new threads?
59 */
60 bool driveout_new_threads;
61 /**
62 * Does this SA drives out waiting threads?
63 */
64 bool driveout_waiting_threads;
65 /**
66 * identifiaction of ike_sa (SPIs)
67 */
68 ike_sa_id_t *ike_sa_id;
69 /**
70 * the contained ike_sa
71 */
72 ike_sa_t *ike_sa;
73 };
74
75 /**
76 * @see ike_sa_entry_t.destroy
77 */
78 static status_t ike_sa_entry_destroy(ike_sa_entry_t *this)
79 {
80 /* also destroy IKE SA */
81 this->ike_sa->destroy(this->ike_sa);
82 this->ike_sa_id->destroy(this->ike_sa_id);
83 allocator_free(this);
84 return SUCCESS;
85 }
86
87 /**
88 * @brief creates a new entry for the ike_sa list
89 *
90 * This constructor additionaly creates a new and empty SA
91 *
92 * @param ike_sa_id the associated ike_sa_id_t, will be cloned
93 * @return created entry, with ike_sa and ike_sa_id
94 */
95 static ike_sa_entry_t *ike_sa_entry_create(ike_sa_id_t *ike_sa_id)
96 {
97 ike_sa_entry_t *this = allocator_alloc_thing(ike_sa_entry_t);
98
99 if (this == NULL)
100 {
101 return NULL;
102 }
103
104 /* destroy function */
105 this->destroy = ike_sa_entry_destroy;
106
107 this->waiting_threads = 0;
108 pthread_cond_init(&(this->condvar), NULL);
109
110 /* we set checkout flag when we really give it out */
111 this->checked_out = FALSE;
112 this->driveout_new_threads = FALSE;
113 this->driveout_waiting_threads = FALSE;
114
115 /* ike_sa_id is always cloned */
116 ike_sa_id->clone(ike_sa_id, &(this->ike_sa_id));
117 if (this->ike_sa_id == NULL)
118 {
119 allocator_free(this);
120 return NULL;
121 }
122
123 /* create new ike_sa */
124 this->ike_sa = ike_sa_create(ike_sa_id);
125 if (this->ike_sa == NULL)
126 {
127 this->ike_sa_id->destroy(this->ike_sa_id);
128 allocator_free(this);
129 return NULL;
130
131 }
132 return this;
133 }
134
135 typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
136
137 /**
138 * Additional private members to ike_sa_manager_t
139 */
140 struct private_ike_sa_manager_t {
141 /**
142 * Public members
143 */
144 ike_sa_manager_t public;
145
146 /**
147 * @brief get next spi
148 *
149 * we give out SPIs incremental
150 *
151 * @param this the ike_sa_manager
152 * @param spi[out] spi will be written here
153 * @return SUCCESS or,
154 * OUT_OF_RES when we already served 2^64 SPIs ;-)
155 */
156 status_t (*get_next_spi) (private_ike_sa_manager_t *this, u_int64_t *spi);
157
158 /**
159 * @brief find the ike_sa_entry in the list by SPIs
160 *
161 * This function simply iterates over the linked list. A hash-table
162 * would be more efficient when storing a lot of IKE_SAs...
163 *
164 * @param this the ike_sa_manager containing the list
165 * @param ike_sa_id id of the ike_sa, containing SPIs
166 * @param entry[out] pointer to set to the found entry
167 * @return
168 * - SUCCESS when found,
169 * - NOT_FOUND when no such ike_sa_id in list
170 * - OUT_OF_RES
171 */
172 status_t (*get_entry_by_id) (private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry);
173
174 /**
175 * @brief find the ike_sa_entry in the list by pointer to SA.
176 *
177 * This function simply iterates over the linked list. A hash-table
178 * would be more efficient when storing a lot of IKE_SAs...
179 *
180 * @param this the ike_sa_manager containing the list
181 * @param ike_sa pointer to the ike_sa
182 * @param entry[out] pointer to set to the found entry
183 * @return
184 * - SUCCESS when found,
185 * - NOT_FOUND when no such ike_sa_id in list
186 * - OUT_OF_RES
187 */
188 status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry);
189
190 /**
191 * @brief delete an entry from the linked list
192 *
193 * @param this the ike_sa_manager containing the list
194 * @param entry entry to delete
195 * @return
196 * - SUCCESS when found,
197 * - NOT_FOUND when no such ike_sa_id in list
198 */
199 status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry);
200
201 /**
202 * lock for exclusivly accessing the manager
203 */
204 pthread_mutex_t mutex;
205
206 /**
207 * Logger used for this IKE SA Manager
208 */
209 logger_t *logger;
210
211 /**
212 * Linked list with entries for the ike_sa
213 */
214 linked_list_t *ike_sa_list;
215
216 /**
217 * Next SPI, needed for incremental creation of SPIs
218 */
219 u_int64_t next_spi;
220 };
221
222
223 /**
224 * @see private_ike_sa_manager_t.get_entry_by_id
225 */
226 static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry)
227 {
228 linked_list_t *list = this->ike_sa_list;
229 linked_list_iterator_t *iterator;
230 status_t status;
231
232 /* create iterator over list of ike_sa's */
233 status = list->create_iterator(list, &iterator, TRUE);
234 if (status != SUCCESS)
235 {
236 this->logger->log(this->logger,ERROR,"Fatal Error: could not create iterator: %s",mapping_find(status_m,status));
237 /* out of res */
238 return status;
239 }
240
241 /* default status */
242 status = NOT_FOUND;
243
244
245 while (iterator->has_next(iterator))
246 {
247 ike_sa_entry_t *current;
248 bool are_equal = FALSE;
249
250 iterator->current(iterator, (void**)&current);
251 if (current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0) {
252 /* seems to be a half ready ike_sa */
253 if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == ike_sa_id->get_initiator_spi(ike_sa_id))
254 && (ike_sa_id->is_initiator(ike_sa_id) == current->ike_sa_id->is_initiator(current->ike_sa_id)))
255 {
256 this->logger->log(this->logger,CONTROL | MOST,"Found entry by initiator spi %d",ike_sa_id->get_initiator_spi(ike_sa_id));
257 *entry = current;
258 status = SUCCESS;
259 break;
260 }
261 }
262 current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id, &are_equal);
263 if (are_equal)
264 {
265 this->logger->log(this->logger,CONTROL | MOST,"Found entry by full ID");
266 *entry = current;
267 status = SUCCESS;
268 break;
269 }
270 }
271
272 iterator->destroy(iterator);
273 return status;
274 }
275
276 /**
277 * @see private_ike_sa_manager_t.get_entry_by_sa
278 */
279 static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry)
280 {
281 linked_list_t *list = this->ike_sa_list;
282 linked_list_iterator_t *iterator;
283 status_t status;
284
285 status = list->create_iterator(list, &iterator, TRUE);
286 if (status != SUCCESS)
287 {
288 this->logger->log(this->logger,ERROR,"Fatal Error: could not create iterator: %s",mapping_find(status_m,status));
289 return status;
290 }
291
292 /* default status */
293 status = NOT_FOUND;
294
295 while (iterator->has_next(iterator))
296 {
297 ike_sa_entry_t *current;
298 iterator->current(iterator, (void**)&current);
299 /* only pointers are compared */
300 if (current->ike_sa == ike_sa)
301 {
302 this->logger->log(this->logger,CONTROL | MOST,"Found entry by pointer");
303 *entry = current;
304 status = SUCCESS;
305 break;
306 }
307 }
308 iterator->destroy(iterator);
309 return status;
310 }
311
312 /**
313 * @see private_ike_sa_manager_s.delete_entry
314 */
315 static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry)
316 {
317 linked_list_t *list = this->ike_sa_list;
318 linked_list_iterator_t *iterator;
319 status_t status;
320
321 status = list->create_iterator(list, &iterator, TRUE);
322
323 if (status != SUCCESS)
324 {
325 this->logger->log(this->logger,ERROR,"Fatal Error: could not create iterator: %s",mapping_find(status_m,status));
326 return status;
327 }
328
329 status = NOT_FOUND;
330
331 while (iterator->has_next(iterator))
332 {
333 ike_sa_entry_t *current;
334 iterator->current(iterator, (void**)&current);
335 if (current == entry)
336 {
337 this->logger->log(this->logger,CONTROL | MOST,"Found entry by pointer. Going to delete it.");
338 list->remove(list, iterator);
339 entry->destroy(entry);
340 status = SUCCESS;
341 break;
342 }
343 }
344 iterator->destroy(iterator);
345 return status;
346 }
347
348
349 /**
350 * @see private_ike_sa_manager_t.get_next_spi
351 */
352 static status_t get_next_spi(private_ike_sa_manager_t *this, u_int64_t *spi)
353 {
354 this->next_spi++;
355 if (this->next_spi == 0) {
356 /* our software ran so incredible stable, we have no more
357 * SPIs to give away :-/. */
358 this->logger->log(this->logger,CONTROL | MOST,"No more SPI values available. WOW!");
359 return OUT_OF_RES;
360 }
361 *spi = this->next_spi;
362 return SUCCESS;
363 }
364
365 /**
366 * @see ike_sa_manager_s.checkout_ike_sa
367 */
368 static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa)
369 {
370 bool responder_spi_set;
371 bool initiator_spi_set;
372 status_t retval;
373
374 /* each access is locked */
375 pthread_mutex_lock(&(this->mutex));
376
377 responder_spi_set = (FALSE != ike_sa_id->get_responder_spi(ike_sa_id));
378 initiator_spi_set = (FALSE != ike_sa_id->get_initiator_spi(ike_sa_id));
379
380 if (initiator_spi_set && responder_spi_set)
381 {
382 /* we SHOULD have an IKE_SA for these SPIs in the list,
383 * if not, we can't handle the request...
384 */
385 ike_sa_entry_t *entry;
386 /* look for the entry */
387 if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
388 {
389 /* can we give this ike_sa out to new requesters?*/
390 if (entry->driveout_new_threads)
391 {
392 this->logger->log(this->logger,CONTROL|MORE,"Drive out new thread for existing IKE_SA");
393 /* no we can't */
394 retval = NOT_FOUND;
395 }
396 else
397 {
398 /* is this IKE_SA already checked out ??
399 * are we welcome to get this SA ? */
400 while (entry->checked_out && !entry->driveout_waiting_threads)
401 {
402 /* so wait until we can get it for us.
403 * we register us as waiting.
404 */
405 entry->waiting_threads++;
406 pthread_cond_wait(&(entry->condvar), &(this->mutex));
407 entry->waiting_threads--;
408 }
409
410 /* hm, a deletion request forbids us to get this SA, go home */
411 if (entry->driveout_waiting_threads)
412 {
413 /* we must signal here, others are interested that we leave */
414 pthread_cond_signal(&(entry->condvar));
415 this->logger->log(this->logger,CONTROL|MORE,"Drive out waiting thread for existing IKE_SA");
416 retval = NOT_FOUND;
417 }
418 else
419 {
420 this->logger->log(this->logger,CONTROL|MOST,"IKE SA successfully checked out");
421 /* ok, this IKE_SA is finally ours */
422 entry->checked_out = TRUE;
423 *ike_sa = entry->ike_sa;
424 /* DON'T use return, we must unlock the mutex! */
425 retval = SUCCESS;
426 }
427 }
428 }
429 else
430 {
431 this->logger->log(this->logger,ERROR | MORE,"IKE SA not stored in known IKE_SA list");
432 /* looks like there is no such IKE_SA, better luck next time... */
433 /* DON'T use return, we must unlock the mutex! */
434 retval = NOT_FOUND;
435 }
436 }
437 else if (initiator_spi_set && !responder_spi_set)
438 {
439 /* an IKE_SA_INIT from an another endpoint,
440 * he is the initiator.
441 * For simplicity, we do NOT check for retransmitted
442 * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
443 * Request (even a retransmitted one) will result in a
444 * IKE_SA. This could be improved...
445 */
446 u_int64_t responder_spi;
447 ike_sa_entry_t *new_ike_sa_entry;
448
449
450 /* set SPIs, we are the responder */
451 retval = this->get_next_spi(this, &responder_spi);
452
453 if (retval == SUCCESS)
454 { /* next SPI could be created */
455
456 /* we also set arguments spi, so its still valid */
457 ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
458
459 /* create entry */
460 new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
461 if (new_ike_sa_entry != NULL)
462 {
463 retval = this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
464 if (retval == SUCCESS)
465 {
466 /* check ike_sa out */
467 this->logger->log(this->logger,CONTROL | MORE ,"IKE_SA added to list of known IKE_SA's");
468 new_ike_sa_entry->checked_out = TRUE;
469 *ike_sa = new_ike_sa_entry->ike_sa;
470
471 /* DON'T use return, we must unlock the mutex! */
472 }
473 else
474 {
475 /* ike_sa_entry could not be added to list*/
476 this->logger->log(this->logger,ERROR,"Fatal error: ike_sa_entry could not be added to list");
477 }
478 }
479 else
480 {
481 /* new ike_sa_entry could not be created */
482 this->logger->log(this->logger,ERROR,"Fatal error: ike_sa_entry could not be created");
483 }
484 }
485 else
486 { /* next SPI could not be created */
487 this->logger->log(this->logger,ERROR,"Fatal error: Next SPI could not be created");
488 }
489
490 }
491 else if (!initiator_spi_set && !responder_spi_set)
492 {
493 /* creation of an IKE_SA from local site,
494 * we are the initiator!
495 */
496 u_int64_t initiator_spi;
497 ike_sa_entry_t *new_ike_sa_entry;
498
499 retval = this->get_next_spi(this, &initiator_spi);
500 if (retval == SUCCESS)
501 {
502 /* we also set arguments SPI, so its still valid */
503 ike_sa_id->set_initiator_spi(ike_sa_id, initiator_spi);
504
505 /* create entry */
506 new_ike_sa_entry = ike_sa_entry_create(ike_sa_id);
507 if (new_ike_sa_entry != NULL)
508 {
509 retval = this->ike_sa_list->insert_last(this->ike_sa_list, new_ike_sa_entry);
510
511 if (retval == SUCCESS)
512 {
513 /* check ike_sa out */
514 this->logger->log(this->logger,CONTROL | MORE ,"New IKE_SA created and added to list of known IKE_SA's");
515 new_ike_sa_entry->checked_out = TRUE;
516 *ike_sa = new_ike_sa_entry->ike_sa;
517
518 /* DON'T use return, we must unlock the mutex! */
519 }
520 else
521 {
522 /* ike_sa_entry could not be added to list*/
523 this->logger->log(this->logger,ERROR,"Fatal error: ike_sa_entry could not be added to list");
524 }
525 }
526 else
527 {
528 /* new ike_sa_entry could not be created */
529 this->logger->log(this->logger,ERROR,"Fatal error: ike_sa_entry could not be created");
530 }
531 }
532 else
533 {
534 /* next SPI could not be created */
535 this->logger->log(this->logger,ERROR,"Fatal error: Next SPI could not be created");
536 }
537
538
539 }
540 else
541 {
542 /* responder set, initiator not: here is something seriously wrong! */
543 this->logger->log(this->logger,ERROR | MORE,"Invalid IKE_SA SPI's");
544 /* DON'T use return, we must unlock the mutex! */
545 retval = INVALID_ARG;
546 }
547
548 pthread_mutex_unlock(&(this->mutex));
549 /* OK, unlocked... */
550 return retval;
551 }
552
553 /**
554 * Implements ike_sa_manager_t-function checkin.
555 * @see ike_sa_manager_t.checkin.
556 */
557 static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
558 {
559 /* to check the SA back in, we look for the pointer of the ike_sa
560 * in all entries.
561 * We can't search by SPI's since the MAY have changed (e.g. on reception
562 * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary...
563 */
564 status_t retval;
565 ike_sa_entry_t *entry;
566
567 pthread_mutex_lock(&(this->mutex));
568
569 /* look for the entry */
570 if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
571 {
572 /* ike_sa_id must be updated */
573 entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
574 /* signal waiting threads */
575 entry->checked_out = FALSE;
576 this->logger->log(this->logger,CONTROL | MORE,"Checkin of IKE_SA successful.");
577 pthread_cond_signal(&(entry->condvar));
578 retval = SUCCESS;
579 }
580 else
581 {
582 this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin nonexisting IKE_SA");
583 /* this SA is no more, this REALLY should not happen */
584 retval = NOT_FOUND;
585 }
586 pthread_mutex_unlock(&(this->mutex));
587 return retval;
588 }
589
590
591 /**
592 * Implements ike_sa_manager_t-function checkin_and_delete.
593 * @see ike_sa_manager_t.checkin_and_delete.
594 */
595 static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
596 {
597 /* deletion is a bit complex, we must garant that no thread is waiting for
598 * this SA.
599 * We take this SA from the list, and start signaling while threads
600 * are in the condvar.
601 */
602 ike_sa_entry_t *entry;
603 status_t retval;
604
605 pthread_mutex_lock(&(this->mutex));
606
607 if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS)
608 {
609 /* mark it, so now new threads can acquire this SA */
610 entry->driveout_new_threads = TRUE;
611 /* additionaly, drive out waiting threads */
612 entry->driveout_waiting_threads = TRUE;
613
614 /* wait until all workers have done their work */
615 while (entry->waiting_threads > 0)
616 {
617 /* let the other threads do some work*/
618 pthread_cond_signal(&(entry->condvar));
619 /* and the nice thing, they will wake us again when their work is done */
620 pthread_cond_wait(&(entry->condvar), &(this->mutex));
621 }
622 /* ok, we are alone now, no threads waiting in the entry's condvar */
623 this->delete_entry(this, entry);
624 this->logger->log(this->logger,CONTROL | MORE,"Checkin and delete of IKE_SA successful");
625 retval = SUCCESS;
626 }
627 else
628 {
629 this->logger->log(this->logger,ERROR,"Fatal Error: Tried to checkin and delete nonexisting IKE_SA");
630 retval = NOT_FOUND;
631 }
632
633 pthread_mutex_unlock(&(this->mutex));
634 return retval;
635 }
636
637 /**
638 * Implements ike_sa_manager_t-function delete.
639 * @see ike_sa_manager_t.delete.
640 */
641 static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
642 {
643 /* deletion is a bit complex, we must garant that no thread is waiting for
644 * this SA.
645 * We take this SA from the list, and start signaling while threads
646 * are in the condvar.
647 */
648 ike_sa_entry_t *entry;
649 status_t retval;
650
651 pthread_mutex_lock(&(this->mutex));
652
653 if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
654 {
655 /* mark it, so now new threads can acquire this SA */
656 entry->driveout_new_threads = TRUE;
657
658 /* wait until all workers have done their work */
659 while (entry->waiting_threads)
660 {
661 /* wake up all */
662 pthread_cond_signal(&(entry->condvar));
663 /* and the nice thing, they will wake us again when their work is done */
664 pthread_cond_wait(&(entry->condvar), &(this->mutex));
665 }
666 /* ok, we are alone now, no threads waiting in the entry's condvar */
667 this->delete_entry(this, entry);
668 this->logger->log(this->logger,CONTROL | MORE,"Delete of IKE_SA successful");
669 retval = SUCCESS;
670 }
671 else
672 {
673 this->logger->log(this->logger,ERROR,"Fatal Error: Tried to delete nonexisting IKE_SA");
674 retval = NOT_FOUND;
675 }
676
677 pthread_mutex_unlock(&(this->mutex));
678 return retval;
679 }
680
681 /**
682 * Implements ike_sa_manager_t-function destroy.
683 * @see ike_sa_manager_t.destroy.
684 */
685 static status_t destroy(private_ike_sa_manager_t *this)
686 {
687 /* destroy all list entries */
688 linked_list_t *list = this->ike_sa_list;
689 linked_list_iterator_t *iterator;
690 status_t status;
691 ike_sa_entry_t *entry;
692
693 pthread_mutex_lock(&(this->mutex));
694
695 this->logger->log(this->logger,CONTROL | MORE,"Going to destroy IKE_SA manager and all managed IKE_SA's");
696
697 /* Step 1: drive out all waiting threads */
698 status = list->create_iterator(list, &iterator, TRUE);
699
700 if (status != SUCCESS)
701 {
702 this->logger->log(this->logger,ERROR,"Fatal Error: Create of iterator while destroying IKE_SA-Manager failed");
703 return FAILED;
704 }
705
706 this->logger->log(this->logger,CONTROL | MOST,"Set driveout flags for all stored IKE_SA's");
707 while (iterator->has_next(iterator))
708 {
709 iterator->current(iterator, (void**)&entry);
710 /* do not accept new threads, drive out waiting threads */
711 entry->driveout_new_threads = TRUE;
712 entry->driveout_waiting_threads = TRUE;
713 }
714
715 this->logger->log(this->logger,CONTROL | MOST,"Wait for all threads to leave IKE_SA's");
716 /* Step 2: wait until all are gone */
717 iterator->reset(iterator);
718 while (iterator->has_next(iterator))
719 {
720 iterator->current(iterator, (void**)&entry);
721 while (entry->waiting_threads)
722 {
723 /* wake up all */
724 pthread_cond_signal(&(entry->condvar));
725 /* go sleeping until they are gone */
726 pthread_cond_wait(&(entry->condvar), &(this->mutex));
727 }
728 }
729 this->logger->log(this->logger,CONTROL | MOST,"Delete all IKE_SA's");
730 /* Step 3: delete all entries */
731 iterator->destroy(iterator);
732
733 while (list->get_count(list) > 0)
734 {
735 list->get_first(list, (void**)&entry);
736 this->delete_entry(this, entry);
737 }
738 list->destroy(list);
739 this->logger->log(this->logger,CONTROL | MOST,"IKE_SA's deleted");
740 pthread_mutex_unlock(&(this->mutex));
741
742 /* destroy logger at end */
743 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
744
745 allocator_free(this);
746
747 return SUCCESS;
748 }
749
750 /*
751 * Described in header
752 */
753 ike_sa_manager_t *ike_sa_manager_create()
754 {
755 private_ike_sa_manager_t *this = allocator_alloc_thing(private_ike_sa_manager_t);
756
757 /* assign public functions */
758 this->public.destroy = (status_t(*)(ike_sa_manager_t*))destroy;
759 this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id, ike_sa_t **sa))checkout;
760 this->public.checkin = (status_t(*)(ike_sa_manager_t*, ike_sa_t *sa))checkin;
761 this->public.delete = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id))delete;
762 this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkin_and_delete;
763
764 /* initialize private functions */
765 this->get_next_spi = get_next_spi;
766 this->get_entry_by_sa = get_entry_by_sa;
767 this->get_entry_by_id = get_entry_by_id;
768 this->delete_entry = delete_entry;
769
770 /* initialize private variables */
771 this->logger = global_logger_manager->create_logger(global_logger_manager,IKE_SA_MANAGER,NULL);
772 if (this->logger == NULL)
773 {
774 allocator_free(this);
775 return NULL;
776 }
777
778 this->ike_sa_list = linked_list_create();
779 if (this->ike_sa_list == NULL)
780 {
781 this->logger->log(this->logger,ERROR,"Fatal error: Failed to create list for managed IKE_SA");
782 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
783 allocator_free(this);
784 return NULL;
785 }
786
787 pthread_mutex_init(&(this->mutex), NULL);
788
789 this->next_spi = 0;
790
791 return (ike_sa_manager_t*)this;
792 }