Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/mediation_manager.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2007 Tobias Brunner
3: * HSR 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 <threading/mutex.h>
20: #include <collections/linked_list.h>
21: #include <processing/jobs/mediation_job.h>
22:
23: typedef struct peer_t peer_t;
24:
25: /**
26: * An entry in the linked list.
27: */
28: struct peer_t {
29: /** id of the peer */
30: identification_t *id;
31:
32: /** sa id of the peer, NULL if offline */
33: ike_sa_id_t *ike_sa_id;
34:
35: /** list of peer ids that requested this peer */
36: linked_list_t *requested_by;
37: };
38:
39: /**
40: * Implementation of peer_t.destroy.
41: */
42: static void peer_destroy(peer_t *this)
43: {
44: DESTROY_IF(this->id);
45: DESTROY_IF(this->ike_sa_id);
46: this->requested_by->destroy_offset(this->requested_by,
47: 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;
57: INIT(this,
58: .id = id->clone(id),
59: .ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL,
60: .requested_by = linked_list_create(),
61: );
62: return this;
63: }
64:
65: typedef struct private_mediation_manager_t private_mediation_manager_t;
66:
67: /**
68: * Additional private members of mediation_manager_t.
69: */
70: struct private_mediation_manager_t {
71: /**
72: * Public interface of mediation_manager_t.
73: */
74: mediation_manager_t public;
75:
76: /**
77: * Lock for exclusively accessing the manager.
78: */
79: mutex_t *mutex;
80:
81: /**
82: * Linked list with state entries.
83: */
84: linked_list_t *peers;
85: };
86:
87: /**
88: * Registers a peer's ID at another peer, if it is not yet registered
89: */
90: static void register_peer(peer_t *peer, identification_t *peer_id)
91: {
92: enumerator_t *enumerator;
93: identification_t *current;
94:
95: enumerator = peer->requested_by->create_enumerator(peer->requested_by);
96: while (enumerator->enumerate(enumerator, (void**)¤t))
97: {
98: if (peer_id->equals(peer_id, current))
99: {
100: enumerator->destroy(enumerator);
101: return;
102: }
103: }
104: enumerator->destroy(enumerator);
105:
106: peer->requested_by->insert_last(peer->requested_by,
107: peer_id->clone(peer_id));
108: }
109:
110: /**
111: * Get a peer_t object by a peer's id
112: */
113: static status_t get_peer_by_id(private_mediation_manager_t *this,
114: identification_t *id, peer_t **peer)
115: {
116: enumerator_t *enumerator;
117: peer_t *current;
118: status_t status = NOT_FOUND;
119:
120: enumerator = this->peers->create_enumerator(this->peers);
121: while (enumerator->enumerate(enumerator, (void**)¤t))
122: {
123: if (id->equals(id, current->id))
124: {
125: if (peer)
126: {
127: *peer = current;
128: }
129: status = SUCCESS;
130: break;
131: }
132: }
133: enumerator->destroy(enumerator);
134:
135: return status;
136: }
137:
138: /**
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
141: * peers.
142: */
143: static void unregister_peer(private_mediation_manager_t *this,
144: identification_t *peer_id)
145: {
146: enumerator_t *enumerator, *enumerator_r;
147: peer_t *peer;
148: identification_t *registered;
149:
150: enumerator = this->peers->create_enumerator(this->peers);
151: while (enumerator->enumerate(enumerator, (void**)&peer))
152: {
153: enumerator_r = peer->requested_by->create_enumerator(peer->requested_by);
154: while (enumerator_r->enumerate(enumerator_r, (void**)®istered))
155: {
156: if (peer_id->equals(peer_id, registered))
157: {
158: peer->requested_by->remove_at(peer->requested_by, enumerator_r);
159: registered->destroy(registered);
160: break;
161: }
162: }
163: enumerator_r->destroy(enumerator_r);
164:
165: if (!peer->ike_sa_id &&
166: !peer->requested_by->get_count(peer->requested_by))
167: {
168: this->peers->remove_at(this->peers, enumerator);
169: peer_destroy(peer);
170: break;
171: }
172: }
173: enumerator->destroy(enumerator);
174: }
175:
176: METHOD(mediation_manager_t, remove_sa, void,
177: private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id)
178: {
179: enumerator_t *enumerator;
180: peer_t *peer;
181:
182: this->mutex->lock(this->mutex);
183:
184: enumerator = this->peers->create_enumerator(this->peers);
185: while (enumerator->enumerate(enumerator, (void**)&peer))
186: {
187: if (ike_sa_id->equals(ike_sa_id, peer->ike_sa_id))
188: {
189: this->peers->remove_at(this->peers, enumerator);
190:
191: unregister_peer(this, peer->id);
192:
193: peer_destroy(peer);
194: break;
195: }
196: }
197: enumerator->destroy(enumerator);
198:
199: this->mutex->unlock(this->mutex);
200: }
201:
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)
205: {
206: enumerator_t *enumerator;
207: peer_t *peer;
208: bool found = FALSE;
209:
210: this->mutex->lock(this->mutex);
211:
212: enumerator = this->peers->create_enumerator(this->peers);
213: while (enumerator->enumerate(enumerator, (void**)&peer))
214: {
215: if (peer_id->equals(peer_id, peer->id))
216: {
217: DESTROY_IF(peer->ike_sa_id);
218: found = TRUE;
219: break;
220: }
221: }
222: enumerator->destroy(enumerator);
223:
224: if (!found)
225: {
226: DBG2(DBG_IKE, "adding peer '%Y'", peer_id);
227: peer = peer_create(peer_id, NULL);
228: this->peers->insert_last(this->peers, peer);
229: }
230:
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;
233:
234: /* send callbacks to registered peers */
235: identification_t *requester;
236: while(peer->requested_by->remove_last(peer->requested_by,
237: (void**)&requester) == SUCCESS)
238: {
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);
242: }
243:
244: this->mutex->unlock(this->mutex);
245: }
246:
247: METHOD(mediation_manager_t, check, ike_sa_id_t*,
248: private_mediation_manager_t *this, identification_t *peer_id)
249: {
250: peer_t *peer;
251: ike_sa_id_t *ike_sa_id;
252:
253: this->mutex->lock(this->mutex);
254:
255: if (get_peer_by_id(this, peer_id, &peer) != SUCCESS)
256: {
257: this->mutex->unlock(this->mutex);
258: return NULL;
259: }
260:
261: ike_sa_id = peer->ike_sa_id;
262:
263: this->mutex->unlock(this->mutex);
264:
265: return ike_sa_id;
266: }
267:
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)
271: {
272: peer_t *peer;
273: ike_sa_id_t *ike_sa_id;
274:
275: this->mutex->lock(this->mutex);
276:
277: if (get_peer_by_id(this, peer_id, &peer) != SUCCESS)
278: {
279: DBG2(DBG_IKE, "adding peer %Y", peer_id);
280: peer = peer_create(peer_id, NULL);
281: this->peers->insert_last(this->peers, peer);
282: }
283:
284: if (!peer->ike_sa_id)
285: {
286: /* the peer is not online */
287: DBG2(DBG_IKE, "requested peer '%Y' is offline, registering peer '%Y'",
288: peer_id, requester);
289: register_peer(peer, requester);
290: this->mutex->unlock(this->mutex);
291: return NULL;
292: }
293:
294: ike_sa_id = peer->ike_sa_id;
295:
296: this->mutex->unlock(this->mutex);
297:
298: return ike_sa_id;
299: }
300:
301: METHOD(mediation_manager_t, destroy, void,
302: private_mediation_manager_t *this)
303: {
304: this->mutex->lock(this->mutex);
305:
306: this->peers->destroy_function(this->peers, (void*)peer_destroy);
307:
308: this->mutex->unlock(this->mutex);
309: this->mutex->destroy(this->mutex);
310: free(this);
311: }
312:
313: /*
314: * Described in header.
315: */
316: mediation_manager_t *mediation_manager_create()
317: {
318: private_mediation_manager_t *this;
319:
320: INIT(this,
321: .public = {
322: .destroy = _destroy,
323: .remove = _remove_sa,
324: .update_sa_id = _update_sa_id,
325: .check = _check,
326: .check_and_register = _check_and_register,
327: },
328: .peers = linked_list_create(),
329: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
330: );
331: return &this->public;
332: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>