fast finishing connectivity checks on the initiators side
This commit is contained in:
@@ -40,6 +40,10 @@
|
|||||||
/* max number of retransmissions */
|
/* max number of retransmissions */
|
||||||
#define ME_MAX_RETRANS 13
|
#define ME_MAX_RETRANS 13
|
||||||
|
|
||||||
|
/* time to wait before the initiator finishes the connectivity checks after
|
||||||
|
* the first check has succeeded */
|
||||||
|
#define ME_WAIT_TO_FINISH 1000 /* ms */
|
||||||
|
|
||||||
|
|
||||||
typedef struct private_connect_manager_t private_connect_manager_t;
|
typedef struct private_connect_manager_t private_connect_manager_t;
|
||||||
|
|
||||||
@@ -193,6 +197,9 @@ struct check_list_t {
|
|||||||
/** TRUE if this is the initiator */
|
/** TRUE if this is the initiator */
|
||||||
bool is_initiator;
|
bool is_initiator;
|
||||||
|
|
||||||
|
/** TRUE if the initiator is finishing the checks */
|
||||||
|
bool is_finishing;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,6 +247,7 @@ static check_list_t *check_list_create(identification_t *initiator, identificati
|
|||||||
this->triggered = linked_list_create();
|
this->triggered = linked_list_create();
|
||||||
this->state = CHECK_NONE;
|
this->state = CHECK_NONE;
|
||||||
this->is_initiator = is_initiator;
|
this->is_initiator = is_initiator;
|
||||||
|
this->is_finishing = FALSE;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -413,7 +421,7 @@ static sender_data_t *sender_data_create(private_connect_manager_t *connect_mana
|
|||||||
{
|
{
|
||||||
sender_data_t *this = malloc_thing(sender_data_t);
|
sender_data_t *this = malloc_thing(sender_data_t);
|
||||||
this->connect_manager = connect_manager;
|
this->connect_manager = connect_manager;
|
||||||
this->connect_id = connect_id;
|
this->connect_id = chunk_clone(connect_id);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,51 +604,6 @@ static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoi
|
|||||||
(void**)endpoint, host);
|
(void**)endpoint, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the state of the whole checklist
|
|
||||||
*/
|
|
||||||
static void update_checklist_state(check_list_t *checklist)
|
|
||||||
{
|
|
||||||
iterator_t *iterator;
|
|
||||||
endpoint_pair_t *current;
|
|
||||||
bool in_progress = FALSE, succeeded = FALSE;
|
|
||||||
|
|
||||||
iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
|
|
||||||
while (iterator->iterate(iterator, (void**)¤t))
|
|
||||||
{
|
|
||||||
switch(current->state)
|
|
||||||
{
|
|
||||||
case CHECK_WAITING:
|
|
||||||
/* at least one is still waiting -> checklist remains
|
|
||||||
* in waiting state */
|
|
||||||
iterator->destroy(iterator);
|
|
||||||
return;
|
|
||||||
case CHECK_IN_PROGRESS:
|
|
||||||
in_progress = TRUE;
|
|
||||||
break;
|
|
||||||
case CHECK_SUCCEEDED:
|
|
||||||
succeeded = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iterator->destroy(iterator);
|
|
||||||
|
|
||||||
if (in_progress)
|
|
||||||
{
|
|
||||||
checklist->state = CHECK_IN_PROGRESS;
|
|
||||||
}
|
|
||||||
else if (succeeded)
|
|
||||||
{
|
|
||||||
checklist->state = CHECK_SUCCEEDED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
checklist->state = CHECK_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
|
* Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
|
||||||
*/
|
*/
|
||||||
@@ -924,6 +887,91 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t *
|
|||||||
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
|
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
|
||||||
static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
|
static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After one of the initiator's pairs has succeeded we finish the checks without
|
||||||
|
* waiting for all the timeouts
|
||||||
|
*/
|
||||||
|
static job_requeue_t initiator_finish(sender_data_t *data)
|
||||||
|
{
|
||||||
|
private_connect_manager_t *this = data->connect_manager;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&(this->mutex));
|
||||||
|
|
||||||
|
check_list_t *checklist;
|
||||||
|
if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "checklist with id '%B' not found, can't finish connectivity checks",
|
||||||
|
&data->connect_id);
|
||||||
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
|
return JOB_REQUEUE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_checks(this, checklist);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
|
|
||||||
|
return JOB_REQUEUE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the state of the whole checklist
|
||||||
|
*/
|
||||||
|
static void update_checklist_state(private_connect_manager_t *this, check_list_t *checklist)
|
||||||
|
{
|
||||||
|
iterator_t *iterator;
|
||||||
|
endpoint_pair_t *current;
|
||||||
|
bool in_progress = FALSE, succeeded = FALSE;
|
||||||
|
|
||||||
|
iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
|
||||||
|
while (iterator->iterate(iterator, (void**)¤t))
|
||||||
|
{
|
||||||
|
switch(current->state)
|
||||||
|
{
|
||||||
|
case CHECK_WAITING:
|
||||||
|
/* at least one is still waiting -> checklist remains
|
||||||
|
* in waiting state */
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
return;
|
||||||
|
case CHECK_IN_PROGRESS:
|
||||||
|
in_progress = TRUE;
|
||||||
|
break;
|
||||||
|
case CHECK_SUCCEEDED:
|
||||||
|
succeeded = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
|
||||||
|
if (checklist->is_initiator && succeeded && !checklist->is_finishing)
|
||||||
|
{
|
||||||
|
/* instead of waiting until all checks have finished (i.e. all
|
||||||
|
* retransmissions have failed) the initiator finishes the checks
|
||||||
|
* right after the first check has succeeded. to allow a probably
|
||||||
|
* better pair to succeed, we still wait a certain time */
|
||||||
|
DBG2(DBG_IKE, "fast finishing checks for checklist '%B'", &checklist->connect_id);
|
||||||
|
|
||||||
|
sender_data_t *data = sender_data_create(this, checklist->connect_id);
|
||||||
|
job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
|
||||||
|
charon->scheduler->schedule_job(charon->scheduler, job, ME_WAIT_TO_FINISH);
|
||||||
|
checklist->is_finishing = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_progress)
|
||||||
|
{
|
||||||
|
checklist->state = CHECK_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
else if (succeeded)
|
||||||
|
{
|
||||||
|
checklist->state = CHECK_SUCCEEDED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checklist->state = CHECK_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is triggered for each sent check after a specific timeout
|
* This function is triggered for each sent check after a specific timeout
|
||||||
*/
|
*/
|
||||||
@@ -970,7 +1018,7 @@ static job_requeue_t retransmit(retransmit_data_t *data)
|
|||||||
queue_retransmission(this, checklist, pair);
|
queue_retransmission(this, checklist, pair);
|
||||||
|
|
||||||
retransmit_end:
|
retransmit_end:
|
||||||
update_checklist_state(checklist);
|
update_checklist_state(this, checklist);
|
||||||
|
|
||||||
switch(checklist->state)
|
switch(checklist->state)
|
||||||
{
|
{
|
||||||
@@ -1114,8 +1162,7 @@ static job_requeue_t sender(sender_data_t *data)
|
|||||||
check_destroy(check);
|
check_destroy(check);
|
||||||
|
|
||||||
/* schedule this job again */
|
/* schedule this job again */
|
||||||
u_int32_t N = this->checklists->get_count(this->checklists);
|
schedule_checks(this, checklist, ME_INTERVAL);
|
||||||
schedule_checks(this, checklist, ME_INTERVAL * N);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&(this->mutex));
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
|
|
||||||
@@ -1128,8 +1175,7 @@ static job_requeue_t sender(sender_data_t *data)
|
|||||||
*/
|
*/
|
||||||
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
|
static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
|
||||||
{
|
{
|
||||||
chunk_t connect_id = chunk_clone(checklist->connect_id);
|
sender_data_t *data = sender_data_create(this, checklist->connect_id);
|
||||||
sender_data_t *data = sender_data_create(this, connect_id);
|
|
||||||
job_t *job = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
|
job_t *job = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
|
||||||
charon->scheduler->schedule_job(charon->scheduler, job, time);
|
charon->scheduler->schedule_job(charon->scheduler, job, time);
|
||||||
}
|
}
|
||||||
@@ -1225,7 +1271,7 @@ static void process_response(private_connect_manager_t *this, check_t *check,
|
|||||||
local_endpoints->insert_last(local_endpoints, local_endpoint);
|
local_endpoints->insert_last(local_endpoints, local_endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_checklist_state(checklist);
|
update_checklist_state(this, checklist);
|
||||||
|
|
||||||
switch(checklist->state)
|
switch(checklist->state)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user