2 * Copyright (C) 2007 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "mediation_manager.h"
19 #include <threading/mutex.h>
20 #include <collections/linked_list.h>
21 #include <processing/jobs/mediation_job.h>
23 typedef struct peer_t peer_t
;
26 * An entry in the linked list.
32 /** sa id of the peer, NULL if offline */
33 ike_sa_id_t
*ike_sa_id
;
35 /** list of peer ids that reuested this peer */
36 linked_list_t
*requested_by
;
40 * Implementation of peer_t.destroy.
42 static void peer_destroy(peer_t
*this)
45 DESTROY_IF(this->ike_sa_id
);
46 this->requested_by
->destroy_offset(this->requested_by
,
47 offsetof(identification_t
, destroy
));
52 * Creates a new entry for the list.
54 static peer_t
*peer_create(identification_t
*id
, ike_sa_id_t
* ike_sa_id
)
59 .ike_sa_id
= ike_sa_id ? ike_sa_id
->clone(ike_sa_id
) : NULL
,
60 .requested_by
= linked_list_create(),
65 typedef struct private_mediation_manager_t private_mediation_manager_t
;
68 * Additional private members of mediation_manager_t.
70 struct private_mediation_manager_t
{
72 * Public interface of mediation_manager_t.
74 mediation_manager_t
public;
77 * Lock for exclusivly accessing the manager.
82 * Linked list with state entries.
88 * Registers a peer's ID at another peer, if it is not yet registered
90 static void register_peer(peer_t
*peer
, identification_t
*peer_id
)
92 enumerator_t
*enumerator
;
93 identification_t
*current
;
95 enumerator
= peer
->requested_by
->create_enumerator(peer
->requested_by
);
96 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
98 if (peer_id
->equals(peer_id
, current
))
100 enumerator
->destroy(enumerator
);
104 enumerator
->destroy(enumerator
);
106 peer
->requested_by
->insert_last(peer
->requested_by
,
107 peer_id
->clone(peer_id
));
111 * Get a peer_t object by a peer's id
113 static status_t
get_peer_by_id(private_mediation_manager_t
*this,
114 identification_t
*id
, peer_t
**peer
)
116 enumerator_t
*enumerator
;
118 status_t status
= NOT_FOUND
;
120 enumerator
= this->peers
->create_enumerator(this->peers
);
121 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
123 if (id
->equals(id
, current
->id
))
133 enumerator
->destroy(enumerator
);
139 * Check if a given peer is registered at other peers. If so, remove it there
140 * and then remove peers completely that are not online and have no registered
143 static void unregister_peer(private_mediation_manager_t
*this,
144 identification_t
*peer_id
)
146 enumerator_t
*enumerator
, *enumerator_r
;
148 identification_t
*registered
;
150 enumerator
= this->peers
->create_enumerator(this->peers
);
151 while (enumerator
->enumerate(enumerator
, (void**)&peer
))
153 enumerator_r
= peer
->requested_by
->create_enumerator(peer
->requested_by
);
154 while (enumerator_r
->enumerate(enumerator_r
, (void**)®istered
))
156 if (peer_id
->equals(peer_id
, registered
))
158 peer
->requested_by
->remove_at(peer
->requested_by
, enumerator_r
);
159 registered
->destroy(registered
);
163 enumerator_r
->destroy(enumerator_r
);
165 if (!peer
->ike_sa_id
&&
166 !peer
->requested_by
->get_count(peer
->requested_by
))
168 this->peers
->remove_at(this->peers
, enumerator
);
173 enumerator
->destroy(enumerator
);
176 METHOD(mediation_manager_t
, remove_sa
, void,
177 private_mediation_manager_t
*this, ike_sa_id_t
*ike_sa_id
)
179 enumerator_t
*enumerator
;
182 this->mutex
->lock(this->mutex
);
184 enumerator
= this->peers
->create_enumerator(this->peers
);
185 while (enumerator
->enumerate(enumerator
, (void**)&peer
))
187 if (ike_sa_id
->equals(ike_sa_id
, peer
->ike_sa_id
))
189 this->peers
->remove_at(this->peers
, enumerator
);
191 unregister_peer(this, peer
->id
);
197 enumerator
->destroy(enumerator
);
199 this->mutex
->unlock(this->mutex
);
202 METHOD(mediation_manager_t
, update_sa_id
, void,
203 private_mediation_manager_t
*this, identification_t
*peer_id
,
204 ike_sa_id_t
*ike_sa_id
)
206 enumerator_t
*enumerator
;
210 this->mutex
->lock(this->mutex
);
212 enumerator
= this->peers
->create_enumerator(this->peers
);
213 while (enumerator
->enumerate(enumerator
, (void**)&peer
))
215 if (peer_id
->equals(peer_id
, peer
->id
))
217 DESTROY_IF(peer
->ike_sa_id
);
222 enumerator
->destroy(enumerator
);
226 DBG2(DBG_IKE
, "adding peer '%Y'", peer_id
);
227 peer
= peer_create(peer_id
, NULL
);
228 this->peers
->insert_last(this->peers
, peer
);
231 DBG2(DBG_IKE
, "changing registered IKE_SA ID of peer '%Y'", peer_id
);
232 peer
->ike_sa_id
= ike_sa_id ? ike_sa_id
->clone(ike_sa_id
) : NULL
;
234 /* send callbacks to registered peers */
235 identification_t
*requester
;
236 while(peer
->requested_by
->remove_last(peer
->requested_by
,
237 (void**)&requester
) == SUCCESS
)
239 job_t
*job
= (job_t
*)mediation_callback_job_create(requester
, peer_id
);
240 lib
->processor
->queue_job(lib
->processor
, job
);
241 requester
->destroy(requester
);
244 this->mutex
->unlock(this->mutex
);
247 METHOD(mediation_manager_t
, check
, ike_sa_id_t
*,
248 private_mediation_manager_t
*this, identification_t
*peer_id
)
251 ike_sa_id_t
*ike_sa_id
;
253 this->mutex
->lock(this->mutex
);
255 if (get_peer_by_id(this, peer_id
, &peer
) != SUCCESS
)
257 this->mutex
->unlock(this->mutex
);
261 ike_sa_id
= peer
->ike_sa_id
;
263 this->mutex
->unlock(this->mutex
);
268 METHOD(mediation_manager_t
, check_and_register
, ike_sa_id_t
*,
269 private_mediation_manager_t
*this, identification_t
*peer_id
,
270 identification_t
*requester
)
273 ike_sa_id_t
*ike_sa_id
;
275 this->mutex
->lock(this->mutex
);
277 if (get_peer_by_id(this, peer_id
, &peer
) != SUCCESS
)
279 DBG2(DBG_IKE
, "adding peer %Y", peer_id
);
280 peer
= peer_create(peer_id
, NULL
);
281 this->peers
->insert_last(this->peers
, peer
);
284 if (!peer
->ike_sa_id
)
286 /* the peer is not online */
287 DBG2(DBG_IKE
, "requested peer '%Y' is offline, registering peer '%Y'",
289 register_peer(peer
, requester
);
290 this->mutex
->unlock(this->mutex
);
294 ike_sa_id
= peer
->ike_sa_id
;
296 this->mutex
->unlock(this->mutex
);
301 METHOD(mediation_manager_t
, destroy
, void,
302 private_mediation_manager_t
*this)
304 this->mutex
->lock(this->mutex
);
306 this->peers
->destroy_function(this->peers
, (void*)peer_destroy
);
308 this->mutex
->unlock(this->mutex
);
309 this->mutex
->destroy(this->mutex
);
314 * Described in header.
316 mediation_manager_t
*mediation_manager_create()
318 private_mediation_manager_t
*this;
323 .remove
= _remove_sa
,
324 .update_sa_id
= _update_sa_id
,
326 .check_and_register
= _check_and_register
,
328 .peers
= linked_list_create(),
329 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
331 return &this->public;