ike: Maintain per-IKE_SA CHILD_SAs in the global CHILD_SA manager
[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 u_int32_t reschedule = 0;
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, install, diff;
77
78 child_sa->get_usestats(child_sa, TRUE, &in, NULL, NULL);
79 child_sa->get_usestats(child_sa, FALSE, &out, NULL, NULL);
80 install = child_sa->get_installtime(child_sa);
81
82 diff = time_monotonic(NULL) - max(max(in, out), install);
83
84 if (diff >= this->timeout)
85 {
86 delete = child_sa->get_spi(child_sa, TRUE);
87 proto = child_sa->get_protocol(child_sa);
88 }
89 else
90 {
91 reschedule = this->timeout - diff;
92 }
93 }
94 children++;
95 }
96 enumerator->destroy(enumerator);
97
98 if (delete)
99 {
100 if (children == 1 && this->close_ike)
101 {
102 DBG1(DBG_JOB, "deleting IKE_SA after %d seconds "
103 "of CHILD_SA inactivity", this->timeout);
104 status = ike_sa->delete(ike_sa);
105 }
106 else
107 {
108 DBG1(DBG_JOB, "deleting CHILD_SA after %d seconds "
109 "of inactivity", this->timeout);
110 status = ike_sa->delete_child_sa(ike_sa, proto, delete, FALSE);
111 }
112 }
113 if (status == DESTROY_ME)
114 {
115 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
116 ike_sa);
117 }
118 else
119 {
120 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
121 }
122 }
123 if (reschedule)
124 {
125 return JOB_RESCHEDULE(reschedule);
126 }
127 return JOB_REQUEUE_NONE;
128 }
129
130 METHOD(job_t, get_priority, job_priority_t,
131 private_inactivity_job_t *this)
132 {
133 return JOB_PRIO_MEDIUM;
134 }
135
136 /**
137 * See header
138 */
139 inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout,
140 bool close_ike)
141 {
142 private_inactivity_job_t *this;
143
144 INIT(this,
145 .public = {
146 .job_interface = {
147 .execute = _execute,
148 .get_priority = _get_priority,
149 .destroy = _destroy,
150 },
151 },
152 .reqid = reqid,
153 .timeout = timeout,
154 .close_ike = close_ike,
155 );
156
157 return &this->public;
158 }