From d4425c1b6671a52c57dcd4678ff31e28ffc21b07 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 9 Nov 2005 11:44:49 +0000 Subject: [PATCH] - finish functionality of ike_sa_manager - tested --- Source/charon/ike_sa_manager.c | 213 ++++++++++++++-------- Source/charon/ike_sa_manager.h | 76 ++++++-- Source/charon/tests.c | 7 + Source/charon/tests/ike_sa_manager_test.c | 180 +++++++++++++++--- 4 files changed, 359 insertions(+), 117 deletions(-) diff --git a/Source/charon/ike_sa_manager.c b/Source/charon/ike_sa_manager.c index 267e3b0da3..dac03c2b12 100644 --- a/Source/charon/ike_sa_manager.c +++ b/Source/charon/ike_sa_manager.c @@ -34,7 +34,7 @@ typedef struct ike_sa_entry_s ike_sa_entry_t; struct ike_sa_entry_s { /** - * destructor, recursivly destroys ike_sa + * destructor, also destroys ike_sa */ status_t (*destroy) (ike_sa_entry_t *this); /** @@ -49,6 +49,14 @@ struct ike_sa_entry_s { * is this ike_sa currently checked out? */ bool checked_out; + /** + * does this SA let new treads in? + */ + bool driveout_new_threads; + /** + * does this SA drives out new threads? + */ + bool driveout_waiting_threads;; /** * identifiaction of ike_sa (SPIs) */ @@ -59,13 +67,15 @@ struct ike_sa_entry_s { ike_sa_t *ike_sa; }; +/** + * @see ike_sa_entry_t.destroy + */ static status_t ike_sa_entry_destroy(ike_sa_entry_t *this) { this->ike_sa->destroy(this->ike_sa); this->ike_sa_id->destroy(this->ike_sa_id); allocator_free(this); return SUCCESS; - } @@ -86,6 +96,8 @@ ike_sa_entry_t *ike_sa_entry_create(ike_sa_id_t *ike_sa_id) pthread_cond_init(&(this->condvar), NULL); /* we set checkout flag when we really give it out */ this->checked_out = FALSE; + this->driveout_new_threads = FALSE; + this->driveout_waiting_threads = FALSE; this->ike_sa_id = ike_sa_id; this->ike_sa = ike_sa_create(ike_sa_id); return this; @@ -132,14 +144,19 @@ struct private_ike_sa_manager_s { * would be more efficient when storing a lot of IKE_SAs... * * @param this the ike_sa_manager containing the list - * @param ike_sad pointer to the ike_sa + * @param ike_sa pointer to the ike_sa * @param entry[out] pointer to set to the found entry * @return SUCCESS when found, * NOT_FOUND when no such ike_sa_id in list */ status_t (*get_entry_by_sa) (private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry); /** - * @brief + * @brief delete an entry from the linked list + * + * @param this the ike_sa_manager containing the list + * @param entry entry to delete + * @return SUCCESS when found, + * NOT_FOUND when no such ike_sa_id in list */ status_t (*delete_entry) (private_ike_sa_manager_t *this, ike_sa_entry_t *entry); /** @@ -159,9 +176,9 @@ struct private_ike_sa_manager_s { /** - * @see private_ike_sa_manager_t.get_ike_sa_entry + * @see private_ike_sa_manager_t.get_entry_by_id */ -static status_t get_ike_sa_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_entry_t **entry) +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) { linked_list_t *list = this->list; linked_list_iterator_t *iterator; @@ -184,9 +201,9 @@ static status_t get_ike_sa_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id } /** - * @see private_ike_sa_manager_t.get_ike_sa_entry_by_sa + * @see private_ike_sa_manager_t.get_entry_by_sa */ -static status_t get_ike_sa_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry) +static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa, ike_sa_entry_t **entry) { linked_list_t *list = this->list; linked_list_iterator_t *iterator; @@ -206,6 +223,30 @@ static status_t get_ike_sa_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_t return NOT_FOUND; } +/** + * @see private_ike_sa_manager_t.delete_entry + */ +static status_t delete_entry(private_ike_sa_manager_t *this, ike_sa_entry_t *entry) +{ + linked_list_t *list = this->list; + linked_list_iterator_t *iterator; + list->create_iterator(list, &iterator, TRUE); + while (iterator->has_next(iterator)) + { + ike_sa_entry_t *current; + iterator->current(iterator, (void**)¤t); + if (current == entry) + { + list->remove(list, iterator); + entry->destroy(entry); + iterator->destroy(iterator); + return SUCCESS; + } + } + iterator->destroy(iterator); + return NOT_FOUND; +} + /** * @see private_ike_sa_manager_t.get_next_spi @@ -230,7 +271,7 @@ static status_t get_next_spi(private_ike_sa_manager_t *this, spi_t *spi) /** * @see ike_sa_manager_s.checkout_ike_sa */ -static status_t checkout_ike_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa) +static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t **ike_sa) { bool responder_spi_set; bool initiator_spi_set; @@ -250,27 +291,44 @@ static status_t checkout_ike_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike /* look for the entry */ if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { - /* is this IKE_SA already checked out ?? */ - while (entry->checked_out) + /* can we give this out to new requesters? */ + if (entry->driveout_new_threads) { - /* so wait until we can get it for us. - * we register us as waiting. - */ - entry->waiting_threads++; - pthread_cond_wait(&(entry->condvar), &(this->mutex)); - entry->waiting_threads--; + retval = NOT_FOUND; + } + else + { + /* is this IKE_SA already checked out ?? + * are we welcome to get this SA ? */ + while (entry->checked_out && !entry->driveout_waiting_threads) + { + /* so wait until we can get it for us. + * we register us as waiting. + */ + entry->waiting_threads++; + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + entry->waiting_threads--; + } + /* hm, a deletion request forbids us to get this SA, go home */ + if (entry->driveout_waiting_threads) + { + /* we must signal here, others are interested that we leave */ + pthread_cond_signal(&(entry->condvar)); + retval = NOT_FOUND; + } + else + { + /* ok, this IKE_SA is finally ours */ + entry->checked_out = TRUE; + *ike_sa = entry->ike_sa; + /* DON'T use return, we must unlock the mutex! */ + retval = SUCCESS; + } } - /* ok, this IKE_SA is finally ours */ - entry->checked_out = TRUE; - *ike_sa = entry->ike_sa; - /* DON'T use return, we must unlock the mutex! */ - retval = SUCCESS; - } else { /* looks like there is no such IKE_SA, better luck next time... */ - /* DON'T use return, we must unlock the mutex! */ retval = NOT_FOUND; } @@ -317,6 +375,7 @@ static status_t checkout_ike_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike /* set SPIs */ memset(&responder_spi, 0, sizeof(spi_t)); + this->get_next_spi(this, &initiator_spi); /* we also set arguments SPI, so its still valid */ @@ -347,7 +406,7 @@ static status_t checkout_ike_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike return retval; } -static status_t checkin_ike_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* to check the SA back in, we look for the pointer of the ike_sa * in all entries. @@ -356,10 +415,9 @@ static status_t checkin_ike_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) */ status_t retval; ike_sa_entry_t *entry; - + pthread_mutex_lock(&(this->mutex)); - /* look for the entry */ if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) { @@ -381,48 +439,35 @@ static status_t checkin_ike_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) -static status_t delete_ike_sa_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +static status_t checkin_and_delete(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. * We take this SA from the list, and start signaling while threads * are in the condvar. */ - linked_list_t *list = this->list; - linked_list_iterator_t *iterator; ike_sa_entry_t *entry; - bool found = FALSE; status_t retval; pthread_mutex_lock(&(this->mutex)); - /* remove SA from list */ - list->create_iterator(list, &iterator, TRUE); - while (iterator->has_next(iterator)) + if (this->get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) { - iterator->current(iterator, (void**)&entry); - if (entry->ike_sa == ike_sa) - { - list->remove(list, iterator); - found = TRUE; - break; - } - } - iterator->destroy(iterator); + /* mark it, so now new threads can acquire this SA */ + entry->driveout_new_threads = TRUE; + /* additionaly, drive out waiting threads */ + entry->driveout_waiting_threads = TRUE; - if (found) - { /* wait until all workers have done their work */ while (entry->waiting_threads) { - /* wake up all */ + /* let the other threads do some work*/ pthread_cond_signal(&(entry->condvar)); /* and the nice thing, they will wake us again when their work is done */ pthread_cond_wait(&(entry->condvar), &(this->mutex)); } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - entry->destroy(entry); + this->delete_entry(this, entry); retval = SUCCESS; } else @@ -434,39 +479,23 @@ static status_t delete_ike_sa_by_sa(private_ike_sa_manager_t *this, ike_sa_t *ik return retval; } -static status_t delete_ike_sa_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) +static status_t delete(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) { /* deletion is a bit complex, we must garant that no thread is waiting for * this SA. * We take this SA from the list, and start signaling while threads * are in the condvar. */ - linked_list_t *list = this->list; - linked_list_iterator_t *iterator; ike_sa_entry_t *entry; - bool found = FALSE; status_t retval; pthread_mutex_lock(&(this->mutex)); - /* remove SA from list */ - list->create_iterator(list, &iterator, TRUE); - while (iterator->has_next(iterator)) + if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) { - bool are_equal = FALSE; - iterator->current(iterator, (void**)&entry); - entry->ike_sa_id->equals(entry->ike_sa_id, ike_sa_id, &are_equal); - if (are_equal) - { - list->remove(list, iterator); - found = TRUE; - break; - } - } - iterator->destroy(iterator); + /* mark it, so now new threads can acquire this SA */ + entry->driveout_new_threads = TRUE; - if (found) - { /* wait until all workers have done their work */ while (entry->waiting_threads) { @@ -475,9 +504,8 @@ static status_t delete_ike_sa_by_id(private_ike_sa_manager_t *this, ike_sa_id_t /* and the nice thing, they will wake us again when their work is done */ pthread_cond_wait(&(entry->condvar), &(this->mutex)); } - /* ok, we are alone now, no threads waiting in the entry's condvar */ - entry->destroy(entry); + this->delete_entry(this, entry); retval = SUCCESS; } else @@ -494,16 +522,46 @@ static status_t destroy(private_ike_sa_manager_t *this) /* destroy all list entries */ linked_list_t *list = this->list; linked_list_iterator_t *iterator; + + pthread_mutex_lock(&(this->mutex)); + + /* Step 1: drive out all waiting threads */ list->create_iterator(list, &iterator, TRUE); while (iterator->has_next(iterator)) { ike_sa_entry_t *entry; iterator->current(iterator, (void**)&entry); - entry->destroy(entry); + /* do not accept new threads, drive out waiting threads */ + entry->driveout_new_threads = TRUE; + entry->driveout_waiting_threads = TRUE; + } + /* Step 2: wait until all are gone */ + iterator->reset(iterator); + while (iterator->has_next(iterator)) + { + ike_sa_entry_t *entry; + iterator->current(iterator, (void**)&entry); + while (entry->waiting_threads) + { + /* wake up all */ + pthread_cond_signal(&(entry->condvar)); + /* go sleeping until they are gone */ + pthread_cond_wait(&(entry->condvar), &(this->mutex)); + } + } + /* Step 3: delete all entries */ + iterator->reset(iterator); + while (iterator->has_next(iterator)) + { + ike_sa_entry_t *entry; + iterator->current(iterator, (void**)&entry); + this->delete_entry(this, entry); } iterator->destroy(iterator); list->destroy(list); + + pthread_mutex_unlock(&(this->mutex)); allocator_free(this); @@ -517,15 +575,16 @@ ike_sa_manager_t *ike_sa_manager_create() /* assign public functions */ this->public.destroy = (status_t(*)(ike_sa_manager_t*))destroy; - this->public.checkout_ike_sa = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id, ike_sa_t **sa))checkout_ike_sa; - this->public.checkin_ike_sa = (status_t(*)(ike_sa_manager_t*, ike_sa_t *sa))checkin_ike_sa; - this->public.delete_ike_sa_by_id = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id))delete_ike_sa_by_id; - this->public.delete_ike_sa_by_sa = (status_t(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))delete_ike_sa_by_sa; + this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id, ike_sa_t **sa))checkout; + this->public.checkin = (status_t(*)(ike_sa_manager_t*, ike_sa_t *sa))checkin; + this->public.delete = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t *sa_id))delete; + this->public.checkin_and_delete = (status_t(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkin_and_delete; /* initialize private data */ this->get_next_spi = get_next_spi; - this->get_entry_by_sa = get_ike_sa_entry_by_sa; - this->get_entry_by_id = get_ike_sa_entry_by_id; + this->get_entry_by_sa = get_entry_by_sa; + this->get_entry_by_id = get_entry_by_id; + this->delete_entry = delete_entry; this->list = linked_list_create(); if (this->list == NULL) diff --git a/Source/charon/ike_sa_manager.h b/Source/charon/ike_sa_manager.h index ffd9d95cf9..0b3acdbcb9 100644 --- a/Source/charon/ike_sa_manager.h +++ b/Source/charon/ike_sa_manager.h @@ -34,31 +34,81 @@ * the manager, and checked back in after usage. * The manager also handles deletion of SAs. * + * @todo checking of double-checkouts from the same threads would be nice. + * This could be by comparing thread-ids via pthread_self()... + * */ typedef struct ike_sa_manager_s ike_sa_manager_t; struct ike_sa_manager_s { - - status_t (*checkout_ike_sa) (ike_sa_manager_t*, ike_sa_id_t *sa_id, ike_sa_t **ike_sa); - status_t (*checkin_ike_sa) (ike_sa_manager_t*, ike_sa_t *ike_sa); - status_t (*delete_ike_sa_by_id) (ike_sa_manager_t*, ike_sa_id_t *ike_sa_id); - status_t (*delete_ike_sa_by_sa) (ike_sa_manager_t*, ike_sa_t *ike_sa); + /** + * @brief Checkout an IKE_SA, create it when necesarry + * + * Checks out a SA by its ID. An SA will be created, when: + * - Responder SPI is not set (when received an IKE_SA_INIT from initiator) + * - Both SPIs are not set (for initiating IKE_SA_INIT) + * Management of SPIs is the managers job, he will set it. + * This function blocks until SA is available for checkout. + * + * @warning checking out two times without checking in will + * result in a deadlock! + * + * @param ike_sa_manager the manager object + * @param ike_sa_id[in/out] the SA identifier, will be updated + * @param ike_sa[out] checked out SA + * @returns SUCCESS if checkout successful + * NOT_FOUND when no such SA is available + */ + status_t (*checkout) (ike_sa_manager_t* ike_sa_manager, ike_sa_id_t *sa_id, ike_sa_t **ike_sa); + /** + * @brief Checkin the SA after usage + * + * @warning the pointer MUST NOT be used after checkin! The SA must be checked + * out again! + * + * @param ike_sa_manager the manager object + * @param ike_sa_id[in/out] the SA identifier, will be updated + * @param ike_sa[out] checked out SA + * @returns SUCCESS if checked in + * NOT_FOUND when not found (shouldn't happen!) + */ + status_t (*checkin) (ike_sa_manager_t* ike_sa_manager, ike_sa_t *ike_sa); + /** + * @brief delete a SA, wich was not checked out + * + * @warning do not use this when the SA is already checked out, this will + * deadlock! + * + * @param ike_sa_manager the manager object + * @param ike_sa_id[in/out] the SA identifier + * @returns SUCCESS if found + * NOT_FOUND when no such SA is available + */ + status_t (*delete) (ike_sa_manager_t* ike_sa_manager, ike_sa_id_t *ike_sa_id); + /** + * @brief delete a checked out SA + * + * @param ike_sa_manager the manager object + * @param ike_sa SA to delete + * @returns SUCCESS if found + * NOT_FOUND when no such SA is available + */ + status_t (*checkin_and_delete) (ike_sa_manager_t* ike_sa_manager, ike_sa_t *ike_sa); /** - * @brief Destroys a linked_list object + * @brief Destroys the manager with all associated SAs * - * @warning all items are removed before deleting the list. The - * associated values are NOT destroyed. - * Destroying an list which is not empty may cause - * memory leaks! + * Threads will be driven out, so all SAs can be deleted cleanly * - * @param linked_list calling object + * @param ike_sa_manager the manager object * @returns SUCCESS if succeeded, FAILED otherwise */ - status_t (*destroy) (ike_sa_manager_t *isam); + status_t (*destroy) (ike_sa_manager_t *ike_sa_manager); }; /** - * @brief Create the IKE_SA-Manager + * @brief Create a manager + * + * @returns the manager */ ike_sa_manager_t *ike_sa_manager_create(); diff --git a/Source/charon/tests.c b/Source/charon/tests.c index 565b2e15c4..490703c105 100644 --- a/Source/charon/tests.c +++ b/Source/charon/tests.c @@ -40,6 +40,7 @@ #include "tests/receiver_test.h" #include "tests/ike_sa_id_test.h" #include "tests/ike_sa_test.h" +#include "tests/ike_sa_manager_test.h" #include "tests/generator_test.h" @@ -112,6 +113,11 @@ test_t ike_sa_id_test = {test_ike_sa_id,"IKE_SA-Identifier"}; test_t ike_sa_test = {test_ike_sa,"IKE_SA"}; +/** + * Test for ike_sa_manager_t + */ +test_t ike_sa_manager_test = {test_ike_sa_manager, "IKE_SA-Manager"}; + /** * Test for generator_t */ @@ -156,6 +162,7 @@ socket_t *global_socket; &ike_sa_id_test, &ike_sa_test, &generator_test, + &ike_sa_manager_test, NULL }; diff --git a/Source/charon/tests/ike_sa_manager_test.c b/Source/charon/tests/ike_sa_manager_test.c index 9d812a634b..e85efe1604 100644 --- a/Source/charon/tests/ike_sa_manager_test.c +++ b/Source/charon/tests/ike_sa_manager_test.c @@ -33,23 +33,27 @@ static struct ike_sa_manager_test_struct_s { tester_t *tester; ike_sa_manager_t *isam; -} globals; +} td; -static void sa_blocker_thread(ike_sa_id_t *ike_sa_id) +static void successful_thread(ike_sa_id_t *ike_sa_id) { ike_sa_t *ike_sa; - ike_sa_manager_t *isam; - tester_t *tester; status_t status; - isam = globals.isam; - tester = globals.tester; - status = isam->checkout_ike_sa(isam, ike_sa_id, &ike_sa); - tester->assert_true(tester, (status == SUCCESS), "checkout_ike_sa as blocker"); - sleep(1); - status = isam->checkin_ike_sa(isam, ike_sa); - + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + td.tester->assert_true(td.tester, (status == SUCCESS), "checkout of a blocked ike_sa"); + usleep(10000); + status = td.isam->checkin(td.isam, ike_sa); + td.tester->assert_true(td.tester, (status == SUCCESS), "checkin of a requested ike_sa"); +} + +static void failed_thread(ike_sa_id_t *ike_sa_id) +{ + ike_sa_t *ike_sa; + status_t status; + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + td.tester->assert_true(td.tester, (status == NOT_FOUND), "IKE_SA already deleted"); } void test_ike_sa_manager(tester_t *tester) @@ -58,28 +62,150 @@ void test_ike_sa_manager(tester_t *tester) spi_t initiator, responder; ike_sa_id_t *ike_sa_id; ike_sa_t *ike_sa; - ike_sa_manager_t *isam; - pthread_t threads[3]; + int thread_count = 200; + int sa_count = 50; + int i; + pthread_t threads[thread_count]; - isam = ike_sa_manager_create(); + td.tester = tester; + td.isam = ike_sa_manager_create(); - /* we play initiator for IKE_SA_INIT first */ + + + + + /* First Test: + * we play initiator for IKE_SA_INIT first + * create an IKE_SA, + * + */ memset(&initiator, 0, sizeof(initiator)); memset(&responder, 0, sizeof(responder)); ike_sa_id = ike_sa_id_create(initiator, responder, INITIATOR); - status = isam->checkout_ike_sa(isam, ike_sa_id, &ike_sa); - - tester->assert_true(tester, (status == SUCCESS), "checkout_ike_sa as initiator"); - pthread_create(&threads[0], NULL, (void*(*)(void*))sa_blocker_thread, (void*)ike_sa_id); - - - status = isam->checkin_ike_sa(isam, ike_sa); - - pthread_join(threads[0], NULL); - - + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkout unexisting IKE_SA"); + /* for testing purposes, we manipulate the responder spi. + * this is usually done be the response from the communication partner, + * but we don't have one... + */ ike_sa_id->destroy(ike_sa_id); - isam->destroy(isam); + ike_sa_id = ike_sa->get_id(ike_sa); + responder.low = 123; + ike_sa_id->set_responder_spi(ike_sa_id, responder); + /* check in, so we should have a "completed" sa, specified by ike_sa_id */ + status = td.isam->checkin(td.isam, ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkin modified IKE_SA"); + + /* now we check it out and start some other threads */ + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkout existing IKE_SA 1"); + + + + for (i = 0; i < thread_count; i++) + { + if (pthread_create(&threads[i], NULL, (void*(*)(void*))successful_thread, (void*)ike_sa_id)) + { + /* failed, decrease list */ + thread_count--; + i--; + } + } + sleep(1); + + status = td.isam->checkin(td.isam, ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkin IKE_SA"); + + + sleep(1); + /* we now delete the IKE_SA, while it is requested by the threads. + * this should block until the have done their work.*/ + status = td.isam->delete(td.isam, ike_sa_id); + tester->assert_true(tester, (status == SUCCESS), "delete IKE_SA by id"); + + + for (i = 0; i < thread_count; i++) + { + pthread_join(threads[i], NULL); + } + + + + + + /* Second Test: + * now we simulate our partner initiates an IKE_SA_INIT, + * so we are the responder. + * + */ + + memset(&initiator, 0, sizeof(initiator)); + memset(&responder, 0, sizeof(responder)); + + initiator.low = 123; + ike_sa_id = ike_sa_id_create(initiator, responder, RESPONDER); + + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkout unexisting IKE_SA 2"); + //ike_sa_id->destroy(ike_sa_id); + for (i = 0; i < thread_count; i++) + { + if (pthread_create(&threads[i], NULL, (void*(*)(void*))failed_thread, (void*)ike_sa_id)) + { + /* failed, decrease list */ + thread_count--; + i--; + } + } + /* let them go acquiring */ + sleep(1); + + /* this time, we delete the ike_sa while its checked out */ + td.isam->checkin_and_delete(td.isam, ike_sa); + tester->assert_true(tester, (status == SUCCESS), "delete IKE_SA by SA"); + + for (i = 0; i < thread_count; i++) + { + pthread_join(threads[i], NULL); + } + + /* Third Test: + * put in a lot of IKE_SAs, check it out, set a thread waiting + * and destroy the manager... + */ + + memset(&initiator, 0, sizeof(initiator)); + memset(&responder, 0, sizeof(responder)); + + thread_count = sa_count; + + for (i = 0; i < sa_count; i++) + { + initiator.low = i + 1; + ike_sa_id = ike_sa_id_create(initiator, responder, RESPONDER); + + status = td.isam->checkout(td.isam, ike_sa_id, &ike_sa); + tester->assert_true(tester, (status == SUCCESS), "checkout unexisting IKE_SA 3"); + + if (pthread_create(&threads[i], NULL, (void*(*)(void*))failed_thread, (void*)ike_sa_id)) + { + /* failed, decrease list */ + thread_count--; + } + //ike_sa_id->destroy(ike_sa_id); + } + + /* let them go acquiring */ + sleep(1); + + td.isam->destroy(td.isam); + + for (i = 0; i < thread_count; i++) + { + pthread_join(threads[i], NULL); + } + } +