xref: /netbsd-src/external/bsd/tmux/dist/compat/imsg-buffer.c (revision f844e94ef29eebc7999c12636b87f541bb86868b)
1*f844e94eSwiz /*	$OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $	*/
2698d5317Sjmmv 
3698d5317Sjmmv /*
4*f844e94eSwiz  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5698d5317Sjmmv  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6698d5317Sjmmv  *
7698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
8698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
9698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
10698d5317Sjmmv  *
11698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16698d5317Sjmmv  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17698d5317Sjmmv  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18698d5317Sjmmv  */
19698d5317Sjmmv 
2099e242abSchristos #include <sys/types.h>
21698d5317Sjmmv #include <sys/socket.h>
22698d5317Sjmmv #include <sys/uio.h>
23*f844e94eSwiz #include <arpa/inet.h>
24698d5317Sjmmv 
2599e242abSchristos #include <limits.h>
26698d5317Sjmmv #include <errno.h>
27*f844e94eSwiz #include <stdint.h>
28698d5317Sjmmv #include <stdlib.h>
29698d5317Sjmmv #include <string.h>
30698d5317Sjmmv #include <unistd.h>
31698d5317Sjmmv 
32e9a2d6faSchristos #include "compat.h"
3399e242abSchristos #include "imsg.h"
34698d5317Sjmmv 
35*f844e94eSwiz #undef htobe16
36*f844e94eSwiz #define htobe16 htons
37*f844e94eSwiz #undef htobe32
38*f844e94eSwiz #define htobe32 htonl
39*f844e94eSwiz #undef htobe64
40*f844e94eSwiz #define htobe64 htonll
41*f844e94eSwiz #undef be16toh
42*f844e94eSwiz #define be16toh ntohs
43*f844e94eSwiz #undef be32toh
44*f844e94eSwiz #define be32toh ntohl
45*f844e94eSwiz #undef be64toh
46*f844e94eSwiz #define be64toh ntohll
47*f844e94eSwiz 
48c7e17de0Schristos static int	ibuf_realloc(struct ibuf *, size_t);
49c7e17de0Schristos static void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
50c7e17de0Schristos static void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
51*f844e94eSwiz static void	msgbuf_drain(struct msgbuf *, size_t);
52698d5317Sjmmv 
53698d5317Sjmmv struct ibuf *
ibuf_open(size_t len)54698d5317Sjmmv ibuf_open(size_t len)
55698d5317Sjmmv {
56698d5317Sjmmv 	struct ibuf	*buf;
57698d5317Sjmmv 
58*f844e94eSwiz 	if (len == 0) {
59*f844e94eSwiz 		errno = EINVAL;
60*f844e94eSwiz 		return (NULL);
61*f844e94eSwiz 	}
62698d5317Sjmmv 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
63698d5317Sjmmv 		return (NULL);
64*f844e94eSwiz 	if ((buf->buf = calloc(len, 1)) == NULL) {
65698d5317Sjmmv 		free(buf);
66698d5317Sjmmv 		return (NULL);
67698d5317Sjmmv 	}
68698d5317Sjmmv 	buf->size = buf->max = len;
69698d5317Sjmmv 	buf->fd = -1;
70698d5317Sjmmv 
71698d5317Sjmmv 	return (buf);
72698d5317Sjmmv }
73698d5317Sjmmv 
74698d5317Sjmmv struct ibuf *
ibuf_dynamic(size_t len,size_t max)75698d5317Sjmmv ibuf_dynamic(size_t len, size_t max)
76698d5317Sjmmv {
77698d5317Sjmmv 	struct ibuf	*buf;
78698d5317Sjmmv 
79*f844e94eSwiz 	if (max == 0 || max < len) {
80*f844e94eSwiz 		errno = EINVAL;
81698d5317Sjmmv 		return (NULL);
82*f844e94eSwiz 	}
83698d5317Sjmmv 
84*f844e94eSwiz 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
85698d5317Sjmmv 		return (NULL);
86*f844e94eSwiz 	if (len > 0) {
87*f844e94eSwiz 		if ((buf->buf = calloc(len, 1)) == NULL) {
88*f844e94eSwiz 			free(buf);
89*f844e94eSwiz 			return (NULL);
90*f844e94eSwiz 		}
91*f844e94eSwiz 	}
92*f844e94eSwiz 	buf->size = len;
93698d5317Sjmmv 	buf->max = max;
94*f844e94eSwiz 	buf->fd = -1;
95698d5317Sjmmv 
96698d5317Sjmmv 	return (buf);
97698d5317Sjmmv }
98698d5317Sjmmv 
99c7e17de0Schristos static int
ibuf_realloc(struct ibuf * buf,size_t len)100698d5317Sjmmv ibuf_realloc(struct ibuf *buf, size_t len)
101698d5317Sjmmv {
102e271dbb8Schristos 	unsigned char	*b;
103698d5317Sjmmv 
104698d5317Sjmmv 	/* on static buffers max is eq size and so the following fails */
105*f844e94eSwiz 	if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
10699e242abSchristos 		errno = ERANGE;
107698d5317Sjmmv 		return (-1);
108698d5317Sjmmv 	}
109698d5317Sjmmv 
110e9a2d6faSchristos 	b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
111698d5317Sjmmv 	if (b == NULL)
112698d5317Sjmmv 		return (-1);
113698d5317Sjmmv 	buf->buf = b;
114698d5317Sjmmv 	buf->size = buf->wpos + len;
115698d5317Sjmmv 
116698d5317Sjmmv 	return (0);
117698d5317Sjmmv }
118698d5317Sjmmv 
119698d5317Sjmmv void *
ibuf_reserve(struct ibuf * buf,size_t len)120698d5317Sjmmv ibuf_reserve(struct ibuf *buf, size_t len)
121698d5317Sjmmv {
122698d5317Sjmmv 	void	*b;
123698d5317Sjmmv 
124*f844e94eSwiz 	if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
125*f844e94eSwiz 		errno = ERANGE;
126*f844e94eSwiz 		return (NULL);
127*f844e94eSwiz 	}
128*f844e94eSwiz 
129698d5317Sjmmv 	if (buf->wpos + len > buf->size)
130698d5317Sjmmv 		if (ibuf_realloc(buf, len) == -1)
131698d5317Sjmmv 			return (NULL);
132698d5317Sjmmv 
133698d5317Sjmmv 	b = buf->buf + buf->wpos;
134698d5317Sjmmv 	buf->wpos += len;
135698d5317Sjmmv 	return (b);
136698d5317Sjmmv }
137698d5317Sjmmv 
138*f844e94eSwiz int
ibuf_add(struct ibuf * buf,const void * data,size_t len)139*f844e94eSwiz ibuf_add(struct ibuf *buf, const void *data, size_t len)
140*f844e94eSwiz {
141*f844e94eSwiz 	void *b;
142*f844e94eSwiz 
143*f844e94eSwiz 	if ((b = ibuf_reserve(buf, len)) == NULL)
144*f844e94eSwiz 		return (-1);
145*f844e94eSwiz 
146*f844e94eSwiz 	memcpy(b, data, len);
147*f844e94eSwiz 	return (0);
148*f844e94eSwiz }
149*f844e94eSwiz 
150*f844e94eSwiz int
ibuf_add_ibuf(struct ibuf * buf,const struct ibuf * from)151*f844e94eSwiz ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
152*f844e94eSwiz {
153*f844e94eSwiz 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
154*f844e94eSwiz }
155*f844e94eSwiz 
156*f844e94eSwiz /* remove after tree is converted */
157*f844e94eSwiz int
ibuf_add_buf(struct ibuf * buf,const struct ibuf * from)158*f844e94eSwiz ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
159*f844e94eSwiz {
160*f844e94eSwiz 	return ibuf_add_ibuf(buf, from);
161*f844e94eSwiz }
162*f844e94eSwiz 
163*f844e94eSwiz int
ibuf_add_n8(struct ibuf * buf,uint64_t value)164*f844e94eSwiz ibuf_add_n8(struct ibuf *buf, uint64_t value)
165*f844e94eSwiz {
166*f844e94eSwiz 	uint8_t v;
167*f844e94eSwiz 
168*f844e94eSwiz 	if (value > UINT8_MAX) {
169*f844e94eSwiz 		errno = EINVAL;
170*f844e94eSwiz 		return (-1);
171*f844e94eSwiz 	}
172*f844e94eSwiz 	v = value;
173*f844e94eSwiz 	return ibuf_add(buf, &v, sizeof(v));
174*f844e94eSwiz }
175*f844e94eSwiz 
176*f844e94eSwiz int
ibuf_add_n16(struct ibuf * buf,uint64_t value)177*f844e94eSwiz ibuf_add_n16(struct ibuf *buf, uint64_t value)
178*f844e94eSwiz {
179*f844e94eSwiz 	uint16_t v;
180*f844e94eSwiz 
181*f844e94eSwiz 	if (value > UINT16_MAX) {
182*f844e94eSwiz 		errno = EINVAL;
183*f844e94eSwiz 		return (-1);
184*f844e94eSwiz 	}
185*f844e94eSwiz 	v = htobe16(value);
186*f844e94eSwiz 	return ibuf_add(buf, &v, sizeof(v));
187*f844e94eSwiz }
188*f844e94eSwiz 
189*f844e94eSwiz int
ibuf_add_n32(struct ibuf * buf,uint64_t value)190*f844e94eSwiz ibuf_add_n32(struct ibuf *buf, uint64_t value)
191*f844e94eSwiz {
192*f844e94eSwiz 	uint32_t v;
193*f844e94eSwiz 
194*f844e94eSwiz 	if (value > UINT32_MAX) {
195*f844e94eSwiz 		errno = EINVAL;
196*f844e94eSwiz 		return (-1);
197*f844e94eSwiz 	}
198*f844e94eSwiz 	v = htobe32(value);
199*f844e94eSwiz 	return ibuf_add(buf, &v, sizeof(v));
200*f844e94eSwiz }
201*f844e94eSwiz 
202*f844e94eSwiz int
ibuf_add_n64(struct ibuf * buf,uint64_t value)203*f844e94eSwiz ibuf_add_n64(struct ibuf *buf, uint64_t value)
204*f844e94eSwiz {
205*f844e94eSwiz 	value = htobe64(value);
206*f844e94eSwiz 	return ibuf_add(buf, &value, sizeof(value));
207*f844e94eSwiz }
208*f844e94eSwiz 
209*f844e94eSwiz int
ibuf_add_h16(struct ibuf * buf,uint64_t value)210*f844e94eSwiz ibuf_add_h16(struct ibuf *buf, uint64_t value)
211*f844e94eSwiz {
212*f844e94eSwiz 	uint16_t v;
213*f844e94eSwiz 
214*f844e94eSwiz 	if (value > UINT16_MAX) {
215*f844e94eSwiz 		errno = EINVAL;
216*f844e94eSwiz 		return (-1);
217*f844e94eSwiz 	}
218*f844e94eSwiz 	v = value;
219*f844e94eSwiz 	return ibuf_add(buf, &v, sizeof(v));
220*f844e94eSwiz }
221*f844e94eSwiz 
222*f844e94eSwiz int
ibuf_add_h32(struct ibuf * buf,uint64_t value)223*f844e94eSwiz ibuf_add_h32(struct ibuf *buf, uint64_t value)
224*f844e94eSwiz {
225*f844e94eSwiz 	uint32_t v;
226*f844e94eSwiz 
227*f844e94eSwiz 	if (value > UINT32_MAX) {
228*f844e94eSwiz 		errno = EINVAL;
229*f844e94eSwiz 		return (-1);
230*f844e94eSwiz 	}
231*f844e94eSwiz 	v = value;
232*f844e94eSwiz 	return ibuf_add(buf, &v, sizeof(v));
233*f844e94eSwiz }
234*f844e94eSwiz 
235*f844e94eSwiz int
ibuf_add_h64(struct ibuf * buf,uint64_t value)236*f844e94eSwiz ibuf_add_h64(struct ibuf *buf, uint64_t value)
237*f844e94eSwiz {
238*f844e94eSwiz 	return ibuf_add(buf, &value, sizeof(value));
239*f844e94eSwiz }
240*f844e94eSwiz 
241*f844e94eSwiz int
ibuf_add_zero(struct ibuf * buf,size_t len)242*f844e94eSwiz ibuf_add_zero(struct ibuf *buf, size_t len)
243*f844e94eSwiz {
244*f844e94eSwiz 	void *b;
245*f844e94eSwiz 
246*f844e94eSwiz 	if ((b = ibuf_reserve(buf, len)) == NULL)
247*f844e94eSwiz 		return (-1);
248*f844e94eSwiz 	memset(b, 0, len);
249*f844e94eSwiz 	return (0);
250*f844e94eSwiz }
251*f844e94eSwiz 
252698d5317Sjmmv void *
ibuf_seek(struct ibuf * buf,size_t pos,size_t len)253698d5317Sjmmv ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
254698d5317Sjmmv {
255*f844e94eSwiz 	/* only allow seeking between rpos and wpos */
256*f844e94eSwiz 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
257*f844e94eSwiz 	    ibuf_size(buf) < pos + len) {
258*f844e94eSwiz 		errno = ERANGE;
259698d5317Sjmmv 		return (NULL);
260*f844e94eSwiz 	}
261698d5317Sjmmv 
262*f844e94eSwiz 	return (buf->buf + buf->rpos + pos);
263*f844e94eSwiz }
264*f844e94eSwiz 
265*f844e94eSwiz int
ibuf_set(struct ibuf * buf,size_t pos,const void * data,size_t len)266*f844e94eSwiz ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
267*f844e94eSwiz {
268*f844e94eSwiz 	void *b;
269*f844e94eSwiz 
270*f844e94eSwiz 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
271*f844e94eSwiz 		return (-1);
272*f844e94eSwiz 
273*f844e94eSwiz 	memcpy(b, data, len);
274*f844e94eSwiz 	return (0);
275*f844e94eSwiz }
276*f844e94eSwiz 
277*f844e94eSwiz int
ibuf_set_n8(struct ibuf * buf,size_t pos,uint64_t value)278*f844e94eSwiz ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
279*f844e94eSwiz {
280*f844e94eSwiz 	uint8_t v;
281*f844e94eSwiz 
282*f844e94eSwiz 	if (value > UINT8_MAX) {
283*f844e94eSwiz 		errno = EINVAL;
284*f844e94eSwiz 		return (-1);
285*f844e94eSwiz 	}
286*f844e94eSwiz 	v = value;
287*f844e94eSwiz 	return (ibuf_set(buf, pos, &v, sizeof(v)));
288*f844e94eSwiz }
289*f844e94eSwiz 
290*f844e94eSwiz int
ibuf_set_n16(struct ibuf * buf,size_t pos,uint64_t value)291*f844e94eSwiz ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
292*f844e94eSwiz {
293*f844e94eSwiz 	uint16_t v;
294*f844e94eSwiz 
295*f844e94eSwiz 	if (value > UINT16_MAX) {
296*f844e94eSwiz 		errno = EINVAL;
297*f844e94eSwiz 		return (-1);
298*f844e94eSwiz 	}
299*f844e94eSwiz 	v = htobe16(value);
300*f844e94eSwiz 	return (ibuf_set(buf, pos, &v, sizeof(v)));
301*f844e94eSwiz }
302*f844e94eSwiz 
303*f844e94eSwiz int
ibuf_set_n32(struct ibuf * buf,size_t pos,uint64_t value)304*f844e94eSwiz ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
305*f844e94eSwiz {
306*f844e94eSwiz 	uint32_t v;
307*f844e94eSwiz 
308*f844e94eSwiz 	if (value > UINT32_MAX) {
309*f844e94eSwiz 		errno = EINVAL;
310*f844e94eSwiz 		return (-1);
311*f844e94eSwiz 	}
312*f844e94eSwiz 	v = htobe32(value);
313*f844e94eSwiz 	return (ibuf_set(buf, pos, &v, sizeof(v)));
314*f844e94eSwiz }
315*f844e94eSwiz 
316*f844e94eSwiz int
ibuf_set_n64(struct ibuf * buf,size_t pos,uint64_t value)317*f844e94eSwiz ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
318*f844e94eSwiz {
319*f844e94eSwiz 	value = htobe64(value);
320*f844e94eSwiz 	return (ibuf_set(buf, pos, &value, sizeof(value)));
321*f844e94eSwiz }
322*f844e94eSwiz 
323*f844e94eSwiz int
ibuf_set_h16(struct ibuf * buf,size_t pos,uint64_t value)324*f844e94eSwiz ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
325*f844e94eSwiz {
326*f844e94eSwiz 	uint16_t v;
327*f844e94eSwiz 
328*f844e94eSwiz 	if (value > UINT16_MAX) {
329*f844e94eSwiz 		errno = EINVAL;
330*f844e94eSwiz 		return (-1);
331*f844e94eSwiz 	}
332*f844e94eSwiz 	v = value;
333*f844e94eSwiz 	return (ibuf_set(buf, pos, &v, sizeof(v)));
334*f844e94eSwiz }
335*f844e94eSwiz 
336*f844e94eSwiz int
ibuf_set_h32(struct ibuf * buf,size_t pos,uint64_t value)337*f844e94eSwiz ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
338*f844e94eSwiz {
339*f844e94eSwiz 	uint32_t v;
340*f844e94eSwiz 
341*f844e94eSwiz 	if (value > UINT32_MAX) {
342*f844e94eSwiz 		errno = EINVAL;
343*f844e94eSwiz 		return (-1);
344*f844e94eSwiz 	}
345*f844e94eSwiz 	v = value;
346*f844e94eSwiz 	return (ibuf_set(buf, pos, &v, sizeof(v)));
347*f844e94eSwiz }
348*f844e94eSwiz 
349*f844e94eSwiz int
ibuf_set_h64(struct ibuf * buf,size_t pos,uint64_t value)350*f844e94eSwiz ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
351*f844e94eSwiz {
352*f844e94eSwiz 	return (ibuf_set(buf, pos, &value, sizeof(value)));
353*f844e94eSwiz }
354*f844e94eSwiz 
355*f844e94eSwiz void *
ibuf_data(const struct ibuf * buf)356*f844e94eSwiz ibuf_data(const struct ibuf *buf)
357*f844e94eSwiz {
358*f844e94eSwiz 	return (buf->buf + buf->rpos);
359698d5317Sjmmv }
360698d5317Sjmmv 
361698d5317Sjmmv size_t
ibuf_size(const struct ibuf * buf)362*f844e94eSwiz ibuf_size(const struct ibuf *buf)
363698d5317Sjmmv {
364*f844e94eSwiz 	return (buf->wpos - buf->rpos);
365698d5317Sjmmv }
366698d5317Sjmmv 
367698d5317Sjmmv size_t
ibuf_left(const struct ibuf * buf)368*f844e94eSwiz ibuf_left(const struct ibuf *buf)
369698d5317Sjmmv {
370*f844e94eSwiz 	if (buf->max == 0)
371*f844e94eSwiz 		return (0);
372698d5317Sjmmv 	return (buf->max - buf->wpos);
373698d5317Sjmmv }
374698d5317Sjmmv 
375*f844e94eSwiz int
ibuf_truncate(struct ibuf * buf,size_t len)376*f844e94eSwiz ibuf_truncate(struct ibuf *buf, size_t len)
377*f844e94eSwiz {
378*f844e94eSwiz 	if (ibuf_size(buf) >= len) {
379*f844e94eSwiz 		buf->wpos = buf->rpos + len;
380*f844e94eSwiz 		return (0);
381*f844e94eSwiz 	}
382*f844e94eSwiz 	if (buf->max == 0) {
383*f844e94eSwiz 		/* only allow to truncate down */
384*f844e94eSwiz 		errno = ERANGE;
385*f844e94eSwiz 		return (-1);
386*f844e94eSwiz 	}
387*f844e94eSwiz 	return ibuf_add_zero(buf, len - ibuf_size(buf));
388*f844e94eSwiz }
389*f844e94eSwiz 
390*f844e94eSwiz void
ibuf_rewind(struct ibuf * buf)391*f844e94eSwiz ibuf_rewind(struct ibuf *buf)
392*f844e94eSwiz {
393*f844e94eSwiz 	buf->rpos = 0;
394*f844e94eSwiz }
395*f844e94eSwiz 
396698d5317Sjmmv void
ibuf_close(struct msgbuf * msgbuf,struct ibuf * buf)397698d5317Sjmmv ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
398698d5317Sjmmv {
399698d5317Sjmmv 	ibuf_enqueue(msgbuf, buf);
400698d5317Sjmmv }
401698d5317Sjmmv 
402*f844e94eSwiz void
ibuf_from_buffer(struct ibuf * buf,void * data,size_t len)403*f844e94eSwiz ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
404*f844e94eSwiz {
405*f844e94eSwiz 	memset(buf, 0, sizeof(*buf));
406*f844e94eSwiz 	buf->buf = data;
407*f844e94eSwiz 	buf->size = buf->wpos = len;
408*f844e94eSwiz 	buf->fd = -1;
409*f844e94eSwiz }
410*f844e94eSwiz 
411*f844e94eSwiz void
ibuf_from_ibuf(struct ibuf * buf,const struct ibuf * from)412*f844e94eSwiz ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
413*f844e94eSwiz {
414*f844e94eSwiz 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
415*f844e94eSwiz }
416*f844e94eSwiz 
417*f844e94eSwiz int
ibuf_get(struct ibuf * buf,void * data,size_t len)418*f844e94eSwiz ibuf_get(struct ibuf *buf, void *data, size_t len)
419*f844e94eSwiz {
420*f844e94eSwiz 	if (ibuf_size(buf) < len) {
421*f844e94eSwiz 		errno = EBADMSG;
422*f844e94eSwiz 		return (-1);
423*f844e94eSwiz 	}
424*f844e94eSwiz 
425*f844e94eSwiz 	memcpy(data, ibuf_data(buf), len);
426*f844e94eSwiz 	buf->rpos += len;
427*f844e94eSwiz 	return (0);
428*f844e94eSwiz }
429*f844e94eSwiz 
430*f844e94eSwiz int
ibuf_get_ibuf(struct ibuf * buf,size_t len,struct ibuf * new)431*f844e94eSwiz ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
432*f844e94eSwiz {
433*f844e94eSwiz 	if (ibuf_size(buf) < len) {
434*f844e94eSwiz 		errno = EBADMSG;
435*f844e94eSwiz 		return (-1);
436*f844e94eSwiz 	}
437*f844e94eSwiz 
438*f844e94eSwiz 	ibuf_from_buffer(new, ibuf_data(buf), len);
439*f844e94eSwiz 	buf->rpos += len;
440*f844e94eSwiz 	return (0);
441*f844e94eSwiz }
442*f844e94eSwiz 
443*f844e94eSwiz int
ibuf_get_n8(struct ibuf * buf,uint8_t * value)444*f844e94eSwiz ibuf_get_n8(struct ibuf *buf, uint8_t *value)
445*f844e94eSwiz {
446*f844e94eSwiz 	return ibuf_get(buf, value, sizeof(*value));
447*f844e94eSwiz }
448*f844e94eSwiz 
449*f844e94eSwiz int
ibuf_get_n16(struct ibuf * buf,uint16_t * value)450*f844e94eSwiz ibuf_get_n16(struct ibuf *buf, uint16_t *value)
451*f844e94eSwiz {
452*f844e94eSwiz 	int rv;
453*f844e94eSwiz 
454*f844e94eSwiz 	rv = ibuf_get(buf, value, sizeof(*value));
455*f844e94eSwiz 	*value = be16toh(*value);
456*f844e94eSwiz 	return (rv);
457*f844e94eSwiz }
458*f844e94eSwiz 
459*f844e94eSwiz int
ibuf_get_n32(struct ibuf * buf,uint32_t * value)460*f844e94eSwiz ibuf_get_n32(struct ibuf *buf, uint32_t *value)
461*f844e94eSwiz {
462*f844e94eSwiz 	int rv;
463*f844e94eSwiz 
464*f844e94eSwiz 	rv = ibuf_get(buf, value, sizeof(*value));
465*f844e94eSwiz 	*value = be32toh(*value);
466*f844e94eSwiz 	return (rv);
467*f844e94eSwiz }
468*f844e94eSwiz 
469*f844e94eSwiz int
ibuf_get_n64(struct ibuf * buf,uint64_t * value)470*f844e94eSwiz ibuf_get_n64(struct ibuf *buf, uint64_t *value)
471*f844e94eSwiz {
472*f844e94eSwiz 	int rv;
473*f844e94eSwiz 
474*f844e94eSwiz 	rv = ibuf_get(buf, value, sizeof(*value));
475*f844e94eSwiz 	*value = be64toh(*value);
476*f844e94eSwiz 	return (rv);
477*f844e94eSwiz }
478*f844e94eSwiz 
479*f844e94eSwiz int
ibuf_get_h16(struct ibuf * buf,uint16_t * value)480*f844e94eSwiz ibuf_get_h16(struct ibuf *buf, uint16_t *value)
481*f844e94eSwiz {
482*f844e94eSwiz 	return ibuf_get(buf, value, sizeof(*value));
483*f844e94eSwiz }
484*f844e94eSwiz 
485*f844e94eSwiz int
ibuf_get_h32(struct ibuf * buf,uint32_t * value)486*f844e94eSwiz ibuf_get_h32(struct ibuf *buf, uint32_t *value)
487*f844e94eSwiz {
488*f844e94eSwiz 	return ibuf_get(buf, value, sizeof(*value));
489*f844e94eSwiz }
490*f844e94eSwiz 
491*f844e94eSwiz int
ibuf_get_h64(struct ibuf * buf,uint64_t * value)492*f844e94eSwiz ibuf_get_h64(struct ibuf *buf, uint64_t *value)
493*f844e94eSwiz {
494*f844e94eSwiz 	return ibuf_get(buf, value, sizeof(*value));
495*f844e94eSwiz }
496*f844e94eSwiz 
497*f844e94eSwiz int
ibuf_skip(struct ibuf * buf,size_t len)498*f844e94eSwiz ibuf_skip(struct ibuf *buf, size_t len)
499*f844e94eSwiz {
500*f844e94eSwiz 	if (ibuf_size(buf) < len) {
501*f844e94eSwiz 		errno = EBADMSG;
502*f844e94eSwiz 		return (-1);
503*f844e94eSwiz 	}
504*f844e94eSwiz 
505*f844e94eSwiz 	buf->rpos += len;
506*f844e94eSwiz 	return (0);
507*f844e94eSwiz }
508*f844e94eSwiz 
509*f844e94eSwiz void
ibuf_free(struct ibuf * buf)510*f844e94eSwiz ibuf_free(struct ibuf *buf)
511*f844e94eSwiz {
512*f844e94eSwiz 	if (buf == NULL)
513*f844e94eSwiz 		return;
514*f844e94eSwiz 	if (buf->max == 0)	/* if buf lives on the stack */
515*f844e94eSwiz 		abort();	/* abort before causing more harm */
516*f844e94eSwiz 	if (buf->fd != -1)
517*f844e94eSwiz 		close(buf->fd);
518*f844e94eSwiz 	freezero(buf->buf, buf->size);
519*f844e94eSwiz 	free(buf);
520*f844e94eSwiz }
521*f844e94eSwiz 
522*f844e94eSwiz int
ibuf_fd_avail(struct ibuf * buf)523*f844e94eSwiz ibuf_fd_avail(struct ibuf *buf)
524*f844e94eSwiz {
525*f844e94eSwiz 	return (buf->fd != -1);
526*f844e94eSwiz }
527*f844e94eSwiz 
528*f844e94eSwiz int
ibuf_fd_get(struct ibuf * buf)529*f844e94eSwiz ibuf_fd_get(struct ibuf *buf)
530*f844e94eSwiz {
531*f844e94eSwiz 	int fd;
532*f844e94eSwiz 
533*f844e94eSwiz 	fd = buf->fd;
534*f844e94eSwiz 	buf->fd = -1;
535*f844e94eSwiz 	return (fd);
536*f844e94eSwiz }
537*f844e94eSwiz 
538*f844e94eSwiz void
ibuf_fd_set(struct ibuf * buf,int fd)539*f844e94eSwiz ibuf_fd_set(struct ibuf *buf, int fd)
540*f844e94eSwiz {
541*f844e94eSwiz 	if (buf->max == 0)	/* if buf lives on the stack */
542*f844e94eSwiz 		abort();	/* abort before causing more harm */
543*f844e94eSwiz 	if (buf->fd != -1)
544*f844e94eSwiz 		close(buf->fd);
545*f844e94eSwiz 	buf->fd = fd;
546*f844e94eSwiz }
547*f844e94eSwiz 
548698d5317Sjmmv int
ibuf_write(struct msgbuf * msgbuf)549698d5317Sjmmv ibuf_write(struct msgbuf *msgbuf)
550698d5317Sjmmv {
551698d5317Sjmmv 	struct iovec	 iov[IOV_MAX];
552698d5317Sjmmv 	struct ibuf	*buf;
553698d5317Sjmmv 	unsigned int	 i = 0;
554698d5317Sjmmv 	ssize_t	n;
555698d5317Sjmmv 
55699e242abSchristos 	memset(&iov, 0, sizeof(iov));
557698d5317Sjmmv 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
558698d5317Sjmmv 		if (i >= IOV_MAX)
559698d5317Sjmmv 			break;
560*f844e94eSwiz 		iov[i].iov_base = ibuf_data(buf);
561*f844e94eSwiz 		iov[i].iov_len = ibuf_size(buf);
562698d5317Sjmmv 		i++;
563698d5317Sjmmv 	}
564698d5317Sjmmv 
56599e242abSchristos again:
566698d5317Sjmmv 	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
56799e242abSchristos 		if (errno == EINTR)
56899e242abSchristos 			goto again;
56999e242abSchristos 		if (errno == ENOBUFS)
57099e242abSchristos 			errno = EAGAIN;
571698d5317Sjmmv 		return (-1);
572698d5317Sjmmv 	}
573698d5317Sjmmv 
574698d5317Sjmmv 	if (n == 0) {			/* connection closed */
575698d5317Sjmmv 		errno = 0;
57699e242abSchristos 		return (0);
577698d5317Sjmmv 	}
578698d5317Sjmmv 
579698d5317Sjmmv 	msgbuf_drain(msgbuf, n);
580698d5317Sjmmv 
58199e242abSchristos 	return (1);
582698d5317Sjmmv }
583698d5317Sjmmv 
584698d5317Sjmmv void
msgbuf_init(struct msgbuf * msgbuf)585698d5317Sjmmv msgbuf_init(struct msgbuf *msgbuf)
586698d5317Sjmmv {
587698d5317Sjmmv 	msgbuf->queued = 0;
588698d5317Sjmmv 	msgbuf->fd = -1;
589698d5317Sjmmv 	TAILQ_INIT(&msgbuf->bufs);
590698d5317Sjmmv }
591698d5317Sjmmv 
592*f844e94eSwiz static void
msgbuf_drain(struct msgbuf * msgbuf,size_t n)593698d5317Sjmmv msgbuf_drain(struct msgbuf *msgbuf, size_t n)
594698d5317Sjmmv {
595698d5317Sjmmv 	struct ibuf	*buf, *next;
596698d5317Sjmmv 
597698d5317Sjmmv 	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
598698d5317Sjmmv 	    buf = next) {
599698d5317Sjmmv 		next = TAILQ_NEXT(buf, entry);
600*f844e94eSwiz 		if (n >= ibuf_size(buf)) {
601*f844e94eSwiz 			n -= ibuf_size(buf);
602698d5317Sjmmv 			ibuf_dequeue(msgbuf, buf);
603698d5317Sjmmv 		} else {
604698d5317Sjmmv 			buf->rpos += n;
605698d5317Sjmmv 			n = 0;
606698d5317Sjmmv 		}
607698d5317Sjmmv 	}
608698d5317Sjmmv }
609698d5317Sjmmv 
610698d5317Sjmmv void
msgbuf_clear(struct msgbuf * msgbuf)611698d5317Sjmmv msgbuf_clear(struct msgbuf *msgbuf)
612698d5317Sjmmv {
613698d5317Sjmmv 	struct ibuf	*buf;
614698d5317Sjmmv 
615698d5317Sjmmv 	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
616698d5317Sjmmv 		ibuf_dequeue(msgbuf, buf);
617698d5317Sjmmv }
618698d5317Sjmmv 
619698d5317Sjmmv int
msgbuf_write(struct msgbuf * msgbuf)620698d5317Sjmmv msgbuf_write(struct msgbuf *msgbuf)
621698d5317Sjmmv {
622698d5317Sjmmv 	struct iovec	 iov[IOV_MAX];
623*f844e94eSwiz 	struct ibuf	*buf, *buf0 = NULL;
624698d5317Sjmmv 	unsigned int	 i = 0;
625698d5317Sjmmv 	ssize_t		 n;
626698d5317Sjmmv 	struct msghdr	 msg;
627698d5317Sjmmv 	struct cmsghdr	*cmsg;
628698d5317Sjmmv 	union {
629698d5317Sjmmv 		struct cmsghdr	hdr;
630698d5317Sjmmv 		char		buf[CMSG_SPACE(sizeof(int))];
631698d5317Sjmmv 	} cmsgbuf;
632698d5317Sjmmv 
63399e242abSchristos 	memset(&iov, 0, sizeof(iov));
63499e242abSchristos 	memset(&msg, 0, sizeof(msg));
63599e242abSchristos 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
636698d5317Sjmmv 	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
637698d5317Sjmmv 		if (i >= IOV_MAX)
638698d5317Sjmmv 			break;
639*f844e94eSwiz 		if (i > 0 && buf->fd != -1)
640*f844e94eSwiz 			break;
641*f844e94eSwiz 		iov[i].iov_base = ibuf_data(buf);
642*f844e94eSwiz 		iov[i].iov_len = ibuf_size(buf);
643698d5317Sjmmv 		i++;
644698d5317Sjmmv 		if (buf->fd != -1)
645*f844e94eSwiz 			buf0 = buf;
646698d5317Sjmmv 	}
647698d5317Sjmmv 
648698d5317Sjmmv 	msg.msg_iov = iov;
649698d5317Sjmmv 	msg.msg_iovlen = i;
650698d5317Sjmmv 
651*f844e94eSwiz 	if (buf0 != NULL) {
652698d5317Sjmmv 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
6539692a535Sjoerg 		msg.msg_controllen = CMSG_SPACE(sizeof(int));
654698d5317Sjmmv 		cmsg = CMSG_FIRSTHDR(&msg);
655698d5317Sjmmv 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
656698d5317Sjmmv 		cmsg->cmsg_level = SOL_SOCKET;
657698d5317Sjmmv 		cmsg->cmsg_type = SCM_RIGHTS;
658*f844e94eSwiz 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
659698d5317Sjmmv 	}
660698d5317Sjmmv 
66199e242abSchristos again:
662698d5317Sjmmv 	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
66399e242abSchristos 		if (errno == EINTR)
66499e242abSchristos 			goto again;
66599e242abSchristos 		if (errno == ENOBUFS)
66699e242abSchristos 			errno = EAGAIN;
667698d5317Sjmmv 		return (-1);
668698d5317Sjmmv 	}
669698d5317Sjmmv 
670698d5317Sjmmv 	if (n == 0) {			/* connection closed */
671698d5317Sjmmv 		errno = 0;
67299e242abSchristos 		return (0);
673698d5317Sjmmv 	}
674698d5317Sjmmv 
675698d5317Sjmmv 	/*
676698d5317Sjmmv 	 * assumption: fd got sent if sendmsg sent anything
677698d5317Sjmmv 	 * this works because fds are passed one at a time
678698d5317Sjmmv 	 */
679*f844e94eSwiz 	if (buf0 != NULL) {
680*f844e94eSwiz 		close(buf0->fd);
681*f844e94eSwiz 		buf0->fd = -1;
682698d5317Sjmmv 	}
683698d5317Sjmmv 
684698d5317Sjmmv 	msgbuf_drain(msgbuf, n);
685698d5317Sjmmv 
68699e242abSchristos 	return (1);
687698d5317Sjmmv }
688698d5317Sjmmv 
689*f844e94eSwiz uint32_t
msgbuf_queuelen(struct msgbuf * msgbuf)690*f844e94eSwiz msgbuf_queuelen(struct msgbuf *msgbuf)
691*f844e94eSwiz {
692*f844e94eSwiz 	return (msgbuf->queued);
693*f844e94eSwiz }
694*f844e94eSwiz 
695c7e17de0Schristos static void
ibuf_enqueue(struct msgbuf * msgbuf,struct ibuf * buf)696698d5317Sjmmv ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
697698d5317Sjmmv {
698*f844e94eSwiz 	if (buf->max == 0)	/* if buf lives on the stack */
699*f844e94eSwiz 		abort();	/* abort before causing more harm */
700698d5317Sjmmv 	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
701698d5317Sjmmv 	msgbuf->queued++;
702698d5317Sjmmv }
703698d5317Sjmmv 
704c7e17de0Schristos static void
ibuf_dequeue(struct msgbuf * msgbuf,struct ibuf * buf)705698d5317Sjmmv ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
706698d5317Sjmmv {
707698d5317Sjmmv 	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
708698d5317Sjmmv 	msgbuf->queued--;
709698d5317Sjmmv 	ibuf_free(buf);
710698d5317Sjmmv }
711