controller: Add option to force destruction of an IKE_SA
[strongswan.git] / src / libcharon / control / controller.c
index 6a37fff..3ff1c4b 100644 (file)
@@ -117,10 +117,17 @@ struct interface_listener_t {
         */
        spinlock_t *lock;
 
-       /**
-        * whether to check limits
-        */
-       bool limits;
+       union {
+               /**
+                * whether to check limits during initiation
+                */
+               bool limits;
+
+               /**
+                * whether to force termination
+                */
+               bool force;
+       } options;
 };
 
 
@@ -423,7 +430,7 @@ METHOD(job_t, initiate_execute, job_requeue_t,
        }
        peer_cfg->destroy(peer_cfg);
 
-       if (listener->limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
+       if (listener->options.limits && ike_sa->get_state(ike_sa) == IKE_CREATED)
        {       /* only check if we are not reusing an IKE_SA */
                u_int half_open, limit_half_open, limit_job_load;
 
@@ -508,7 +515,7 @@ METHOD(controller_t, initiate, status_t,
                        .child_cfg = child_cfg,
                        .peer_cfg = peer_cfg,
                        .lock = spinlock_create(),
-                       .limits = limits,
+                       .options.limits = limits,
                },
                .public = {
                        .execute = _initiate_execute,
@@ -557,8 +564,8 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t,
        listener->ike_sa = ike_sa;
        listener->lock->unlock(listener->lock);
 
-       if (ike_sa->delete(ike_sa, FALSE) != DESTROY_ME)
-       {       /* delete failed */
+       if (ike_sa->delete(ike_sa, listener->options.force) != DESTROY_ME)
+       {       /* delete queued */
                listener->status = FAILED;
                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
        }
@@ -575,7 +582,7 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t,
 }
 
 METHOD(controller_t, terminate_ike, status_t,
-       controller_t *this, uint32_t unique_id,
+       controller_t *this, uint32_t unique_id, bool force,
        controller_cb_t callback, void *param, u_int timeout)
 {
        interface_job_t *job;
@@ -610,13 +617,24 @@ METHOD(controller_t, terminate_ike, status_t,
 
        if (callback == NULL)
        {
+               job->listener.options.force = force;
                terminate_ike_execute(job);
        }
        else
        {
+               if (!timeout)
+               {
+                       job->listener.options.force = force;
+               }
                if (wait_for_listener(job, timeout))
                {
                        job->listener.status = OUT_OF_RES;
+
+                       if (force)
+                       {       /* force termination once timeout is reached */
+                               job->listener.options.force = TRUE;
+                               terminate_ike_execute(job);
+                       }
                }
        }
        status = job->listener.status;