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