Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/mediation_manager.c, revision 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>