ed247e06ea22423b12b7592cc014c1dc59aed25f
[strongswan.git] / src / charon / processing / jobs / initiate_mediation_job.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
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 * $Id$
16 */
17
18 #include "initiate_mediation_job.h"
19
20 #include <sa/ike_sa.h>
21 #include <daemon.h>
22
23
24 typedef struct private_initiate_mediation_job_t private_initiate_mediation_job_t;
25
26 /**
27 * Private data of an initiate_mediation_job_t Object
28 */
29 struct private_initiate_mediation_job_t {
30 /**
31 * public initiate_mediation_job_t interface
32 */
33 initiate_mediation_job_t public;
34
35 /**
36 * ID of the IKE_SA of the mediated connection.
37 */
38 ike_sa_id_t *mediated_sa_id;
39
40 /**
41 * ID of the IKE_SA of the mediation connection.
42 */
43 ike_sa_id_t *mediation_sa_id;
44 };
45
46 /**
47 * Implements job_t.destroy.
48 */
49 static void destroy(private_initiate_mediation_job_t *this)
50 {
51 DESTROY_IF(this->mediation_sa_id);
52 DESTROY_IF(this->mediated_sa_id);
53 free(this);
54 }
55
56 /**
57 * Implementation of job_t.execute.
58 */
59 static void initiate(private_initiate_mediation_job_t *this)
60 {
61 ike_sa_t *mediated_sa, *mediation_sa;
62 peer_cfg_t *mediated_cfg, *mediation_cfg;
63
64 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
65 this->mediated_sa_id);
66 if (mediated_sa)
67 {
68 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
69 mediated_cfg->get_ref(mediated_cfg);
70
71 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
72
73 mediation_cfg = mediated_cfg->get_mediated_by(mediated_cfg);
74 mediation_cfg->get_ref(mediation_cfg);
75
76 if (charon->connect_manager->check_and_register(charon->connect_manager,
77 mediation_cfg->get_my_id(mediation_cfg),
78 mediated_cfg->get_peer_id(mediated_cfg),
79 this->mediated_sa_id))
80 {
81 mediated_cfg->destroy(mediated_cfg);
82 mediation_cfg->destroy(mediation_cfg);
83
84 mediated_sa = charon->ike_sa_manager->checkout(
85 charon->ike_sa_manager, this->mediated_sa_id);
86 if (mediated_sa)
87 {
88 DBG1(DBG_IKE, "mediation with the same peer is already in "
89 "progress, queued");
90 charon->ike_sa_manager->checkin(
91 charon->ike_sa_manager, mediated_sa);
92 }
93 destroy(this);
94 return;
95 }
96 /* we need an additional reference because initiate consumes one */
97 mediation_cfg->get_ref(mediation_cfg);
98
99 /* this function call blocks until the connection is up or failed
100 * we do not check the status, but NEED_MORE would be returned on success
101 * because the registered callback returns FALSE then
102 * this->mediation_sa_id is set in the callback */
103 charon->controller->initiate(charon->controller, mediation_cfg, NULL,
104 controller_cb_empty, this);
105 if (!this->mediation_sa_id)
106 {
107 mediation_cfg->destroy(mediation_cfg);
108 mediated_cfg->destroy(mediated_cfg);
109 mediated_sa = charon->ike_sa_manager->checkout(
110 charon->ike_sa_manager, this->mediated_sa_id);
111 if (mediated_sa)
112 {
113 DBG1(DBG_IKE, "initiating mediation connection failed");
114 charon->ike_sa_manager->checkin_and_destroy(
115 charon->ike_sa_manager, mediated_sa);
116 }
117 destroy(this);
118 return;
119 }
120 mediation_cfg->destroy(mediation_cfg);
121
122 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
123 this->mediation_sa_id);
124
125 if (mediation_sa)
126 {
127 if (mediation_sa->initiate_mediation(mediation_sa,
128 mediated_cfg) != SUCCESS)
129 {
130 mediated_cfg->destroy(mediated_cfg);
131 charon->ike_sa_manager->checkin_and_destroy(
132 charon->ike_sa_manager, mediation_sa);
133 mediated_sa = charon->ike_sa_manager->checkout(
134 charon->ike_sa_manager, this->mediated_sa_id);
135 if (mediated_sa)
136 {
137 DBG1(DBG_IKE, "establishing mediation connection failed");
138 charon->ike_sa_manager->checkin_and_destroy(
139 charon->ike_sa_manager, mediated_sa);
140 }
141 destroy(this);
142 return;
143 }
144
145 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
146 }
147
148 mediated_cfg->destroy(mediated_cfg);
149 }
150 destroy(this);
151 }
152
153 /**
154 * Implementation of job_t.execute.
155 */
156 static void reinitiate(private_initiate_mediation_job_t *this)
157 {
158 ike_sa_t *mediated_sa, *mediation_sa;
159 peer_cfg_t *mediated_cfg;
160
161 mediated_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
162 this->mediated_sa_id);
163 if (mediated_sa)
164 {
165 mediated_cfg = mediated_sa->get_peer_cfg(mediated_sa);
166 mediated_cfg->get_ref(mediated_cfg);
167 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediated_sa);
168
169 mediation_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
170 this->mediation_sa_id);
171 if (mediation_sa)
172 {
173 if (mediation_sa->initiate_mediation(mediation_sa, mediated_cfg) != SUCCESS)
174 {
175 DBG1(DBG_JOB, "initiating mediated connection '%s' failed",
176 mediated_cfg->get_name(mediated_cfg));
177 mediated_cfg->destroy(mediated_cfg);
178 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, mediation_sa);
179 mediated_sa = charon->ike_sa_manager->checkout(
180 charon->ike_sa_manager, this->mediated_sa_id);
181 if (mediated_sa)
182 {
183 DBG1(DBG_IKE, "establishing mediation connection failed");
184 charon->ike_sa_manager->checkin_and_destroy(
185 charon->ike_sa_manager, mediated_sa);
186 }
187 destroy(this);
188 return;
189 }
190 charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa);
191 }
192
193 mediated_cfg->destroy(mediated_cfg);
194 }
195 destroy(this);
196 }
197
198 /**
199 * Creates an empty job
200 */
201 static private_initiate_mediation_job_t *initiate_mediation_job_create_empty()
202 {
203 private_initiate_mediation_job_t *this = malloc_thing(private_initiate_mediation_job_t);
204
205 /* interface functions */
206 this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
207
208 /* private variables */
209 this->mediation_sa_id = NULL;
210 this->mediated_sa_id = NULL;
211
212 return this;
213 }
214
215 /*
216 * Described in header
217 */
218 initiate_mediation_job_t *initiate_mediation_job_create(ike_sa_id_t *ike_sa_id)
219 {
220 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
221
222 this->public.job_interface.execute = (void (*) (job_t *)) initiate;
223
224 this->mediated_sa_id = ike_sa_id->clone(ike_sa_id);
225
226 return &this->public;
227 }
228
229 /*
230 * Described in header
231 */
232 initiate_mediation_job_t *reinitiate_mediation_job_create(ike_sa_id_t *mediation_sa_id,
233 ike_sa_id_t *mediated_sa_id)
234 {
235 private_initiate_mediation_job_t *this = initiate_mediation_job_create_empty();
236
237 this->public.job_interface.execute = (void (*) (job_t *)) reinitiate;
238
239 this->mediation_sa_id = mediation_sa_id->clone(mediation_sa_id);
240 this->mediated_sa_id = mediated_sa_id->clone(mediated_sa_id);
241
242 return &this->public;
243 }