1 /* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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.
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.
19 #include <sys/types.h>
20 #include <sys/socket.h>
28 #include "got_compat.h"
31 int imsg_fd_overhead
= 0;
33 static int imsg_get_fd(struct imsgbuf
*);
36 imsg_init(struct imsgbuf
*ibuf
, int fd
)
38 msgbuf_init(&ibuf
->w
);
39 memset(&ibuf
->r
, 0, sizeof(ibuf
->r
));
43 TAILQ_INIT(&ibuf
->fds
);
47 imsg_read(struct imsgbuf
*ibuf
)
53 char buf
[CMSG_SPACE(sizeof(int) * 1)];
60 memset(&msg
, 0, sizeof(msg
));
61 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
63 iov
.iov_base
= ibuf
->r
.buf
+ ibuf
->r
.wpos
;
64 iov
.iov_len
= sizeof(ibuf
->r
.buf
) - ibuf
->r
.wpos
;
67 msg
.msg_control
= &cmsgbuf
.buf
;
68 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
70 if ((ifd
= calloc(1, sizeof(struct imsg_fd
))) == NULL
)
74 if (getdtablecount() + imsg_fd_overhead
+
75 (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
82 if ((n
= recvmsg(ibuf
->fd
, &msg
, 0)) == -1) {
90 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
91 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
92 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
93 cmsg
->cmsg_type
== SCM_RIGHTS
) {
98 * We only accept one file descriptor. Due to C
99 * padding rules, our control buffer might contain
100 * more than one fd, and we must close them.
102 j
= ((char *)cmsg
+ cmsg
->cmsg_len
-
103 (char *)CMSG_DATA(cmsg
)) / sizeof(int);
104 for (i
= 0; i
< j
; i
++) {
105 fd
= ((int *)CMSG_DATA(cmsg
))[i
];
108 TAILQ_INSERT_TAIL(&ibuf
->fds
, ifd
,
115 /* we do not handle other ctl data level */
124 imsg_get(struct imsgbuf
*ibuf
, struct imsg
*imsg
)
126 size_t av
, left
, datalen
;
130 if (IMSG_HEADER_SIZE
> av
)
133 memcpy(&imsg
->hdr
, ibuf
->r
.buf
, sizeof(imsg
->hdr
));
134 if (imsg
->hdr
.len
< IMSG_HEADER_SIZE
||
135 imsg
->hdr
.len
> MAX_IMSGSIZE
) {
139 if (imsg
->hdr
.len
> av
)
141 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
142 ibuf
->r
.rptr
= ibuf
->r
.buf
+ IMSG_HEADER_SIZE
;
145 else if ((imsg
->data
= malloc(datalen
)) == NULL
)
148 if (imsg
->hdr
.flags
& IMSGF_HASFD
)
149 imsg
->fd
= imsg_get_fd(ibuf
);
153 memcpy(imsg
->data
, ibuf
->r
.rptr
, datalen
);
155 if (imsg
->hdr
.len
< av
) {
156 left
= av
- imsg
->hdr
.len
;
157 memmove(&ibuf
->r
.buf
, ibuf
->r
.buf
+ imsg
->hdr
.len
, left
);
162 return (datalen
+ IMSG_HEADER_SIZE
);
166 imsg_compose(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
, pid_t pid
,
167 int fd
, const void *data
, uint16_t datalen
)
171 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
174 if (imsg_add(wbuf
, data
, datalen
) == -1)
179 imsg_close(ibuf
, wbuf
);
185 imsg_composev(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
, pid_t pid
,
186 int fd
, const struct iovec
*iov
, int iovcnt
)
191 for (i
= 0; i
< iovcnt
; i
++)
192 datalen
+= iov
[i
].iov_len
;
194 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
197 for (i
= 0; i
< iovcnt
; i
++)
198 if (imsg_add(wbuf
, iov
[i
].iov_base
, iov
[i
].iov_len
) == -1)
203 imsg_close(ibuf
, wbuf
);
210 imsg_create(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
, pid_t pid
,
216 datalen
+= IMSG_HEADER_SIZE
;
217 if (datalen
> MAX_IMSGSIZE
) {
225 if ((hdr
.pid
= pid
) == 0)
227 if ((wbuf
= ibuf_dynamic(datalen
, MAX_IMSGSIZE
)) == NULL
) {
230 if (imsg_add(wbuf
, &hdr
, sizeof(hdr
)) == -1)
237 imsg_add(struct ibuf
*msg
, const void *data
, uint16_t datalen
)
240 if (ibuf_add(msg
, data
, datalen
) == -1) {
248 imsg_close(struct imsgbuf
*ibuf
, struct ibuf
*msg
)
250 struct imsg_hdr
*hdr
;
252 hdr
= (struct imsg_hdr
*)msg
->buf
;
254 hdr
->flags
&= ~IMSGF_HASFD
;
256 hdr
->flags
|= IMSGF_HASFD
;
258 hdr
->len
= (uint16_t)msg
->wpos
;
260 ibuf_close(&ibuf
->w
, msg
);
264 imsg_free(struct imsg
*imsg
)
266 freezero(imsg
->data
, imsg
->hdr
.len
- IMSG_HEADER_SIZE
);
270 imsg_get_fd(struct imsgbuf
*ibuf
)
275 if ((ifd
= TAILQ_FIRST(&ibuf
->fds
)) == NULL
)
279 TAILQ_REMOVE(&ibuf
->fds
, ifd
, entry
);
286 imsg_flush(struct imsgbuf
*ibuf
)
288 while (ibuf
->w
.queued
)
289 if (msgbuf_write(&ibuf
->w
) <= 0)
295 imsg_clear(struct imsgbuf
*ibuf
)
299 msgbuf_clear(&ibuf
->w
);
300 while ((fd
= imsg_get_fd(ibuf
)) != -1)