1 b69b73ef 2023-11-25 thomas /* $OpenBSD: imsg-buffer.c,v 1.17 2023/10/24 14:05:23 claudio Exp $ */
4 dd038bc6 2021-09-21 thomas.ad * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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.
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.
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>
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>
29 dd038bc6 2021-09-21 thomas.ad #include "got_compat.h"
30 4fccd2fe 2023-03-08 thomas #include "imsg.h"
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 3ef3f36a 2023-07-05 op static void msgbuf_drain(struct msgbuf *, size_t);
37 dd038bc6 2021-09-21 thomas.ad struct ibuf *
38 dd038bc6 2021-09-21 thomas.ad ibuf_open(size_t len)
40 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
42 3ef3f36a 2023-07-05 op if (len == 0) {
43 3ef3f36a 2023-07-05 op errno = EINVAL;
44 3ef3f36a 2023-07-05 op return (NULL);
46 dd038bc6 2021-09-21 thomas.ad if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
47 dd038bc6 2021-09-21 thomas.ad return (NULL);
48 3ef3f36a 2023-07-05 op if ((buf->buf = calloc(len, 1)) == NULL) {
49 dd038bc6 2021-09-21 thomas.ad free(buf);
50 dd038bc6 2021-09-21 thomas.ad return (NULL);
52 dd038bc6 2021-09-21 thomas.ad buf->size = buf->max = len;
53 dd038bc6 2021-09-21 thomas.ad buf->fd = -1;
55 dd038bc6 2021-09-21 thomas.ad return (buf);
58 dd038bc6 2021-09-21 thomas.ad struct ibuf *
59 dd038bc6 2021-09-21 thomas.ad ibuf_dynamic(size_t len, size_t max)
61 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
63 3ef3f36a 2023-07-05 op if (max < len) {
64 3ef3f36a 2023-07-05 op errno = EINVAL;
65 dd038bc6 2021-09-21 thomas.ad return (NULL);
68 3ef3f36a 2023-07-05 op if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
69 dd038bc6 2021-09-21 thomas.ad return (NULL);
70 3ef3f36a 2023-07-05 op if (len > 0) {
71 3ef3f36a 2023-07-05 op if ((buf->buf = calloc(len, 1)) == NULL) {
73 3ef3f36a 2023-07-05 op return (NULL);
76 3ef3f36a 2023-07-05 op buf->size = len;
77 3ef3f36a 2023-07-05 op buf->max = max;
80 dd038bc6 2021-09-21 thomas.ad return (buf);
83 dd038bc6 2021-09-21 thomas.ad static int
84 dd038bc6 2021-09-21 thomas.ad ibuf_realloc(struct ibuf *buf, size_t len)
86 3ef3f36a 2023-07-05 op unsigned char *b;
88 dd038bc6 2021-09-21 thomas.ad /* on static buffers max is eq size and so the following fails */
89 3ef3f36a 2023-07-05 op if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
90 dd038bc6 2021-09-21 thomas.ad errno = ERANGE;
91 dd038bc6 2021-09-21 thomas.ad return (-1);
94 c0faa645 2021-09-21 thomas.ad b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
95 dd038bc6 2021-09-21 thomas.ad if (b == NULL)
96 dd038bc6 2021-09-21 thomas.ad return (-1);
97 dd038bc6 2021-09-21 thomas.ad buf->buf = b;
98 dd038bc6 2021-09-21 thomas.ad buf->size = buf->wpos + len;
100 dd038bc6 2021-09-21 thomas.ad return (0);
103 dd038bc6 2021-09-21 thomas.ad void *
104 dd038bc6 2021-09-21 thomas.ad ibuf_reserve(struct ibuf *buf, size_t len)
106 dd038bc6 2021-09-21 thomas.ad void *b;
108 3ef3f36a 2023-07-05 op if (len > SIZE_MAX - buf->wpos) {
109 3ef3f36a 2023-07-05 op errno = ERANGE;
110 3ef3f36a 2023-07-05 op return (NULL);
113 dd038bc6 2021-09-21 thomas.ad if (buf->wpos + len > buf->size)
114 dd038bc6 2021-09-21 thomas.ad if (ibuf_realloc(buf, len) == -1)
115 dd038bc6 2021-09-21 thomas.ad return (NULL);
117 dd038bc6 2021-09-21 thomas.ad b = buf->buf + buf->wpos;
118 dd038bc6 2021-09-21 thomas.ad buf->wpos += len;
119 3ef3f36a 2023-07-05 op memset(b, 0, len);
120 dd038bc6 2021-09-21 thomas.ad return (b);
124 3ef3f36a 2023-07-05 op ibuf_add(struct ibuf *buf, const void *data, size_t len)
128 3ef3f36a 2023-07-05 op if ((b = ibuf_reserve(buf, len)) == NULL)
131 3ef3f36a 2023-07-05 op memcpy(b, data, len);
136 3ef3f36a 2023-07-05 op ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
138 3ef3f36a 2023-07-05 op return ibuf_add(buf, from->buf, from->wpos);
142 3ef3f36a 2023-07-05 op ibuf_add_n8(struct ibuf *buf, uint64_t value)
146 3ef3f36a 2023-07-05 op if (value > UINT8_MAX) {
147 3ef3f36a 2023-07-05 op errno = EINVAL;
151 3ef3f36a 2023-07-05 op return ibuf_add(buf, &v, sizeof(v));
155 3ef3f36a 2023-07-05 op ibuf_add_n16(struct ibuf *buf, uint64_t value)
159 3ef3f36a 2023-07-05 op if (value > UINT16_MAX) {
160 3ef3f36a 2023-07-05 op errno = EINVAL;
163 3ef3f36a 2023-07-05 op v = htobe16(value);
164 3ef3f36a 2023-07-05 op return ibuf_add(buf, &v, sizeof(v));
168 3ef3f36a 2023-07-05 op ibuf_add_n32(struct ibuf *buf, uint64_t value)
172 3ef3f36a 2023-07-05 op if (value > UINT32_MAX) {
173 3ef3f36a 2023-07-05 op errno = EINVAL;
176 3ef3f36a 2023-07-05 op v = htobe32(value);
177 3ef3f36a 2023-07-05 op return ibuf_add(buf, &v, sizeof(v));
181 3ef3f36a 2023-07-05 op ibuf_add_n64(struct ibuf *buf, uint64_t value)
183 3ef3f36a 2023-07-05 op value = htobe64(value);
184 3ef3f36a 2023-07-05 op return ibuf_add(buf, &value, sizeof(value));
188 3ef3f36a 2023-07-05 op ibuf_add_zero(struct ibuf *buf, size_t len)
192 3ef3f36a 2023-07-05 op if ((b = ibuf_reserve(buf, len)) == NULL)
197 dd038bc6 2021-09-21 thomas.ad void *
198 dd038bc6 2021-09-21 thomas.ad ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
200 dd038bc6 2021-09-21 thomas.ad /* only allowed to seek in already written parts */
201 3ef3f36a 2023-07-05 op if (len > SIZE_MAX - pos || pos + len > buf->wpos) {
202 3ef3f36a 2023-07-05 op errno = ERANGE;
203 dd038bc6 2021-09-21 thomas.ad return (NULL);
206 dd038bc6 2021-09-21 thomas.ad return (buf->buf + pos);
210 3ef3f36a 2023-07-05 op ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
214 3ef3f36a 2023-07-05 op if ((b = ibuf_seek(buf, pos, len)) == NULL)
217 3ef3f36a 2023-07-05 op memcpy(b, data, len);
222 3ef3f36a 2023-07-05 op ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
226 3ef3f36a 2023-07-05 op if (value > UINT8_MAX) {
227 3ef3f36a 2023-07-05 op errno = EINVAL;
231 3ef3f36a 2023-07-05 op return (ibuf_set(buf, pos, &v, sizeof(v)));
235 3ef3f36a 2023-07-05 op ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
239 3ef3f36a 2023-07-05 op if (value > UINT16_MAX) {
240 3ef3f36a 2023-07-05 op errno = EINVAL;
243 3ef3f36a 2023-07-05 op v = htobe16(value);
244 3ef3f36a 2023-07-05 op return (ibuf_set(buf, pos, &v, sizeof(v)));
248 3ef3f36a 2023-07-05 op ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
252 3ef3f36a 2023-07-05 op if (value > UINT32_MAX) {
253 3ef3f36a 2023-07-05 op errno = EINVAL;
256 3ef3f36a 2023-07-05 op v = htobe32(value);
257 3ef3f36a 2023-07-05 op return (ibuf_set(buf, pos, &v, sizeof(v)));
261 3ef3f36a 2023-07-05 op ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
263 3ef3f36a 2023-07-05 op value = htobe64(value);
264 3ef3f36a 2023-07-05 op return (ibuf_set(buf, pos, &value, sizeof(value)));
268 3ef3f36a 2023-07-05 op ibuf_data(struct ibuf *buf)
270 3ef3f36a 2023-07-05 op return (buf->buf);
273 dd038bc6 2021-09-21 thomas.ad size_t
274 dd038bc6 2021-09-21 thomas.ad ibuf_size(struct ibuf *buf)
276 dd038bc6 2021-09-21 thomas.ad return (buf->wpos);
279 dd038bc6 2021-09-21 thomas.ad size_t
280 dd038bc6 2021-09-21 thomas.ad ibuf_left(struct ibuf *buf)
282 dd038bc6 2021-09-21 thomas.ad return (buf->max - buf->wpos);
286 dd038bc6 2021-09-21 thomas.ad ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
288 dd038bc6 2021-09-21 thomas.ad ibuf_enqueue(msgbuf, buf);
292 3ef3f36a 2023-07-05 op ibuf_free(struct ibuf *buf)
294 3ef3f36a 2023-07-05 op if (buf == NULL)
296 3ef3f36a 2023-07-05 op if (buf->fd != -1)
297 3ef3f36a 2023-07-05 op close(buf->fd);
298 3ef3f36a 2023-07-05 op freezero(buf->buf, buf->size);
303 3ef3f36a 2023-07-05 op ibuf_fd_avail(struct ibuf *buf)
305 3ef3f36a 2023-07-05 op return (buf->fd != -1);
309 3ef3f36a 2023-07-05 op ibuf_fd_get(struct ibuf *buf)
313 3ef3f36a 2023-07-05 op fd = buf->fd;
314 3ef3f36a 2023-07-05 op buf->fd = -1;
319 3ef3f36a 2023-07-05 op ibuf_fd_set(struct ibuf *buf, int fd)
321 3ef3f36a 2023-07-05 op if (buf->fd != -1)
322 3ef3f36a 2023-07-05 op close(buf->fd);
323 3ef3f36a 2023-07-05 op buf->fd = fd;
327 dd038bc6 2021-09-21 thomas.ad ibuf_write(struct msgbuf *msgbuf)
329 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
330 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
331 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
332 dd038bc6 2021-09-21 thomas.ad ssize_t n;
334 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
335 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
336 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
337 dd038bc6 2021-09-21 thomas.ad break;
338 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
339 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
343 dd038bc6 2021-09-21 thomas.ad again:
344 dd038bc6 2021-09-21 thomas.ad if ((n = writev(msgbuf->fd, iov, i)) == -1) {
345 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
346 dd038bc6 2021-09-21 thomas.ad goto again;
347 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
348 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
349 dd038bc6 2021-09-21 thomas.ad return (-1);
352 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
353 dd038bc6 2021-09-21 thomas.ad errno = 0;
354 dd038bc6 2021-09-21 thomas.ad return (0);
357 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
359 dd038bc6 2021-09-21 thomas.ad return (1);
363 dd038bc6 2021-09-21 thomas.ad msgbuf_init(struct msgbuf *msgbuf)
365 dd038bc6 2021-09-21 thomas.ad msgbuf->queued = 0;
366 dd038bc6 2021-09-21 thomas.ad msgbuf->fd = -1;
367 dd038bc6 2021-09-21 thomas.ad TAILQ_INIT(&msgbuf->bufs);
371 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(struct msgbuf *msgbuf, size_t n)
373 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf, *next;
375 dd038bc6 2021-09-21 thomas.ad for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
376 dd038bc6 2021-09-21 thomas.ad buf = next) {
377 dd038bc6 2021-09-21 thomas.ad next = TAILQ_NEXT(buf, entry);
378 3ef3f36a 2023-07-05 op if (n >= buf->wpos - buf->rpos) {
379 dd038bc6 2021-09-21 thomas.ad n -= buf->wpos - buf->rpos;
380 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
381 dd038bc6 2021-09-21 thomas.ad } else {
382 dd038bc6 2021-09-21 thomas.ad buf->rpos += n;
383 dd038bc6 2021-09-21 thomas.ad n = 0;
389 dd038bc6 2021-09-21 thomas.ad msgbuf_clear(struct msgbuf *msgbuf)
391 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
393 dd038bc6 2021-09-21 thomas.ad while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
394 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
398 dd038bc6 2021-09-21 thomas.ad msgbuf_write(struct msgbuf *msgbuf)
400 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
401 3ef3f36a 2023-07-05 op struct ibuf *buf, *buf0 = NULL;
402 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
403 dd038bc6 2021-09-21 thomas.ad ssize_t n;
404 dd038bc6 2021-09-21 thomas.ad struct msghdr msg;
405 dd038bc6 2021-09-21 thomas.ad struct cmsghdr *cmsg;
406 dd038bc6 2021-09-21 thomas.ad union {
407 dd038bc6 2021-09-21 thomas.ad struct cmsghdr hdr;
408 dd038bc6 2021-09-21 thomas.ad char buf[CMSG_SPACE(sizeof(int))];
409 dd038bc6 2021-09-21 thomas.ad } cmsgbuf;
411 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
412 dd038bc6 2021-09-21 thomas.ad memset(&msg, 0, sizeof(msg));
413 dd038bc6 2021-09-21 thomas.ad memset(&cmsgbuf, 0, sizeof(cmsgbuf));
414 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
415 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
416 dd038bc6 2021-09-21 thomas.ad break;
417 3ef3f36a 2023-07-05 op if (i > 0 && buf->fd != -1)
419 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
420 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
422 dd038bc6 2021-09-21 thomas.ad if (buf->fd != -1)
426 dd038bc6 2021-09-21 thomas.ad msg.msg_iov = iov;
427 dd038bc6 2021-09-21 thomas.ad msg.msg_iovlen = i;
429 3ef3f36a 2023-07-05 op if (buf0 != NULL) {
430 dd038bc6 2021-09-21 thomas.ad msg.msg_control = (caddr_t)&cmsgbuf.buf;
431 dd038bc6 2021-09-21 thomas.ad msg.msg_controllen = sizeof(cmsgbuf.buf);
432 dd038bc6 2021-09-21 thomas.ad cmsg = CMSG_FIRSTHDR(&msg);
433 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_len = CMSG_LEN(sizeof(int));
434 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_level = SOL_SOCKET;
435 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_type = SCM_RIGHTS;
436 3ef3f36a 2023-07-05 op *(int *)CMSG_DATA(cmsg) = buf0->fd;
439 dd038bc6 2021-09-21 thomas.ad again:
440 dd038bc6 2021-09-21 thomas.ad if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
441 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
442 dd038bc6 2021-09-21 thomas.ad goto again;
443 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
444 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
445 dd038bc6 2021-09-21 thomas.ad return (-1);
448 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
449 dd038bc6 2021-09-21 thomas.ad errno = 0;
450 dd038bc6 2021-09-21 thomas.ad return (0);
454 dd038bc6 2021-09-21 thomas.ad * assumption: fd got sent if sendmsg sent anything
455 dd038bc6 2021-09-21 thomas.ad * this works because fds are passed one at a time
457 3ef3f36a 2023-07-05 op if (buf0 != NULL) {
458 3ef3f36a 2023-07-05 op close(buf0->fd);
459 3ef3f36a 2023-07-05 op buf0->fd = -1;
462 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
464 dd038bc6 2021-09-21 thomas.ad return (1);
467 dd038bc6 2021-09-21 thomas.ad static void
468 dd038bc6 2021-09-21 thomas.ad ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
470 dd038bc6 2021-09-21 thomas.ad TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
471 dd038bc6 2021-09-21 thomas.ad msgbuf->queued++;
474 dd038bc6 2021-09-21 thomas.ad static void
475 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
477 dd038bc6 2021-09-21 thomas.ad TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
479 dd038bc6 2021-09-21 thomas.ad msgbuf->queued--;
480 dd038bc6 2021-09-21 thomas.ad ibuf_free(buf);