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