1 3ef3f36a 2023-07-05 op /* $OpenBSD: imsg-buffer.c,v 1.16 2023/06/19 17:19:50 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 #ifdef NOTYET
297 3ef3f36a 2023-07-05 op if (buf->fd != -1)
298 3ef3f36a 2023-07-05 op close(buf->fd);
300 3ef3f36a 2023-07-05 op freezero(buf->buf, buf->size);
305 3ef3f36a 2023-07-05 op ibuf_fd_avail(struct ibuf *buf)
307 3ef3f36a 2023-07-05 op return (buf->fd != -1);
311 3ef3f36a 2023-07-05 op ibuf_fd_get(struct ibuf *buf)
315 3ef3f36a 2023-07-05 op fd = buf->fd;
316 3ef3f36a 2023-07-05 op #ifdef NOTYET
317 3ef3f36a 2023-07-05 op buf->fd = -1;
323 3ef3f36a 2023-07-05 op ibuf_fd_set(struct ibuf *buf, int fd)
325 3ef3f36a 2023-07-05 op if (buf->fd != -1)
326 3ef3f36a 2023-07-05 op close(buf->fd);
327 3ef3f36a 2023-07-05 op buf->fd = fd;
331 dd038bc6 2021-09-21 thomas.ad ibuf_write(struct msgbuf *msgbuf)
333 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
334 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
335 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
336 dd038bc6 2021-09-21 thomas.ad ssize_t n;
338 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
339 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
340 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
341 dd038bc6 2021-09-21 thomas.ad break;
342 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
343 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
347 dd038bc6 2021-09-21 thomas.ad again:
348 dd038bc6 2021-09-21 thomas.ad if ((n = writev(msgbuf->fd, iov, i)) == -1) {
349 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
350 dd038bc6 2021-09-21 thomas.ad goto again;
351 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
352 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
353 dd038bc6 2021-09-21 thomas.ad return (-1);
356 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
357 dd038bc6 2021-09-21 thomas.ad errno = 0;
358 dd038bc6 2021-09-21 thomas.ad return (0);
361 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
363 dd038bc6 2021-09-21 thomas.ad return (1);
367 dd038bc6 2021-09-21 thomas.ad msgbuf_init(struct msgbuf *msgbuf)
369 dd038bc6 2021-09-21 thomas.ad msgbuf->queued = 0;
370 dd038bc6 2021-09-21 thomas.ad msgbuf->fd = -1;
371 dd038bc6 2021-09-21 thomas.ad TAILQ_INIT(&msgbuf->bufs);
375 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(struct msgbuf *msgbuf, size_t n)
377 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf, *next;
379 dd038bc6 2021-09-21 thomas.ad for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
380 dd038bc6 2021-09-21 thomas.ad buf = next) {
381 dd038bc6 2021-09-21 thomas.ad next = TAILQ_NEXT(buf, entry);
382 3ef3f36a 2023-07-05 op if (n >= buf->wpos - buf->rpos) {
383 dd038bc6 2021-09-21 thomas.ad n -= buf->wpos - buf->rpos;
384 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
385 dd038bc6 2021-09-21 thomas.ad } else {
386 dd038bc6 2021-09-21 thomas.ad buf->rpos += n;
387 dd038bc6 2021-09-21 thomas.ad n = 0;
393 dd038bc6 2021-09-21 thomas.ad msgbuf_clear(struct msgbuf *msgbuf)
395 dd038bc6 2021-09-21 thomas.ad struct ibuf *buf;
397 dd038bc6 2021-09-21 thomas.ad while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
398 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(msgbuf, buf);
402 dd038bc6 2021-09-21 thomas.ad msgbuf_write(struct msgbuf *msgbuf)
404 dd038bc6 2021-09-21 thomas.ad struct iovec iov[IOV_MAX];
405 3ef3f36a 2023-07-05 op struct ibuf *buf, *buf0 = NULL;
406 dd038bc6 2021-09-21 thomas.ad unsigned int i = 0;
407 dd038bc6 2021-09-21 thomas.ad ssize_t n;
408 dd038bc6 2021-09-21 thomas.ad struct msghdr msg;
409 dd038bc6 2021-09-21 thomas.ad struct cmsghdr *cmsg;
410 dd038bc6 2021-09-21 thomas.ad union {
411 dd038bc6 2021-09-21 thomas.ad struct cmsghdr hdr;
412 dd038bc6 2021-09-21 thomas.ad char buf[CMSG_SPACE(sizeof(int))];
413 dd038bc6 2021-09-21 thomas.ad } cmsgbuf;
415 dd038bc6 2021-09-21 thomas.ad memset(&iov, 0, sizeof(iov));
416 dd038bc6 2021-09-21 thomas.ad memset(&msg, 0, sizeof(msg));
417 dd038bc6 2021-09-21 thomas.ad memset(&cmsgbuf, 0, sizeof(cmsgbuf));
418 dd038bc6 2021-09-21 thomas.ad TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
419 dd038bc6 2021-09-21 thomas.ad if (i >= IOV_MAX)
420 dd038bc6 2021-09-21 thomas.ad break;
421 3ef3f36a 2023-07-05 op if (i > 0 && buf->fd != -1)
423 dd038bc6 2021-09-21 thomas.ad iov[i].iov_base = buf->buf + buf->rpos;
424 dd038bc6 2021-09-21 thomas.ad iov[i].iov_len = buf->wpos - buf->rpos;
426 dd038bc6 2021-09-21 thomas.ad if (buf->fd != -1)
430 dd038bc6 2021-09-21 thomas.ad msg.msg_iov = iov;
431 dd038bc6 2021-09-21 thomas.ad msg.msg_iovlen = i;
433 3ef3f36a 2023-07-05 op if (buf0 != NULL) {
434 dd038bc6 2021-09-21 thomas.ad msg.msg_control = (caddr_t)&cmsgbuf.buf;
435 dd038bc6 2021-09-21 thomas.ad msg.msg_controllen = sizeof(cmsgbuf.buf);
436 dd038bc6 2021-09-21 thomas.ad cmsg = CMSG_FIRSTHDR(&msg);
437 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_len = CMSG_LEN(sizeof(int));
438 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_level = SOL_SOCKET;
439 dd038bc6 2021-09-21 thomas.ad cmsg->cmsg_type = SCM_RIGHTS;
440 3ef3f36a 2023-07-05 op *(int *)CMSG_DATA(cmsg) = buf0->fd;
443 dd038bc6 2021-09-21 thomas.ad again:
444 dd038bc6 2021-09-21 thomas.ad if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
445 dd038bc6 2021-09-21 thomas.ad if (errno == EINTR)
446 dd038bc6 2021-09-21 thomas.ad goto again;
447 dd038bc6 2021-09-21 thomas.ad if (errno == ENOBUFS)
448 dd038bc6 2021-09-21 thomas.ad errno = EAGAIN;
449 dd038bc6 2021-09-21 thomas.ad return (-1);
452 dd038bc6 2021-09-21 thomas.ad if (n == 0) { /* connection closed */
453 dd038bc6 2021-09-21 thomas.ad errno = 0;
454 dd038bc6 2021-09-21 thomas.ad return (0);
458 dd038bc6 2021-09-21 thomas.ad * assumption: fd got sent if sendmsg sent anything
459 dd038bc6 2021-09-21 thomas.ad * this works because fds are passed one at a time
461 3ef3f36a 2023-07-05 op if (buf0 != NULL) {
462 3ef3f36a 2023-07-05 op close(buf0->fd);
463 3ef3f36a 2023-07-05 op buf0->fd = -1;
466 dd038bc6 2021-09-21 thomas.ad msgbuf_drain(msgbuf, n);
468 dd038bc6 2021-09-21 thomas.ad return (1);
471 dd038bc6 2021-09-21 thomas.ad static void
472 dd038bc6 2021-09-21 thomas.ad ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
474 dd038bc6 2021-09-21 thomas.ad TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
475 dd038bc6 2021-09-21 thomas.ad msgbuf->queued++;
478 dd038bc6 2021-09-21 thomas.ad static void
479 dd038bc6 2021-09-21 thomas.ad ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
481 dd038bc6 2021-09-21 thomas.ad TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
483 3ef3f36a 2023-07-05 op if (buf->fd != -1) {
484 dd038bc6 2021-09-21 thomas.ad close(buf->fd);
485 3ef3f36a 2023-07-05 op buf->fd = -1;
488 dd038bc6 2021-09-21 thomas.ad msgbuf->queued--;
489 dd038bc6 2021-09-21 thomas.ad ibuf_free(buf);