Blame


1 dd038bc6 2021-09-21 thomas.ad /* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
2 dd038bc6 2021-09-21 thomas.ad
3 dd038bc6 2021-09-21 thomas.ad /*
4 dd038bc6 2021-09-21 thomas.ad * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 dd038bc6 2021-09-21 thomas.ad *
6 dd038bc6 2021-09-21 thomas.ad * Permission to use, copy, modify, and distribute this software for any
7 dd038bc6 2021-09-21 thomas.ad * purpose with or without fee is hereby granted, provided that the above
8 dd038bc6 2021-09-21 thomas.ad * copyright notice and this permission notice appear in all copies.
9 dd038bc6 2021-09-21 thomas.ad *
10 dd038bc6 2021-09-21 thomas.ad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 dd038bc6 2021-09-21 thomas.ad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 dd038bc6 2021-09-21 thomas.ad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 dd038bc6 2021-09-21 thomas.ad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 dd038bc6 2021-09-21 thomas.ad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 dd038bc6 2021-09-21 thomas.ad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 dd038bc6 2021-09-21 thomas.ad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 dd038bc6 2021-09-21 thomas.ad */
18 dd038bc6 2021-09-21 thomas.ad
19 dd038bc6 2021-09-21 thomas.ad #include <sys/types.h>
20 dd038bc6 2021-09-21 thomas.ad #include <sys/socket.h>
21 dd038bc6 2021-09-21 thomas.ad #include <sys/uio.h>
22 dd038bc6 2021-09-21 thomas.ad
23 dd038bc6 2021-09-21 thomas.ad #include <limits.h>
24 dd038bc6 2021-09-21 thomas.ad #include <errno.h>
25 dd038bc6 2021-09-21 thomas.ad #include <stdlib.h>
26 dd038bc6 2021-09-21 thomas.ad #include <string.h>
27 dd038bc6 2021-09-21 thomas.ad #include <unistd.h>
28 dd038bc6 2021-09-21 thomas.ad
29 dd038bc6 2021-09-21 thomas.ad #include "got_compat.h"
30 4fccd2fe 2023-03-08 thomas #include "imsg.h"
31 dd038bc6 2021-09-21 thomas.ad
32 dd038bc6 2021-09-21 thomas.ad static int ibuf_realloc(struct ibuf *, size_t);
33 dd038bc6 2021-09-21 thomas.ad static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
34 dd038bc6 2021-09-21 thomas.ad static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
35 dd038bc6 2021-09-21 thomas.ad
36 dd038bc6 2021-09-21 thomas.ad struct ibuf *
37 dd038bc6 2021-09-21 thomas.ad ibuf_open(size_t len)
38 dd038bc6 2021-09-21 thomas.ad {
39 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
40 dd038bc6 2021-09-21 thomas.ad
41 dd038bc6 2021-09-21 thomas.ad if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
42 dd038bc6 2021-09-21 thomas.ad return (NULL);
43 dd038bc6 2021-09-21 thomas.ad if ((buf->buf = malloc(len)) == NULL) {
44 dd038bc6 2021-09-21 thomas.ad free(buf);
45 dd038bc6 2021-09-21 thomas.ad return (NULL);
46 dd038bc6 2021-09-21 thomas.ad }
47 dd038bc6 2021-09-21 thomas.ad buf->size = buf->max = len;
48 dd038bc6 2021-09-21 thomas.ad buf->fd = -1;
49 dd038bc6 2021-09-21 thomas.ad
50 dd038bc6 2021-09-21 thomas.ad return (buf);
51 dd038bc6 2021-09-21 thomas.ad }
52 dd038bc6 2021-09-21 thomas.ad
53 dd038bc6 2021-09-21 thomas.ad struct ibuf *
54 dd038bc6 2021-09-21 thomas.ad ibuf_dynamic(size_t len, size_t max)
55 dd038bc6 2021-09-21 thomas.ad {
56 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
57 dd038bc6 2021-09-21 thomas.ad
58 dd038bc6 2021-09-21 thomas.ad if (max < len)
59 dd038bc6 2021-09-21 thomas.ad return (NULL);
60 dd038bc6 2021-09-21 thomas.ad
61 dd038bc6 2021-09-21 thomas.ad if ((buf = ibuf_open(len)) == NULL)
62 dd038bc6 2021-09-21 thomas.ad return (NULL);
63 dd038bc6 2021-09-21 thomas.ad
64 dd038bc6 2021-09-21 thomas.ad if (max > 0)
65 dd038bc6 2021-09-21 thomas.ad buf->max = max;
66 dd038bc6 2021-09-21 thomas.ad
67 dd038bc6 2021-09-21 thomas.ad return (buf);
68 dd038bc6 2021-09-21 thomas.ad }
69 dd038bc6 2021-09-21 thomas.ad
70 dd038bc6 2021-09-21 thomas.ad static int
71 dd038bc6 2021-09-21 thomas.ad ibuf_realloc(struct ibuf *buf, size_t len)
72 dd038bc6 2021-09-21 thomas.ad {
73 dd038bc6 2021-09-21 thomas.ad u_char *b;
74 dd038bc6 2021-09-21 thomas.ad
75 dd038bc6 2021-09-21 thomas.ad /* on static buffers max is eq size and so the following fails */
76 dd038bc6 2021-09-21 thomas.ad if (buf->wpos + len > buf->max) {
77 dd038bc6 2021-09-21 thomas.ad errno = ERANGE;
78 dd038bc6 2021-09-21 thomas.ad return (-1);
79 dd038bc6 2021-09-21 thomas.ad }
80 dd038bc6 2021-09-21 thomas.ad
81 c0faa645 2021-09-21 thomas.ad b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
82 dd038bc6 2021-09-21 thomas.ad if (b == NULL)
83 dd038bc6 2021-09-21 thomas.ad return (-1);
84 dd038bc6 2021-09-21 thomas.ad buf->buf = b;
85 dd038bc6 2021-09-21 thomas.ad buf->size = buf->wpos + len;
86 dd038bc6 2021-09-21 thomas.ad
87 dd038bc6 2021-09-21 thomas.ad return (0);
88 dd038bc6 2021-09-21 thomas.ad }
89 dd038bc6 2021-09-21 thomas.ad
90 dd038bc6 2021-09-21 thomas.ad int
91 dd038bc6 2021-09-21 thomas.ad ibuf_add(struct ibuf *buf, const void *data, size_t len)
92 dd038bc6 2021-09-21 thomas.ad {
93 dd038bc6 2021-09-21 thomas.ad if (buf->wpos + len > buf->size)
94 dd038bc6 2021-09-21 thomas.ad if (ibuf_realloc(buf, len) == -1)
95 dd038bc6 2021-09-21 thomas.ad return (-1);
96 dd038bc6 2021-09-21 thomas.ad
97 dd038bc6 2021-09-21 thomas.ad memcpy(buf->buf + buf->wpos, data, len);
98 dd038bc6 2021-09-21 thomas.ad buf->wpos += len;
99 dd038bc6 2021-09-21 thomas.ad return (0);
100 dd038bc6 2021-09-21 thomas.ad }
101 dd038bc6 2021-09-21 thomas.ad
102 dd038bc6 2021-09-21 thomas.ad void *
103 dd038bc6 2021-09-21 thomas.ad ibuf_reserve(struct ibuf *buf, size_t len)
104 dd038bc6 2021-09-21 thomas.ad {
105 dd038bc6 2021-09-21 thomas.ad void *b;
106 dd038bc6 2021-09-21 thomas.ad
107 dd038bc6 2021-09-21 thomas.ad if (buf->wpos + len > buf->size)
108 dd038bc6 2021-09-21 thomas.ad if (ibuf_realloc(buf, len) == -1)
109 dd038bc6 2021-09-21 thomas.ad return (NULL);
110 dd038bc6 2021-09-21 thomas.ad
111 dd038bc6 2021-09-21 thomas.ad b = buf->buf + buf->wpos;
112 dd038bc6 2021-09-21 thomas.ad buf->wpos += len;
113 dd038bc6 2021-09-21 thomas.ad return (b);
114 dd038bc6 2021-09-21 thomas.ad }
115 dd038bc6 2021-09-21 thomas.ad
116 dd038bc6 2021-09-21 thomas.ad void *
117 dd038bc6 2021-09-21 thomas.ad ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
118 dd038bc6 2021-09-21 thomas.ad {
119 dd038bc6 2021-09-21 thomas.ad /* only allowed to seek in already written parts */
120 dd038bc6 2021-09-21 thomas.ad if (pos + len > buf->wpos)
121 dd038bc6 2021-09-21 thomas.ad return (NULL);
122 dd038bc6 2021-09-21 thomas.ad
123 dd038bc6 2021-09-21 thomas.ad return (buf->buf + pos);
124 dd038bc6 2021-09-21 thomas.ad }
125 dd038bc6 2021-09-21 thomas.ad
126 dd038bc6 2021-09-21 thomas.ad size_t
127 dd038bc6 2021-09-21 thomas.ad ibuf_size(struct ibuf *buf)
128 dd038bc6 2021-09-21 thomas.ad {
129 dd038bc6 2021-09-21 thomas.ad return (buf->wpos);
130 dd038bc6 2021-09-21 thomas.ad }
131 dd038bc6 2021-09-21 thomas.ad
132 dd038bc6 2021-09-21 thomas.ad size_t
133 dd038bc6 2021-09-21 thomas.ad ibuf_left(struct ibuf *buf)
134 dd038bc6 2021-09-21 thomas.ad {
135 dd038bc6 2021-09-21 thomas.ad return (buf->max - buf->wpos);
136 dd038bc6 2021-09-21 thomas.ad }
137 dd038bc6 2021-09-21 thomas.ad
138 dd038bc6 2021-09-21 thomas.ad void
139 dd038bc6 2021-09-21 thomas.ad ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
140 dd038bc6 2021-09-21 thomas.ad {
141 dd038bc6 2021-09-21 thomas.ad ibuf_enqueue(msgbuf, buf);
142 dd038bc6 2021-09-21 thomas.ad }
143 dd038bc6 2021-09-21 thomas.ad
144 dd038bc6 2021-09-21 thomas.ad int
145 dd038bc6 2021-09-21 thomas.ad ibuf_write(struct msgbuf *msgbuf)
146 dd038bc6 2021-09-21 thomas.ad {
147 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
148 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
149 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
150 dd038bc6 2021-09-21 thomas.ad ssize_t n;
151 dd038bc6 2021-09-21 thomas.ad
152 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
153 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
154 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
155 dd038bc6 2021-09-21 thomas.ad break;
156 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
157 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
158 dd038bc6 2021-09-21 thomas.ad i++;
159 dd038bc6 2021-09-21 thomas.ad }
160 dd038bc6 2021-09-21 thomas.ad
161 dd038bc6 2021-09-21 thomas.ad again:
162 dd038bc6 2021-09-21 thomas.ad if ((n = writev(msgbuf->fd, iov, i)) == -1) {
163 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
164 dd038bc6 2021-09-21 thomas.ad goto again;
165 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
166 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
167 dd038bc6 2021-09-21 thomas.ad return (-1);
168 dd038bc6 2021-09-21 thomas.ad }
169 dd038bc6 2021-09-21 thomas.ad
170 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
171 dd038bc6 2021-09-21 thomas.ad errno = 0;
172 dd038bc6 2021-09-21 thomas.ad return (0);
173 dd038bc6 2021-09-21 thomas.ad }
174 dd038bc6 2021-09-21 thomas.ad
175 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
176 dd038bc6 2021-09-21 thomas.ad
177 dd038bc6 2021-09-21 thomas.ad return (1);
178 dd038bc6 2021-09-21 thomas.ad }
179 dd038bc6 2021-09-21 thomas.ad
180 dd038bc6 2021-09-21 thomas.ad void
181 dd038bc6 2021-09-21 thomas.ad ibuf_free(struct ibuf *buf)
182 dd038bc6 2021-09-21 thomas.ad {
183 dd038bc6 2021-09-21 thomas.ad if (buf == NULL)
184 dd038bc6 2021-09-21 thomas.ad return;
185 dd038bc6 2021-09-21 thomas.ad freezero(buf->buf, buf->size);
186 dd038bc6 2021-09-21 thomas.ad free(buf);
187 dd038bc6 2021-09-21 thomas.ad }
188 dd038bc6 2021-09-21 thomas.ad
189 dd038bc6 2021-09-21 thomas.ad void
190 dd038bc6 2021-09-21 thomas.ad msgbuf_init(struct msgbuf *msgbuf)
191 dd038bc6 2021-09-21 thomas.ad {
192 dd038bc6 2021-09-21 thomas.ad msgbuf->queued = 0;
193 dd038bc6 2021-09-21 thomas.ad msgbuf->fd = -1;
194 dd038bc6 2021-09-21 thomas.ad TAILQ_INIT(&msgbuf->bufs);
195 dd038bc6 2021-09-21 thomas.ad }
196 dd038bc6 2021-09-21 thomas.ad
197 dd038bc6 2021-09-21 thomas.ad void
198 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(struct msgbuf *msgbuf, size_t n)
199 dd038bc6 2021-09-21 thomas.ad {
200 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf, *next;
201 dd038bc6 2021-09-21 thomas.ad
202 dd038bc6 2021-09-21 thomas.ad for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
203 dd038bc6 2021-09-21 thomas.ad buf = next) {
204 dd038bc6 2021-09-21 thomas.ad next = TAILQ_NEXT(buf, entry);
205 dd038bc6 2021-09-21 thomas.ad if (buf->rpos + n >= buf->wpos) {
206 dd038bc6 2021-09-21 thomas.ad n -= buf->wpos - buf->rpos;
207 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
208 dd038bc6 2021-09-21 thomas.ad } else {
209 dd038bc6 2021-09-21 thomas.ad buf->rpos += n;
210 dd038bc6 2021-09-21 thomas.ad n = 0;
211 dd038bc6 2021-09-21 thomas.ad }
212 dd038bc6 2021-09-21 thomas.ad }
213 dd038bc6 2021-09-21 thomas.ad }
214 dd038bc6 2021-09-21 thomas.ad
215 dd038bc6 2021-09-21 thomas.ad void
216 dd038bc6 2021-09-21 thomas.ad msgbuf_clear(struct msgbuf *msgbuf)
217 dd038bc6 2021-09-21 thomas.ad {
218 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
219 dd038bc6 2021-09-21 thomas.ad
220 dd038bc6 2021-09-21 thomas.ad while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
221 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
222 dd038bc6 2021-09-21 thomas.ad }
223 dd038bc6 2021-09-21 thomas.ad
224 dd038bc6 2021-09-21 thomas.ad int
225 dd038bc6 2021-09-21 thomas.ad msgbuf_write(struct msgbuf *msgbuf)
226 dd038bc6 2021-09-21 thomas.ad {
227 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
228 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
229 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
230 dd038bc6 2021-09-21 thomas.ad ssize_t n;
231 dd038bc6 2021-09-21 thomas.ad struct msghdr msg;
232 dd038bc6 2021-09-21 thomas.ad struct cmsghdr *cmsg;
233 dd038bc6 2021-09-21 thomas.ad union {
234 dd038bc6 2021-09-21 thomas.ad struct cmsghdr hdr;
235 dd038bc6 2021-09-21 thomas.ad char buf[CMSG_SPACE(sizeof(int))];
236 dd038bc6 2021-09-21 thomas.ad } cmsgbuf;
237 dd038bc6 2021-09-21 thomas.ad
238 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
239 dd038bc6 2021-09-21 thomas.ad memset(&msg, 0, sizeof(msg));
240 dd038bc6 2021-09-21 thomas.ad memset(&cmsgbuf, 0, sizeof(cmsgbuf));
241 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
242 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
243 dd038bc6 2021-09-21 thomas.ad break;
244 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
245 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
246 dd038bc6 2021-09-21 thomas.ad i++;
247 dd038bc6 2021-09-21 thomas.ad if (buf->fd != -1)
248 dd038bc6 2021-09-21 thomas.ad break;
249 dd038bc6 2021-09-21 thomas.ad }
250 dd038bc6 2021-09-21 thomas.ad
251 dd038bc6 2021-09-21 thomas.ad msg.msg_iov = iov;
252 dd038bc6 2021-09-21 thomas.ad msg.msg_iovlen = i;
253 dd038bc6 2021-09-21 thomas.ad
254 dd038bc6 2021-09-21 thomas.ad if (buf != NULL && buf->fd != -1) {
255 dd038bc6 2021-09-21 thomas.ad msg.msg_control = (caddr_t)&cmsgbuf.buf;
256 dd038bc6 2021-09-21 thomas.ad msg.msg_controllen = sizeof(cmsgbuf.buf);
257 dd038bc6 2021-09-21 thomas.ad cmsg = CMSG_FIRSTHDR(&msg);
258 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_len = CMSG_LEN(sizeof(int));
259 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_level = SOL_SOCKET;
260 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_type = SCM_RIGHTS;
261 dd038bc6 2021-09-21 thomas.ad *(int *)CMSG_DATA(cmsg) = buf->fd;
262 dd038bc6 2021-09-21 thomas.ad }
263 dd038bc6 2021-09-21 thomas.ad
264 dd038bc6 2021-09-21 thomas.ad again:
265 dd038bc6 2021-09-21 thomas.ad if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
266 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
267 dd038bc6 2021-09-21 thomas.ad goto again;
268 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
269 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
270 dd038bc6 2021-09-21 thomas.ad return (-1);
271 dd038bc6 2021-09-21 thomas.ad }
272 dd038bc6 2021-09-21 thomas.ad
273 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
274 dd038bc6 2021-09-21 thomas.ad errno = 0;
275 dd038bc6 2021-09-21 thomas.ad return (0);
276 dd038bc6 2021-09-21 thomas.ad }
277 dd038bc6 2021-09-21 thomas.ad
278 dd038bc6 2021-09-21 thomas.ad /*
279 dd038bc6 2021-09-21 thomas.ad * assumption: fd got sent if sendmsg sent anything
280 dd038bc6 2021-09-21 thomas.ad * this works because fds are passed one at a time
281 dd038bc6 2021-09-21 thomas.ad */
282 dd038bc6 2021-09-21 thomas.ad if (buf != NULL && buf->fd != -1) {
283 dd038bc6 2021-09-21 thomas.ad close(buf->fd);
284 dd038bc6 2021-09-21 thomas.ad buf->fd = -1;
285 dd038bc6 2021-09-21 thomas.ad }
286 dd038bc6 2021-09-21 thomas.ad
287 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
288 dd038bc6 2021-09-21 thomas.ad
289 dd038bc6 2021-09-21 thomas.ad return (1);
290 dd038bc6 2021-09-21 thomas.ad }
291 dd038bc6 2021-09-21 thomas.ad
292 dd038bc6 2021-09-21 thomas.ad static void
293 dd038bc6 2021-09-21 thomas.ad ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
294 dd038bc6 2021-09-21 thomas.ad {
295 dd038bc6 2021-09-21 thomas.ad TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
296 dd038bc6 2021-09-21 thomas.ad msgbuf->queued++;
297 dd038bc6 2021-09-21 thomas.ad }
298 dd038bc6 2021-09-21 thomas.ad
299 dd038bc6 2021-09-21 thomas.ad static void
300 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
301 dd038bc6 2021-09-21 thomas.ad {
302 dd038bc6 2021-09-21 thomas.ad TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
303 dd038bc6 2021-09-21 thomas.ad
304 dd038bc6 2021-09-21 thomas.ad if (buf->fd != -1)
305 dd038bc6 2021-09-21 thomas.ad close(buf->fd);
306 dd038bc6 2021-09-21 thomas.ad
307 dd038bc6 2021-09-21 thomas.ad msgbuf->queued--;
308 dd038bc6 2021-09-21 thomas.ad ibuf_free(buf);
309 dd038bc6 2021-09-21 thomas.ad }