Home | History | Annotate | Line # | Download | only in compat
imsg-buffer.c revision 1.13
      1 /*	$OpenBSD: imsg-buffer.c,v 1.35 2025/06/04 09:06:56 claudio Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2023 Claudio Jeker <claudio (at) openbsd.org>
      5  * Copyright (c) 2003, 2004 Henning Brauer <henning (at) openbsd.org>
      6  *
      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.
     10  *
     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.
     18  */
     19 
     20 #include <sys/types.h>
     21 #include <sys/socket.h>
     22 #include <sys/uio.h>
     23 #include <arpa/inet.h>
     24 
     25 #include <limits.h>
     26 #include <errno.h>
     27 #include <stdint.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <unistd.h>
     31 
     32 #include "compat.h"
     33 #include "imsg.h"
     34 
     35 #undef htobe16
     36 #define htobe16 htons
     37 #undef htobe32
     38 #define htobe32 htonl
     39 #undef htobe64
     40 #define htobe64 htonll
     41 #undef be16toh
     42 #define be16toh ntohs
     43 #undef be32toh
     44 #define be32toh ntohl
     45 #undef be64toh
     46 #define be64toh ntohll
     47 
     48 struct ibufqueue {
     49 	TAILQ_HEAD(, ibuf)	bufs;
     50 	uint32_t		queued;
     51 };
     52 
     53 struct msgbuf {
     54 	struct ibufqueue	 bufs;
     55 	struct ibufqueue	 rbufs;
     56 	char			*rbuf;
     57 	struct ibuf		*rpmsg;
     58 	struct ibuf		*(*readhdr)(struct ibuf *, void *, int *);
     59 	void			*rarg;
     60 	size_t			 roff;
     61 	size_t			 hdrsize;
     62 };
     63 
     64 static void	msgbuf_drain(struct msgbuf *, size_t);
     65 static void	ibufq_init(struct ibufqueue *);
     66 
     67 #define	IBUF_FD_MARK_ON_STACK	-2
     68 
     69 struct ibuf *
     70 ibuf_open(size_t len)
     71 {
     72 	struct ibuf	*buf;
     73 
     74 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
     75 		return (NULL);
     76 	if (len > 0) {
     77 		if ((buf->buf = calloc(len, 1)) == NULL) {
     78 			free(buf);
     79 			return (NULL);
     80 		}
     81 	}
     82 	buf->size = buf->max = len;
     83 	buf->fd = -1;
     84 
     85 	return (buf);
     86 }
     87 
     88 struct ibuf *
     89 ibuf_dynamic(size_t len, size_t max)
     90 {
     91 	struct ibuf	*buf;
     92 
     93 	if (max == 0 || max < len) {
     94 		errno = EINVAL;
     95 		return (NULL);
     96 	}
     97 
     98 	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
     99 		return (NULL);
    100 	if (len > 0) {
    101 		if ((buf->buf = calloc(len, 1)) == NULL) {
    102 			free(buf);
    103 			return (NULL);
    104 		}
    105 	}
    106 	buf->size = len;
    107 	buf->max = max;
    108 	buf->fd = -1;
    109 
    110 	return (buf);
    111 }
    112 
    113 void *
    114 ibuf_reserve(struct ibuf *buf, size_t len)
    115 {
    116 	void	*b;
    117 
    118 	if (len > SIZE_MAX - buf->wpos) {
    119 		errno = ERANGE;
    120 		return (NULL);
    121 	}
    122 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
    123 		/* can not grow stack buffers */
    124 		errno = EINVAL;
    125 		return (NULL);
    126 	}
    127 
    128 	if (buf->wpos + len > buf->size) {
    129 		unsigned char	*nb;
    130 
    131 		/* check if buffer is allowed to grow */
    132 		if (buf->wpos + len > buf->max) {
    133 			errno = ERANGE;
    134 			return (NULL);
    135 		}
    136 		nb = realloc(buf->buf, buf->wpos + len);
    137 		if (nb == NULL)
    138 			return (NULL);
    139 		memset(nb + buf->size, 0, buf->wpos + len - buf->size);
    140 		buf->buf = nb;
    141 		buf->size = buf->wpos + len;
    142 	}
    143 
    144 	b = buf->buf + buf->wpos;
    145 	buf->wpos += len;
    146 	return (b);
    147 }
    148 
    149 int
    150 ibuf_add(struct ibuf *buf, const void *data, size_t len)
    151 {
    152 	void *b;
    153 
    154 	if (len == 0)
    155 		return (0);
    156 
    157 	if ((b = ibuf_reserve(buf, len)) == NULL)
    158 		return (-1);
    159 
    160 	memcpy(b, data, len);
    161 	return (0);
    162 }
    163 
    164 int
    165 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
    166 {
    167 	return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
    168 }
    169 
    170 int
    171 ibuf_add_n8(struct ibuf *buf, uint64_t value)
    172 {
    173 	uint8_t v;
    174 
    175 	if (value > UINT8_MAX) {
    176 		errno = EINVAL;
    177 		return (-1);
    178 	}
    179 	v = value;
    180 	return ibuf_add(buf, &v, sizeof(v));
    181 }
    182 
    183 int
    184 ibuf_add_n16(struct ibuf *buf, uint64_t value)
    185 {
    186 	uint16_t v;
    187 
    188 	if (value > UINT16_MAX) {
    189 		errno = EINVAL;
    190 		return (-1);
    191 	}
    192 	v = htobe16(value);
    193 	return ibuf_add(buf, &v, sizeof(v));
    194 }
    195 
    196 int
    197 ibuf_add_n32(struct ibuf *buf, uint64_t value)
    198 {
    199 	uint32_t v;
    200 
    201 	if (value > UINT32_MAX) {
    202 		errno = EINVAL;
    203 		return (-1);
    204 	}
    205 	v = htobe32(value);
    206 	return ibuf_add(buf, &v, sizeof(v));
    207 }
    208 
    209 int
    210 ibuf_add_n64(struct ibuf *buf, uint64_t value)
    211 {
    212 	value = htobe64(value);
    213 	return ibuf_add(buf, &value, sizeof(value));
    214 }
    215 
    216 int
    217 ibuf_add_h16(struct ibuf *buf, uint64_t value)
    218 {
    219 	uint16_t v;
    220 
    221 	if (value > UINT16_MAX) {
    222 		errno = EINVAL;
    223 		return (-1);
    224 	}
    225 	v = value;
    226 	return ibuf_add(buf, &v, sizeof(v));
    227 }
    228 
    229 int
    230 ibuf_add_h32(struct ibuf *buf, uint64_t value)
    231 {
    232 	uint32_t v;
    233 
    234 	if (value > UINT32_MAX) {
    235 		errno = EINVAL;
    236 		return (-1);
    237 	}
    238 	v = value;
    239 	return ibuf_add(buf, &v, sizeof(v));
    240 }
    241 
    242 int
    243 ibuf_add_h64(struct ibuf *buf, uint64_t value)
    244 {
    245 	return ibuf_add(buf, &value, sizeof(value));
    246 }
    247 
    248 int
    249 ibuf_add_zero(struct ibuf *buf, size_t len)
    250 {
    251 	void *b;
    252 
    253 	if (len == 0)
    254 		return (0);
    255 
    256 	if ((b = ibuf_reserve(buf, len)) == NULL)
    257 		return (-1);
    258 	memset(b, 0, len);
    259 	return (0);
    260 }
    261 
    262 int
    263 ibuf_add_strbuf(struct ibuf *buf, const char *str, size_t len)
    264 {
    265 	char *b;
    266 	size_t n;
    267 
    268 	if ((b = ibuf_reserve(buf, len)) == NULL)
    269 		return (-1);
    270 
    271 	n = strlcpy(b, str, len);
    272 	if (n >= len) {
    273 		/* also covers the case where len == 0 */
    274 		errno = EOVERFLOW;
    275 		return (-1);
    276 	}
    277 	memset(b + n, 0, len - n);
    278 	return (0);
    279 }
    280 
    281 void *
    282 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
    283 {
    284 	/* only allow seeking between rpos and wpos */
    285 	if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
    286 	    ibuf_size(buf) < pos + len) {
    287 		errno = ERANGE;
    288 		return (NULL);
    289 	}
    290 
    291 	return (buf->buf + buf->rpos + pos);
    292 }
    293 
    294 int
    295 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
    296 {
    297 	void *b;
    298 
    299 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
    300 		return (-1);
    301 
    302 	if (len == 0)
    303 		return (0);
    304 	memcpy(b, data, len);
    305 	return (0);
    306 }
    307 
    308 int
    309 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
    310 {
    311 	uint8_t v;
    312 
    313 	if (value > UINT8_MAX) {
    314 		errno = EINVAL;
    315 		return (-1);
    316 	}
    317 	v = value;
    318 	return (ibuf_set(buf, pos, &v, sizeof(v)));
    319 }
    320 
    321 int
    322 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
    323 {
    324 	uint16_t v;
    325 
    326 	if (value > UINT16_MAX) {
    327 		errno = EINVAL;
    328 		return (-1);
    329 	}
    330 	v = htobe16(value);
    331 	return (ibuf_set(buf, pos, &v, sizeof(v)));
    332 }
    333 
    334 int
    335 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
    336 {
    337 	uint32_t v;
    338 
    339 	if (value > UINT32_MAX) {
    340 		errno = EINVAL;
    341 		return (-1);
    342 	}
    343 	v = htobe32(value);
    344 	return (ibuf_set(buf, pos, &v, sizeof(v)));
    345 }
    346 
    347 int
    348 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
    349 {
    350 	value = htobe64(value);
    351 	return (ibuf_set(buf, pos, &value, sizeof(value)));
    352 }
    353 
    354 int
    355 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
    356 {
    357 	uint16_t v;
    358 
    359 	if (value > UINT16_MAX) {
    360 		errno = EINVAL;
    361 		return (-1);
    362 	}
    363 	v = value;
    364 	return (ibuf_set(buf, pos, &v, sizeof(v)));
    365 }
    366 
    367 int
    368 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
    369 {
    370 	uint32_t v;
    371 
    372 	if (value > UINT32_MAX) {
    373 		errno = EINVAL;
    374 		return (-1);
    375 	}
    376 	v = value;
    377 	return (ibuf_set(buf, pos, &v, sizeof(v)));
    378 }
    379 
    380 int
    381 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
    382 {
    383 	return (ibuf_set(buf, pos, &value, sizeof(value)));
    384 }
    385 
    386 int
    387 ibuf_set_maxsize(struct ibuf *buf, size_t max)
    388 {
    389 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
    390 		/* can't fiddle with stack buffers */
    391 		errno = EINVAL;
    392 		return (-1);
    393 	}
    394 	if (max > buf->max) {
    395 		errno = ERANGE;
    396 		return (-1);
    397 	}
    398 	buf->max = max;
    399 	return (0);
    400 }
    401 
    402 void *
    403 ibuf_data(const struct ibuf *buf)
    404 {
    405 	return (buf->buf + buf->rpos);
    406 }
    407 
    408 size_t
    409 ibuf_size(const struct ibuf *buf)
    410 {
    411 	return (buf->wpos - buf->rpos);
    412 }
    413 
    414 size_t
    415 ibuf_left(const struct ibuf *buf)
    416 {
    417 	/* on stack buffers have no space left */
    418 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
    419 		return (0);
    420 	return (buf->max - buf->wpos);
    421 }
    422 
    423 int
    424 ibuf_truncate(struct ibuf *buf, size_t len)
    425 {
    426 	if (ibuf_size(buf) >= len) {
    427 		buf->wpos = buf->rpos + len;
    428 		return (0);
    429 	}
    430 	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
    431 		/* only allow to truncate down for stack buffers */
    432 		errno = ERANGE;
    433 		return (-1);
    434 	}
    435 	return ibuf_add_zero(buf, len - ibuf_size(buf));
    436 }
    437 
    438 void
    439 ibuf_rewind(struct ibuf *buf)
    440 {
    441 	buf->rpos = 0;
    442 }
    443 
    444 void
    445 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
    446 {
    447 	ibufq_push(&msgbuf->bufs, buf);
    448 }
    449 
    450 void
    451 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
    452 {
    453 	memset(buf, 0, sizeof(*buf));
    454 	buf->buf = data;
    455 	buf->size = buf->wpos = len;
    456 	buf->fd = IBUF_FD_MARK_ON_STACK;
    457 }
    458 
    459 void
    460 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
    461 {
    462 	ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
    463 }
    464 
    465 int
    466 ibuf_get(struct ibuf *buf, void *data, size_t len)
    467 {
    468 	if (ibuf_size(buf) < len) {
    469 		errno = EBADMSG;
    470 		return (-1);
    471 	}
    472 
    473 	memcpy(data, ibuf_data(buf), len);
    474 	buf->rpos += len;
    475 	return (0);
    476 }
    477 
    478 int
    479 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
    480 {
    481 	if (ibuf_size(buf) < len) {
    482 		errno = EBADMSG;
    483 		return (-1);
    484 	}
    485 
    486 	ibuf_from_buffer(new, ibuf_data(buf), len);
    487 	buf->rpos += len;
    488 	return (0);
    489 }
    490 
    491 int
    492 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
    493 {
    494 	return ibuf_get(buf, value, sizeof(*value));
    495 }
    496 
    497 int
    498 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
    499 {
    500 	return ibuf_get(buf, value, sizeof(*value));
    501 }
    502 
    503 int
    504 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
    505 {
    506 	return ibuf_get(buf, value, sizeof(*value));
    507 }
    508 
    509 int
    510 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
    511 {
    512 	return ibuf_get(buf, value, sizeof(*value));
    513 }
    514 
    515 int
    516 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
    517 {
    518 	int rv;
    519 
    520 	rv = ibuf_get(buf, value, sizeof(*value));
    521 	*value = be16toh(*value);
    522 	return (rv);
    523 }
    524 
    525 int
    526 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
    527 {
    528 	int rv;
    529 
    530 	rv = ibuf_get(buf, value, sizeof(*value));
    531 	*value = be32toh(*value);
    532 	return (rv);
    533 }
    534 
    535 int
    536 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
    537 {
    538 	int rv;
    539 
    540 	rv = ibuf_get(buf, value, sizeof(*value));
    541 	*value = be64toh(*value);
    542 	return (rv);
    543 }
    544 
    545 char *
    546 ibuf_get_string(struct ibuf *buf, size_t len)
    547 {
    548 	char *str;
    549 
    550 	if (ibuf_size(buf) < len) {
    551 		errno = EBADMSG;
    552 		return (NULL);
    553 	}
    554 
    555 	str = strndup(ibuf_data(buf), len);
    556 	if (str == NULL)
    557 		return (NULL);
    558 	buf->rpos += len;
    559 	return (str);
    560 }
    561 
    562 int
    563 ibuf_get_strbuf(struct ibuf *buf, char *str, size_t len)
    564 {
    565 	if (len == 0) {
    566 		errno = EINVAL;
    567 		return (-1);
    568 	}
    569 
    570 	if (ibuf_get(buf, str, len) == -1)
    571 		return -1;
    572 	if (str[len - 1] != '\0') {
    573 		str[len - 1] = '\0';
    574 		errno = EOVERFLOW;
    575 		return -1;
    576 	}
    577 	return 0;
    578 }
    579 
    580 int
    581 ibuf_skip(struct ibuf *buf, size_t len)
    582 {
    583 	if (ibuf_size(buf) < len) {
    584 		errno = EBADMSG;
    585 		return (-1);
    586 	}
    587 
    588 	buf->rpos += len;
    589 	return (0);
    590 }
    591 
    592 void
    593 ibuf_free(struct ibuf *buf)
    594 {
    595 	int save_errno = errno;
    596 
    597 	if (buf == NULL)
    598 		return;
    599 	/* if buf lives on the stack abort before causing more harm */
    600 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
    601 		abort();
    602 	if (buf->fd >= 0)
    603 		close(buf->fd);
    604 	freezero(buf->buf, buf->size);
    605 	free(buf);
    606 	errno = save_errno;
    607 }
    608 
    609 int
    610 ibuf_fd_avail(struct ibuf *buf)
    611 {
    612 	return (buf->fd >= 0);
    613 }
    614 
    615 int
    616 ibuf_fd_get(struct ibuf *buf)
    617 {
    618 	int fd;
    619 
    620 	/* negative fds are internal use and equivalent to -1 */
    621 	if (buf->fd < 0)
    622 		return (-1);
    623 	fd = buf->fd;
    624 	buf->fd = -1;
    625 	return (fd);
    626 }
    627 
    628 void
    629 ibuf_fd_set(struct ibuf *buf, int fd)
    630 {
    631 	/* if buf lives on the stack abort before causing more harm */
    632 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
    633 		abort();
    634 	if (buf->fd >= 0)
    635 		close(buf->fd);
    636 	buf->fd = -1;
    637 	if (fd >= 0)
    638 		buf->fd = fd;
    639 }
    640 
    641 struct msgbuf *
    642 msgbuf_new(void)
    643 {
    644 	struct msgbuf *msgbuf;
    645 
    646 	if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
    647 		return (NULL);
    648 	ibufq_init(&msgbuf->bufs);
    649 	ibufq_init(&msgbuf->rbufs);
    650 
    651 	return msgbuf;
    652 }
    653 
    654 struct msgbuf *
    655 msgbuf_new_reader(size_t hdrsz,
    656     struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
    657 {
    658 	struct msgbuf *msgbuf;
    659 	char *buf;
    660 
    661 	if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
    662 		errno = EINVAL;
    663 		return (NULL);
    664 	}
    665 
    666 	if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
    667 		return (NULL);
    668 
    669 	msgbuf = msgbuf_new();
    670 	if (msgbuf == NULL) {
    671 		free(buf);
    672 		return (NULL);
    673 	}
    674 
    675 	msgbuf->rbuf = buf;
    676 	msgbuf->hdrsize = hdrsz;
    677 	msgbuf->readhdr = readhdr;
    678 	msgbuf->rarg = arg;
    679 
    680 	return (msgbuf);
    681 }
    682 
    683 void
    684 msgbuf_free(struct msgbuf *msgbuf)
    685 {
    686 	if (msgbuf == NULL)
    687 		return;
    688 	msgbuf_clear(msgbuf);
    689 	free(msgbuf->rbuf);
    690 	free(msgbuf);
    691 }
    692 
    693 uint32_t
    694 msgbuf_queuelen(struct msgbuf *msgbuf)
    695 {
    696 	return ibufq_queuelen(&msgbuf->bufs);
    697 }
    698 
    699 void
    700 msgbuf_clear(struct msgbuf *msgbuf)
    701 {
    702 	/* write side */
    703 	ibufq_flush(&msgbuf->bufs);
    704 
    705 	/* read side */
    706 	ibufq_flush(&msgbuf->rbufs);
    707 	msgbuf->roff = 0;
    708 	ibuf_free(msgbuf->rpmsg);
    709 	msgbuf->rpmsg = NULL;
    710 }
    711 
    712 struct ibuf *
    713 msgbuf_get(struct msgbuf *msgbuf)
    714 {
    715 	return ibufq_pop(&msgbuf->rbufs);
    716 }
    717 
    718 void
    719 msgbuf_concat(struct msgbuf *msgbuf, struct ibufqueue *from)
    720 {
    721 	ibufq_concat(&msgbuf->bufs, from);
    722 }
    723 
    724 int
    725 ibuf_write(int fd, struct msgbuf *msgbuf)
    726 {
    727 	struct iovec	 iov[IOV_MAX];
    728 	struct ibuf	*buf;
    729 	unsigned int	 i = 0;
    730 	ssize_t	n;
    731 
    732 	memset(&iov, 0, sizeof(iov));
    733 	TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
    734 		if (i >= IOV_MAX)
    735 			break;
    736 		iov[i].iov_base = ibuf_data(buf);
    737 		iov[i].iov_len = ibuf_size(buf);
    738 		i++;
    739 	}
    740 	if (i == 0)
    741 		return (0);	/* nothing queued */
    742 
    743  again:
    744 	if ((n = writev(fd, iov, i)) == -1) {
    745 		if (errno == EINTR)
    746 			goto again;
    747 		if (errno == EAGAIN || errno == ENOBUFS)
    748 			/* lets retry later again */
    749 			return (0);
    750 		return (-1);
    751 	}
    752 
    753 	msgbuf_drain(msgbuf, n);
    754 	return (0);
    755 }
    756 
    757 int
    758 msgbuf_write(int fd, struct msgbuf *msgbuf)
    759 {
    760 	struct iovec	 iov[IOV_MAX];
    761 	struct ibuf	*buf, *buf0 = NULL;
    762 	unsigned int	 i = 0;
    763 	ssize_t		 n;
    764 	struct msghdr	 msg;
    765 	struct cmsghdr	*cmsg;
    766 	union {
    767 		struct cmsghdr	hdr;
    768 		char		buf[CMSG_SPACE(sizeof(int))];
    769 	} cmsgbuf;
    770 
    771 	memset(&iov, 0, sizeof(iov));
    772 	memset(&msg, 0, sizeof(msg));
    773 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
    774 	TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
    775 		if (i >= IOV_MAX)
    776 			break;
    777 		if (i > 0 && buf->fd != -1)
    778 			break;
    779 		iov[i].iov_base = ibuf_data(buf);
    780 		iov[i].iov_len = ibuf_size(buf);
    781 		i++;
    782 		if (buf->fd != -1)
    783 			buf0 = buf;
    784 	}
    785 
    786 	if (i == 0)
    787 		return (0);	/* nothing queued */
    788 
    789 	msg.msg_iov = iov;
    790 	msg.msg_iovlen = i;
    791 
    792 	if (buf0 != NULL) {
    793 		msg.msg_control = (caddr_t)&cmsgbuf.buf;
    794 		msg.msg_controllen = CMSG_SPACE(sizeof(cmsgbuf.buf));
    795 		cmsg = CMSG_FIRSTHDR(&msg);
    796 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    797 		cmsg->cmsg_level = SOL_SOCKET;
    798 		cmsg->cmsg_type = SCM_RIGHTS;
    799 		*(int *)CMSG_DATA(cmsg) = buf0->fd;
    800 	}
    801 
    802  again:
    803 	if ((n = sendmsg(fd, &msg, 0)) == -1) {
    804 		if (errno == EINTR)
    805 			goto again;
    806 		if (errno == EAGAIN || errno == ENOBUFS)
    807 			/* lets retry later again */
    808 			return (0);
    809 		return (-1);
    810 	}
    811 
    812 	/*
    813 	 * assumption: fd got sent if sendmsg sent anything
    814 	 * this works because fds are passed one at a time
    815 	 */
    816 	if (buf0 != NULL) {
    817 		close(buf0->fd);
    818 		buf0->fd = -1;
    819 	}
    820 
    821 	msgbuf_drain(msgbuf, n);
    822 
    823 	return (0);
    824 }
    825 
    826 static int
    827 ibuf_read_process(struct msgbuf *msgbuf, int fd)
    828 {
    829 	struct ibuf rbuf, msg;
    830 	ssize_t sz;
    831 
    832 	ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
    833 
    834 	do {
    835 		if (msgbuf->rpmsg == NULL) {
    836 			if (ibuf_size(&rbuf) < msgbuf->hdrsize)
    837 				break;
    838 			/* get size from header */
    839 			ibuf_from_buffer(&msg, ibuf_data(&rbuf),
    840 			    msgbuf->hdrsize);
    841 			if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
    842 			    msgbuf->rarg, &fd)) == NULL)
    843 				goto fail;
    844 		}
    845 
    846 		if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
    847 			sz = ibuf_left(msgbuf->rpmsg);
    848 		else
    849 			sz = ibuf_size(&rbuf);
    850 
    851 		/* neither call below can fail */
    852 		if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
    853 		    ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
    854 			goto fail;
    855 
    856 		if (ibuf_left(msgbuf->rpmsg) == 0) {
    857 			ibufq_push(&msgbuf->rbufs, msgbuf->rpmsg);
    858 			msgbuf->rpmsg = NULL;
    859 		}
    860 	} while (ibuf_size(&rbuf) > 0);
    861 
    862 	if (ibuf_size(&rbuf) > 0)
    863 		memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
    864 	msgbuf->roff = ibuf_size(&rbuf);
    865 
    866 	if (fd != -1)
    867 		close(fd);
    868 	return (1);
    869 
    870  fail:
    871 	/* XXX how to properly clean up is unclear */
    872 	if (fd != -1)
    873 		close(fd);
    874 	return (-1);
    875 }
    876 
    877 int
    878 ibuf_read(int fd, struct msgbuf *msgbuf)
    879 {
    880 	struct iovec	iov;
    881 	ssize_t		n;
    882 
    883 	if (msgbuf->rbuf == NULL) {
    884 		errno = EINVAL;
    885 		return (-1);
    886 	}
    887 
    888 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
    889 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
    890 
    891  again:
    892 	if ((n = readv(fd, &iov, 1)) == -1) {
    893 		if (errno == EINTR)
    894 			goto again;
    895 		if (errno == EAGAIN)
    896 			/* lets retry later again */
    897 			return (1);
    898 		return (-1);
    899 	}
    900 	if (n == 0)	/* connection closed */
    901 		return (0);
    902 
    903 	msgbuf->roff += n;
    904 	/* new data arrived, try to process it */
    905 	return (ibuf_read_process(msgbuf, -1));
    906 }
    907 
    908 int
    909 msgbuf_read(int fd, struct msgbuf *msgbuf)
    910 {
    911 	struct msghdr		 msg;
    912 	struct cmsghdr		*cmsg;
    913 	union {
    914 		struct cmsghdr hdr;
    915 		char	buf[CMSG_SPACE(sizeof(int) * 1)];
    916 	} cmsgbuf;
    917 	struct iovec		 iov;
    918 	ssize_t			 n;
    919 	int			 fdpass = -1;
    920 
    921 	if (msgbuf->rbuf == NULL) {
    922 		errno = EINVAL;
    923 		return (-1);
    924 	}
    925 
    926 	memset(&msg, 0, sizeof(msg));
    927 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
    928 
    929 	iov.iov_base = msgbuf->rbuf + msgbuf->roff;
    930 	iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
    931 	msg.msg_iov = &iov;
    932 	msg.msg_iovlen = 1;
    933 	msg.msg_control = &cmsgbuf.buf;
    934 	msg.msg_controllen = sizeof(cmsgbuf.buf);
    935 
    936 again:
    937 	if ((n = recvmsg(fd, &msg, 0)) == -1) {
    938 		if (errno == EINTR)
    939 			goto again;
    940 		if (errno == EMSGSIZE)
    941 			/*
    942 			 * Not enough fd slots: fd passing failed, retry
    943 			 * to receive the message without fd.
    944 			 * imsg_get_fd() will return -1 in that case.
    945 			 */
    946 			goto again;
    947 		if (errno == EAGAIN)
    948 			/* lets retry later again */
    949 			return (1);
    950 		return (-1);
    951 	}
    952 	if (n == 0)	/* connection closed */
    953 		return (0);
    954 
    955 	msgbuf->roff += n;
    956 
    957 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
    958 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    959 		if (cmsg->cmsg_level == SOL_SOCKET &&
    960 		    cmsg->cmsg_type == SCM_RIGHTS) {
    961 			int i, j, f;
    962 
    963 			/*
    964 			 * We only accept one file descriptor.  Due to C
    965 			 * padding rules, our control buffer might contain
    966 			 * more than one fd, and we must close them.
    967 			 */
    968 			j = ((char *)cmsg + cmsg->cmsg_len -
    969 			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
    970 			for (i = 0; i < j; i++) {
    971 				f = ((int *)CMSG_DATA(cmsg))[i];
    972 				if (i == 0)
    973 					fdpass = f;
    974 				else
    975 					close(f);
    976 			}
    977 		}
    978 		/* we do not handle other ctl data level */
    979 	}
    980 
    981 	/* new data arrived, try to process it */
    982 	return (ibuf_read_process(msgbuf, fdpass));
    983 }
    984 
    985 static void
    986 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
    987 {
    988 	struct ibuf	*buf;
    989 
    990 	while ((buf = TAILQ_FIRST(&msgbuf->bufs.bufs)) != NULL) {
    991 		if (n >= ibuf_size(buf)) {
    992 			n -= ibuf_size(buf);
    993 			TAILQ_REMOVE(&msgbuf->bufs.bufs, buf, entry);
    994 			msgbuf->bufs.queued--;
    995 			ibuf_free(buf);
    996 		} else {
    997 			buf->rpos += n;
    998 			return;
    999 		}
   1000 	}
   1001 }
   1002 
   1003 static void
   1004 ibufq_init(struct ibufqueue *bufq)
   1005 {
   1006 	TAILQ_INIT(&bufq->bufs);
   1007 	bufq->queued = 0;
   1008 }
   1009 
   1010 struct ibufqueue *
   1011 ibufq_new(void)
   1012 {
   1013 	struct ibufqueue *bufq;
   1014 
   1015 	if ((bufq = calloc(1, sizeof(*bufq))) == NULL)
   1016 		return NULL;
   1017 	ibufq_init(bufq);
   1018 	return bufq;
   1019 }
   1020 
   1021 void
   1022 ibufq_free(struct ibufqueue *bufq)
   1023 {
   1024 	if (bufq == NULL)
   1025 		return;
   1026 	ibufq_flush(bufq);
   1027 	free(bufq);
   1028 }
   1029 
   1030 struct ibuf *
   1031 ibufq_pop(struct ibufqueue *bufq)
   1032 {
   1033 	struct ibuf *buf;
   1034 
   1035 	if ((buf = TAILQ_FIRST(&bufq->bufs)) == NULL)
   1036 		return NULL;
   1037 	TAILQ_REMOVE(&bufq->bufs, buf, entry);
   1038 	bufq->queued--;
   1039 	return buf;
   1040 }
   1041 
   1042 void
   1043 ibufq_push(struct ibufqueue *bufq, struct ibuf *buf)
   1044 {
   1045 	/* if buf lives on the stack abort before causing more harm */
   1046 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
   1047 		abort();
   1048 	TAILQ_INSERT_TAIL(&bufq->bufs, buf, entry);
   1049 	bufq->queued++;
   1050 }
   1051 
   1052 uint32_t
   1053 ibufq_queuelen(struct ibufqueue *bufq)
   1054 {
   1055 	return (bufq->queued);
   1056 }
   1057 
   1058 void
   1059 ibufq_concat(struct ibufqueue *to, struct ibufqueue *from)
   1060 {
   1061 	to->queued += from->queued;
   1062 	TAILQ_CONCAT(&to->bufs, &from->bufs, entry);
   1063 	from->queued = 0;
   1064 }
   1065 
   1066 void
   1067 ibufq_flush(struct ibufqueue *bufq)
   1068 {
   1069 	struct ibuf *buf;
   1070 
   1071 	while ((buf = TAILQ_FIRST(&bufq->bufs)) != NULL) {
   1072 		TAILQ_REMOVE(&bufq->bufs, buf, entry);
   1073 		ibuf_free(buf);
   1074 	}
   1075 	bufq->queued = 0;
   1076 }
   1077