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