1/* $Id: imsg.c,v 1.5 2012/01/20 14:08:04 joerg Exp $ */ 2/* $OpenBSD: imsg.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */ 3 4/* 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include <sys/param.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 "tmux.h" 30 31int imsg_get_fd(struct imsgbuf *); 32 33void 34imsg_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 44ssize_t 45imsg_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 = CMSG_SPACE(sizeof(int) * 16); 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) { 82 close(fd); 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 94ssize_t 95imsg_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 && datalen != 0) 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 134int 135imsg_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 ibuf *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 153int 154imsg_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 ibuf *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 */ 178struct ibuf * 179imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, 180 pid_t pid, u_int16_t datalen) 181{ 182 struct ibuf *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 = ibuf_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 205int 206imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) 207{ 208 if (datalen) 209 if (ibuf_add(msg, data, datalen) == -1) { 210 ibuf_free(msg); 211 return (-1); 212 } 213 return (datalen); 214} 215 216void 217imsg_close(struct imsgbuf *ibuf, struct ibuf *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 ibuf_close(&ibuf->w, msg); 230} 231 232void 233imsg_free(struct imsg *imsg) 234{ 235 free(imsg->data); 236} 237 238int 239imsg_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 254int 255imsg_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 263void 264imsg_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} 272