ikev2: Add possibility to delay initiation of a queued task
Such a task is not initiated unless a certain time has passed. This allows delaying certain tasks but avoids problems if we'd do this via a scheduled job (e.g. if the IKE_SA is rekeyed in the meantime). If the IKE_SA is rekeyed the delay of such tasks is reset when the tasks are adopted i.e. they get executed immediately on the new IKE_SA. This hasn't been implemented for IKEv1 yet.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2015 Tobias Brunner
|
||||
* Copyright (C) 2006-2016 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -2620,6 +2620,12 @@ METHOD(ike_sa_t, queue_task, void,
|
||||
this->task_manager->queue_task(this->task_manager, task);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, queue_task_delayed, void,
|
||||
private_ike_sa_t *this, task_t *task, uint32_t delay)
|
||||
{
|
||||
this->task_manager->queue_task_delayed(this->task_manager, task, delay);
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, inherit_pre, void,
|
||||
private_ike_sa_t *this, ike_sa_t *other_public)
|
||||
{
|
||||
@@ -2938,6 +2944,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
|
||||
.create_task_enumerator = _create_task_enumerator,
|
||||
.flush_queue = _flush_queue,
|
||||
.queue_task = _queue_task,
|
||||
.queue_task_delayed = _queue_task_delayed,
|
||||
#ifdef ME
|
||||
.act_as_mediation_server = _act_as_mediation_server,
|
||||
.get_server_reflexive_host = _get_server_reflexive_host,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2015 Tobias Brunner
|
||||
* Copyright (C) 2006-2016 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -1123,6 +1123,15 @@ struct ike_sa_t {
|
||||
*/
|
||||
void (*queue_task)(ike_sa_t *this, task_t *task);
|
||||
|
||||
/**
|
||||
* Queue a task in the manager, but delay its initiation for at least the
|
||||
* given number of seconds.
|
||||
*
|
||||
* @param task task to queue
|
||||
* @param delay minimum delay in s before initiating the task
|
||||
*/
|
||||
void (*queue_task_delayed)(ike_sa_t *this, task_t *task, uint32_t delay);
|
||||
|
||||
/**
|
||||
* Inherit required attributes to new SA before rekeying.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2016 Tobias Brunner
|
||||
* Copyright (C) 2007-2011 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -1513,8 +1513,8 @@ static bool has_queued(private_task_manager_t *this, task_type_t type)
|
||||
return found;
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, queue_task, void,
|
||||
private_task_manager_t *this, task_t *task)
|
||||
METHOD(task_manager_t, queue_task_delayed, void,
|
||||
private_task_manager_t *this, task_t *task, uint32_t delay)
|
||||
{
|
||||
task_type_t type = task->get_type(task);
|
||||
|
||||
@@ -1535,6 +1535,12 @@ METHOD(task_manager_t, queue_task, void,
|
||||
this->queued_tasks->insert_last(this->queued_tasks, task);
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, queue_task, void,
|
||||
private_task_manager_t *this, task_t *task)
|
||||
{
|
||||
queue_task_delayed(this, task, 0);
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, queue_ike, void,
|
||||
private_task_manager_t *this)
|
||||
{
|
||||
@@ -1975,6 +1981,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
|
||||
.task_manager = {
|
||||
.process_message = _process_message,
|
||||
.queue_task = _queue_task,
|
||||
.queue_task_delayed = _queue_task_delayed,
|
||||
.queue_ike = _queue_ike,
|
||||
.queue_ike_rekey = _queue_ike_rekey,
|
||||
.queue_ike_reauth = _queue_ike_reauth,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2016 Tobias Brunner
|
||||
* Copyright (C) 2007-2010 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -43,30 +43,14 @@
|
||||
#include <encoding/payloads/unknown_payload.h>
|
||||
#include <processing/jobs/retransmit_job.h>
|
||||
#include <processing/jobs/delete_ike_sa_job.h>
|
||||
#include <processing/jobs/initiate_tasks_job.h>
|
||||
|
||||
#ifdef ME
|
||||
#include <sa/ikev2/tasks/ike_me.h>
|
||||
#endif
|
||||
|
||||
typedef struct exchange_t exchange_t;
|
||||
|
||||
/**
|
||||
* An exchange in the air, used do detect and handle retransmission
|
||||
*/
|
||||
struct exchange_t {
|
||||
|
||||
/**
|
||||
* Message ID used for this transaction
|
||||
*/
|
||||
uint32_t mid;
|
||||
|
||||
/**
|
||||
* generated packet for retransmission
|
||||
*/
|
||||
packet_t *packet;
|
||||
};
|
||||
|
||||
typedef struct private_task_manager_t private_task_manager_t;
|
||||
typedef struct queued_task_t queued_task_t;
|
||||
|
||||
/**
|
||||
* private data of the task manager
|
||||
@@ -181,6 +165,22 @@ struct private_task_manager_t {
|
||||
bool make_before_break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queued tasks
|
||||
*/
|
||||
struct queued_task_t {
|
||||
|
||||
/**
|
||||
* Queued task
|
||||
*/
|
||||
task_t *task;
|
||||
|
||||
/**
|
||||
* Time before which the task is not to be initiated
|
||||
*/
|
||||
timeval_t time;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset retransmission packet list
|
||||
*/
|
||||
@@ -216,6 +216,12 @@ METHOD(task_manager_t, flush_queue, void,
|
||||
}
|
||||
while (array_remove(array, ARRAY_TAIL, &task))
|
||||
{
|
||||
if (queue == TASK_QUEUE_QUEUED)
|
||||
{
|
||||
queued_task_t *queued = (queued_task_t*)task;
|
||||
task = queued->task;
|
||||
free(queued);
|
||||
}
|
||||
task->destroy(task);
|
||||
}
|
||||
}
|
||||
@@ -229,22 +235,28 @@ METHOD(task_manager_t, flush, void,
|
||||
}
|
||||
|
||||
/**
|
||||
* move a task of a specific type from the queue to the active list
|
||||
* Move a task of a specific type from the queue to the active list, if it is
|
||||
* not delayed.
|
||||
*/
|
||||
static bool activate_task(private_task_manager_t *this, task_type_t type)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
task_t *task;
|
||||
queued_task_t *queued;
|
||||
timeval_t now;
|
||||
bool found = FALSE;
|
||||
|
||||
time_monotonic(&now);
|
||||
|
||||
enumerator = array_create_enumerator(this->queued_tasks);
|
||||
while (enumerator->enumerate(enumerator, (void**)&task))
|
||||
while (enumerator->enumerate(enumerator, (void**)&queued))
|
||||
{
|
||||
if (task->get_type(task) == type)
|
||||
if (queued->task->get_type(queued->task) == type &&
|
||||
!timercmp(&now, &queued->time, <))
|
||||
{
|
||||
DBG2(DBG_IKE, " activating %N task", task_type_names, type);
|
||||
array_remove_at(this->queued_tasks, enumerator);
|
||||
array_insert(this->active_tasks, ARRAY_TAIL, task);
|
||||
array_insert(this->active_tasks, ARRAY_TAIL, queued->task);
|
||||
free(queued);
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
@@ -1524,18 +1536,19 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, queue_task, void,
|
||||
private_task_manager_t *this, task_t *task)
|
||||
METHOD(task_manager_t, queue_task_delayed, void,
|
||||
private_task_manager_t *this, task_t *task, uint32_t delay)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
queued_task_t *queued;
|
||||
timeval_t time;
|
||||
|
||||
if (task->get_type(task) == TASK_IKE_MOBIKE)
|
||||
{ /* there is no need to queue more than one mobike task */
|
||||
enumerator_t *enumerator;
|
||||
task_t *current;
|
||||
|
||||
enumerator = array_create_enumerator(this->queued_tasks);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
while (enumerator->enumerate(enumerator, &queued))
|
||||
{
|
||||
if (current->get_type(current) == TASK_IKE_MOBIKE)
|
||||
if (queued->task->get_type(queued->task) == TASK_IKE_MOBIKE)
|
||||
{
|
||||
enumerator->destroy(enumerator);
|
||||
task->destroy(task);
|
||||
@@ -1544,8 +1557,35 @@ METHOD(task_manager_t, queue_task, void,
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
|
||||
array_insert(this->queued_tasks, ARRAY_TAIL, task);
|
||||
time_monotonic(&time);
|
||||
if (delay)
|
||||
{
|
||||
job_t *job;
|
||||
|
||||
DBG2(DBG_IKE, "queueing %N task (delayed by %us)", task_type_names,
|
||||
task->get_type(task), delay);
|
||||
time.tv_sec += delay;
|
||||
|
||||
job = (job_t*)initiate_tasks_job_create(
|
||||
this->ike_sa->get_id(this->ike_sa));
|
||||
lib->scheduler->schedule_job_tv(lib->scheduler, job, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG2(DBG_IKE, "queueing %N task", task_type_names,
|
||||
task->get_type(task));
|
||||
}
|
||||
INIT(queued,
|
||||
.task = task,
|
||||
.time = time,
|
||||
);
|
||||
array_insert(this->queued_tasks, ARRAY_TAIL, queued);
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, queue_task, void,
|
||||
private_task_manager_t *this, task_t *task)
|
||||
{
|
||||
queue_task_delayed(this, task, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1555,12 +1595,12 @@ static bool has_queued(private_task_manager_t *this, task_type_t type)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
bool found = FALSE;
|
||||
task_t *task;
|
||||
queued_task_t *queued;
|
||||
|
||||
enumerator = array_create_enumerator(this->queued_tasks);
|
||||
while (enumerator->enumerate(enumerator, &task))
|
||||
while (enumerator->enumerate(enumerator, &queued))
|
||||
{
|
||||
if (task->get_type(task) == type)
|
||||
if (queued->task->get_type(queued->task) == type)
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -1639,7 +1679,7 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
|
||||
child_cfg_t *cfg;
|
||||
ike_sa_t *new;
|
||||
host_t *host;
|
||||
task_t *task;
|
||||
queued_task_t *queued;
|
||||
|
||||
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
|
||||
this->ike_sa->get_version(this->ike_sa), TRUE);
|
||||
@@ -1670,13 +1710,14 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
enumerator = array_create_enumerator(this->queued_tasks);
|
||||
while (enumerator->enumerate(enumerator, &task))
|
||||
while (enumerator->enumerate(enumerator, &queued))
|
||||
{
|
||||
if (task->get_type(task) == TASK_CHILD_CREATE)
|
||||
if (queued->task->get_type(queued->task) == TASK_CHILD_CREATE)
|
||||
{
|
||||
task->migrate(task, new);
|
||||
new->queue_task(new, task);
|
||||
queued->task->migrate(queued->task, new);
|
||||
new->queue_task(new, queued->task);
|
||||
array_remove_at(this->queued_tasks, enumerator);
|
||||
free(queued);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
@@ -1801,34 +1842,62 @@ METHOD(task_manager_t, adopt_tasks, void,
|
||||
private_task_manager_t *this, task_manager_t *other_public)
|
||||
{
|
||||
private_task_manager_t *other = (private_task_manager_t*)other_public;
|
||||
task_t *task;
|
||||
queued_task_t *queued;
|
||||
timeval_t now;
|
||||
|
||||
time_monotonic(&now);
|
||||
|
||||
/* move queued tasks from other to this */
|
||||
while (array_remove(other->queued_tasks, ARRAY_TAIL, &task))
|
||||
while (array_remove(other->queued_tasks, ARRAY_TAIL, &queued))
|
||||
{
|
||||
DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
|
||||
task->migrate(task, this->ike_sa);
|
||||
array_insert(this->queued_tasks, ARRAY_HEAD, task);
|
||||
DBG2(DBG_IKE, "migrating %N task", task_type_names,
|
||||
queued->task->get_type(queued->task));
|
||||
queued->task->migrate(queued->task, this->ike_sa);
|
||||
/* don't delay tasks on the new IKE_SA */
|
||||
queued->time = now;
|
||||
array_insert(this->queued_tasks, ARRAY_HEAD, queued);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates child-creating tasks from src to dst
|
||||
* Migrates child-creating tasks from other to this
|
||||
*/
|
||||
static void migrate_child_tasks(private_task_manager_t *this,
|
||||
array_t *src, array_t *dst)
|
||||
private_task_manager_t *other,
|
||||
task_queue_t queue)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
array_t *array;
|
||||
task_t *task;
|
||||
|
||||
enumerator = array_create_enumerator(src);
|
||||
switch (queue)
|
||||
{
|
||||
case TASK_QUEUE_ACTIVE:
|
||||
array = other->active_tasks;
|
||||
break;
|
||||
case TASK_QUEUE_QUEUED:
|
||||
array = other->queued_tasks;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
enumerator = array_create_enumerator(array);
|
||||
while (enumerator->enumerate(enumerator, &task))
|
||||
{
|
||||
queued_task_t *queued = NULL;
|
||||
|
||||
if (queue == TASK_QUEUE_QUEUED)
|
||||
{
|
||||
queued = (queued_task_t*)task;
|
||||
task = queued->task;
|
||||
}
|
||||
if (task->get_type(task) == TASK_CHILD_CREATE)
|
||||
{
|
||||
array_remove_at(src, enumerator);
|
||||
array_remove_at(array, enumerator);
|
||||
task->migrate(task, this->ike_sa);
|
||||
array_insert(dst, ARRAY_TAIL, task);
|
||||
queue_task(this, task);
|
||||
free(queued);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
@@ -1840,9 +1909,9 @@ METHOD(task_manager_t, adopt_child_tasks, void,
|
||||
private_task_manager_t *other = (private_task_manager_t*)other_public;
|
||||
|
||||
/* move active child tasks from other to this */
|
||||
migrate_child_tasks(this, other->active_tasks, this->queued_tasks);
|
||||
migrate_child_tasks(this, other, TASK_QUEUE_ACTIVE);
|
||||
/* do the same for queued tasks */
|
||||
migrate_child_tasks(this, other->queued_tasks, this->queued_tasks);
|
||||
migrate_child_tasks(this, other, TASK_QUEUE_QUEUED);
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, busy, bool,
|
||||
@@ -1855,7 +1924,9 @@ METHOD(task_manager_t, reset, void,
|
||||
private_task_manager_t *this, uint32_t initiate, uint32_t respond)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
queued_task_t *queued;
|
||||
task_t *task;
|
||||
timeval_t now;
|
||||
|
||||
/* reset message counters and retransmit packets */
|
||||
clear_packets(this->responding.packets);
|
||||
@@ -1874,11 +1945,13 @@ METHOD(task_manager_t, reset, void,
|
||||
}
|
||||
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
|
||||
|
||||
time_monotonic(&now);
|
||||
/* reset queued tasks */
|
||||
enumerator = array_create_enumerator(this->queued_tasks);
|
||||
while (enumerator->enumerate(enumerator, &task))
|
||||
while (enumerator->enumerate(enumerator, &queued))
|
||||
{
|
||||
task->migrate(task, this->ike_sa);
|
||||
queued->time = now;
|
||||
queued->task->migrate(queued->task, this->ike_sa);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
@@ -1886,12 +1959,25 @@ METHOD(task_manager_t, reset, void,
|
||||
while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
|
||||
{
|
||||
task->migrate(task, this->ike_sa);
|
||||
array_insert(this->queued_tasks, ARRAY_HEAD, task);
|
||||
INIT(queued,
|
||||
.task = task,
|
||||
.time = now,
|
||||
);
|
||||
array_insert(this->queued_tasks, ARRAY_HEAD, queued);
|
||||
}
|
||||
|
||||
this->reset = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter queued tasks
|
||||
*/
|
||||
static bool filter_queued(void *unused, queued_task_t **queued, task_t **task)
|
||||
{
|
||||
*task = (*queued)->task;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
|
||||
private_task_manager_t *this, task_queue_t queue)
|
||||
{
|
||||
@@ -1902,7 +1988,9 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
|
||||
case TASK_QUEUE_PASSIVE:
|
||||
return array_create_enumerator(this->passive_tasks);
|
||||
case TASK_QUEUE_QUEUED:
|
||||
return array_create_enumerator(this->queued_tasks);
|
||||
return enumerator_create_filter(
|
||||
array_create_enumerator(this->queued_tasks),
|
||||
(void*)filter_queued, NULL, NULL);
|
||||
default:
|
||||
return enumerator_create_empty();
|
||||
}
|
||||
@@ -1938,6 +2026,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
|
||||
.task_manager = {
|
||||
.process_message = _process_message,
|
||||
.queue_task = _queue_task,
|
||||
.queue_task_delayed = _queue_task_delayed,
|
||||
.queue_ike = _queue_ike,
|
||||
.queue_ike_rekey = _queue_ike_rekey,
|
||||
.queue_ike_reauth = _queue_ike_reauth,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 Tobias Brunner
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -122,7 +123,17 @@ struct task_manager_t {
|
||||
*
|
||||
* @param task task to queue
|
||||
*/
|
||||
void (*queue_task) (task_manager_t *this, task_t *task);
|
||||
void (*queue_task)(task_manager_t *this, task_t *task);
|
||||
|
||||
/**
|
||||
* Queue a task in the manager, but delay its initiation for at least the
|
||||
* given number of seconds.
|
||||
*
|
||||
* @param task task to queue
|
||||
* @param delay minimum delay in s before initiating the task
|
||||
*/
|
||||
void (*queue_task_delayed)(task_manager_t *this, task_t *task,
|
||||
uint32_t delay);
|
||||
|
||||
/**
|
||||
* Queue IKE_SA establishing tasks.
|
||||
|
||||
Reference in New Issue
Block a user