Annotation of embedaddon/strongswan/src/libcharon/plugins/lookip/lookip_socket.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>