Annotation of embedaddon/strongswan/src/libstrongswan/networking/streams/stream.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Martin Willi
        !             3:  * Copyright (C) 2013 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 <library.h>
        !            17: #include <errno.h>
        !            18: #include <unistd.h>
        !            19: 
        !            20: #include "stream.h"
        !            21: 
        !            22: typedef struct private_stream_t private_stream_t;
        !            23: 
        !            24: /**
        !            25:  * Private data of an stream_t object.
        !            26:  */
        !            27: struct private_stream_t {
        !            28: 
        !            29:        /**
        !            30:         * Public stream_t interface.
        !            31:         */
        !            32:        stream_t public;
        !            33: 
        !            34:        /**
        !            35:         * Underlying socket
        !            36:         */
        !            37:        int fd;
        !            38: 
        !            39:        /**
        !            40:         * Callback if data is ready to read
        !            41:         */
        !            42:        stream_cb_t read_cb;
        !            43: 
        !            44:        /**
        !            45:         * Data for read-ready callback
        !            46:         */
        !            47:        void *read_data;
        !            48: 
        !            49:        /**
        !            50:         * Callback if write is non-blocking
        !            51:         */
        !            52:        stream_cb_t write_cb;
        !            53: 
        !            54:        /**
        !            55:         * Data for write-ready callback
        !            56:         */
        !            57:        void *write_data;
        !            58: };
        !            59: 
        !            60: METHOD(stream_t, read_, ssize_t,
        !            61:        private_stream_t *this, void *buf, size_t len, bool block)
        !            62: {
        !            63:        while (TRUE)
        !            64:        {
        !            65:                ssize_t ret;
        !            66: 
        !            67:                if (block)
        !            68:                {
        !            69:                        ret = recv(this->fd, buf, len, 0);
        !            70:                }
        !            71:                else
        !            72:                {
        !            73:                        ret = recv(this->fd, buf, len, MSG_DONTWAIT);
        !            74:                        if (ret == -1 && errno == EAGAIN)
        !            75:                        {
        !            76:                                /* unify EGAIN and EWOULDBLOCK */
        !            77:                                errno = EWOULDBLOCK;
        !            78:                        }
        !            79:                }
        !            80:                if (ret == -1 && errno == EINTR)
        !            81:                {       /* interrupted, try again */
        !            82:                        continue;
        !            83:                }
        !            84:                return ret;
        !            85:        }
        !            86: }
        !            87: 
        !            88: METHOD(stream_t, read_all, bool,
        !            89:        private_stream_t *this, void *buf, size_t len)
        !            90: {
        !            91:        ssize_t ret;
        !            92: 
        !            93:        while (len)
        !            94:        {
        !            95:                ret = read_(this, buf, len, TRUE);
        !            96:                if (ret < 0)
        !            97:                {
        !            98:                        return FALSE;
        !            99:                }
        !           100:                if (ret == 0)
        !           101:                {
        !           102:                        errno = ECONNRESET;
        !           103:                        return FALSE;
        !           104:                }
        !           105:                len -= ret;
        !           106:                buf += ret;
        !           107:        }
        !           108:        return TRUE;
        !           109: }
        !           110: 
        !           111: METHOD(stream_t, write_, ssize_t,
        !           112:        private_stream_t *this, void *buf, size_t len, bool block)
        !           113: {
        !           114:        ssize_t ret;
        !           115: 
        !           116:        while (TRUE)
        !           117:        {
        !           118:                if (block)
        !           119:                {
        !           120:                        ret = send(this->fd, buf, len, 0);
        !           121:                }
        !           122:                else
        !           123:                {
        !           124:                        ret = send(this->fd, buf, len, MSG_DONTWAIT);
        !           125:                        if (ret == -1 && errno == EAGAIN)
        !           126:                        {
        !           127:                                /* unify EGAIN and EWOULDBLOCK */
        !           128:                                errno = EWOULDBLOCK;
        !           129:                        }
        !           130:                }
        !           131:                if (ret == -1 && errno == EINTR)
        !           132:                {       /* interrupted, try again */
        !           133:                        continue;
        !           134:                }
        !           135:                return ret;
        !           136:        }
        !           137: }
        !           138: 
        !           139: METHOD(stream_t, write_all, bool,
        !           140:        private_stream_t *this, void *buf, size_t len)
        !           141: {
        !           142:        ssize_t ret;
        !           143: 
        !           144:        while (len)
        !           145:        {
        !           146:                ret = write_(this, buf, len, TRUE);
        !           147:                if (ret < 0)
        !           148:                {
        !           149:                        return FALSE;
        !           150:                }
        !           151:                if (ret == 0)
        !           152:                {
        !           153:                        errno = ECONNRESET;
        !           154:                        return FALSE;
        !           155:                }
        !           156:                len -= ret;
        !           157:                buf += ret;
        !           158:        }
        !           159:        return TRUE;
        !           160: }
        !           161: 
        !           162: /**
        !           163:  * Watcher callback
        !           164:  */
        !           165: static bool watch(private_stream_t *this, int fd, watcher_event_t event)
        !           166: {
        !           167:        bool keep = FALSE;
        !           168:        stream_cb_t cb;
        !           169: 
        !           170:        switch (event)
        !           171:        {
        !           172:                case WATCHER_READ:
        !           173:                        cb = this->read_cb;
        !           174:                        this->read_cb = NULL;
        !           175:                        keep = cb(this->read_data, &this->public);
        !           176:                        if (keep)
        !           177:                        {
        !           178:                                this->read_cb = cb;
        !           179:                        }
        !           180:                        break;
        !           181:                case WATCHER_WRITE:
        !           182:                        cb = this->write_cb;
        !           183:                        this->write_cb = NULL;
        !           184:                        keep = cb(this->write_data, &this->public);
        !           185:                        if (keep)
        !           186:                        {
        !           187:                                this->write_cb = cb;
        !           188:                        }
        !           189:                        break;
        !           190:                case WATCHER_EXCEPT:
        !           191:                        break;
        !           192:        }
        !           193:        return keep;
        !           194: }
        !           195: 
        !           196: /**
        !           197:  * Register watcher for stream callbacks
        !           198:  */
        !           199: static void add_watcher(private_stream_t *this)
        !           200: {
        !           201:        watcher_event_t events = 0;
        !           202: 
        !           203:        if (this->read_cb)
        !           204:        {
        !           205:                events |= WATCHER_READ;
        !           206:        }
        !           207:        if (this->write_cb)
        !           208:        {
        !           209:                events |= WATCHER_WRITE;
        !           210:        }
        !           211:        if (events)
        !           212:        {
        !           213:                lib->watcher->add(lib->watcher, this->fd, events,
        !           214:                                                  (watcher_cb_t)watch, this);
        !           215:        }
        !           216: }
        !           217: 
        !           218: METHOD(stream_t, on_read, void,
        !           219:        private_stream_t *this, stream_cb_t cb, void *data)
        !           220: {
        !           221:        lib->watcher->remove(lib->watcher, this->fd);
        !           222: 
        !           223:        this->read_cb = cb;
        !           224:        this->read_data = data;
        !           225: 
        !           226:        add_watcher(this);
        !           227: }
        !           228: 
        !           229: METHOD(stream_t, on_write, void,
        !           230:        private_stream_t *this, stream_cb_t cb, void *data)
        !           231: {
        !           232:        lib->watcher->remove(lib->watcher, this->fd);
        !           233: 
        !           234:        this->write_cb = cb;
        !           235:        this->write_data = data;
        !           236: 
        !           237:        add_watcher(this);
        !           238: }
        !           239: 
        !           240: METHOD(stream_t, get_file, FILE*,
        !           241:        private_stream_t *this)
        !           242: {
        !           243:        FILE *file;
        !           244:        int fd;
        !           245: 
        !           246:        /* fclose() closes the FD passed to fdopen(), so dup() it */
        !           247:        fd = dup(this->fd);
        !           248:        if (fd == -1)
        !           249:        {
        !           250:                return NULL;
        !           251:        }
        !           252:        file = fdopen(fd, "w+");
        !           253:        if (!file)
        !           254:        {
        !           255:                close(fd);
        !           256:        }
        !           257:        return file;
        !           258: }
        !           259: 
        !           260: METHOD(stream_t, destroy, void,
        !           261:        private_stream_t *this)
        !           262: {
        !           263:        lib->watcher->remove(lib->watcher, this->fd);
        !           264:        close(this->fd);
        !           265:        free(this);
        !           266: }
        !           267: 
        !           268: /**
        !           269:  * See header
        !           270:  */
        !           271: stream_t *stream_create_from_fd(int fd)
        !           272: {
        !           273:        private_stream_t *this;
        !           274: 
        !           275:        INIT(this,
        !           276:                .public = {
        !           277:                        .read = _read_,
        !           278:                        .read_all = _read_all,
        !           279:                        .on_read = _on_read,
        !           280:                        .write = _write_,
        !           281:                        .write_all = _write_all,
        !           282:                        .on_write = _on_write,
        !           283:                        .get_file = _get_file,
        !           284:                        .destroy = _destroy,
        !           285:                },
        !           286:                .fd = fd,
        !           287:        );
        !           288: 
        !           289:        return &this->public;
        !           290: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>