1*929d2bb2Sclaudio /* $OpenBSD: io.c,v 1.27 2024/11/26 13:59:09 claudio Exp $ */ 29a7e9e7fSjob /* 3a945dbeeSclaudio * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> 49a7e9e7fSjob * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 59a7e9e7fSjob * 69a7e9e7fSjob * Permission to use, copy, modify, and distribute this software for any 79a7e9e7fSjob * purpose with or without fee is hereby granted, provided that the above 89a7e9e7fSjob * copyright notice and this permission notice appear in all copies. 99a7e9e7fSjob * 109a7e9e7fSjob * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 119a7e9e7fSjob * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 129a7e9e7fSjob * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 139a7e9e7fSjob * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 149a7e9e7fSjob * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 159a7e9e7fSjob * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 169a7e9e7fSjob * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 179a7e9e7fSjob */ 189a7e9e7fSjob 199a7e9e7fSjob #include <sys/queue.h> 201ef5b48aSclaudio #include <sys/socket.h> 219a7e9e7fSjob 229a7e9e7fSjob #include <err.h> 231ef5b48aSclaudio #include <errno.h> 249a7e9e7fSjob #include <fcntl.h> 259a7e9e7fSjob #include <stdint.h> 269a7e9e7fSjob #include <stdlib.h> 279a7e9e7fSjob #include <string.h> 289a7e9e7fSjob #include <unistd.h> 2908db1177Sclaudio #include <imsg.h> 309a7e9e7fSjob 319a7e9e7fSjob #include "extern.h" 329a7e9e7fSjob 33*929d2bb2Sclaudio #define IO_FD_MARK 0x80000000U 34*929d2bb2Sclaudio 359a7e9e7fSjob /* 362defcb52Sclaudio * Create new io buffer, call io_close() when done with it. 372defcb52Sclaudio * Function always returns a new buffer. 382defcb52Sclaudio */ 392defcb52Sclaudio struct ibuf * 4025f7afeeSclaudio io_new_buffer(void) 412defcb52Sclaudio { 422defcb52Sclaudio struct ibuf *b; 432defcb52Sclaudio 44b5fa5d51Sclaudio if ((b = ibuf_dynamic(64, MAX_MSG_SIZE)) == NULL) 452defcb52Sclaudio err(1, NULL); 46cf954fffSclaudio ibuf_add_zero(b, sizeof(size_t)); /* can not fail */ 472defcb52Sclaudio return b; 482defcb52Sclaudio } 492defcb52Sclaudio 502defcb52Sclaudio /* 512defcb52Sclaudio * Add a simple object of static size to the io buffer. 529a7e9e7fSjob */ 539a7e9e7fSjob void 5408db1177Sclaudio io_simple_buffer(struct ibuf *b, const void *res, size_t sz) 559a7e9e7fSjob { 5608db1177Sclaudio if (ibuf_add(b, res, sz) == -1) 57498a9228Sbenno err(1, NULL); 589a7e9e7fSjob } 599a7e9e7fSjob 609a7e9e7fSjob /* 6108db1177Sclaudio * Add a sz sized buffer into the io buffer. 629a7e9e7fSjob */ 639a7e9e7fSjob void 6408db1177Sclaudio io_buf_buffer(struct ibuf *b, const void *p, size_t sz) 659a7e9e7fSjob { 6608db1177Sclaudio if (ibuf_add(b, &sz, sizeof(size_t)) == -1) 6708db1177Sclaudio err(1, NULL); 689a7e9e7fSjob if (sz > 0) 6908db1177Sclaudio if (ibuf_add(b, p, sz) == -1) 7008db1177Sclaudio err(1, NULL); 719a7e9e7fSjob } 729a7e9e7fSjob 739a7e9e7fSjob /* 7408db1177Sclaudio * Add a string into the io buffer. 759a7e9e7fSjob */ 769a7e9e7fSjob void 7708db1177Sclaudio io_str_buffer(struct ibuf *b, const char *p) 789a7e9e7fSjob { 799a7e9e7fSjob size_t sz = (p == NULL) ? 0 : strlen(p); 809a7e9e7fSjob 8108db1177Sclaudio io_buf_buffer(b, p, sz); 829a7e9e7fSjob } 839a7e9e7fSjob 849a7e9e7fSjob /* 852defcb52Sclaudio * Finish and enqueue a io buffer. 862defcb52Sclaudio */ 872defcb52Sclaudio void 8825f7afeeSclaudio io_close_buffer(struct msgbuf *msgbuf, struct ibuf *b) 892defcb52Sclaudio { 902defcb52Sclaudio size_t len; 912defcb52Sclaudio 92b5fa5d51Sclaudio len = ibuf_size(b); 93*929d2bb2Sclaudio if (ibuf_fd_avail(b)) 94*929d2bb2Sclaudio len |= IO_FD_MARK; 95cf954fffSclaudio ibuf_set(b, 0, &len, sizeof(len)); 962defcb52Sclaudio ibuf_close(msgbuf, b); 972defcb52Sclaudio } 982defcb52Sclaudio 992defcb52Sclaudio /* 1007eb79a4aSclaudio * Read of an ibuf and extract sz byte from there. 1019a7e9e7fSjob * Does nothing if "sz" is zero. 1027eb79a4aSclaudio * Return 1 on success or 0 if there was not enough data. 1039a7e9e7fSjob */ 1049a7e9e7fSjob void 1057eb79a4aSclaudio io_read_buf(struct ibuf *b, void *res, size_t sz) 1069a7e9e7fSjob { 1079a7e9e7fSjob if (sz == 0) 1089a7e9e7fSjob return; 109edece116Sclaudio if (ibuf_get(b, res, sz) == -1) 110edece116Sclaudio err(1, "bad internal framing"); 1119a7e9e7fSjob } 1129a7e9e7fSjob 1139a7e9e7fSjob /* 11445a66391Sclaudio * Read a string (returns NULL for zero-length strings), allocating 1159a7e9e7fSjob * space for it. 1167eb79a4aSclaudio * Return 1 on success or 0 if there was not enough data. 1179a7e9e7fSjob */ 1189a7e9e7fSjob void 1197eb79a4aSclaudio io_read_str(struct ibuf *b, char **res) 1209a7e9e7fSjob { 1219a7e9e7fSjob size_t sz; 1229a7e9e7fSjob 1237eb79a4aSclaudio io_read_buf(b, &sz, sizeof(sz)); 12445a66391Sclaudio if (sz == 0) { 12545a66391Sclaudio *res = NULL; 12645a66391Sclaudio return; 12745a66391Sclaudio } 1289a7e9e7fSjob if ((*res = calloc(sz + 1, 1)) == NULL) 129498a9228Sbenno err(1, NULL); 1307eb79a4aSclaudio io_read_buf(b, *res, sz); 1319a7e9e7fSjob } 1321ef5b48aSclaudio 1331ef5b48aSclaudio /* 1347eb79a4aSclaudio * Read a binary buffer, allocating space for it. 1357eb79a4aSclaudio * If the buffer is zero-sized, this won't allocate "res", but 1367eb79a4aSclaudio * will still initialise it to NULL. 1377eb79a4aSclaudio * Return 1 on success or 0 if there was not enough data. 1387eb79a4aSclaudio */ 1397eb79a4aSclaudio void 1407eb79a4aSclaudio io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz) 1417eb79a4aSclaudio { 1427eb79a4aSclaudio *res = NULL; 1435ef05219Sjsg io_read_buf(b, sz, sizeof(*sz)); 1447eb79a4aSclaudio if (*sz == 0) 1457eb79a4aSclaudio return; 1467eb79a4aSclaudio if ((*res = malloc(*sz)) == NULL) 1477eb79a4aSclaudio err(1, NULL); 1487eb79a4aSclaudio io_read_buf(b, *res, *sz); 1497eb79a4aSclaudio } 1507eb79a4aSclaudio 151*929d2bb2Sclaudio struct ibuf * 152*929d2bb2Sclaudio io_parse_hdr(struct ibuf *buf, void *arg, int *fd) 1537eb79a4aSclaudio { 154*929d2bb2Sclaudio struct ibuf *b; 155*929d2bb2Sclaudio size_t len; 156*929d2bb2Sclaudio int hasfd = 0; 1577eb79a4aSclaudio 158*929d2bb2Sclaudio if (ibuf_get(buf, &len, sizeof(len)) == -1) 159*929d2bb2Sclaudio return NULL; 160*929d2bb2Sclaudio 161*929d2bb2Sclaudio if (len & IO_FD_MARK) { 162*929d2bb2Sclaudio hasfd = 1; 163*929d2bb2Sclaudio len &= ~IO_FD_MARK; 164b5fa5d51Sclaudio } 165*929d2bb2Sclaudio if (len <= sizeof(len) || len > MAX_MSG_SIZE) { 166*929d2bb2Sclaudio errno = ERANGE; 167*929d2bb2Sclaudio return NULL; 168*929d2bb2Sclaudio } 169*929d2bb2Sclaudio if ((b = ibuf_open(len)) == NULL) 170*929d2bb2Sclaudio return NULL; 171*929d2bb2Sclaudio if (hasfd) { 172*929d2bb2Sclaudio ibuf_fd_set(b, *fd); 173*929d2bb2Sclaudio *fd = -1; 174*929d2bb2Sclaudio } 175*929d2bb2Sclaudio return b; 1767eb79a4aSclaudio } 1777eb79a4aSclaudio 1787eb79a4aSclaudio struct ibuf * 179b5fa5d51Sclaudio io_buf_get(struct msgbuf *msgq) 1807eb79a4aSclaudio { 181b5fa5d51Sclaudio struct ibuf *b; 1827eb79a4aSclaudio 183b5fa5d51Sclaudio if ((b = msgbuf_get(msgq)) == NULL) 18497f73431Sclaudio return NULL; 1857eb79a4aSclaudio 186b5fa5d51Sclaudio ibuf_skip(b, sizeof(size_t)); 1877eb79a4aSclaudio return b; 1887eb79a4aSclaudio } 189