Return to mediation_manager.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / sa / ikev2 |
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: }