Annotation of embedaddon/tmux/compat/imsg-buffer.c, revision 1.1

1.1     ! misho       1: /*     $OpenBSD: imsg-buffer.c,v 1.10 2017/04/11 09:57:19 reyk Exp $   */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18: 
        !            19: #include <sys/types.h>
        !            20: #include <sys/socket.h>
        !            21: #include <sys/uio.h>
        !            22: 
        !            23: #include <limits.h>
        !            24: #include <errno.h>
        !            25: #include <stdlib.h>
        !            26: #include <string.h>
        !            27: #include <unistd.h>
        !            28: 
        !            29: #include "compat.h"
        !            30: #include "imsg.h"
        !            31: 
        !            32: int    ibuf_realloc(struct ibuf *, size_t);
        !            33: void   ibuf_enqueue(struct msgbuf *, struct ibuf *);
        !            34: void   ibuf_dequeue(struct msgbuf *, struct ibuf *);
        !            35: 
        !            36: struct ibuf *
        !            37: ibuf_open(size_t len)
        !            38: {
        !            39:        struct ibuf     *buf;
        !            40: 
        !            41:        if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
        !            42:                return (NULL);
        !            43:        if ((buf->buf = malloc(len)) == NULL) {
        !            44:                free(buf);
        !            45:                return (NULL);
        !            46:        }
        !            47:        buf->size = buf->max = len;
        !            48:        buf->fd = -1;
        !            49: 
        !            50:        return (buf);
        !            51: }
        !            52: 
        !            53: struct ibuf *
        !            54: ibuf_dynamic(size_t len, size_t max)
        !            55: {
        !            56:        struct ibuf     *buf;
        !            57: 
        !            58:        if (max < len)
        !            59:                return (NULL);
        !            60: 
        !            61:        if ((buf = ibuf_open(len)) == NULL)
        !            62:                return (NULL);
        !            63: 
        !            64:        if (max > 0)
        !            65:                buf->max = max;
        !            66: 
        !            67:        return (buf);
        !            68: }
        !            69: 
        !            70: int
        !            71: ibuf_realloc(struct ibuf *buf, size_t len)
        !            72: {
        !            73:        u_char  *b;
        !            74: 
        !            75:        /* on static buffers max is eq size and so the following fails */
        !            76:        if (buf->wpos + len > buf->max) {
        !            77:                errno = ERANGE;
        !            78:                return (-1);
        !            79:        }
        !            80: 
        !            81:        b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
        !            82:        if (b == NULL)
        !            83:                return (-1);
        !            84:        buf->buf = b;
        !            85:        buf->size = buf->wpos + len;
        !            86: 
        !            87:        return (0);
        !            88: }
        !            89: 
        !            90: int
        !            91: ibuf_add(struct ibuf *buf, const void *data, size_t len)
        !            92: {
        !            93:        if (buf->wpos + len > buf->size)
        !            94:                if (ibuf_realloc(buf, len) == -1)
        !            95:                        return (-1);
        !            96: 
        !            97:        memcpy(buf->buf + buf->wpos, data, len);
        !            98:        buf->wpos += len;
        !            99:        return (0);
        !           100: }
        !           101: 
        !           102: void *
        !           103: ibuf_reserve(struct ibuf *buf, size_t len)
        !           104: {
        !           105:        void    *b;
        !           106: 
        !           107:        if (buf->wpos + len > buf->size)
        !           108:                if (ibuf_realloc(buf, len) == -1)
        !           109:                        return (NULL);
        !           110: 
        !           111:        b = buf->buf + buf->wpos;
        !           112:        buf->wpos += len;
        !           113:        return (b);
        !           114: }
        !           115: 
        !           116: void *
        !           117: ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
        !           118: {
        !           119:        /* only allowed to seek in already written parts */
        !           120:        if (pos + len > buf->wpos)
        !           121:                return (NULL);
        !           122: 
        !           123:        return (buf->buf + pos);
        !           124: }
        !           125: 
        !           126: size_t
        !           127: ibuf_size(struct ibuf *buf)
        !           128: {
        !           129:        return (buf->wpos);
        !           130: }
        !           131: 
        !           132: size_t
        !           133: ibuf_left(struct ibuf *buf)
        !           134: {
        !           135:        return (buf->max - buf->wpos);
        !           136: }
        !           137: 
        !           138: void
        !           139: ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
        !           140: {
        !           141:        ibuf_enqueue(msgbuf, buf);
        !           142: }
        !           143: 
        !           144: int
        !           145: ibuf_write(struct msgbuf *msgbuf)
        !           146: {
        !           147:        struct iovec     iov[IOV_MAX];
        !           148:        struct ibuf     *buf;
        !           149:        unsigned int     i = 0;
        !           150:        ssize_t n;
        !           151: 
        !           152:        memset(&iov, 0, sizeof(iov));
        !           153:        TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
        !           154:                if (i >= IOV_MAX)
        !           155:                        break;
        !           156:                iov[i].iov_base = buf->buf + buf->rpos;
        !           157:                iov[i].iov_len = buf->wpos - buf->rpos;
        !           158:                i++;
        !           159:        }
        !           160: 
        !           161: again:
        !           162:        if ((n = writev(msgbuf->fd, iov, i)) == -1) {
        !           163:                if (errno == EINTR)
        !           164:                        goto again;
        !           165:                if (errno == ENOBUFS)
        !           166:                        errno = EAGAIN;
        !           167:                return (-1);
        !           168:        }
        !           169: 
        !           170:        if (n == 0) {                   /* connection closed */
        !           171:                errno = 0;
        !           172:                return (0);
        !           173:        }
        !           174: 
        !           175:        msgbuf_drain(msgbuf, n);
        !           176: 
        !           177:        return (1);
        !           178: }
        !           179: 
        !           180: void
        !           181: ibuf_free(struct ibuf *buf)
        !           182: {
        !           183:        if (buf == NULL)
        !           184:                return;
        !           185:        freezero(buf->buf, buf->size);
        !           186:        free(buf);
        !           187: }
        !           188: 
        !           189: void
        !           190: msgbuf_init(struct msgbuf *msgbuf)
        !           191: {
        !           192:        msgbuf->queued = 0;
        !           193:        msgbuf->fd = -1;
        !           194:        TAILQ_INIT(&msgbuf->bufs);
        !           195: }
        !           196: 
        !           197: void
        !           198: msgbuf_drain(struct msgbuf *msgbuf, size_t n)
        !           199: {
        !           200:        struct ibuf     *buf, *next;
        !           201: 
        !           202:        for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
        !           203:            buf = next) {
        !           204:                next = TAILQ_NEXT(buf, entry);
        !           205:                if (buf->rpos + n >= buf->wpos) {
        !           206:                        n -= buf->wpos - buf->rpos;
        !           207:                        ibuf_dequeue(msgbuf, buf);
        !           208:                } else {
        !           209:                        buf->rpos += n;
        !           210:                        n = 0;
        !           211:                }
        !           212:        }
        !           213: }
        !           214: 
        !           215: void
        !           216: msgbuf_clear(struct msgbuf *msgbuf)
        !           217: {
        !           218:        struct ibuf     *buf;
        !           219: 
        !           220:        while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
        !           221:                ibuf_dequeue(msgbuf, buf);
        !           222: }
        !           223: 
        !           224: int
        !           225: msgbuf_write(struct msgbuf *msgbuf)
        !           226: {
        !           227:        struct iovec     iov[IOV_MAX];
        !           228:        struct ibuf     *buf;
        !           229:        unsigned int     i = 0;
        !           230:        ssize_t          n;
        !           231:        struct msghdr    msg;
        !           232:        struct cmsghdr  *cmsg;
        !           233:        union {
        !           234:                struct cmsghdr  hdr;
        !           235:                char            buf[CMSG_SPACE(sizeof(int))];
        !           236:        } cmsgbuf;
        !           237: 
        !           238:        memset(&iov, 0, sizeof(iov));
        !           239:        memset(&msg, 0, sizeof(msg));
        !           240:        memset(&cmsgbuf, 0, sizeof(cmsgbuf));
        !           241:        TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
        !           242:                if (i >= IOV_MAX)
        !           243:                        break;
        !           244:                iov[i].iov_base = buf->buf + buf->rpos;
        !           245:                iov[i].iov_len = buf->wpos - buf->rpos;
        !           246:                i++;
        !           247:                if (buf->fd != -1)
        !           248:                        break;
        !           249:        }
        !           250: 
        !           251:        msg.msg_iov = iov;
        !           252:        msg.msg_iovlen = i;
        !           253: 
        !           254:        if (buf != NULL && buf->fd != -1) {
        !           255:                msg.msg_control = (caddr_t)&cmsgbuf.buf;
        !           256:                msg.msg_controllen = sizeof(cmsgbuf.buf);
        !           257:                cmsg = CMSG_FIRSTHDR(&msg);
        !           258:                cmsg->cmsg_len = CMSG_LEN(sizeof(int));
        !           259:                cmsg->cmsg_level = SOL_SOCKET;
        !           260:                cmsg->cmsg_type = SCM_RIGHTS;
        !           261:                *(int *)CMSG_DATA(cmsg) = buf->fd;
        !           262:        }
        !           263: 
        !           264: again:
        !           265:        if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
        !           266:                if (errno == EINTR)
        !           267:                        goto again;
        !           268:                if (errno == ENOBUFS)
        !           269:                        errno = EAGAIN;
        !           270:                return (-1);
        !           271:        }
        !           272: 
        !           273:        if (n == 0) {                   /* connection closed */
        !           274:                errno = 0;
        !           275:                return (0);
        !           276:        }
        !           277: 
        !           278:        /*
        !           279:         * assumption: fd got sent if sendmsg sent anything
        !           280:         * this works because fds are passed one at a time
        !           281:         */
        !           282:        if (buf != NULL && buf->fd != -1) {
        !           283:                close(buf->fd);
        !           284:                buf->fd = -1;
        !           285:        }
        !           286: 
        !           287:        msgbuf_drain(msgbuf, n);
        !           288: 
        !           289:        return (1);
        !           290: }
        !           291: 
        !           292: void
        !           293: ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
        !           294: {
        !           295:        TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
        !           296:        msgbuf->queued++;
        !           297: }
        !           298: 
        !           299: void
        !           300: ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
        !           301: {
        !           302:        TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
        !           303: 
        !           304:        if (buf->fd != -1)
        !           305:                close(buf->fd);
        !           306: 
        !           307:        msgbuf->queued--;
        !           308:        ibuf_free(buf);
        !           309: }

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