6f02f2a0a36113b7984863b04033369980caf2fe
[strongswan.git] / src / libcharon / processing / jobs / mediation_job.c
1 /*
2 * Copyright (C) 2007 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
16 #include "mediation_job.h"
17
18 #include <encoding/payloads/endpoint_notify.h>
19 #include <daemon.h>
20
21
22 typedef struct private_mediation_job_t private_mediation_job_t;
23
24 /**
25 * Private data of an mediation_job_t Object
26 */
27 struct private_mediation_job_t {
28 /**
29 * public mediation_job_t interface
30 */
31 mediation_job_t public;
32
33 /**
34 * ID of target peer.
35 */
36 identification_t *target;
37
38 /**
39 * ID of the source peer.
40 */
41 identification_t *source;
42
43 /**
44 * ME_CONNECTID
45 */
46 chunk_t connect_id;
47
48 /**
49 * ME_CONNECTKEY
50 */
51 chunk_t connect_key;
52
53 /**
54 * Submitted endpoints
55 */
56 linked_list_t *endpoints;
57
58 /**
59 * Is this a callback job?
60 */
61 bool callback;
62
63 /**
64 * Is this a response?
65 */
66 bool response;
67 };
68
69 METHOD(job_t, destroy, void,
70 private_mediation_job_t *this)
71 {
72 DESTROY_IF(this->target);
73 DESTROY_IF(this->source);
74 chunk_free(&this->connect_id);
75 chunk_free(&this->connect_key);
76 DESTROY_OFFSET_IF(this->endpoints, offsetof(endpoint_notify_t, destroy));
77 free(this);
78 }
79
80 METHOD(job_t, execute, void,
81 private_mediation_job_t *this)
82 {
83 ike_sa_id_t *target_sa_id;
84
85 target_sa_id = charon->mediation_manager->check(charon->mediation_manager, this->target);
86
87 if (target_sa_id)
88 {
89 ike_sa_t *target_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
90 target_sa_id);
91 if (target_sa)
92 {
93 if (this->callback)
94 {
95 /* send callback to a peer */
96 if (target_sa->callback(target_sa, this->source) != SUCCESS)
97 {
98 DBG1(DBG_JOB, "callback for '%Y' to '%Y' failed",
99 this->source, this->target);
100 charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa);
101 destroy(this);
102 return;
103 }
104 }
105 else
106 {
107 /* normal mediation between two peers */
108 if (target_sa->relay(target_sa, this->source, this->connect_id,
109 this->connect_key, this->endpoints, this->response) != SUCCESS)
110 {
111 DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed",
112 this->source, this->target);
113 charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa);
114 /* FIXME: notify the initiator */
115 destroy(this);
116 return;
117 }
118 }
119
120 charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa);
121 }
122 else
123 {
124 DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed: "
125 "SA not found", this->source, this->target);
126 }
127 }
128 else
129 {
130 DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed: "
131 "peer is not online anymore", this->source, this->target);
132 }
133 destroy(this);
134 }
135
136 METHOD(job_t, get_priority, job_priority_t,
137 private_mediation_job_t *this)
138 {
139 return JOB_PRIO_MEDIUM;
140 }
141
142 /**
143 * Creates an empty mediation job
144 */
145 static private_mediation_job_t *mediation_job_create_empty()
146 {
147 private_mediation_job_t *this;
148 INIT(this,
149 .public = {
150 .job_interface = {
151 .execute = _execute,
152 .get_priority = _get_priority,
153 .destroy = _destroy,
154 },
155 },
156 );
157 return this;
158 }
159
160 /*
161 * Described in header
162 */
163 mediation_job_t *mediation_job_create(identification_t *peer_id,
164 identification_t *requester, chunk_t connect_id, chunk_t connect_key,
165 linked_list_t *endpoints, bool response)
166 {
167 private_mediation_job_t *this = mediation_job_create_empty();
168
169 this->target = peer_id->clone(peer_id);
170 this->source = requester->clone(requester);
171 this->connect_id = chunk_clone(connect_id);
172 this->connect_key = chunk_clone(connect_key);
173 this->endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
174 this->response = response;
175
176 return &this->public;
177 }
178
179 /*
180 * Described in header
181 */
182 mediation_job_t *mediation_callback_job_create(identification_t *requester,
183 identification_t *peer_id)
184 {
185 private_mediation_job_t *this = mediation_job_create_empty();
186
187 this->target = requester->clone(requester);
188 this->source = peer_id->clone(peer_id);
189 this->callback = TRUE;
190
191 return &this->public;
192 }