Annotation of src/usr.bin/tmux/imsg.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: imsg.c,v 1.1 2009/08/11 17:18:35 nicm 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 imsg_get_fd(struct imsgbuf *);
32:
33: void
34: imsg_init(struct imsgbuf *ibuf, int fd)
35: {
36: msgbuf_init(&ibuf->w);
37: bzero(&ibuf->r, sizeof(ibuf->r));
38: ibuf->fd = fd;
39: ibuf->w.fd = fd;
40: ibuf->pid = getpid();
41: TAILQ_INIT(&ibuf->fds);
42: }
43:
44: ssize_t
45: imsg_read(struct imsgbuf *ibuf)
46: {
47: struct msghdr msg;
48: struct cmsghdr *cmsg;
49: union {
50: struct cmsghdr hdr;
51: char buf[CMSG_SPACE(sizeof(int) * 16)];
52: } cmsgbuf;
53: struct iovec iov;
54: ssize_t n;
55: int fd;
56: struct imsg_fd *ifd;
57:
58: bzero(&msg, sizeof(msg));
59:
60: iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
61: iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
62: msg.msg_iov = &iov;
63: msg.msg_iovlen = 1;
64: msg.msg_control = &cmsgbuf.buf;
65: msg.msg_controllen = sizeof(cmsgbuf.buf);
66:
67: if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
68: if (errno != EINTR && errno != EAGAIN) {
69: return (-1);
70: }
71: return (-2);
72: }
73:
74: ibuf->r.wpos += n;
75:
76: for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
77: cmsg = CMSG_NXTHDR(&msg, cmsg)) {
78: if (cmsg->cmsg_level == SOL_SOCKET &&
79: cmsg->cmsg_type == SCM_RIGHTS) {
80: fd = (*(int *)CMSG_DATA(cmsg));
81: if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
1.2 ! nicm 82: close(fd);
1.1 nicm 83: return (-1);
84: }
85: ifd->fd = fd;
86: TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry);
87: }
88: /* we do not handle other ctl data level */
89: }
90:
91: return (n);
92: }
93:
94: ssize_t
95: imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
96: {
97: size_t av, left, datalen;
98:
99: av = ibuf->r.wpos;
100:
101: if (IMSG_HEADER_SIZE > av)
102: return (0);
103:
104: memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
105: if (imsg->hdr.len < IMSG_HEADER_SIZE ||
106: imsg->hdr.len > MAX_IMSGSIZE) {
107: errno = ERANGE;
108: return (-1);
109: }
110: if (imsg->hdr.len > av)
111: return (0);
112: datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
113: ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
114: if ((imsg->data = malloc(datalen)) == NULL)
115: return (-1);
116:
117: if (imsg->hdr.flags & IMSGF_HASFD)
118: imsg->fd = imsg_get_fd(ibuf);
119: else
120: imsg->fd = -1;
121:
122: memcpy(imsg->data, ibuf->r.rptr, datalen);
123:
124: if (imsg->hdr.len < av) {
125: left = av - imsg->hdr.len;
126: memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
127: ibuf->r.wpos = left;
128: } else
129: ibuf->r.wpos = 0;
130:
131: return (datalen + IMSG_HEADER_SIZE);
132: }
133:
134: int
135: imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
136: pid_t pid, int fd, void *data, u_int16_t datalen)
137: {
138: struct buf *wbuf;
139:
140: if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
141: return (-1);
142:
143: if (imsg_add(wbuf, data, datalen) == -1)
144: return (-1);
145:
146: wbuf->fd = fd;
147:
148: imsg_close(ibuf, wbuf);
149:
150: return (1);
151: }
152:
153: int
154: imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
155: pid_t pid, int fd, const struct iovec *iov, int iovcnt)
156: {
157: struct buf *wbuf;
158: int i, datalen = 0;
159:
160: for (i = 0; i < iovcnt; i++)
161: datalen += iov[i].iov_len;
162:
163: if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
164: return (-1);
165:
166: for (i = 0; i < iovcnt; i++)
167: if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
168: return (-1);
169:
170: wbuf->fd = fd;
171:
172: imsg_close(ibuf, wbuf);
173:
174: return (1);
175: }
176:
177: /* ARGSUSED */
178: struct buf *
179: imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
180: pid_t pid, u_int16_t datalen)
181: {
182: struct buf *wbuf;
183: struct imsg_hdr hdr;
184:
185: datalen += IMSG_HEADER_SIZE;
186: if (datalen > MAX_IMSGSIZE) {
187: errno = ERANGE;
188: return (NULL);
189: }
190:
191: hdr.type = type;
192: hdr.flags = 0;
193: hdr.peerid = peerid;
194: if ((hdr.pid = pid) == 0)
195: hdr.pid = ibuf->pid;
196: if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
197: return (NULL);
198: }
199: if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
200: return (NULL);
201:
202: return (wbuf);
203: }
204:
205: int
206: imsg_add(struct buf *msg, void *data, u_int16_t datalen)
207: {
208: if (datalen)
209: if (buf_add(msg, data, datalen) == -1) {
210: buf_free(msg);
211: return (-1);
212: }
213: return (datalen);
214: }
215:
216: void
217: imsg_close(struct imsgbuf *ibuf, struct buf *msg)
218: {
219: struct imsg_hdr *hdr;
220:
221: hdr = (struct imsg_hdr *)msg->buf;
222:
223: hdr->flags &= ~IMSGF_HASFD;
224: if (msg->fd != -1)
225: hdr->flags |= IMSGF_HASFD;
226:
227: hdr->len = (u_int16_t)msg->wpos;
228:
229: buf_close(&ibuf->w, msg);
230: }
231:
232: void
233: imsg_free(struct imsg *imsg)
234: {
235: free(imsg->data);
236: }
237:
238: int
239: imsg_get_fd(struct imsgbuf *ibuf)
240: {
241: int fd;
242: struct imsg_fd *ifd;
243:
244: if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
245: return (-1);
246:
247: fd = ifd->fd;
248: TAILQ_REMOVE(&ibuf->fds, ifd, entry);
249: free(ifd);
250:
251: return (fd);
252: }
253:
254: int
255: imsg_flush(struct imsgbuf *ibuf)
256: {
257: while (ibuf->w.queued)
258: if (msgbuf_write(&ibuf->w) < 0)
259: return (-1);
260: return (0);
261: }
262:
263: void
264: imsg_clear(struct imsgbuf *ibuf)
265: {
266: int fd;
267:
268: msgbuf_clear(&ibuf->w);
269: while ((fd = imsg_get_fd(ibuf)) != -1)
270: close(fd);
271: }