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