Give processor_t more control over the lifecycle of a job
[strongswan.git] / src / libcharon / processing / jobs / inactivity_job.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "inactivity_job.h"
17
18 #include <daemon.h>
19
20 typedef struct private_inactivity_job_t private_inactivity_job_t;
21
22 /**
23 * Private data of an inactivity_job_t object.
24 */
25 struct private_inactivity_job_t {
26
27 /**
28 * Public inactivity_job_t interface.
29 */
30 inactivity_job_t public;
31
32 /**
33 * Reqid of CHILD_SA to check
34 */
35 u_int32_t reqid;
36
37 /**
38 * Inactivity timeout
39 */
40 u_int32_t timeout;
41
42 /**
43 * Close IKE_SA if last remaining CHILD inactive?
44 */
45 bool close_ike;
46 };
47
48 METHOD(job_t, destroy, void,
49 private_inactivity_job_t *this)
50 {
51 free(this);
52 }
53
54 METHOD(job_t, execute, job_requeue_t,
55 private_inactivity_job_t *this)
56 {
57 ike_sa_t *ike_sa;
58 bool rescheduled = FALSE;
59
60 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
61 this->reqid, TRUE);
62 if (ike_sa)
63 {
64 enumerator_t *enumerator;
65 child_sa_t *child_sa;
66 u_int32_t delete = 0;
67 protocol_id_t proto = 0;
68 int children = 0;
69 status_t status = SUCCESS;
70
71 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
72 while (enumerator->enumerate(enumerator, (void**)&child_sa))
73 {
74 if (child_sa->get_reqid(child_sa) == this->reqid)
75 {
76 time_t in, out, diff;
77
78 child_sa->get_usestats(child_sa, TRUE, &in, NULL);
79 child_sa->get_usestats(child_sa, FALSE, &out, NULL);
80
81 diff = time_monotonic(NULL) - max(in, out);
82
83 if (diff >= this->timeout)
84 {
85 delete = child_sa->get_spi(child_sa, TRUE);
86 proto = child_sa->get_protocol(child_sa);
87 }
88 else
89 {
90 lib->scheduler->schedule_job(lib->scheduler,
91 &this->public.job_interface, this->timeout - diff);
92 rescheduled = TRUE;
93 }
94 }
95 children++;
96 }
97 enumerator->destroy(enumerator);
98
99 if (delete)
100 {
101 if (children == 1 && this->close_ike)
102 {
103 DBG1(DBG_JOB, "deleting IKE_SA after %d seconds "
104 "of CHILD_SA inactivity", this->timeout);
105 status = ike_sa->delete(ike_sa);
106 }
107 else
108 {
109 DBG1(DBG_JOB, "deleting CHILD_SA after %d seconds "
110 "of inactivity", this->timeout);
111 status = ike_sa->delete_child_sa(ike_sa, proto, delete, FALSE);
112 }
113 }
114 if (status == DESTROY_ME)
115 {
116 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
117 ike_sa);
118 }
119 else
120 {
121 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
122 }
123 }
124 if (rescheduled)
125 {
126 return JOB_REQUEUE_SCHEDULED;
127 }
128 return JOB_REQUEUE_NONE;
129 }
130
131 METHOD(job_t, get_priority, job_priority_t,
132 private_inactivity_job_t *this)
133 {
134 return JOB_PRIO_MEDIUM;
135 }
136
137 /**
138 * See header
139 */
140 inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout,
141 bool close_ike)
142 {
143 private_inactivity_job_t *this;
144
145 INIT(this,
146 .public = {
147 .job_interface = {
148 .execute = _execute,
149 .get_priority = _get_priority,
150 .destroy = _destroy,
151 },
152 },
153 .reqid = reqid,
154 .timeout = timeout,
155 .close_ike = close_ike,
156 );
157
158 return &this->public;
159 }
160