Annotation of embedaddon/strongswan/src/libcharon/plugins/lookip/lookip_socket.c, revision 1.1.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>