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: }