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>