added .gitignore files to NM applet
[strongswan.git] / src / charon / sa / mediation_manager.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_manager.h"
17
18 #include <daemon.h>
19 #include <utils/mutex.h>
20 #include <utils/linked_list.h>
21 #include <processing/jobs/mediation_job.h>
22
23
24 typedef struct peer_t peer_t;
25
26 /**
27 * An entry in the linked list.
28 */
29 struct peer_t {
30 /** id of the peer */
31 identification_t *id;
32
33 /** sa id of the peer, NULL if offline */
34 ike_sa_id_t *ike_sa_id;
35
36 /** list of peer ids that reuested this peer */
37 linked_list_t *requested_by;
38 };
39
40 /**
41 * Implementation of peer_t.destroy.
42 */
43 static void peer_destroy(peer_t *this)
44 {
45 DESTROY_IF(this->id);
46 DESTROY_IF(this->ike_sa_id);
47 this->requested_by->destroy_offset(this->requested_by, offsetof(identification_t, destroy));
48 free(this);
49 }
50
51 /**
52 * Creates a new entry for the list.
53 */
54 static peer_t *peer_create(identification_t *id, ike_sa_id_t* ike_sa_id)
55 {
56 peer_t *this = malloc_thing(peer_t);
57
58 /* clone everything */
59 this->id = id->clone(id);
60 this->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL;
61 this->requested_by = linked_list_create();
62
63 return this;
64 }
65
66
67 typedef struct private_mediation_manager_t private_mediation_manager_t;
68
69 /**
70 * Additional private members of mediation_manager_t.
71 */
72 struct private_mediation_manager_t {
73 /**
74 * Public interface of mediation_manager_t.
75 */
76 mediation_manager_t public;
77
78 /**
79 * Lock for exclusivly accessing the manager.
80 */
81 mutex_t *mutex;
82
83 /**
84 * Linked list with state entries.
85 */
86 linked_list_t *peers;
87 };
88
89 /**
90 * Registers a peer's ID at another peer, if it is not yet registered
91 */
92 static void register_peer(peer_t *peer, identification_t *peer_id)
93 {
94 iterator_t *iterator;
95 identification_t *current;
96
97 iterator = peer->requested_by->create_iterator(peer->requested_by, TRUE);
98 while (iterator->iterate(iterator, (void**)&current))
99 {
100 if (peer_id->equals(peer_id, current))
101 {
102 iterator->destroy(iterator);
103 return;
104 }
105 }
106 iterator->destroy(iterator);
107
108 peer->requested_by->insert_last(peer->requested_by, peer_id->clone(peer_id));
109 }
110
111 /**
112 * Get a peer_t object by a peer's id
113 */
114 static status_t get_peer_by_id(private_mediation_manager_t *this,
115 identification_t *id, peer_t **peer)
116 {
117 iterator_t *iterator;
118 peer_t *current;
119 status_t status = NOT_FOUND;
120
121 iterator = this->peers->create_iterator(this->peers, TRUE);
122 while (iterator->iterate(iterator, (void**)&current))
123 {
124 if (id->equals(id, current->id))
125 {
126 if (peer)
127 {
128 *peer = current;
129 }
130 status = SUCCESS;
131 break;
132 }
133 }
134 iterator->destroy(iterator);
135
136 return status;
137 }
138
139 /**
140 * Check if a given peer is registered at other peers. If so, remove it there
141 * and then remove peers completely that are not online and have no registered
142 * peers.
143 */
144 static void unregister_peer(private_mediation_manager_t *this, identification_t *peer_id)
145 {
146 iterator_t *iterator, *iterator_r;
147 peer_t *peer;
148 identification_t *registered;
149
150 iterator = this->peers->create_iterator(this->peers, TRUE);
151 while (iterator->iterate(iterator, (void**)&peer))
152 {
153 iterator_r = peer->requested_by->create_iterator(peer->requested_by, TRUE);
154 while (iterator_r->iterate(iterator_r, (void**)&registered))
155 {
156 if (peer_id->equals(peer_id, registered))
157 {
158 iterator_r->remove(iterator_r);
159 registered->destroy(registered);
160 break;
161 }
162 }
163 iterator_r->destroy(iterator_r);
164
165 if (!peer->ike_sa_id && !peer->requested_by->get_count(peer->requested_by))
166 {
167 iterator->remove(iterator);
168 peer_destroy(peer);
169 break;
170 }
171 }
172 iterator->destroy(iterator);
173 }
174
175 /**
176 * Implementation of mediation_manager_t.remove
177 */
178 static void remove_sa(private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id)
179 {
180 iterator_t *iterator;
181 peer_t *peer;
182
183 this->mutex->lock(this->mutex);
184
185 iterator = this->peers->create_iterator(this->peers, TRUE);
186 while (iterator->iterate(iterator, (void**)&peer))
187 {
188 if (ike_sa_id->equals(ike_sa_id, peer->ike_sa_id))
189 {
190 iterator->remove(iterator);
191
192 unregister_peer(this, peer->id);
193
194 peer_destroy(peer);
195 break;
196 }
197 }
198 iterator->destroy(iterator);
199
200 this->mutex->unlock(this->mutex);
201 }
202
203 /**
204 * Implementation of mediation_manager_t.update_sa_id
205 */
206 static void update_sa_id(private_mediation_manager_t *this, identification_t *peer_id, ike_sa_id_t *ike_sa_id)
207 {
208 iterator_t *iterator;
209 peer_t *peer;
210 bool found = FALSE;
211
212 this->mutex->lock(this->mutex);
213
214 iterator = this->peers->create_iterator(this->peers, TRUE);
215 while (iterator->iterate(iterator, (void**)&peer))
216 {
217 if (peer_id->equals(peer_id, peer->id))
218 {
219 DESTROY_IF(peer->ike_sa_id);
220 found = TRUE;
221 break;
222 }
223 }
224 iterator->destroy(iterator);
225
226 if (!found)
227 {
228 DBG2(DBG_IKE, "adding peer '%Y'", peer_id);
229 peer = peer_create(peer_id, NULL);
230 this->peers->insert_last(this->peers, peer);
231 }
232
233 DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%Y'", peer_id);
234 peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL;
235
236 /* send callbacks to registered peers */
237 identification_t *requester;
238 while(peer->requested_by->remove_last(peer->requested_by, (void**)&requester) == SUCCESS)
239 {
240 job_t *job = (job_t*)mediation_callback_job_create(requester, peer_id);
241 charon->processor->queue_job(charon->processor, job);
242 requester->destroy(requester);
243 }
244
245 this->mutex->unlock(this->mutex);
246 }
247
248 /**
249 * Implementation of mediation_manager_t.check.
250 */
251 static ike_sa_id_t *check(private_mediation_manager_t *this,
252 identification_t *peer_id)
253 {
254 peer_t *peer;
255 ike_sa_id_t *ike_sa_id;
256
257 this->mutex->lock(this->mutex);
258
259 if (get_peer_by_id(this, peer_id, &peer) != SUCCESS)
260 {
261 this->mutex->unlock(this->mutex);
262 return NULL;
263 }
264
265 ike_sa_id = peer->ike_sa_id;
266
267 this->mutex->unlock(this->mutex);
268
269 return ike_sa_id;
270 }
271
272 /**
273 * Implementation of mediation_manager_t.check_and_register.
274 */
275 static ike_sa_id_t *check_and_register(private_mediation_manager_t *this,
276 identification_t *peer_id, identification_t *requester)
277 {
278 peer_t *peer;
279 ike_sa_id_t *ike_sa_id;
280
281 this->mutex->lock(this->mutex);
282
283 if (get_peer_by_id(this, peer_id, &peer) != SUCCESS)
284 {
285 DBG2(DBG_IKE, "adding peer %Y", peer_id);
286 peer = peer_create(peer_id, NULL);
287 this->peers->insert_last(this->peers, peer);
288 }
289
290 if (!peer->ike_sa_id)
291 {
292 /* the peer is not online */
293 DBG2(DBG_IKE, "requested peer '%Y' is offline, registering peer '%Y'", peer_id, requester);
294 register_peer(peer, requester);
295 this->mutex->unlock(this->mutex);
296 return NULL;
297 }
298
299 ike_sa_id = peer->ike_sa_id;
300
301 this->mutex->unlock(this->mutex);
302
303 return ike_sa_id;
304 }
305
306 /**
307 * Implementation of mediation_manager_t.destroy.
308 */
309 static void destroy(private_mediation_manager_t *this)
310 {
311 this->mutex->lock(this->mutex);
312
313 this->peers->destroy_function(this->peers, (void*)peer_destroy);
314
315 this->mutex->unlock(this->mutex);
316 this->mutex->destroy(this->mutex);
317 free(this);
318 }
319
320 /*
321 * Described in header.
322 */
323 mediation_manager_t *mediation_manager_create()
324 {
325 private_mediation_manager_t *this = malloc_thing(private_mediation_manager_t);
326
327 this->public.destroy = (void(*)(mediation_manager_t*))destroy;
328 this->public.remove = (void(*)(mediation_manager_t*,ike_sa_id_t*))remove_sa;
329 this->public.update_sa_id = (void(*)(mediation_manager_t*,identification_t*,ike_sa_id_t*))update_sa_id;
330 this->public.check = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*))check;
331 this->public.check_and_register = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*,identification_t*))check_and_register;
332
333 this->peers = linked_list_create();
334 this->mutex = mutex_create(MUTEX_DEFAULT);
335
336 return (mediation_manager_t*)this;
337 }