Annotation of embedaddon/tmux/compat/imsg-buffer.c, revision 1.1.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>