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>