1 /* $OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $ */
4 * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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.
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.
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
32 #include "got_compat.h"
36 TAILQ_HEAD(, ibuf
) bufs
;
37 TAILQ_HEAD(, ibuf
) rbufs
;
41 struct ibuf
*(*readhdr
)(struct ibuf
*, void *, int *);
47 static void msgbuf_read_enqueue(struct msgbuf
*, struct ibuf
*);
48 static void msgbuf_enqueue(struct msgbuf
*, struct ibuf
*);
49 static void msgbuf_dequeue(struct msgbuf
*, struct ibuf
*);
50 static void msgbuf_drain(struct msgbuf
*, size_t);
52 #define IBUF_FD_MARK_ON_STACK -2
59 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
62 if ((buf
->buf
= calloc(len
, 1)) == NULL
) {
67 buf
->size
= buf
->max
= len
;
74 ibuf_dynamic(size_t len
, size_t max
)
78 if (max
== 0 || max
< len
) {
83 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
86 if ((buf
->buf
= calloc(len
, 1)) == NULL
) {
99 ibuf_reserve(struct ibuf
*buf
, size_t len
)
103 if (len
> SIZE_MAX
- buf
->wpos
) {
107 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
) {
108 /* can not grow stack buffers */
113 if (buf
->wpos
+ len
> buf
->size
) {
116 /* check if buffer is allowed to grow */
117 if (buf
->wpos
+ len
> buf
->max
) {
121 nb
= realloc(buf
->buf
, buf
->wpos
+ len
);
124 memset(nb
+ buf
->size
, 0, buf
->wpos
+ len
- buf
->size
);
126 buf
->size
= buf
->wpos
+ len
;
129 b
= buf
->buf
+ buf
->wpos
;
135 ibuf_add(struct ibuf
*buf
, const void *data
, size_t len
)
139 if ((b
= ibuf_reserve(buf
, len
)) == NULL
)
142 memcpy(b
, data
, len
);
147 ibuf_add_ibuf(struct ibuf
*buf
, const struct ibuf
*from
)
149 return ibuf_add(buf
, ibuf_data(from
), ibuf_size(from
));
153 ibuf_add_n8(struct ibuf
*buf
, uint64_t value
)
157 if (value
> UINT8_MAX
) {
162 return ibuf_add(buf
, &v
, sizeof(v
));
166 ibuf_add_n16(struct ibuf
*buf
, uint64_t value
)
170 if (value
> UINT16_MAX
) {
175 return ibuf_add(buf
, &v
, sizeof(v
));
179 ibuf_add_n32(struct ibuf
*buf
, uint64_t value
)
183 if (value
> UINT32_MAX
) {
188 return ibuf_add(buf
, &v
, sizeof(v
));
192 ibuf_add_n64(struct ibuf
*buf
, uint64_t value
)
194 value
= htobe64(value
);
195 return ibuf_add(buf
, &value
, sizeof(value
));
199 ibuf_add_h16(struct ibuf
*buf
, uint64_t value
)
203 if (value
> UINT16_MAX
) {
208 return ibuf_add(buf
, &v
, sizeof(v
));
212 ibuf_add_h32(struct ibuf
*buf
, uint64_t value
)
216 if (value
> UINT32_MAX
) {
221 return ibuf_add(buf
, &v
, sizeof(v
));
225 ibuf_add_h64(struct ibuf
*buf
, uint64_t value
)
227 return ibuf_add(buf
, &value
, sizeof(value
));
231 ibuf_add_zero(struct ibuf
*buf
, size_t len
)
235 if ((b
= ibuf_reserve(buf
, len
)) == NULL
)
242 ibuf_seek(struct ibuf
*buf
, size_t pos
, size_t len
)
244 /* only allow seeking between rpos and wpos */
245 if (ibuf_size(buf
) < pos
|| SIZE_MAX
- pos
< len
||
246 ibuf_size(buf
) < pos
+ len
) {
251 return (buf
->buf
+ buf
->rpos
+ pos
);
255 ibuf_set(struct ibuf
*buf
, size_t pos
, const void *data
, size_t len
)
259 if ((b
= ibuf_seek(buf
, pos
, len
)) == NULL
)
262 memcpy(b
, data
, len
);
267 ibuf_set_n8(struct ibuf
*buf
, size_t pos
, uint64_t value
)
271 if (value
> UINT8_MAX
) {
276 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
280 ibuf_set_n16(struct ibuf
*buf
, size_t pos
, uint64_t value
)
284 if (value
> UINT16_MAX
) {
289 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
293 ibuf_set_n32(struct ibuf
*buf
, size_t pos
, uint64_t value
)
297 if (value
> UINT32_MAX
) {
302 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
306 ibuf_set_n64(struct ibuf
*buf
, size_t pos
, uint64_t value
)
308 value
= htobe64(value
);
309 return (ibuf_set(buf
, pos
, &value
, sizeof(value
)));
313 ibuf_set_h16(struct ibuf
*buf
, size_t pos
, uint64_t value
)
317 if (value
> UINT16_MAX
) {
322 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
326 ibuf_set_h32(struct ibuf
*buf
, size_t pos
, uint64_t value
)
330 if (value
> UINT32_MAX
) {
335 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
339 ibuf_set_h64(struct ibuf
*buf
, size_t pos
, uint64_t value
)
341 return (ibuf_set(buf
, pos
, &value
, sizeof(value
)));
345 ibuf_data(const struct ibuf
*buf
)
347 return (buf
->buf
+ buf
->rpos
);
351 ibuf_size(const struct ibuf
*buf
)
353 return (buf
->wpos
- buf
->rpos
);
357 ibuf_left(const struct ibuf
*buf
)
359 /* on stack buffers have no space left */
360 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
362 return (buf
->max
- buf
->wpos
);
366 ibuf_truncate(struct ibuf
*buf
, size_t len
)
368 if (ibuf_size(buf
) >= len
) {
369 buf
->wpos
= buf
->rpos
+ len
;
372 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
) {
373 /* only allow to truncate down for stack buffers */
377 return ibuf_add_zero(buf
, len
- ibuf_size(buf
));
381 ibuf_rewind(struct ibuf
*buf
)
387 ibuf_close(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
389 msgbuf_enqueue(msgbuf
, buf
);
393 ibuf_from_buffer(struct ibuf
*buf
, void *data
, size_t len
)
395 memset(buf
, 0, sizeof(*buf
));
397 buf
->size
= buf
->wpos
= len
;
398 buf
->fd
= IBUF_FD_MARK_ON_STACK
;
402 ibuf_from_ibuf(struct ibuf
*buf
, const struct ibuf
*from
)
404 ibuf_from_buffer(buf
, ibuf_data(from
), ibuf_size(from
));
408 ibuf_get(struct ibuf
*buf
, void *data
, size_t len
)
410 if (ibuf_size(buf
) < len
) {
415 memcpy(data
, ibuf_data(buf
), len
);
421 ibuf_get_ibuf(struct ibuf
*buf
, size_t len
, struct ibuf
*new)
423 if (ibuf_size(buf
) < len
) {
428 ibuf_from_buffer(new, ibuf_data(buf
), len
);
434 ibuf_get_h16(struct ibuf
*buf
, uint16_t *value
)
436 return ibuf_get(buf
, value
, sizeof(*value
));
440 ibuf_get_h32(struct ibuf
*buf
, uint32_t *value
)
442 return ibuf_get(buf
, value
, sizeof(*value
));
446 ibuf_get_h64(struct ibuf
*buf
, uint64_t *value
)
448 return ibuf_get(buf
, value
, sizeof(*value
));
452 ibuf_get_n8(struct ibuf
*buf
, uint8_t *value
)
454 return ibuf_get(buf
, value
, sizeof(*value
));
458 ibuf_get_n16(struct ibuf
*buf
, uint16_t *value
)
462 rv
= ibuf_get(buf
, value
, sizeof(*value
));
463 *value
= be16toh(*value
);
468 ibuf_get_n32(struct ibuf
*buf
, uint32_t *value
)
472 rv
= ibuf_get(buf
, value
, sizeof(*value
));
473 *value
= be32toh(*value
);
478 ibuf_get_n64(struct ibuf
*buf
, uint64_t *value
)
482 rv
= ibuf_get(buf
, value
, sizeof(*value
));
483 *value
= be64toh(*value
);
488 ibuf_get_string(struct ibuf
*buf
, size_t len
)
492 if (ibuf_size(buf
) < len
) {
497 str
= strndup(ibuf_data(buf
), len
);
505 ibuf_skip(struct ibuf
*buf
, size_t len
)
507 if (ibuf_size(buf
) < len
) {
517 ibuf_free(struct ibuf
*buf
)
521 /* if buf lives on the stack abort before causing more harm */
522 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
526 freezero(buf
->buf
, buf
->size
);
531 ibuf_fd_avail(struct ibuf
*buf
)
533 return (buf
->fd
>= 0);
537 ibuf_fd_get(struct ibuf
*buf
)
541 /* negative fds are internal use and equivalent to -1 */
550 ibuf_fd_set(struct ibuf
*buf
, int fd
)
552 /* if buf lives on the stack abort before causing more harm */
553 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
565 struct msgbuf
*msgbuf
;
567 if ((msgbuf
= calloc(1, sizeof(*msgbuf
))) == NULL
)
570 TAILQ_INIT(&msgbuf
->bufs
);
571 TAILQ_INIT(&msgbuf
->rbufs
);
577 msgbuf_new_reader(size_t hdrsz
,
578 struct ibuf
*(*readhdr
)(struct ibuf
*, void *, int *), void *arg
)
580 struct msgbuf
*msgbuf
;
583 if (hdrsz
== 0 || hdrsz
> IBUF_READ_SIZE
/ 2) {
588 if ((buf
= malloc(IBUF_READ_SIZE
)) == NULL
)
591 msgbuf
= msgbuf_new();
592 if (msgbuf
== NULL
) {
598 msgbuf
->hdrsize
= hdrsz
;
599 msgbuf
->readhdr
= readhdr
;
606 msgbuf_free(struct msgbuf
*msgbuf
)
610 msgbuf_clear(msgbuf
);
616 msgbuf_queuelen(struct msgbuf
*msgbuf
)
618 return (msgbuf
->queued
);
622 msgbuf_clear(struct msgbuf
*msgbuf
)
627 while ((buf
= TAILQ_FIRST(&msgbuf
->bufs
)) != NULL
)
628 msgbuf_dequeue(msgbuf
, buf
);
632 while ((buf
= TAILQ_FIRST(&msgbuf
->rbufs
)) != NULL
) {
633 TAILQ_REMOVE(&msgbuf
->rbufs
, buf
, entry
);
637 ibuf_free(msgbuf
->rpmsg
);
638 msgbuf
->rpmsg
= NULL
;
642 msgbuf_get(struct msgbuf
*msgbuf
)
646 if ((buf
= TAILQ_FIRST(&msgbuf
->rbufs
)) != NULL
)
647 TAILQ_REMOVE(&msgbuf
->rbufs
, buf
, entry
);
652 ibuf_write(int fd
, struct msgbuf
*msgbuf
)
654 struct iovec iov
[IOV_MAX
];
659 memset(&iov
, 0, sizeof(iov
));
660 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
663 iov
[i
].iov_base
= ibuf_data(buf
);
664 iov
[i
].iov_len
= ibuf_size(buf
);
668 return (0); /* nothing queued */
671 if ((n
= writev(fd
, iov
, i
)) == -1) {
674 if (errno
== EAGAIN
|| errno
== ENOBUFS
)
675 /* lets retry later again */
680 msgbuf_drain(msgbuf
, n
);
685 msgbuf_write(int fd
, struct msgbuf
*msgbuf
)
687 struct iovec iov
[IOV_MAX
];
688 struct ibuf
*buf
, *buf0
= NULL
;
692 struct cmsghdr
*cmsg
;
695 char buf
[CMSG_SPACE(sizeof(int))];
698 memset(&iov
, 0, sizeof(iov
));
699 memset(&msg
, 0, sizeof(msg
));
700 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
701 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
704 if (i
> 0 && buf
->fd
!= -1)
706 iov
[i
].iov_base
= ibuf_data(buf
);
707 iov
[i
].iov_len
= ibuf_size(buf
);
714 return (0); /* nothing queued */
720 msg
.msg_control
= (caddr_t
)&cmsgbuf
.buf
;
721 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
722 cmsg
= CMSG_FIRSTHDR(&msg
);
723 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
724 cmsg
->cmsg_level
= SOL_SOCKET
;
725 cmsg
->cmsg_type
= SCM_RIGHTS
;
726 *(int *)CMSG_DATA(cmsg
) = buf0
->fd
;
730 if ((n
= sendmsg(fd
, &msg
, 0)) == -1) {
733 if (errno
== EAGAIN
|| errno
== ENOBUFS
)
734 /* lets retry later again */
740 * assumption: fd got sent if sendmsg sent anything
741 * this works because fds are passed one at a time
748 msgbuf_drain(msgbuf
, n
);
754 ibuf_read_process(struct msgbuf
*msgbuf
, int fd
)
756 struct ibuf rbuf
, msg
;
759 ibuf_from_buffer(&rbuf
, msgbuf
->rbuf
, msgbuf
->roff
);
762 if (msgbuf
->rpmsg
== NULL
) {
763 if (ibuf_size(&rbuf
) < msgbuf
->hdrsize
)
765 /* get size from header */
766 ibuf_from_buffer(&msg
, ibuf_data(&rbuf
),
768 if ((msgbuf
->rpmsg
= msgbuf
->readhdr(&msg
,
769 msgbuf
->rarg
, &fd
)) == NULL
)
773 if (ibuf_left(msgbuf
->rpmsg
) <= ibuf_size(&rbuf
))
774 sz
= ibuf_left(msgbuf
->rpmsg
);
776 sz
= ibuf_size(&rbuf
);
778 /* neither call below can fail */
779 if (ibuf_get_ibuf(&rbuf
, sz
, &msg
) == -1 ||
780 ibuf_add_ibuf(msgbuf
->rpmsg
, &msg
) == -1)
783 if (ibuf_left(msgbuf
->rpmsg
) == 0) {
784 msgbuf_read_enqueue(msgbuf
, msgbuf
->rpmsg
);
785 msgbuf
->rpmsg
= NULL
;
787 } while (ibuf_size(&rbuf
) > 0);
789 if (ibuf_size(&rbuf
) > 0)
790 memmove(msgbuf
->rbuf
, ibuf_data(&rbuf
), ibuf_size(&rbuf
));
791 msgbuf
->roff
= ibuf_size(&rbuf
);
798 /* XXX how to properly clean up is unclear */
805 ibuf_read(int fd
, struct msgbuf
*msgbuf
)
810 if (msgbuf
->rbuf
== NULL
) {
815 iov
.iov_base
= msgbuf
->rbuf
+ msgbuf
->roff
;
816 iov
.iov_len
= IBUF_READ_SIZE
- msgbuf
->roff
;
819 if ((n
= readv(fd
, &iov
, 1)) == -1) {
823 /* lets retry later again */
827 if (n
== 0) /* connection closed */
831 /* new data arrived, try to process it */
832 return (ibuf_read_process(msgbuf
, -1));
836 msgbuf_read(int fd
, struct msgbuf
*msgbuf
)
839 struct cmsghdr
*cmsg
;
842 char buf
[CMSG_SPACE(sizeof(int) * 1)];
848 if (msgbuf
->rbuf
== NULL
) {
853 memset(&msg
, 0, sizeof(msg
));
854 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
856 iov
.iov_base
= msgbuf
->rbuf
+ msgbuf
->roff
;
857 iov
.iov_len
= IBUF_READ_SIZE
- msgbuf
->roff
;
860 msg
.msg_control
= &cmsgbuf
.buf
;
861 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
864 if ((n
= recvmsg(fd
, &msg
, 0)) == -1) {
867 if (errno
== EMSGSIZE
)
869 * Not enough fd slots: fd passing failed, retry
870 * to receive the message without fd.
871 * imsg_get_fd() will return -1 in that case.
875 /* lets retry later again */
879 if (n
== 0) /* connection closed */
884 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
885 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
886 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
887 cmsg
->cmsg_type
== SCM_RIGHTS
) {
891 * We only accept one file descriptor. Due to C
892 * padding rules, our control buffer might contain
893 * more than one fd, and we must close them.
895 j
= ((char *)cmsg
+ cmsg
->cmsg_len
-
896 (char *)CMSG_DATA(cmsg
)) / sizeof(int);
897 for (i
= 0; i
< j
; i
++) {
898 f
= ((int *)CMSG_DATA(cmsg
))[i
];
905 /* we do not handle other ctl data level */
908 /* new data arrived, try to process it */
909 return (ibuf_read_process(msgbuf
, fdpass
));
913 msgbuf_read_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
915 /* if buf lives on the stack abort before causing more harm */
916 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
918 TAILQ_INSERT_TAIL(&msgbuf
->rbufs
, buf
, entry
);
922 msgbuf_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
924 /* if buf lives on the stack abort before causing more harm */
925 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
927 TAILQ_INSERT_TAIL(&msgbuf
->bufs
, buf
, entry
);
932 msgbuf_dequeue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
934 TAILQ_REMOVE(&msgbuf
->bufs
, buf
, entry
);
940 msgbuf_drain(struct msgbuf
*msgbuf
, size_t n
)
942 struct ibuf
*buf
, *next
;
944 for (buf
= TAILQ_FIRST(&msgbuf
->bufs
); buf
!= NULL
&& n
> 0;
946 next
= TAILQ_NEXT(buf
, entry
);
947 if (n
>= ibuf_size(buf
)) {
949 msgbuf_dequeue(msgbuf
, buf
);