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