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