[BACK]Return to imsg-buffer.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/imsg-buffer.c, Revision 1.2

1.2     ! jacekm      1: /*     $OpenBSD: buffer.c,v 1.6 2009/09/15 10:54:59 jacekm Exp $       */
1.1       nicm        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/param.h>
                     20: #include <sys/queue.h>
                     21: #include <sys/socket.h>
                     22: #include <sys/uio.h>
                     23:
                     24: #include <errno.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
                     27: #include <unistd.h>
                     28:
                     29: #include "imsg.h"
                     30:
                     31: int    buf_realloc(struct buf *, size_t);
                     32: void   buf_enqueue(struct msgbuf *, struct buf *);
                     33: void   buf_dequeue(struct msgbuf *, struct buf *);
                     34:
                     35: struct buf *
                     36: buf_open(size_t len)
                     37: {
                     38:        struct buf      *buf;
                     39:
                     40:        if ((buf = calloc(1, sizeof(struct buf))) == NULL)
                     41:                return (NULL);
                     42:        if ((buf->buf = malloc(len)) == NULL) {
                     43:                free(buf);
                     44:                return (NULL);
                     45:        }
                     46:        buf->size = buf->max = len;
                     47:        buf->fd = -1;
                     48:
                     49:        return (buf);
                     50: }
                     51:
                     52: struct buf *
                     53: buf_dynamic(size_t len, size_t max)
                     54: {
                     55:        struct buf      *buf;
                     56:
                     57:        if (max < len)
                     58:                return (NULL);
                     59:
                     60:        if ((buf = buf_open(len)) == NULL)
                     61:                return (NULL);
                     62:
                     63:        if (max > 0)
                     64:                buf->max = max;
                     65:
                     66:        return (buf);
                     67: }
                     68:
                     69: int
                     70: buf_realloc(struct buf *buf, size_t len)
                     71: {
                     72:        u_char  *b;
                     73:
                     74:        /* on static buffers max is eq size and so the following fails */
                     75:        if (buf->wpos + len > buf->max) {
                     76:                errno = ENOMEM;
                     77:                return (-1);
                     78:        }
                     79:
                     80:        b = realloc(buf->buf, buf->wpos + len);
                     81:        if (b == NULL)
                     82:                return (-1);
                     83:        buf->buf = b;
                     84:        buf->size = buf->wpos + len;
                     85:
                     86:        return (0);
                     87: }
                     88:
                     89: int
                     90: buf_add(struct buf *buf, const void *data, size_t len)
                     91: {
                     92:        if (buf->wpos + len > buf->size)
                     93:                if (buf_realloc(buf, len) == -1)
                     94:                        return (-1);
                     95:
                     96:        memcpy(buf->buf + buf->wpos, data, len);
                     97:        buf->wpos += len;
                     98:        return (0);
                     99: }
                    100:
                    101: void *
                    102: buf_reserve(struct buf *buf, size_t len)
                    103: {
                    104:        void    *b;
                    105:
                    106:        if (buf->wpos + len > buf->size)
                    107:                if (buf_realloc(buf, len) == -1)
                    108:                        return (NULL);
                    109:
                    110:        b = buf->buf + buf->wpos;
                    111:        buf->wpos += len;
                    112:        return (b);
                    113: }
                    114:
                    115: void *
                    116: buf_seek(struct buf *buf, size_t pos, size_t len)
                    117: {
                    118:        /* only allowed to seek in already written parts */
                    119:        if (pos + len > buf->wpos)
                    120:                return (NULL);
                    121:
                    122:        return (buf->buf + pos);
                    123: }
                    124:
                    125: size_t
                    126: buf_size(struct buf *buf)
                    127: {
                    128:        return (buf->wpos);
                    129: }
                    130:
                    131: size_t
                    132: buf_left(struct buf *buf)
                    133: {
                    134:        return (buf->max - buf->wpos);
                    135: }
                    136:
                    137: void
                    138: buf_close(struct msgbuf *msgbuf, struct buf *buf)
                    139: {
                    140:        buf_enqueue(msgbuf, buf);
                    141: }
                    142:
                    143: int
                    144: buf_write(struct msgbuf *msgbuf)
                    145: {
                    146:        struct iovec     iov[IOV_MAX];
1.2     ! jacekm    147:        struct buf      *buf;
1.1       nicm      148:        unsigned int     i = 0;
                    149:        ssize_t n;
                    150:
                    151:        bzero(&iov, sizeof(iov));
                    152:        TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
                    153:                if (i >= IOV_MAX)
                    154:                        break;
                    155:                iov[i].iov_base = buf->buf + buf->rpos;
                    156:                iov[i].iov_len = buf->wpos - buf->rpos;
                    157:                i++;
                    158:        }
                    159:
                    160:        if ((n = writev(msgbuf->fd, iov, i)) == -1) {
                    161:                if (errno == EAGAIN || errno == ENOBUFS ||
                    162:                    errno == EINTR)     /* try later */
                    163:                        return (0);
                    164:                else
                    165:                        return (-1);
                    166:        }
                    167:
                    168:        if (n == 0) {                   /* connection closed */
                    169:                errno = 0;
                    170:                return (-2);
                    171:        }
                    172:
1.2     ! jacekm    173:        msgbuf_drain(msgbuf, n);
1.1       nicm      174:
                    175:        return (0);
                    176: }
                    177:
                    178: void
                    179: buf_free(struct buf *buf)
                    180: {
                    181:        free(buf->buf);
                    182:        free(buf);
                    183: }
                    184:
                    185: void
                    186: msgbuf_init(struct msgbuf *msgbuf)
                    187: {
                    188:        msgbuf->queued = 0;
                    189:        msgbuf->fd = -1;
                    190:        TAILQ_INIT(&msgbuf->bufs);
                    191: }
                    192:
                    193: void
1.2     ! jacekm    194: msgbuf_drain(struct msgbuf *msgbuf, size_t n)
        !           195: {
        !           196:        struct buf      *buf, *next;
        !           197:
        !           198:        for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
        !           199:            buf = next) {
        !           200:                next = TAILQ_NEXT(buf, entry);
        !           201:                if (buf->rpos + n >= buf->wpos) {
        !           202:                        n -= buf->wpos - buf->rpos;
        !           203:                        buf_dequeue(msgbuf, buf);
        !           204:                } else {
        !           205:                        buf->rpos += n;
        !           206:                        n = 0;
        !           207:                }
        !           208:        }
        !           209: }
        !           210:
        !           211: void
1.1       nicm      212: msgbuf_clear(struct msgbuf *msgbuf)
                    213: {
                    214:        struct buf      *buf;
                    215:
                    216:        while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
                    217:                buf_dequeue(msgbuf, buf);
                    218: }
                    219:
                    220: int
                    221: msgbuf_write(struct msgbuf *msgbuf)
                    222: {
                    223:        struct iovec     iov[IOV_MAX];
1.2     ! jacekm    224:        struct buf      *buf;
1.1       nicm      225:        unsigned int     i = 0;
                    226:        ssize_t          n;
                    227:        struct msghdr    msg;
                    228:        struct cmsghdr  *cmsg;
                    229:        union {
                    230:                struct cmsghdr  hdr;
                    231:                char            buf[CMSG_SPACE(sizeof(int))];
                    232:        } cmsgbuf;
                    233:
                    234:        bzero(&iov, sizeof(iov));
                    235:        bzero(&msg, sizeof(msg));
                    236:        TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
                    237:                if (i >= IOV_MAX)
                    238:                        break;
                    239:                iov[i].iov_base = buf->buf + buf->rpos;
                    240:                iov[i].iov_len = buf->wpos - buf->rpos;
                    241:                i++;
                    242:                if (buf->fd != -1)
                    243:                        break;
                    244:        }
                    245:
                    246:        msg.msg_iov = iov;
                    247:        msg.msg_iovlen = i;
                    248:
                    249:        if (buf != NULL && buf->fd != -1) {
                    250:                msg.msg_control = (caddr_t)&cmsgbuf.buf;
                    251:                msg.msg_controllen = sizeof(cmsgbuf.buf);
                    252:                cmsg = CMSG_FIRSTHDR(&msg);
                    253:                cmsg->cmsg_len = CMSG_LEN(sizeof(int));
                    254:                cmsg->cmsg_level = SOL_SOCKET;
                    255:                cmsg->cmsg_type = SCM_RIGHTS;
                    256:                *(int *)CMSG_DATA(cmsg) = buf->fd;
                    257:        }
                    258:
                    259:        if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
                    260:                if (errno == EAGAIN || errno == ENOBUFS ||
                    261:                    errno == EINTR)     /* try later */
                    262:                        return (0);
                    263:                else
                    264:                        return (-1);
                    265:        }
                    266:
                    267:        if (n == 0) {                   /* connection closed */
                    268:                errno = 0;
                    269:                return (-2);
                    270:        }
                    271:
                    272:        /*
                    273:         * assumption: fd got sent if sendmsg sent anything
                    274:         * this works because fds are passed one at a time
                    275:         */
                    276:        if (buf != NULL && buf->fd != -1) {
                    277:                close(buf->fd);
                    278:                buf->fd = -1;
                    279:        }
                    280:
1.2     ! jacekm    281:        msgbuf_drain(msgbuf, n);
1.1       nicm      282:
                    283:        return (0);
                    284: }
                    285:
                    286: void
                    287: buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
                    288: {
                    289:        TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
                    290:        msgbuf->queued++;
                    291: }
                    292:
                    293: void
                    294: buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
                    295: {
                    296:        TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
                    297:
                    298:        if (buf->fd != -1)
                    299:                close(buf->fd);
                    300:
                    301:        msgbuf->queued--;
                    302:        buf_free(buf);
                    303: }