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