Return to lookip_socket.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / lookip |
1.1 misho 1: /* 2: * Copyright (C) 2012 Martin Willi 3: * Copyright (C) 2012 revosec AG 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 "lookip_socket.h" 17: 18: #include <sys/types.h> 19: #include <sys/stat.h> 20: #include <sys/socket.h> 21: #include <sys/un.h> 22: #include <unistd.h> 23: #include <errno.h> 24: 25: #include <daemon.h> 26: #include <threading/thread.h> 27: #include <threading/mutex.h> 28: #include <collections/linked_list.h> 29: #include <processing/jobs/callback_job.h> 30: 31: #include "lookip_msg.h" 32: 33: typedef struct private_lookip_socket_t private_lookip_socket_t; 34: 35: /** 36: * Private data of an lookip_socket_t object. 37: */ 38: struct private_lookip_socket_t { 39: 40: /** 41: * Public lookip_socket_t interface. 42: */ 43: lookip_socket_t public; 44: 45: /** 46: * lookip 47: */ 48: lookip_listener_t *listener; 49: 50: /** 51: * stream service accepting connections 52: */ 53: stream_service_t *service; 54: 55: /** 56: * List of connected clients, as entry_t 57: */ 58: linked_list_t *connected; 59: 60: /** 61: * Mutex to lock clients list 62: */ 63: mutex_t *mutex; 64: }; 65: 66: /** 67: * List entry for a connected stream 68: */ 69: typedef struct { 70: /* stream to write to */ 71: stream_t *stream; 72: /* registered for up events? */ 73: bool up; 74: /* registered for down events? */ 75: bool down; 76: /** backref to this for unregistration */ 77: private_lookip_socket_t *this; 78: } entry_t; 79: 80: /** 81: * Clean up a connection entry 82: */ 83: static void entry_destroy(entry_t *entry) 84: { 85: entry->stream->destroy(entry->stream); 86: free(entry); 87: } 88: 89: /** 90: * Data for async disconnect job 91: */ 92: typedef struct { 93: /** socket ref */ 94: private_lookip_socket_t *this; 95: /** stream to disconnect */ 96: stream_t *stream; 97: } disconnect_data_t; 98: 99: /** 100: * Disconnect a stream asynchronously, remove connection entry 101: */ 102: static job_requeue_t disconnect_async(disconnect_data_t *data) 103: { 104: private_lookip_socket_t *this = data->this; 105: enumerator_t *enumerator; 106: entry_t *entry; 107: 108: this->mutex->lock(this->mutex); 109: enumerator = this->connected->create_enumerator(this->connected); 110: while (enumerator->enumerate(enumerator, &entry)) 111: { 112: if (entry->stream == data->stream) 113: { 114: this->connected->remove_at(this->connected, enumerator); 115: if (entry->up || entry->down) 116: { 117: this->listener->remove_listener(this->listener, entry); 118: } 119: entry_destroy(entry); 120: break; 121: } 122: } 123: enumerator->destroy(enumerator); 124: this->mutex->unlock(this->mutex); 125: return JOB_REQUEUE_NONE; 126: } 127: 128: /** 129: * Queue async disconnect job 130: */ 131: static void disconnect(private_lookip_socket_t *this, stream_t *stream) 132: { 133: disconnect_data_t *data; 134: 135: INIT(data, 136: .this = this, 137: .stream = stream, 138: ); 139: 140: lib->processor->queue_job(lib->processor, 141: (job_t*)callback_job_create((void*)disconnect_async, data, 142: free, NULL)); 143: } 144: 145: /** 146: * Callback function for listener up/down events 147: */ 148: static bool event_cb(entry_t *entry, bool up, host_t *vip, host_t *other, 149: identification_t *id, char *name, u_int unique_id) 150: { 151: lookip_response_t resp = { 152: .unique_id = htonl(unique_id), 153: }; 154: 155: if (up) 156: { 157: if (!entry->up) 158: { 159: return TRUE; 160: } 161: resp.type = htonl(LOOKIP_NOTIFY_UP); 162: } 163: else 164: { 165: if (!entry->down) 166: { 167: return TRUE; 168: } 169: resp.type = htonl(LOOKIP_NOTIFY_DOWN); 170: } 171: 172: snprintf(resp.vip, sizeof(resp.vip), "%H", vip); 173: snprintf(resp.ip, sizeof(resp.ip), "%H", other); 174: snprintf(resp.id, sizeof(resp.id), "%Y", id); 175: snprintf(resp.name, sizeof(resp.name), "%s", name); 176: 177: if (entry->stream->write_all(entry->stream, &resp, sizeof(resp))) 178: { 179: return TRUE; 180: } 181: switch (errno) 182: { 183: case ECONNRESET: 184: case EPIPE: 185: /* client disconnected, adios */ 186: break; 187: default: 188: DBG1(DBG_CFG, "sending lookip event failed: %s", strerror(errno)); 189: break; 190: } 191: /* don't unregister, as we return FALSE */ 192: entry->up = entry->down = FALSE; 193: disconnect(entry->this, entry->stream); 194: return FALSE; 195: } 196: 197: /** 198: * Callback function for queries 199: */ 200: static bool query_cb(stream_t *stream, bool up, host_t *vip, host_t *other, 201: identification_t *id, char *name, u_int unique_id) 202: { 203: lookip_response_t resp = { 204: .type = htonl(LOOKIP_ENTRY), 205: .unique_id = htonl(unique_id), 206: }; 207: 208: snprintf(resp.vip, sizeof(resp.vip), "%H", vip); 209: snprintf(resp.ip, sizeof(resp.ip), "%H", other); 210: snprintf(resp.id, sizeof(resp.id), "%Y", id); 211: snprintf(resp.name, sizeof(resp.name), "%s", name); 212: 213: if (stream->write_all(stream, &resp, sizeof(resp))) 214: { 215: return TRUE; 216: } 217: switch (errno) 218: { 219: case ECONNRESET: 220: case EPIPE: 221: /* client disconnected, adios */ 222: break; 223: default: 224: DBG1(DBG_CFG, "sending lookip response failed: %s", strerror(errno)); 225: break; 226: } 227: return FALSE; 228: } 229: 230: /** 231: * Perform a lookup 232: */ 233: static void query(private_lookip_socket_t *this, stream_t *stream, 234: lookip_request_t *req) 235: { 236: 237: host_t *vip = NULL; 238: int matches = 0; 239: 240: if (req) 241: { /* lookup */ 242: req->vip[sizeof(req->vip) - 1] = 0; 243: vip = host_create_from_string(req->vip, 0); 244: if (vip) 245: { 246: matches = this->listener->lookup(this->listener, vip, 247: (void*)query_cb, stream); 248: vip->destroy(vip); 249: } 250: if (matches == 0) 251: { 252: lookip_response_t resp = { 253: .type = htonl(LOOKIP_NOT_FOUND), 254: }; 255: 256: snprintf(resp.vip, sizeof(resp.vip), "%s", req->vip); 257: if (!stream->write_all(stream, &resp, sizeof(resp))) 258: { 259: DBG1(DBG_CFG, "sending lookip not-found failed: %s", 260: strerror(errno)); 261: } 262: } 263: } 264: else 265: { /* dump */ 266: this->listener->lookup(this->listener, NULL, 267: (void*)query_cb, stream); 268: } 269: } 270: 271: /** 272: * Subscribe to virtual IP events 273: */ 274: static void subscribe(private_lookip_socket_t *this, stream_t *stream, bool up) 275: { 276: enumerator_t *enumerator; 277: entry_t *entry; 278: 279: this->mutex->lock(this->mutex); 280: enumerator = this->connected->create_enumerator(this->connected); 281: while (enumerator->enumerate(enumerator, &entry)) 282: { 283: if (entry->stream == stream) 284: { 285: if (!entry->up && !entry->down) 286: { /* newly registered */ 287: this->listener->add_listener(this->listener, 288: (void*)event_cb, entry); 289: } 290: if (up) 291: { 292: entry->up = TRUE; 293: } 294: else 295: { 296: entry->down = TRUE; 297: } 298: } 299: } 300: enumerator->destroy(enumerator); 301: this->mutex->unlock(this->mutex); 302: } 303: 304: /** 305: * Check if a client is subscribed for notifications 306: */ 307: static bool subscribed(private_lookip_socket_t *this, stream_t *stream) 308: { 309: enumerator_t *enumerator; 310: bool subscribed = FALSE; 311: entry_t *entry; 312: 313: this->mutex->lock(this->mutex); 314: enumerator = this->connected->create_enumerator(this->connected); 315: while (enumerator->enumerate(enumerator, &entry)) 316: { 317: if (entry->stream == stream) 318: { 319: subscribed = entry->up || entry->down; 320: break; 321: } 322: } 323: enumerator->destroy(enumerator); 324: this->mutex->unlock(this->mutex); 325: 326: return subscribed; 327: } 328: 329: /** 330: * Dispatch from a socket, on-read callback 331: */ 332: static bool on_read(private_lookip_socket_t *this, stream_t *stream) 333: { 334: lookip_request_t req; 335: 336: if (stream->read_all(stream, &req, sizeof(req))) 337: { 338: switch (ntohl(req.type)) 339: { 340: case LOOKIP_LOOKUP: 341: query(this, stream, &req); 342: return TRUE; 343: case LOOKIP_DUMP: 344: query(this, stream, NULL); 345: return TRUE; 346: case LOOKIP_REGISTER_UP: 347: subscribe(this, stream, TRUE); 348: return TRUE; 349: case LOOKIP_REGISTER_DOWN: 350: subscribe(this, stream, FALSE); 351: return TRUE; 352: case LOOKIP_END: 353: break; 354: default: 355: DBG1(DBG_CFG, "received unknown lookip command"); 356: break; 357: } 358: } 359: else 360: { 361: if (errno != ECONNRESET) 362: { 363: DBG1(DBG_CFG, "receiving lookip request failed: %s", 364: strerror(errno)); 365: } 366: disconnect(this, stream); 367: return FALSE; 368: } 369: if (subscribed(this, stream)) 370: { 371: return TRUE; 372: } 373: disconnect(this, stream); 374: return FALSE; 375: } 376: 377: /** 378: * Accept client connections, dispatch 379: */ 380: static bool on_accept(private_lookip_socket_t *this, stream_t *stream) 381: { 382: entry_t *entry; 383: 384: INIT(entry, 385: .stream = stream, 386: .this = this, 387: ); 388: 389: this->mutex->lock(this->mutex); 390: this->connected->insert_last(this->connected, entry); 391: this->mutex->unlock(this->mutex); 392: 393: stream->on_read(stream, (void*)on_read, this); 394: 395: return TRUE; 396: } 397: 398: METHOD(lookip_socket_t, destroy, void, 399: private_lookip_socket_t *this) 400: { 401: DESTROY_IF(this->service); 402: this->connected->destroy_function(this->connected, (void*)entry_destroy); 403: this->mutex->destroy(this->mutex); 404: free(this); 405: } 406: 407: /** 408: * See header 409: */ 410: lookip_socket_t *lookip_socket_create(lookip_listener_t *listener) 411: { 412: private_lookip_socket_t *this; 413: char *uri; 414: 415: INIT(this, 416: .public = { 417: .destroy = _destroy, 418: }, 419: .listener = listener, 420: .connected = linked_list_create(), 421: .mutex = mutex_create(MUTEX_TYPE_DEFAULT), 422: ); 423: 424: uri = lib->settings->get_str(lib->settings, 425: "%s.plugins.lookip.socket", "unix://" LOOKIP_SOCKET, 426: lib->ns); 427: this->service = lib->streams->create_service(lib->streams, uri, 10); 428: if (!this->service) 429: { 430: DBG1(DBG_CFG, "creating lookip socket failed"); 431: destroy(this); 432: return NULL; 433: } 434: 435: this->service->on_accept(this->service, (stream_service_cb_t)on_accept, 436: this, JOB_PRIO_CRITICAL, 1); 437: 438: return &this->public; 439: }