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>