xref: /openbsd-src/lib/libutil/imsg-buffer.c (revision ff59764deb7c720c75d582b75dac4b924ec7c8a6)
1*ff59764dSclaudio /*	$OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $	*/
2dfaf6462Snicm 
3dfaf6462Snicm /*
44658a150Sclaudio  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5dfaf6462Snicm  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6dfaf6462Snicm  *
7dfaf6462Snicm  * Permission to use, copy, modify, and distribute this software for any
8dfaf6462Snicm  * purpose with or without fee is hereby granted, provided that the above
9dfaf6462Snicm  * copyright notice and this permission notice appear in all copies.
10dfaf6462Snicm  *
11dfaf6462Snicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12dfaf6462Snicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13dfaf6462Snicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14dfaf6462Snicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15dfaf6462Snicm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16dfaf6462Snicm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17dfaf6462Snicm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18dfaf6462Snicm  */
19dfaf6462Snicm 
2082ee50fdSderaadt #include <sys/types.h>
21dfaf6462Snicm #include <sys/queue.h>
22dfaf6462Snicm #include <sys/socket.h>
23dfaf6462Snicm #include <sys/uio.h>
24dfaf6462Snicm 
2582ee50fdSderaadt #include <limits.h>
26dfaf6462Snicm #include <errno.h>
2719778535Sclaudio #include <endian.h>
284658a150Sclaudio #include <stdint.h>
29dfaf6462Snicm #include <stdlib.h>
30dfaf6462Snicm #include <string.h>
31dfaf6462Snicm #include <unistd.h>
32dfaf6462Snicm 
33dfaf6462Snicm #include "imsg.h"
34dfaf6462Snicm 
35156c3c53Sclaudio struct msgbuf {
36156c3c53Sclaudio 	TAILQ_HEAD(, ibuf)	 bufs;
3704d83f12Sclaudio 	TAILQ_HEAD(, ibuf)	 rbufs;
38156c3c53Sclaudio 	uint32_t		 queued;
3904d83f12Sclaudio 	char			*rbuf;
4004d83f12Sclaudio 	struct ibuf		*rpmsg;
41*ff59764dSclaudio 	struct ibuf		*(*readhdr)(struct ibuf *, void *, int *);
4204d83f12Sclaudio 	void			*rarg;
4304d83f12Sclaudio 	size_t			 roff;
4404d83f12Sclaudio 	size_t			 hdrsize;
45156c3c53Sclaudio };
46156c3c53Sclaudio 
4704d83f12Sclaudio static void	msgbuf_read_enqueue(struct msgbuf *, struct ibuf *);
4804886c2dSclaudio static void	msgbuf_enqueue(struct msgbuf *, struct ibuf *);
4904886c2dSclaudio static void	msgbuf_dequeue(struct msgbuf *, struct ibuf *);
5019778535Sclaudio static void	msgbuf_drain(struct msgbuf *, size_t);
51dfaf6462Snicm 
5248950d6eSclaudio #define	IBUF_FD_MARK_ON_STACK	-2
5348950d6eSclaudio 
54dfaf6462Snicm struct ibuf *
55dfaf6462Snicm ibuf_open(size_t len)
56dfaf6462Snicm {
57dfaf6462Snicm 	struct ibuf	*buf;
58dfaf6462Snicm 
59dfaf6462Snicm 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
60dfaf6462Snicm 		return (NULL);
6148950d6eSclaudio 	if (len > 0) {
62e2fc7023Sclaudio 		if ((buf->buf = calloc(len, 1)) == NULL) {
63dfaf6462Snicm 			free(buf);
64dfaf6462Snicm 			return (NULL);
65dfaf6462Snicm 		}
6648950d6eSclaudio 	}
67dfaf6462Snicm 	buf->size = buf->max = len;
68dfaf6462Snicm 	buf->fd = -1;
69dfaf6462Snicm 
70dfaf6462Snicm 	return (buf);
71dfaf6462Snicm }
72dfaf6462Snicm 
73dfaf6462Snicm struct ibuf *
74dfaf6462Snicm ibuf_dynamic(size_t len, size_t max)
75dfaf6462Snicm {
76dfaf6462Snicm 	struct ibuf	*buf;
77dfaf6462Snicm 
784658a150Sclaudio 	if (max == 0 || max < len) {
79e2fc7023Sclaudio 		errno = EINVAL;
80dfaf6462Snicm 		return (NULL);
81e2fc7023Sclaudio 	}
82dfaf6462Snicm 
83e2fc7023Sclaudio 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
84dfaf6462Snicm 		return (NULL);
85e2fc7023Sclaudio 	if (len > 0) {
86e2fc7023Sclaudio 		if ((buf->buf = calloc(len, 1)) == NULL) {
87e2fc7023Sclaudio 			free(buf);
88e2fc7023Sclaudio 			return (NULL);
89e2fc7023Sclaudio 		}
90e2fc7023Sclaudio 	}
91e2fc7023Sclaudio 	buf->size = len;
92dfaf6462Snicm 	buf->max = max;
93e2fc7023Sclaudio 	buf->fd = -1;
94dfaf6462Snicm 
95dfaf6462Snicm 	return (buf);
96dfaf6462Snicm }
97dfaf6462Snicm 
98dfaf6462Snicm void *
99dfaf6462Snicm ibuf_reserve(struct ibuf *buf, size_t len)
100dfaf6462Snicm {
101dfaf6462Snicm 	void	*b;
102dfaf6462Snicm 
10348950d6eSclaudio 	if (len > SIZE_MAX - buf->wpos) {
104c1a45aedStobias 		errno = ERANGE;
105c1a45aedStobias 		return (NULL);
106c1a45aedStobias 	}
10748950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
10848950d6eSclaudio 		/* can not grow stack buffers */
10948950d6eSclaudio 		errno = EINVAL;
11048950d6eSclaudio 		return (NULL);
11148950d6eSclaudio 	}
112c1a45aedStobias 
113013d718aSclaudio 	if (buf->wpos + len > buf->size) {
114013d718aSclaudio 		unsigned char	*nb;
115013d718aSclaudio 
116013d718aSclaudio 		/* check if buffer is allowed to grow */
117013d718aSclaudio 		if (buf->wpos + len > buf->max) {
118013d718aSclaudio 			errno = ERANGE;
119dfaf6462Snicm 			return (NULL);
120013d718aSclaudio 		}
121013d718aSclaudio 		nb = realloc(buf->buf, buf->wpos + len);
122013d718aSclaudio 		if (nb == NULL)
123013d718aSclaudio 			return (NULL);
124013d718aSclaudio 		memset(nb + buf->size, 0, buf->wpos + len - buf->size);
125013d718aSclaudio 		buf->buf = nb;
126013d718aSclaudio 		buf->size = buf->wpos + len;
127013d718aSclaudio 	}
128dfaf6462Snicm 
129dfaf6462Snicm 	b = buf->buf + buf->wpos;
130dfaf6462Snicm 	buf->wpos += len;
131dfaf6462Snicm 	return (b);
132dfaf6462Snicm }
133dfaf6462Snicm 
13419778535Sclaudio int
13519778535Sclaudio ibuf_add(struct ibuf *buf, const void *data, size_t len)
13619778535Sclaudio {
13719778535Sclaudio 	void *b;
13819778535Sclaudio 
13919778535Sclaudio 	if ((b = ibuf_reserve(buf, len)) == NULL)
14019778535Sclaudio 		return (-1);
14119778535Sclaudio 
14219778535Sclaudio 	memcpy(b, data, len);
14319778535Sclaudio 	return (0);
14419778535Sclaudio }
14519778535Sclaudio 
14619778535Sclaudio int
1474658a150Sclaudio ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
1484658a150Sclaudio {
1494658a150Sclaudio 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
1504658a150Sclaudio }
1514658a150Sclaudio 
15219778535Sclaudio int
15319778535Sclaudio ibuf_add_n8(struct ibuf *buf, uint64_t value)
15419778535Sclaudio {
15519778535Sclaudio 	uint8_t v;
15619778535Sclaudio 
15719778535Sclaudio 	if (value > UINT8_MAX) {
15819778535Sclaudio 		errno = EINVAL;
15919778535Sclaudio 		return (-1);
16019778535Sclaudio 	}
16119778535Sclaudio 	v = value;
16219778535Sclaudio 	return ibuf_add(buf, &v, sizeof(v));
16319778535Sclaudio }
16419778535Sclaudio 
16519778535Sclaudio int
16619778535Sclaudio ibuf_add_n16(struct ibuf *buf, uint64_t value)
16719778535Sclaudio {
16819778535Sclaudio 	uint16_t v;
16919778535Sclaudio 
17019778535Sclaudio 	if (value > UINT16_MAX) {
17119778535Sclaudio 		errno = EINVAL;
17219778535Sclaudio 		return (-1);
17319778535Sclaudio 	}
17419778535Sclaudio 	v = htobe16(value);
17519778535Sclaudio 	return ibuf_add(buf, &v, sizeof(v));
17619778535Sclaudio }
17719778535Sclaudio 
17819778535Sclaudio int
17919778535Sclaudio ibuf_add_n32(struct ibuf *buf, uint64_t value)
18019778535Sclaudio {
18119778535Sclaudio 	uint32_t v;
18219778535Sclaudio 
18319778535Sclaudio 	if (value > UINT32_MAX) {
18419778535Sclaudio 		errno = EINVAL;
18519778535Sclaudio 		return (-1);
18619778535Sclaudio 	}
18719778535Sclaudio 	v = htobe32(value);
18819778535Sclaudio 	return ibuf_add(buf, &v, sizeof(v));
18919778535Sclaudio }
19019778535Sclaudio 
19119778535Sclaudio int
19219778535Sclaudio ibuf_add_n64(struct ibuf *buf, uint64_t value)
19319778535Sclaudio {
19419778535Sclaudio 	value = htobe64(value);
19519778535Sclaudio 	return ibuf_add(buf, &value, sizeof(value));
19619778535Sclaudio }
19719778535Sclaudio 
19819778535Sclaudio int
1994658a150Sclaudio ibuf_add_h16(struct ibuf *buf, uint64_t value)
2004658a150Sclaudio {
2014658a150Sclaudio 	uint16_t v;
2024658a150Sclaudio 
2034658a150Sclaudio 	if (value > UINT16_MAX) {
2044658a150Sclaudio 		errno = EINVAL;
2054658a150Sclaudio 		return (-1);
2064658a150Sclaudio 	}
2074658a150Sclaudio 	v = value;
2084658a150Sclaudio 	return ibuf_add(buf, &v, sizeof(v));
2094658a150Sclaudio }
2104658a150Sclaudio 
2114658a150Sclaudio int
2124658a150Sclaudio ibuf_add_h32(struct ibuf *buf, uint64_t value)
2134658a150Sclaudio {
2144658a150Sclaudio 	uint32_t v;
2154658a150Sclaudio 
2164658a150Sclaudio 	if (value > UINT32_MAX) {
2174658a150Sclaudio 		errno = EINVAL;
2184658a150Sclaudio 		return (-1);
2194658a150Sclaudio 	}
2204658a150Sclaudio 	v = value;
2214658a150Sclaudio 	return ibuf_add(buf, &v, sizeof(v));
2224658a150Sclaudio }
2234658a150Sclaudio 
2244658a150Sclaudio int
2254658a150Sclaudio ibuf_add_h64(struct ibuf *buf, uint64_t value)
2264658a150Sclaudio {
2274658a150Sclaudio 	return ibuf_add(buf, &value, sizeof(value));
2284658a150Sclaudio }
2294658a150Sclaudio 
2304658a150Sclaudio int
23119778535Sclaudio ibuf_add_zero(struct ibuf *buf, size_t len)
23219778535Sclaudio {
23319778535Sclaudio 	void *b;
23419778535Sclaudio 
23519778535Sclaudio 	if ((b = ibuf_reserve(buf, len)) == NULL)
23619778535Sclaudio 		return (-1);
2374658a150Sclaudio 	memset(b, 0, len);
23819778535Sclaudio 	return (0);
23919778535Sclaudio }
24019778535Sclaudio 
241dfaf6462Snicm void *
242dfaf6462Snicm ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
243dfaf6462Snicm {
2444658a150Sclaudio 	/* only allow seeking between rpos and wpos */
2454658a150Sclaudio 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
2464658a150Sclaudio 	    ibuf_size(buf) < pos + len) {
24719778535Sclaudio 		errno = ERANGE;
248dfaf6462Snicm 		return (NULL);
24919778535Sclaudio 	}
250dfaf6462Snicm 
2514658a150Sclaudio 	return (buf->buf + buf->rpos + pos);
252dfaf6462Snicm }
253dfaf6462Snicm 
25419778535Sclaudio int
25519778535Sclaudio ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
25619778535Sclaudio {
25719778535Sclaudio 	void *b;
25819778535Sclaudio 
25919778535Sclaudio 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
26019778535Sclaudio 		return (-1);
26119778535Sclaudio 
26219778535Sclaudio 	memcpy(b, data, len);
26319778535Sclaudio 	return (0);
26419778535Sclaudio }
26519778535Sclaudio 
26619778535Sclaudio int
26719778535Sclaudio ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
26819778535Sclaudio {
26919778535Sclaudio 	uint8_t v;
27019778535Sclaudio 
27119778535Sclaudio 	if (value > UINT8_MAX) {
27219778535Sclaudio 		errno = EINVAL;
27319778535Sclaudio 		return (-1);
27419778535Sclaudio 	}
27519778535Sclaudio 	v = value;
27619778535Sclaudio 	return (ibuf_set(buf, pos, &v, sizeof(v)));
27719778535Sclaudio }
27819778535Sclaudio 
27919778535Sclaudio int
28019778535Sclaudio ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
28119778535Sclaudio {
28219778535Sclaudio 	uint16_t v;
28319778535Sclaudio 
28419778535Sclaudio 	if (value > UINT16_MAX) {
28519778535Sclaudio 		errno = EINVAL;
28619778535Sclaudio 		return (-1);
28719778535Sclaudio 	}
28819778535Sclaudio 	v = htobe16(value);
28919778535Sclaudio 	return (ibuf_set(buf, pos, &v, sizeof(v)));
29019778535Sclaudio }
29119778535Sclaudio 
29219778535Sclaudio int
29319778535Sclaudio ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
29419778535Sclaudio {
29519778535Sclaudio 	uint32_t v;
29619778535Sclaudio 
29719778535Sclaudio 	if (value > UINT32_MAX) {
29819778535Sclaudio 		errno = EINVAL;
29919778535Sclaudio 		return (-1);
30019778535Sclaudio 	}
30119778535Sclaudio 	v = htobe32(value);
30219778535Sclaudio 	return (ibuf_set(buf, pos, &v, sizeof(v)));
30319778535Sclaudio }
30419778535Sclaudio 
30519778535Sclaudio int
30619778535Sclaudio ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
30719778535Sclaudio {
30819778535Sclaudio 	value = htobe64(value);
30919778535Sclaudio 	return (ibuf_set(buf, pos, &value, sizeof(value)));
31019778535Sclaudio }
31119778535Sclaudio 
3124658a150Sclaudio int
3134658a150Sclaudio ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
3144658a150Sclaudio {
3154658a150Sclaudio 	uint16_t v;
3164658a150Sclaudio 
3174658a150Sclaudio 	if (value > UINT16_MAX) {
3184658a150Sclaudio 		errno = EINVAL;
3194658a150Sclaudio 		return (-1);
3204658a150Sclaudio 	}
3214658a150Sclaudio 	v = value;
3224658a150Sclaudio 	return (ibuf_set(buf, pos, &v, sizeof(v)));
3234658a150Sclaudio }
3244658a150Sclaudio 
3254658a150Sclaudio int
3264658a150Sclaudio ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
3274658a150Sclaudio {
3284658a150Sclaudio 	uint32_t v;
3294658a150Sclaudio 
3304658a150Sclaudio 	if (value > UINT32_MAX) {
3314658a150Sclaudio 		errno = EINVAL;
3324658a150Sclaudio 		return (-1);
3334658a150Sclaudio 	}
3344658a150Sclaudio 	v = value;
3354658a150Sclaudio 	return (ibuf_set(buf, pos, &v, sizeof(v)));
3364658a150Sclaudio }
3374658a150Sclaudio 
3384658a150Sclaudio int
3394658a150Sclaudio ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
3404658a150Sclaudio {
3414658a150Sclaudio 	return (ibuf_set(buf, pos, &value, sizeof(value)));
3424658a150Sclaudio }
3434658a150Sclaudio 
34419778535Sclaudio void *
3454658a150Sclaudio ibuf_data(const struct ibuf *buf)
34619778535Sclaudio {
3474658a150Sclaudio 	return (buf->buf + buf->rpos);
34819778535Sclaudio }
34919778535Sclaudio 
350dfaf6462Snicm size_t
3514658a150Sclaudio ibuf_size(const struct ibuf *buf)
352dfaf6462Snicm {
3534658a150Sclaudio 	return (buf->wpos - buf->rpos);
354dfaf6462Snicm }
355dfaf6462Snicm 
356dfaf6462Snicm size_t
3574658a150Sclaudio ibuf_left(const struct ibuf *buf)
358dfaf6462Snicm {
35948950d6eSclaudio 	/* on stack buffers have no space left */
36048950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
3614658a150Sclaudio 		return (0);
362dfaf6462Snicm 	return (buf->max - buf->wpos);
363dfaf6462Snicm }
364dfaf6462Snicm 
3654658a150Sclaudio int
3664658a150Sclaudio ibuf_truncate(struct ibuf *buf, size_t len)
3674658a150Sclaudio {
3684658a150Sclaudio 	if (ibuf_size(buf) >= len) {
3694658a150Sclaudio 		buf->wpos = buf->rpos + len;
3704658a150Sclaudio 		return (0);
3714658a150Sclaudio 	}
37248950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
37348950d6eSclaudio 		/* only allow to truncate down for stack buffers */
3744658a150Sclaudio 		errno = ERANGE;
3754658a150Sclaudio 		return (-1);
3764658a150Sclaudio 	}
3774658a150Sclaudio 	return ibuf_add_zero(buf, len - ibuf_size(buf));
3784658a150Sclaudio }
3794658a150Sclaudio 
3804658a150Sclaudio void
3814658a150Sclaudio ibuf_rewind(struct ibuf *buf)
3824658a150Sclaudio {
3834658a150Sclaudio 	buf->rpos = 0;
3844658a150Sclaudio }
3854658a150Sclaudio 
386dfaf6462Snicm void
387dfaf6462Snicm ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
388dfaf6462Snicm {
38904886c2dSclaudio 	msgbuf_enqueue(msgbuf, buf);
390dfaf6462Snicm }
391dfaf6462Snicm 
39219778535Sclaudio void
3934658a150Sclaudio ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
3944658a150Sclaudio {
3954658a150Sclaudio 	memset(buf, 0, sizeof(*buf));
3964658a150Sclaudio 	buf->buf = data;
3974658a150Sclaudio 	buf->size = buf->wpos = len;
39848950d6eSclaudio 	buf->fd = IBUF_FD_MARK_ON_STACK;
3994658a150Sclaudio }
4004658a150Sclaudio 
4014658a150Sclaudio void
4024658a150Sclaudio ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
4034658a150Sclaudio {
4044658a150Sclaudio 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
4054658a150Sclaudio }
4064658a150Sclaudio 
4074658a150Sclaudio int
4084658a150Sclaudio ibuf_get(struct ibuf *buf, void *data, size_t len)
4094658a150Sclaudio {
4104658a150Sclaudio 	if (ibuf_size(buf) < len) {
4114658a150Sclaudio 		errno = EBADMSG;
4124658a150Sclaudio 		return (-1);
4134658a150Sclaudio 	}
4144658a150Sclaudio 
4154658a150Sclaudio 	memcpy(data, ibuf_data(buf), len);
4164658a150Sclaudio 	buf->rpos += len;
4174658a150Sclaudio 	return (0);
4184658a150Sclaudio }
4194658a150Sclaudio 
4204658a150Sclaudio int
4214658a150Sclaudio ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
4224658a150Sclaudio {
4234658a150Sclaudio 	if (ibuf_size(buf) < len) {
4244658a150Sclaudio 		errno = EBADMSG;
4254658a150Sclaudio 		return (-1);
4264658a150Sclaudio 	}
4274658a150Sclaudio 
4284658a150Sclaudio 	ibuf_from_buffer(new, ibuf_data(buf), len);
4294658a150Sclaudio 	buf->rpos += len;
4304658a150Sclaudio 	return (0);
4314658a150Sclaudio }
4324658a150Sclaudio 
4334658a150Sclaudio int
434442dea11Sclaudio ibuf_get_h16(struct ibuf *buf, uint16_t *value)
435442dea11Sclaudio {
436442dea11Sclaudio 	return ibuf_get(buf, value, sizeof(*value));
437442dea11Sclaudio }
438442dea11Sclaudio 
439442dea11Sclaudio int
440442dea11Sclaudio ibuf_get_h32(struct ibuf *buf, uint32_t *value)
441442dea11Sclaudio {
442442dea11Sclaudio 	return ibuf_get(buf, value, sizeof(*value));
443442dea11Sclaudio }
444442dea11Sclaudio 
445442dea11Sclaudio int
446442dea11Sclaudio ibuf_get_h64(struct ibuf *buf, uint64_t *value)
447442dea11Sclaudio {
448442dea11Sclaudio 	return ibuf_get(buf, value, sizeof(*value));
449442dea11Sclaudio }
450442dea11Sclaudio 
451442dea11Sclaudio int
4524658a150Sclaudio ibuf_get_n8(struct ibuf *buf, uint8_t *value)
4534658a150Sclaudio {
4544658a150Sclaudio 	return ibuf_get(buf, value, sizeof(*value));
4554658a150Sclaudio }
4564658a150Sclaudio 
4574658a150Sclaudio int
4584658a150Sclaudio ibuf_get_n16(struct ibuf *buf, uint16_t *value)
4594658a150Sclaudio {
4604658a150Sclaudio 	int rv;
4614658a150Sclaudio 
4624658a150Sclaudio 	rv = ibuf_get(buf, value, sizeof(*value));
4634658a150Sclaudio 	*value = be16toh(*value);
4644658a150Sclaudio 	return (rv);
4654658a150Sclaudio }
4664658a150Sclaudio 
4674658a150Sclaudio int
4684658a150Sclaudio ibuf_get_n32(struct ibuf *buf, uint32_t *value)
4694658a150Sclaudio {
4704658a150Sclaudio 	int rv;
4714658a150Sclaudio 
4724658a150Sclaudio 	rv = ibuf_get(buf, value, sizeof(*value));
4734658a150Sclaudio 	*value = be32toh(*value);
4744658a150Sclaudio 	return (rv);
4754658a150Sclaudio }
4764658a150Sclaudio 
4774658a150Sclaudio int
4784658a150Sclaudio ibuf_get_n64(struct ibuf *buf, uint64_t *value)
4794658a150Sclaudio {
4804658a150Sclaudio 	int rv;
4814658a150Sclaudio 
4824658a150Sclaudio 	rv = ibuf_get(buf, value, sizeof(*value));
4834658a150Sclaudio 	*value = be64toh(*value);
4844658a150Sclaudio 	return (rv);
4854658a150Sclaudio }
4864658a150Sclaudio 
487442dea11Sclaudio char *
488442dea11Sclaudio ibuf_get_string(struct ibuf *buf, size_t len)
4894658a150Sclaudio {
490442dea11Sclaudio 	char *str;
491442dea11Sclaudio 
492442dea11Sclaudio 	if (ibuf_size(buf) < len) {
493442dea11Sclaudio 		errno = EBADMSG;
494442dea11Sclaudio 		return (NULL);
4954658a150Sclaudio 	}
4964658a150Sclaudio 
497442dea11Sclaudio 	str = strndup(ibuf_data(buf), len);
498442dea11Sclaudio 	if (str == NULL)
499442dea11Sclaudio 		return (NULL);
500442dea11Sclaudio 	buf->rpos += len;
501442dea11Sclaudio 	return (str);
5024658a150Sclaudio }
5034658a150Sclaudio 
5044658a150Sclaudio int
5054658a150Sclaudio ibuf_skip(struct ibuf *buf, size_t len)
5064658a150Sclaudio {
5074658a150Sclaudio 	if (ibuf_size(buf) < len) {
5084658a150Sclaudio 		errno = EBADMSG;
5094658a150Sclaudio 		return (-1);
5104658a150Sclaudio 	}
5114658a150Sclaudio 
5124658a150Sclaudio 	buf->rpos += len;
5134658a150Sclaudio 	return (0);
5144658a150Sclaudio }
5154658a150Sclaudio 
5164658a150Sclaudio void
51719778535Sclaudio ibuf_free(struct ibuf *buf)
51819778535Sclaudio {
51919778535Sclaudio 	if (buf == NULL)
52019778535Sclaudio 		return;
52148950d6eSclaudio 	/* if buf lives on the stack abort before causing more harm */
52248950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
52348950d6eSclaudio 		abort();
52448950d6eSclaudio 	if (buf->fd >= 0)
52519778535Sclaudio 		close(buf->fd);
52619778535Sclaudio 	freezero(buf->buf, buf->size);
52719778535Sclaudio 	free(buf);
52819778535Sclaudio }
52919778535Sclaudio 
53019778535Sclaudio int
53119778535Sclaudio ibuf_fd_avail(struct ibuf *buf)
53219778535Sclaudio {
53348950d6eSclaudio 	return (buf->fd >= 0);
53419778535Sclaudio }
53519778535Sclaudio 
53619778535Sclaudio int
53719778535Sclaudio ibuf_fd_get(struct ibuf *buf)
53819778535Sclaudio {
53919778535Sclaudio 	int fd;
54019778535Sclaudio 
54148950d6eSclaudio 	/* negative fds are internal use and equivalent to -1 */
54248950d6eSclaudio 	if (buf->fd < 0)
54348950d6eSclaudio 		return (-1);
54419778535Sclaudio 	fd = buf->fd;
54519778535Sclaudio 	buf->fd = -1;
54619778535Sclaudio 	return (fd);
54719778535Sclaudio }
54819778535Sclaudio 
54919778535Sclaudio void
55019778535Sclaudio ibuf_fd_set(struct ibuf *buf, int fd)
55119778535Sclaudio {
55248950d6eSclaudio 	/* if buf lives on the stack abort before causing more harm */
55348950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
55448950d6eSclaudio 		abort();
55548950d6eSclaudio 	if (buf->fd >= 0)
55619778535Sclaudio 		close(buf->fd);
55748950d6eSclaudio 	buf->fd = -1;
55848950d6eSclaudio 	if (fd >= 0)
55919778535Sclaudio 		buf->fd = fd;
56019778535Sclaudio }
56119778535Sclaudio 
562156c3c53Sclaudio struct msgbuf *
563156c3c53Sclaudio msgbuf_new(void)
56404886c2dSclaudio {
565156c3c53Sclaudio 	struct msgbuf *msgbuf;
566156c3c53Sclaudio 
567156c3c53Sclaudio 	if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
568156c3c53Sclaudio 		return (NULL);
56904886c2dSclaudio 	msgbuf->queued = 0;
57004886c2dSclaudio 	TAILQ_INIT(&msgbuf->bufs);
57104d83f12Sclaudio 	TAILQ_INIT(&msgbuf->rbufs);
572156c3c53Sclaudio 
573156c3c53Sclaudio 	return msgbuf;
574156c3c53Sclaudio }
575156c3c53Sclaudio 
57604d83f12Sclaudio struct msgbuf *
577*ff59764dSclaudio msgbuf_new_reader(size_t hdrsz,
578*ff59764dSclaudio     struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
57904d83f12Sclaudio {
58004d83f12Sclaudio 	struct msgbuf *msgbuf;
58104d83f12Sclaudio 	char *buf;
58204d83f12Sclaudio 
58304d83f12Sclaudio 	if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
58404d83f12Sclaudio 		errno = EINVAL;
58504d83f12Sclaudio 		return (NULL);
58604d83f12Sclaudio 	}
58704d83f12Sclaudio 
58804d83f12Sclaudio 	if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
58904d83f12Sclaudio 		return (NULL);
59004d83f12Sclaudio 
59104d83f12Sclaudio 	msgbuf = msgbuf_new();
59204d83f12Sclaudio 	if (msgbuf == NULL) {
59304d83f12Sclaudio 		free(buf);
59404d83f12Sclaudio 		return (NULL);
59504d83f12Sclaudio 	}
59604d83f12Sclaudio 
59704d83f12Sclaudio 	msgbuf->rbuf = buf;
59804d83f12Sclaudio 	msgbuf->hdrsize = hdrsz;
59904d83f12Sclaudio 	msgbuf->readhdr = readhdr;
60004d83f12Sclaudio 	msgbuf->rarg = arg;
60104d83f12Sclaudio 
60204d83f12Sclaudio 	return (msgbuf);
60304d83f12Sclaudio }
60404d83f12Sclaudio 
605156c3c53Sclaudio void
606156c3c53Sclaudio msgbuf_free(struct msgbuf *msgbuf)
607156c3c53Sclaudio {
608ab837574Stb 	if (msgbuf == NULL)
609ab837574Stb 		return;
610156c3c53Sclaudio 	msgbuf_clear(msgbuf);
61104d83f12Sclaudio 	free(msgbuf->rbuf);
612156c3c53Sclaudio 	free(msgbuf);
61304886c2dSclaudio }
61404886c2dSclaudio 
61504886c2dSclaudio uint32_t
61604886c2dSclaudio msgbuf_queuelen(struct msgbuf *msgbuf)
61704886c2dSclaudio {
61804886c2dSclaudio 	return (msgbuf->queued);
61904886c2dSclaudio }
62004886c2dSclaudio 
62104886c2dSclaudio void
62204886c2dSclaudio msgbuf_clear(struct msgbuf *msgbuf)
62304886c2dSclaudio {
62404886c2dSclaudio 	struct ibuf	*buf;
62504886c2dSclaudio 
62604d83f12Sclaudio 	/* write side */
62704886c2dSclaudio 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
62804886c2dSclaudio 		msgbuf_dequeue(msgbuf, buf);
62904d83f12Sclaudio 	msgbuf->queued = 0;
63004d83f12Sclaudio 
63104d83f12Sclaudio 	/* read side */
63204d83f12Sclaudio 	while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) {
63304d83f12Sclaudio 		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
63404d83f12Sclaudio 		ibuf_free(buf);
63504d83f12Sclaudio 	}
63604d83f12Sclaudio 	msgbuf->roff = 0;
63704d83f12Sclaudio 	ibuf_free(msgbuf->rpmsg);
63804d83f12Sclaudio 	msgbuf->rpmsg = NULL;
63904d83f12Sclaudio }
64004d83f12Sclaudio 
64104d83f12Sclaudio struct ibuf *
64204d83f12Sclaudio msgbuf_get(struct msgbuf *msgbuf)
64304d83f12Sclaudio {
64404d83f12Sclaudio 	struct ibuf	*buf;
64504d83f12Sclaudio 
64604d83f12Sclaudio 	if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL)
64704d83f12Sclaudio 		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
64804d83f12Sclaudio 	return buf;
64904886c2dSclaudio }
65004886c2dSclaudio 
651dfaf6462Snicm int
6524494689aSclaudio ibuf_write(int fd, struct msgbuf *msgbuf)
653dfaf6462Snicm {
654dfaf6462Snicm 	struct iovec	 iov[IOV_MAX];
655dfaf6462Snicm 	struct ibuf	*buf;
656dfaf6462Snicm 	unsigned int	 i = 0;
657dfaf6462Snicm 	ssize_t	n;
658dfaf6462Snicm 
6593c384461Snicm 	memset(&iov, 0, sizeof(iov));
660dfaf6462Snicm 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
661dfaf6462Snicm 		if (i >= IOV_MAX)
662dfaf6462Snicm 			break;
6634658a150Sclaudio 		iov[i].iov_base = ibuf_data(buf);
6644658a150Sclaudio 		iov[i].iov_len = ibuf_size(buf);
665dfaf6462Snicm 		i++;
666dfaf6462Snicm 	}
667317c8015Sclaudio 	if (i == 0)
668317c8015Sclaudio 		return (0);	/* nothing queued */
669dfaf6462Snicm 
670f7a9e704Sgilles  again:
6714494689aSclaudio 	if ((n = writev(fd, iov, i)) == -1) {
672450376abSbenno 		if (errno == EINTR)
673f7a9e704Sgilles 			goto again;
674317c8015Sclaudio 		if (errno == EAGAIN || errno == ENOBUFS)
675317c8015Sclaudio 			/* lets retry later again */
676317c8015Sclaudio 			return (0);
677dfaf6462Snicm 		return (-1);
678dfaf6462Snicm 	}
679dfaf6462Snicm 
680dfaf6462Snicm 	msgbuf_drain(msgbuf, n);
681317c8015Sclaudio 	return (0);
682dfaf6462Snicm }
683dfaf6462Snicm 
684dfaf6462Snicm int
6854494689aSclaudio msgbuf_write(int fd, struct msgbuf *msgbuf)
686dfaf6462Snicm {
687dfaf6462Snicm 	struct iovec	 iov[IOV_MAX];
6882325ad59Seric 	struct ibuf	*buf, *buf0 = NULL;
689dfaf6462Snicm 	unsigned int	 i = 0;
690dfaf6462Snicm 	ssize_t		 n;
691dfaf6462Snicm 	struct msghdr	 msg;
692dfaf6462Snicm 	struct cmsghdr	*cmsg;
693dfaf6462Snicm 	union {
694dfaf6462Snicm 		struct cmsghdr	hdr;
695dfaf6462Snicm 		char		buf[CMSG_SPACE(sizeof(int))];
696dfaf6462Snicm 	} cmsgbuf;
697dfaf6462Snicm 
6983c384461Snicm 	memset(&iov, 0, sizeof(iov));
6993c384461Snicm 	memset(&msg, 0, sizeof(msg));
7003c384461Snicm 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
701dfaf6462Snicm 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
702dfaf6462Snicm 		if (i >= IOV_MAX)
703dfaf6462Snicm 			break;
7042325ad59Seric 		if (i > 0 && buf->fd != -1)
7052325ad59Seric 			break;
7064658a150Sclaudio 		iov[i].iov_base = ibuf_data(buf);
7074658a150Sclaudio 		iov[i].iov_len = ibuf_size(buf);
708dfaf6462Snicm 		i++;
709dfaf6462Snicm 		if (buf->fd != -1)
7102325ad59Seric 			buf0 = buf;
711dfaf6462Snicm 	}
712dfaf6462Snicm 
713317c8015Sclaudio 	if (i == 0)
714317c8015Sclaudio 		return (0);	/* nothing queued */
715317c8015Sclaudio 
716dfaf6462Snicm 	msg.msg_iov = iov;
717dfaf6462Snicm 	msg.msg_iovlen = i;
718dfaf6462Snicm 
7192325ad59Seric 	if (buf0 != NULL) {
720dfaf6462Snicm 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
721dfaf6462Snicm 		msg.msg_controllen = sizeof(cmsgbuf.buf);
722dfaf6462Snicm 		cmsg = CMSG_FIRSTHDR(&msg);
723dfaf6462Snicm 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
724dfaf6462Snicm 		cmsg->cmsg_level = SOL_SOCKET;
725dfaf6462Snicm 		cmsg->cmsg_type = SCM_RIGHTS;
7262325ad59Seric 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
727dfaf6462Snicm 	}
728dfaf6462Snicm 
729f7a9e704Sgilles  again:
7304494689aSclaudio 	if ((n = sendmsg(fd, &msg, 0)) == -1) {
731450376abSbenno 		if (errno == EINTR)
732f7a9e704Sgilles 			goto again;
733317c8015Sclaudio 		if (errno == EAGAIN || errno == ENOBUFS)
734317c8015Sclaudio 			/* lets retry later again */
735f7a9e704Sgilles 			return (0);
736317c8015Sclaudio 		return (-1);
737dfaf6462Snicm 	}
738dfaf6462Snicm 
739dfaf6462Snicm 	/*
740dfaf6462Snicm 	 * assumption: fd got sent if sendmsg sent anything
741dfaf6462Snicm 	 * this works because fds are passed one at a time
742dfaf6462Snicm 	 */
7432325ad59Seric 	if (buf0 != NULL) {
7442325ad59Seric 		close(buf0->fd);
7452325ad59Seric 		buf0->fd = -1;
746dfaf6462Snicm 	}
747dfaf6462Snicm 
748dfaf6462Snicm 	msgbuf_drain(msgbuf, n);
749dfaf6462Snicm 
750317c8015Sclaudio 	return (0);
751dfaf6462Snicm }
752dfaf6462Snicm 
75304d83f12Sclaudio static int
75404d83f12Sclaudio ibuf_read_process(struct msgbuf *msgbuf, int fd)
75504d83f12Sclaudio {
75604d83f12Sclaudio 	struct ibuf rbuf, msg;
75704d83f12Sclaudio 	ssize_t sz;
75804d83f12Sclaudio 
75904d83f12Sclaudio 	ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
76004d83f12Sclaudio 
76104d83f12Sclaudio 	do {
76204d83f12Sclaudio 		if (msgbuf->rpmsg == NULL) {
763*ff59764dSclaudio 			if (ibuf_size(&rbuf) < msgbuf->hdrsize)
76404d83f12Sclaudio 				break;
76504d83f12Sclaudio 			/* get size from header */
76604d83f12Sclaudio 			ibuf_from_buffer(&msg, ibuf_data(&rbuf),
76704d83f12Sclaudio 			    msgbuf->hdrsize);
768*ff59764dSclaudio 			if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
769*ff59764dSclaudio 			    msgbuf->rarg, &fd)) == NULL)
77004d83f12Sclaudio 				goto fail;
77104d83f12Sclaudio 		}
77204d83f12Sclaudio 
77304d83f12Sclaudio 		if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
77404d83f12Sclaudio 			sz = ibuf_left(msgbuf->rpmsg);
77504d83f12Sclaudio 		else
77604d83f12Sclaudio 			sz = ibuf_size(&rbuf);
77704d83f12Sclaudio 
77804d83f12Sclaudio 		/* neither call below can fail */
77904d83f12Sclaudio 		if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
78004d83f12Sclaudio 		    ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
78104d83f12Sclaudio 			goto fail;
78204d83f12Sclaudio 
78304d83f12Sclaudio 		if (ibuf_left(msgbuf->rpmsg) == 0) {
78404d83f12Sclaudio 			msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg);
78504d83f12Sclaudio 			msgbuf->rpmsg = NULL;
78604d83f12Sclaudio 		}
78704d83f12Sclaudio 	} while (ibuf_size(&rbuf) > 0);
78804d83f12Sclaudio 
78904d83f12Sclaudio 	if (ibuf_size(&rbuf) > 0)
79004d83f12Sclaudio 		memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
79104d83f12Sclaudio 	msgbuf->roff = ibuf_size(&rbuf);
79204d83f12Sclaudio 
793*ff59764dSclaudio 	if (fd != -1)
794*ff59764dSclaudio 		close(fd);
79504d83f12Sclaudio 	return (1);
79604d83f12Sclaudio 
79704d83f12Sclaudio  fail:
798*ff59764dSclaudio 	/* XXX how to properly clean up is unclear */
799*ff59764dSclaudio 	if (fd != -1)
800*ff59764dSclaudio 		close(fd);
80104d83f12Sclaudio 	return (-1);
80204d83f12Sclaudio }
80304d83f12Sclaudio 
80404d83f12Sclaudio int
80504d83f12Sclaudio ibuf_read(int fd, struct msgbuf *msgbuf)
80604d83f12Sclaudio {
80704d83f12Sclaudio 	struct iovec	iov;
80804d83f12Sclaudio 	ssize_t		n;
80904d83f12Sclaudio 
81004d83f12Sclaudio 	if (msgbuf->rbuf == NULL) {
81104d83f12Sclaudio 		errno = EINVAL;
81204d83f12Sclaudio 		return (-1);
81304d83f12Sclaudio 	}
81404d83f12Sclaudio 
81504d83f12Sclaudio 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
81604d83f12Sclaudio 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
81704d83f12Sclaudio 
81804d83f12Sclaudio  again:
81904d83f12Sclaudio 	if ((n = readv(fd, &iov, 1)) == -1) {
82004d83f12Sclaudio 		if (errno == EINTR)
82104d83f12Sclaudio 			goto again;
82204d83f12Sclaudio 		if (errno == EAGAIN)
82304d83f12Sclaudio 			/* lets retry later again */
82404d83f12Sclaudio 			return (1);
82504d83f12Sclaudio 		return (-1);
82604d83f12Sclaudio 	}
82704d83f12Sclaudio 	if (n == 0)	/* connection closed */
82804d83f12Sclaudio 		return (0);
82904d83f12Sclaudio 
83004d83f12Sclaudio 	msgbuf->roff += n;
83104d83f12Sclaudio 	/* new data arrived, try to process it */
83204d83f12Sclaudio 	return (ibuf_read_process(msgbuf, -1));
83304d83f12Sclaudio }
83404d83f12Sclaudio 
83504d83f12Sclaudio int
83604d83f12Sclaudio msgbuf_read(int fd, struct msgbuf *msgbuf)
83704d83f12Sclaudio {
83804d83f12Sclaudio 	struct msghdr		 msg;
83904d83f12Sclaudio 	struct cmsghdr		*cmsg;
84004d83f12Sclaudio 	union {
84104d83f12Sclaudio 		struct cmsghdr hdr;
84204d83f12Sclaudio 		char	buf[CMSG_SPACE(sizeof(int) * 1)];
84304d83f12Sclaudio 	} cmsgbuf;
84404d83f12Sclaudio 	struct iovec		 iov;
84504d83f12Sclaudio 	ssize_t			 n;
84604d83f12Sclaudio 	int			 fdpass = -1;
84704d83f12Sclaudio 
84804d83f12Sclaudio 	if (msgbuf->rbuf == NULL) {
84904d83f12Sclaudio 		errno = EINVAL;
85004d83f12Sclaudio 		return (-1);
85104d83f12Sclaudio 	}
85204d83f12Sclaudio 
85304d83f12Sclaudio 	memset(&msg, 0, sizeof(msg));
85404d83f12Sclaudio 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
85504d83f12Sclaudio 
85604d83f12Sclaudio 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
85704d83f12Sclaudio 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
85804d83f12Sclaudio 	msg.msg_iov = &iov;
85904d83f12Sclaudio 	msg.msg_iovlen = 1;
86004d83f12Sclaudio 	msg.msg_control = &cmsgbuf.buf;
86104d83f12Sclaudio 	msg.msg_controllen = sizeof(cmsgbuf.buf);
86204d83f12Sclaudio 
86304d83f12Sclaudio again:
86404d83f12Sclaudio 	if ((n = recvmsg(fd, &msg, 0)) == -1) {
86504d83f12Sclaudio 		if (errno == EINTR)
86604d83f12Sclaudio 			goto again;
86704d83f12Sclaudio 		if (errno == EMSGSIZE)
86804d83f12Sclaudio 			/*
86904d83f12Sclaudio 			 * Not enough fd slots: fd passing failed, retry
87004d83f12Sclaudio 			 * to receive the message without fd.
87104d83f12Sclaudio 			 * imsg_get_fd() will return -1 in that case.
87204d83f12Sclaudio 			 */
87304d83f12Sclaudio 			goto again;
87404d83f12Sclaudio 		if (errno == EAGAIN)
87504d83f12Sclaudio 			/* lets retry later again */
87604d83f12Sclaudio 			return (1);
87704d83f12Sclaudio 		return (-1);
87804d83f12Sclaudio 	}
87904d83f12Sclaudio 	if (n == 0)	/* connection closed */
88004d83f12Sclaudio 		return (0);
88104d83f12Sclaudio 
88204d83f12Sclaudio 	msgbuf->roff += n;
88304d83f12Sclaudio 
88404d83f12Sclaudio 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
88504d83f12Sclaudio 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
88604d83f12Sclaudio 		if (cmsg->cmsg_level == SOL_SOCKET &&
88704d83f12Sclaudio 		    cmsg->cmsg_type == SCM_RIGHTS) {
88804d83f12Sclaudio 			int i, j, f;
88904d83f12Sclaudio 
89004d83f12Sclaudio 			/*
89104d83f12Sclaudio 			 * We only accept one file descriptor.  Due to C
89204d83f12Sclaudio 			 * padding rules, our control buffer might contain
89304d83f12Sclaudio 			 * more than one fd, and we must close them.
89404d83f12Sclaudio 			 */
89504d83f12Sclaudio 			j = ((char *)cmsg + cmsg->cmsg_len -
89604d83f12Sclaudio 			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
89704d83f12Sclaudio 			for (i = 0; i < j; i++) {
89804d83f12Sclaudio 				f = ((int *)CMSG_DATA(cmsg))[i];
89904d83f12Sclaudio 				if (i == 0)
90004d83f12Sclaudio 					fdpass = f;
90104d83f12Sclaudio 				else
90204d83f12Sclaudio 					close(f);
90304d83f12Sclaudio 			}
90404d83f12Sclaudio 		}
90504d83f12Sclaudio 		/* we do not handle other ctl data level */
90604d83f12Sclaudio 	}
90704d83f12Sclaudio 
90804d83f12Sclaudio 	/* new data arrived, try to process it */
90904d83f12Sclaudio 	return (ibuf_read_process(msgbuf, fdpass));
91004d83f12Sclaudio }
91104d83f12Sclaudio 
91204d83f12Sclaudio static void
91304d83f12Sclaudio msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
91404d83f12Sclaudio {
91504d83f12Sclaudio 	/* if buf lives on the stack abort before causing more harm */
91604d83f12Sclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
91704d83f12Sclaudio 		abort();
91804d83f12Sclaudio 	TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry);
91904d83f12Sclaudio }
92004d83f12Sclaudio 
9218c897735Skettenis static void
92204886c2dSclaudio msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
923dfaf6462Snicm {
92448950d6eSclaudio 	/* if buf lives on the stack abort before causing more harm */
92548950d6eSclaudio 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
92648950d6eSclaudio 		abort();
927dfaf6462Snicm 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
928dfaf6462Snicm 	msgbuf->queued++;
929dfaf6462Snicm }
930dfaf6462Snicm 
9318c897735Skettenis static void
93204886c2dSclaudio msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
933dfaf6462Snicm {
934dfaf6462Snicm 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
935dfaf6462Snicm 	msgbuf->queued--;
936dfaf6462Snicm 	ibuf_free(buf);
937dfaf6462Snicm }
93804886c2dSclaudio 
93904886c2dSclaudio static void
94004886c2dSclaudio msgbuf_drain(struct msgbuf *msgbuf, size_t n)
94104886c2dSclaudio {
94204886c2dSclaudio 	struct ibuf	*buf, *next;
94304886c2dSclaudio 
94404886c2dSclaudio 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
94504886c2dSclaudio 	    buf = next) {
94604886c2dSclaudio 		next = TAILQ_NEXT(buf, entry);
94704886c2dSclaudio 		if (n >= ibuf_size(buf)) {
94804886c2dSclaudio 			n -= ibuf_size(buf);
94904886c2dSclaudio 			msgbuf_dequeue(msgbuf, buf);
95004886c2dSclaudio 		} else {
95104886c2dSclaudio 			buf->rpos += n;
95204886c2dSclaudio 			n = 0;
95304886c2dSclaudio 		}
95404886c2dSclaudio 	}
95504886c2dSclaudio }
956