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