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/socket.h>
23 #include <arpa/inet.h>
40 #define htobe64 htonll
46 #define be64toh ntohll
49 TAILQ_HEAD(, ibuf
) bufs
;
50 TAILQ_HEAD(, ibuf
) rbufs
;
54 struct ibuf
*(*readhdr
)(struct ibuf
*, void *, int *);
60 static void msgbuf_read_enqueue(struct msgbuf
*, struct ibuf
*);
61 static void msgbuf_enqueue(struct msgbuf
*, struct ibuf
*);
62 static void msgbuf_dequeue(struct msgbuf
*, struct ibuf
*);
63 static void msgbuf_drain(struct msgbuf
*, size_t);
65 #define IBUF_FD_MARK_ON_STACK -2
72 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
75 if ((buf
->buf
= calloc(len
, 1)) == NULL
) {
80 buf
->size
= buf
->max
= len
;
87 ibuf_dynamic(size_t len
, size_t max
)
91 if (max
== 0 || max
< len
) {
96 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
99 if ((buf
->buf
= calloc(len
, 1)) == NULL
) {
112 ibuf_reserve(struct ibuf
*buf
, size_t len
)
116 if (len
> SIZE_MAX
- buf
->wpos
) {
120 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
) {
121 /* can not grow stack buffers */
126 if (buf
->wpos
+ len
> buf
->size
) {
129 /* check if buffer is allowed to grow */
130 if (buf
->wpos
+ len
> buf
->max
) {
134 nb
= realloc(buf
->buf
, buf
->wpos
+ len
);
137 memset(nb
+ buf
->size
, 0, buf
->wpos
+ len
- buf
->size
);
139 buf
->size
= buf
->wpos
+ len
;
142 b
= buf
->buf
+ buf
->wpos
;
148 ibuf_add(struct ibuf
*buf
, const void *data
, size_t len
)
152 if ((b
= ibuf_reserve(buf
, len
)) == NULL
)
155 memcpy(b
, data
, len
);
160 ibuf_add_ibuf(struct ibuf
*buf
, const struct ibuf
*from
)
162 return ibuf_add(buf
, ibuf_data(from
), ibuf_size(from
));
166 ibuf_add_n8(struct ibuf
*buf
, uint64_t value
)
170 if (value
> UINT8_MAX
) {
175 return ibuf_add(buf
, &v
, sizeof(v
));
179 ibuf_add_n16(struct ibuf
*buf
, uint64_t value
)
183 if (value
> UINT16_MAX
) {
188 return ibuf_add(buf
, &v
, sizeof(v
));
192 ibuf_add_n32(struct ibuf
*buf
, uint64_t value
)
196 if (value
> UINT32_MAX
) {
201 return ibuf_add(buf
, &v
, sizeof(v
));
205 ibuf_add_n64(struct ibuf
*buf
, uint64_t value
)
207 value
= htobe64(value
);
208 return ibuf_add(buf
, &value
, sizeof(value
));
212 ibuf_add_h16(struct ibuf
*buf
, uint64_t value
)
216 if (value
> UINT16_MAX
) {
221 return ibuf_add(buf
, &v
, sizeof(v
));
225 ibuf_add_h32(struct ibuf
*buf
, uint64_t value
)
229 if (value
> UINT32_MAX
) {
234 return ibuf_add(buf
, &v
, sizeof(v
));
238 ibuf_add_h64(struct ibuf
*buf
, uint64_t value
)
240 return ibuf_add(buf
, &value
, sizeof(value
));
244 ibuf_add_zero(struct ibuf
*buf
, size_t len
)
248 if ((b
= ibuf_reserve(buf
, len
)) == NULL
)
255 ibuf_seek(struct ibuf
*buf
, size_t pos
, size_t len
)
257 /* only allow seeking between rpos and wpos */
258 if (ibuf_size(buf
) < pos
|| SIZE_MAX
- pos
< len
||
259 ibuf_size(buf
) < pos
+ len
) {
264 return (buf
->buf
+ buf
->rpos
+ pos
);
268 ibuf_set(struct ibuf
*buf
, size_t pos
, const void *data
, size_t len
)
272 if ((b
= ibuf_seek(buf
, pos
, len
)) == NULL
)
275 memcpy(b
, data
, len
);
280 ibuf_set_n8(struct ibuf
*buf
, size_t pos
, uint64_t value
)
284 if (value
> UINT8_MAX
) {
289 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
293 ibuf_set_n16(struct ibuf
*buf
, size_t pos
, uint64_t value
)
297 if (value
> UINT16_MAX
) {
302 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
306 ibuf_set_n32(struct ibuf
*buf
, size_t pos
, uint64_t value
)
310 if (value
> UINT32_MAX
) {
315 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
319 ibuf_set_n64(struct ibuf
*buf
, size_t pos
, uint64_t value
)
321 value
= htobe64(value
);
322 return (ibuf_set(buf
, pos
, &value
, sizeof(value
)));
326 ibuf_set_h16(struct ibuf
*buf
, size_t pos
, uint64_t value
)
330 if (value
> UINT16_MAX
) {
335 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
339 ibuf_set_h32(struct ibuf
*buf
, size_t pos
, uint64_t value
)
343 if (value
> UINT32_MAX
) {
348 return (ibuf_set(buf
, pos
, &v
, sizeof(v
)));
352 ibuf_set_h64(struct ibuf
*buf
, size_t pos
, uint64_t value
)
354 return (ibuf_set(buf
, pos
, &value
, sizeof(value
)));
358 ibuf_data(const struct ibuf
*buf
)
360 return (buf
->buf
+ buf
->rpos
);
364 ibuf_size(const struct ibuf
*buf
)
366 return (buf
->wpos
- buf
->rpos
);
370 ibuf_left(const struct ibuf
*buf
)
372 /* on stack buffers have no space left */
373 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
375 return (buf
->max
- buf
->wpos
);
379 ibuf_truncate(struct ibuf
*buf
, size_t len
)
381 if (ibuf_size(buf
) >= len
) {
382 buf
->wpos
= buf
->rpos
+ len
;
385 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
) {
386 /* only allow to truncate down for stack buffers */
390 return ibuf_add_zero(buf
, len
- ibuf_size(buf
));
394 ibuf_rewind(struct ibuf
*buf
)
400 ibuf_close(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
402 msgbuf_enqueue(msgbuf
, buf
);
406 ibuf_from_buffer(struct ibuf
*buf
, void *data
, size_t len
)
408 memset(buf
, 0, sizeof(*buf
));
410 buf
->size
= buf
->wpos
= len
;
411 buf
->fd
= IBUF_FD_MARK_ON_STACK
;
415 ibuf_from_ibuf(struct ibuf
*buf
, const struct ibuf
*from
)
417 ibuf_from_buffer(buf
, ibuf_data(from
), ibuf_size(from
));
421 ibuf_get(struct ibuf
*buf
, void *data
, size_t len
)
423 if (ibuf_size(buf
) < len
) {
428 memcpy(data
, ibuf_data(buf
), len
);
434 ibuf_get_ibuf(struct ibuf
*buf
, size_t len
, struct ibuf
*new)
436 if (ibuf_size(buf
) < len
) {
441 ibuf_from_buffer(new, ibuf_data(buf
), len
);
447 ibuf_get_h16(struct ibuf
*buf
, uint16_t *value
)
449 return ibuf_get(buf
, value
, sizeof(*value
));
453 ibuf_get_h32(struct ibuf
*buf
, uint32_t *value
)
455 return ibuf_get(buf
, value
, sizeof(*value
));
459 ibuf_get_h64(struct ibuf
*buf
, uint64_t *value
)
461 return ibuf_get(buf
, value
, sizeof(*value
));
465 ibuf_get_n8(struct ibuf
*buf
, uint8_t *value
)
467 return ibuf_get(buf
, value
, sizeof(*value
));
471 ibuf_get_n16(struct ibuf
*buf
, uint16_t *value
)
475 rv
= ibuf_get(buf
, value
, sizeof(*value
));
476 *value
= be16toh(*value
);
481 ibuf_get_n32(struct ibuf
*buf
, uint32_t *value
)
485 rv
= ibuf_get(buf
, value
, sizeof(*value
));
486 *value
= be32toh(*value
);
491 ibuf_get_n64(struct ibuf
*buf
, uint64_t *value
)
495 rv
= ibuf_get(buf
, value
, sizeof(*value
));
496 *value
= be64toh(*value
);
501 ibuf_get_string(struct ibuf
*buf
, size_t len
)
505 if (ibuf_size(buf
) < len
) {
510 str
= strndup(ibuf_data(buf
), len
);
518 ibuf_skip(struct ibuf
*buf
, size_t len
)
520 if (ibuf_size(buf
) < len
) {
530 ibuf_free(struct ibuf
*buf
)
534 /* if buf lives on the stack abort before causing more harm */
535 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
539 freezero(buf
->buf
, buf
->size
);
544 ibuf_fd_avail(struct ibuf
*buf
)
546 return (buf
->fd
>= 0);
550 ibuf_fd_get(struct ibuf
*buf
)
554 /* negative fds are internal use and equivalent to -1 */
563 ibuf_fd_set(struct ibuf
*buf
, int fd
)
565 /* if buf lives on the stack abort before causing more harm */
566 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
578 struct msgbuf
*msgbuf
;
580 if ((msgbuf
= calloc(1, sizeof(*msgbuf
))) == NULL
)
583 TAILQ_INIT(&msgbuf
->bufs
);
584 TAILQ_INIT(&msgbuf
->rbufs
);
590 msgbuf_new_reader(size_t hdrsz
,
591 struct ibuf
*(*readhdr
)(struct ibuf
*, void *, int *), void *arg
)
593 struct msgbuf
*msgbuf
;
596 if (hdrsz
== 0 || hdrsz
> IBUF_READ_SIZE
/ 2) {
601 if ((buf
= malloc(IBUF_READ_SIZE
)) == NULL
)
604 msgbuf
= msgbuf_new();
605 if (msgbuf
== NULL
) {
611 msgbuf
->hdrsize
= hdrsz
;
612 msgbuf
->readhdr
= readhdr
;
619 msgbuf_free(struct msgbuf
*msgbuf
)
623 msgbuf_clear(msgbuf
);
629 msgbuf_queuelen(struct msgbuf
*msgbuf
)
631 return (msgbuf
->queued
);
635 msgbuf_clear(struct msgbuf
*msgbuf
)
640 while ((buf
= TAILQ_FIRST(&msgbuf
->bufs
)) != NULL
)
641 msgbuf_dequeue(msgbuf
, buf
);
645 while ((buf
= TAILQ_FIRST(&msgbuf
->rbufs
)) != NULL
) {
646 TAILQ_REMOVE(&msgbuf
->rbufs
, buf
, entry
);
650 ibuf_free(msgbuf
->rpmsg
);
651 msgbuf
->rpmsg
= NULL
;
655 msgbuf_get(struct msgbuf
*msgbuf
)
659 if ((buf
= TAILQ_FIRST(&msgbuf
->rbufs
)) != NULL
)
660 TAILQ_REMOVE(&msgbuf
->rbufs
, buf
, entry
);
665 ibuf_write(int fd
, struct msgbuf
*msgbuf
)
667 struct iovec iov
[IOV_MAX
];
672 memset(&iov
, 0, sizeof(iov
));
673 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
676 iov
[i
].iov_base
= ibuf_data(buf
);
677 iov
[i
].iov_len
= ibuf_size(buf
);
681 return (0); /* nothing queued */
684 if ((n
= writev(fd
, iov
, i
)) == -1) {
687 if (errno
== EAGAIN
|| errno
== ENOBUFS
)
688 /* lets retry later again */
693 msgbuf_drain(msgbuf
, n
);
698 msgbuf_write(int fd
, struct msgbuf
*msgbuf
)
700 struct iovec iov
[IOV_MAX
];
701 struct ibuf
*buf
, *buf0
= NULL
;
705 struct cmsghdr
*cmsg
;
708 char buf
[CMSG_SPACE(sizeof(int))];
711 memset(&iov
, 0, sizeof(iov
));
712 memset(&msg
, 0, sizeof(msg
));
713 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
714 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
717 if (i
> 0 && buf
->fd
!= -1)
719 iov
[i
].iov_base
= ibuf_data(buf
);
720 iov
[i
].iov_len
= ibuf_size(buf
);
727 return (0); /* nothing queued */
733 msg
.msg_control
= (caddr_t
)&cmsgbuf
.buf
;
734 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
735 cmsg
= CMSG_FIRSTHDR(&msg
);
736 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
737 cmsg
->cmsg_level
= SOL_SOCKET
;
738 cmsg
->cmsg_type
= SCM_RIGHTS
;
739 *(int *)CMSG_DATA(cmsg
) = buf0
->fd
;
743 if ((n
= sendmsg(fd
, &msg
, 0)) == -1) {
746 if (errno
== EAGAIN
|| errno
== ENOBUFS
)
747 /* lets retry later again */
753 * assumption: fd got sent if sendmsg sent anything
754 * this works because fds are passed one at a time
761 msgbuf_drain(msgbuf
, n
);
767 ibuf_read_process(struct msgbuf
*msgbuf
, int fd
)
769 struct ibuf rbuf
, msg
;
772 ibuf_from_buffer(&rbuf
, msgbuf
->rbuf
, msgbuf
->roff
);
775 if (msgbuf
->rpmsg
== NULL
) {
776 if (ibuf_size(&rbuf
) < msgbuf
->hdrsize
)
778 /* get size from header */
779 ibuf_from_buffer(&msg
, ibuf_data(&rbuf
),
781 if ((msgbuf
->rpmsg
= msgbuf
->readhdr(&msg
,
782 msgbuf
->rarg
, &fd
)) == NULL
)
786 if (ibuf_left(msgbuf
->rpmsg
) <= ibuf_size(&rbuf
))
787 sz
= ibuf_left(msgbuf
->rpmsg
);
789 sz
= ibuf_size(&rbuf
);
791 /* neither call below can fail */
792 if (ibuf_get_ibuf(&rbuf
, sz
, &msg
) == -1 ||
793 ibuf_add_ibuf(msgbuf
->rpmsg
, &msg
) == -1)
796 if (ibuf_left(msgbuf
->rpmsg
) == 0) {
797 msgbuf_read_enqueue(msgbuf
, msgbuf
->rpmsg
);
798 msgbuf
->rpmsg
= NULL
;
800 } while (ibuf_size(&rbuf
) > 0);
802 if (ibuf_size(&rbuf
) > 0)
803 memmove(msgbuf
->rbuf
, ibuf_data(&rbuf
), ibuf_size(&rbuf
));
804 msgbuf
->roff
= ibuf_size(&rbuf
);
811 /* XXX how to properly clean up is unclear */
818 ibuf_read(int fd
, struct msgbuf
*msgbuf
)
823 if (msgbuf
->rbuf
== NULL
) {
828 iov
.iov_base
= msgbuf
->rbuf
+ msgbuf
->roff
;
829 iov
.iov_len
= IBUF_READ_SIZE
- msgbuf
->roff
;
832 if ((n
= readv(fd
, &iov
, 1)) == -1) {
836 /* lets retry later again */
840 if (n
== 0) /* connection closed */
844 /* new data arrived, try to process it */
845 return (ibuf_read_process(msgbuf
, -1));
849 msgbuf_read(int fd
, struct msgbuf
*msgbuf
)
852 struct cmsghdr
*cmsg
;
855 char buf
[CMSG_SPACE(sizeof(int) * 1)];
861 if (msgbuf
->rbuf
== NULL
) {
866 memset(&msg
, 0, sizeof(msg
));
867 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
869 iov
.iov_base
= msgbuf
->rbuf
+ msgbuf
->roff
;
870 iov
.iov_len
= IBUF_READ_SIZE
- msgbuf
->roff
;
873 msg
.msg_control
= &cmsgbuf
.buf
;
874 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
877 if ((n
= recvmsg(fd
, &msg
, 0)) == -1) {
880 if (errno
== EMSGSIZE
)
882 * Not enough fd slots: fd passing failed, retry
883 * to receive the message without fd.
884 * imsg_get_fd() will return -1 in that case.
888 /* lets retry later again */
892 if (n
== 0) /* connection closed */
897 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
898 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
899 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
900 cmsg
->cmsg_type
== SCM_RIGHTS
) {
904 * We only accept one file descriptor. Due to C
905 * padding rules, our control buffer might contain
906 * more than one fd, and we must close them.
908 j
= ((char *)cmsg
+ cmsg
->cmsg_len
-
909 (char *)CMSG_DATA(cmsg
)) / sizeof(int);
910 for (i
= 0; i
< j
; i
++) {
911 f
= ((int *)CMSG_DATA(cmsg
))[i
];
918 /* we do not handle other ctl data level */
921 /* new data arrived, try to process it */
922 return (ibuf_read_process(msgbuf
, fdpass
));
926 msgbuf_read_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
928 /* if buf lives on the stack abort before causing more harm */
929 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
931 TAILQ_INSERT_TAIL(&msgbuf
->rbufs
, buf
, entry
);
935 msgbuf_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
937 /* if buf lives on the stack abort before causing more harm */
938 if (buf
->fd
== IBUF_FD_MARK_ON_STACK
)
940 TAILQ_INSERT_TAIL(&msgbuf
->bufs
, buf
, entry
);
945 msgbuf_dequeue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
947 TAILQ_REMOVE(&msgbuf
->bufs
, buf
, entry
);
953 msgbuf_drain(struct msgbuf
*msgbuf
, size_t n
)
955 struct ibuf
*buf
, *next
;
957 for (buf
= TAILQ_FIRST(&msgbuf
->bufs
); buf
!= NULL
&& n
> 0;
959 next
= TAILQ_NEXT(buf
, entry
);
960 if (n
>= ibuf_size(buf
)) {
962 msgbuf_dequeue(msgbuf
, buf
);