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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 225 ibuf_add_h64(struct ibuf *buf, uint64_t value) 226 { 227 return ibuf_add(buf, &value, sizeof(value)); 228 } 229 230 int 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 * 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 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 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 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 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 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 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 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 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 * 345 ibuf_data(const struct ibuf *buf) 346 { 347 return (buf->buf + buf->rpos); 348 } 349 350 size_t 351 ibuf_size(const struct ibuf *buf) 352 { 353 return (buf->wpos - buf->rpos); 354 } 355 356 size_t 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 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 381 ibuf_rewind(struct ibuf *buf) 382 { 383 buf->rpos = 0; 384 } 385 386 void 387 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) 388 { 389 msgbuf_enqueue(msgbuf, buf); 390 } 391 392 void 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 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 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 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 434 ibuf_get_h16(struct ibuf *buf, uint16_t *value) 435 { 436 return ibuf_get(buf, value, sizeof(*value)); 437 } 438 439 int 440 ibuf_get_h32(struct ibuf *buf, uint32_t *value) 441 { 442 return ibuf_get(buf, value, sizeof(*value)); 443 } 444 445 int 446 ibuf_get_h64(struct ibuf *buf, uint64_t *value) 447 { 448 return ibuf_get(buf, value, sizeof(*value)); 449 } 450 451 int 452 ibuf_get_n8(struct ibuf *buf, uint8_t *value) 453 { 454 return ibuf_get(buf, value, sizeof(*value)); 455 } 456 457 int 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 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 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 * 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 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 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 531 ibuf_fd_avail(struct ibuf *buf) 532 { 533 return (buf->fd >= 0); 534 } 535 536 int 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 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 * 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 * 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 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 616 msgbuf_queuelen(struct msgbuf *msgbuf) 617 { 618 return (msgbuf->queued); 619 } 620 621 void 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 * 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 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 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 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 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 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 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 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 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 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