Merge branch 'obsd-master'
[tmux.git] / compat / imsg-buffer.c
blob9aed0ed342062a7ce5066ac379638ca8b6cb7f8a
1 /* $OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $ */
3 /*
4 * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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.
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.
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/uio.h>
23 #include <arpa/inet.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
32 #include "compat.h"
33 #include "imsg.h"
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
48 static int ibuf_realloc(struct ibuf *, size_t);
49 static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
50 static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
51 static void msgbuf_drain(struct msgbuf *, size_t);
53 struct ibuf *
54 ibuf_open(size_t len)
56 struct ibuf *buf;
58 if (len == 0) {
59 errno = EINVAL;
60 return (NULL);
62 if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
63 return (NULL);
64 if ((buf->buf = calloc(len, 1)) == NULL) {
65 free(buf);
66 return (NULL);
68 buf->size = buf->max = len;
69 buf->fd = -1;
71 return (buf);
74 struct ibuf *
75 ibuf_dynamic(size_t len, size_t max)
77 struct ibuf *buf;
79 if (max == 0 || max < len) {
80 errno = EINVAL;
81 return (NULL);
84 if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
85 return (NULL);
86 if (len > 0) {
87 if ((buf->buf = calloc(len, 1)) == NULL) {
88 free(buf);
89 return (NULL);
92 buf->size = len;
93 buf->max = max;
94 buf->fd = -1;
96 return (buf);
99 static int
100 ibuf_realloc(struct ibuf *buf, size_t len)
102 unsigned char *b;
104 /* on static buffers max is eq size and so the following fails */
105 if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
106 errno = ERANGE;
107 return (-1);
110 b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
111 if (b == NULL)
112 return (-1);
113 buf->buf = b;
114 buf->size = buf->wpos + len;
116 return (0);
119 void *
120 ibuf_reserve(struct ibuf *buf, size_t len)
122 void *b;
124 if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
125 errno = ERANGE;
126 return (NULL);
129 if (buf->wpos + len > buf->size)
130 if (ibuf_realloc(buf, len) == -1)
131 return (NULL);
133 b = buf->buf + buf->wpos;
134 buf->wpos += len;
135 return (b);
139 ibuf_add(struct ibuf *buf, const void *data, size_t len)
141 void *b;
143 if ((b = ibuf_reserve(buf, len)) == NULL)
144 return (-1);
146 memcpy(b, data, len);
147 return (0);
151 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
153 return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
156 /* remove after tree is converted */
158 ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
160 return ibuf_add_ibuf(buf, from);
164 ibuf_add_n8(struct ibuf *buf, uint64_t value)
166 uint8_t v;
168 if (value > UINT8_MAX) {
169 errno = EINVAL;
170 return (-1);
172 v = value;
173 return ibuf_add(buf, &v, sizeof(v));
177 ibuf_add_n16(struct ibuf *buf, uint64_t value)
179 uint16_t v;
181 if (value > UINT16_MAX) {
182 errno = EINVAL;
183 return (-1);
185 v = htobe16(value);
186 return ibuf_add(buf, &v, sizeof(v));
190 ibuf_add_n32(struct ibuf *buf, uint64_t value)
192 uint32_t v;
194 if (value > UINT32_MAX) {
195 errno = EINVAL;
196 return (-1);
198 v = htobe32(value);
199 return ibuf_add(buf, &v, sizeof(v));
203 ibuf_add_n64(struct ibuf *buf, uint64_t value)
205 value = htobe64(value);
206 return ibuf_add(buf, &value, sizeof(value));
210 ibuf_add_h16(struct ibuf *buf, uint64_t value)
212 uint16_t v;
214 if (value > UINT16_MAX) {
215 errno = EINVAL;
216 return (-1);
218 v = value;
219 return ibuf_add(buf, &v, sizeof(v));
223 ibuf_add_h32(struct ibuf *buf, uint64_t value)
225 uint32_t v;
227 if (value > UINT32_MAX) {
228 errno = EINVAL;
229 return (-1);
231 v = value;
232 return ibuf_add(buf, &v, sizeof(v));
236 ibuf_add_h64(struct ibuf *buf, uint64_t value)
238 return ibuf_add(buf, &value, sizeof(value));
242 ibuf_add_zero(struct ibuf *buf, size_t len)
244 void *b;
246 if ((b = ibuf_reserve(buf, len)) == NULL)
247 return (-1);
248 memset(b, 0, len);
249 return (0);
252 void *
253 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
255 /* only allow seeking between rpos and wpos */
256 if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
257 ibuf_size(buf) < pos + len) {
258 errno = ERANGE;
259 return (NULL);
262 return (buf->buf + buf->rpos + pos);
266 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
268 void *b;
270 if ((b = ibuf_seek(buf, pos, len)) == NULL)
271 return (-1);
273 memcpy(b, data, len);
274 return (0);
278 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
280 uint8_t v;
282 if (value > UINT8_MAX) {
283 errno = EINVAL;
284 return (-1);
286 v = value;
287 return (ibuf_set(buf, pos, &v, sizeof(v)));
291 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
293 uint16_t v;
295 if (value > UINT16_MAX) {
296 errno = EINVAL;
297 return (-1);
299 v = htobe16(value);
300 return (ibuf_set(buf, pos, &v, sizeof(v)));
304 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
306 uint32_t v;
308 if (value > UINT32_MAX) {
309 errno = EINVAL;
310 return (-1);
312 v = htobe32(value);
313 return (ibuf_set(buf, pos, &v, sizeof(v)));
317 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
319 value = htobe64(value);
320 return (ibuf_set(buf, pos, &value, sizeof(value)));
324 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
326 uint16_t v;
328 if (value > UINT16_MAX) {
329 errno = EINVAL;
330 return (-1);
332 v = value;
333 return (ibuf_set(buf, pos, &v, sizeof(v)));
337 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
339 uint32_t v;
341 if (value > UINT32_MAX) {
342 errno = EINVAL;
343 return (-1);
345 v = value;
346 return (ibuf_set(buf, pos, &v, sizeof(v)));
350 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
352 return (ibuf_set(buf, pos, &value, sizeof(value)));
355 void *
356 ibuf_data(const struct ibuf *buf)
358 return (buf->buf + buf->rpos);
361 size_t
362 ibuf_size(const struct ibuf *buf)
364 return (buf->wpos - buf->rpos);
367 size_t
368 ibuf_left(const struct ibuf *buf)
370 if (buf->max == 0)
371 return (0);
372 return (buf->max - buf->wpos);
376 ibuf_truncate(struct ibuf *buf, size_t len)
378 if (ibuf_size(buf) >= len) {
379 buf->wpos = buf->rpos + len;
380 return (0);
382 if (buf->max == 0) {
383 /* only allow to truncate down */
384 errno = ERANGE;
385 return (-1);
387 return ibuf_add_zero(buf, len - ibuf_size(buf));
390 void
391 ibuf_rewind(struct ibuf *buf)
393 buf->rpos = 0;
396 void
397 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
399 ibuf_enqueue(msgbuf, buf);
402 void
403 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
405 memset(buf, 0, sizeof(*buf));
406 buf->buf = data;
407 buf->size = buf->wpos = len;
408 buf->fd = -1;
411 void
412 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
414 ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
418 ibuf_get(struct ibuf *buf, void *data, size_t len)
420 if (ibuf_size(buf) < len) {
421 errno = EBADMSG;
422 return (-1);
425 memcpy(data, ibuf_data(buf), len);
426 buf->rpos += len;
427 return (0);
431 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
433 if (ibuf_size(buf) < len) {
434 errno = EBADMSG;
435 return (-1);
438 ibuf_from_buffer(new, ibuf_data(buf), len);
439 buf->rpos += len;
440 return (0);
444 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
446 return ibuf_get(buf, value, sizeof(*value));
450 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
452 int rv;
454 rv = ibuf_get(buf, value, sizeof(*value));
455 *value = be16toh(*value);
456 return (rv);
460 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
462 int rv;
464 rv = ibuf_get(buf, value, sizeof(*value));
465 *value = be32toh(*value);
466 return (rv);
470 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
472 int rv;
474 rv = ibuf_get(buf, value, sizeof(*value));
475 *value = be64toh(*value);
476 return (rv);
480 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
482 return ibuf_get(buf, value, sizeof(*value));
486 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
488 return ibuf_get(buf, value, sizeof(*value));
492 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
494 return ibuf_get(buf, value, sizeof(*value));
498 ibuf_skip(struct ibuf *buf, size_t len)
500 if (ibuf_size(buf) < len) {
501 errno = EBADMSG;
502 return (-1);
505 buf->rpos += len;
506 return (0);
509 void
510 ibuf_free(struct ibuf *buf)
512 if (buf == NULL)
513 return;
514 if (buf->max == 0) /* if buf lives on the stack */
515 abort(); /* abort before causing more harm */
516 if (buf->fd != -1)
517 close(buf->fd);
518 freezero(buf->buf, buf->size);
519 free(buf);
523 ibuf_fd_avail(struct ibuf *buf)
525 return (buf->fd != -1);
529 ibuf_fd_get(struct ibuf *buf)
531 int fd;
533 fd = buf->fd;
534 buf->fd = -1;
535 return (fd);
538 void
539 ibuf_fd_set(struct ibuf *buf, int fd)
541 if (buf->max == 0) /* if buf lives on the stack */
542 abort(); /* abort before causing more harm */
543 if (buf->fd != -1)
544 close(buf->fd);
545 buf->fd = fd;
549 ibuf_write(struct msgbuf *msgbuf)
551 struct iovec iov[IOV_MAX];
552 struct ibuf *buf;
553 unsigned int i = 0;
554 ssize_t n;
556 memset(&iov, 0, sizeof(iov));
557 TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
558 if (i >= IOV_MAX)
559 break;
560 iov[i].iov_base = ibuf_data(buf);
561 iov[i].iov_len = ibuf_size(buf);
562 i++;
565 again:
566 if ((n = writev(msgbuf->fd, iov, i)) == -1) {
567 if (errno == EINTR)
568 goto again;
569 if (errno == ENOBUFS)
570 errno = EAGAIN;
571 return (-1);
574 if (n == 0) { /* connection closed */
575 errno = 0;
576 return (0);
579 msgbuf_drain(msgbuf, n);
581 return (1);
584 void
585 msgbuf_init(struct msgbuf *msgbuf)
587 msgbuf->queued = 0;
588 msgbuf->fd = -1;
589 TAILQ_INIT(&msgbuf->bufs);
592 static void
593 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
595 struct ibuf *buf, *next;
597 for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
598 buf = next) {
599 next = TAILQ_NEXT(buf, entry);
600 if (n >= ibuf_size(buf)) {
601 n -= ibuf_size(buf);
602 ibuf_dequeue(msgbuf, buf);
603 } else {
604 buf->rpos += n;
605 n = 0;
610 void
611 msgbuf_clear(struct msgbuf *msgbuf)
613 struct ibuf *buf;
615 while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
616 ibuf_dequeue(msgbuf, buf);
620 msgbuf_write(struct msgbuf *msgbuf)
622 struct iovec iov[IOV_MAX];
623 struct ibuf *buf, *buf0 = NULL;
624 unsigned int i = 0;
625 ssize_t n;
626 struct msghdr msg;
627 struct cmsghdr *cmsg;
628 union {
629 struct cmsghdr hdr;
630 char buf[CMSG_SPACE(sizeof(int))];
631 } cmsgbuf;
633 memset(&iov, 0, sizeof(iov));
634 memset(&msg, 0, sizeof(msg));
635 memset(&cmsgbuf, 0, sizeof(cmsgbuf));
636 TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
637 if (i >= IOV_MAX)
638 break;
639 if (i > 0 && buf->fd != -1)
640 break;
641 iov[i].iov_base = ibuf_data(buf);
642 iov[i].iov_len = ibuf_size(buf);
643 i++;
644 if (buf->fd != -1)
645 buf0 = buf;
648 msg.msg_iov = iov;
649 msg.msg_iovlen = i;
651 if (buf0 != NULL) {
652 msg.msg_control = (caddr_t)&cmsgbuf.buf;
653 msg.msg_controllen = sizeof(cmsgbuf.buf);
654 cmsg = CMSG_FIRSTHDR(&msg);
655 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
656 cmsg->cmsg_level = SOL_SOCKET;
657 cmsg->cmsg_type = SCM_RIGHTS;
658 *(int *)CMSG_DATA(cmsg) = buf0->fd;
661 again:
662 if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
663 if (errno == EINTR)
664 goto again;
665 if (errno == ENOBUFS)
666 errno = EAGAIN;
667 return (-1);
670 if (n == 0) { /* connection closed */
671 errno = 0;
672 return (0);
676 * assumption: fd got sent if sendmsg sent anything
677 * this works because fds are passed one at a time
679 if (buf0 != NULL) {
680 close(buf0->fd);
681 buf0->fd = -1;
684 msgbuf_drain(msgbuf, n);
686 return (1);
689 uint32_t
690 msgbuf_queuelen(struct msgbuf *msgbuf)
692 return (msgbuf->queued);
695 static void
696 ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
698 if (buf->max == 0) /* if buf lives on the stack */
699 abort(); /* abort before causing more harm */
700 TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
701 msgbuf->queued++;
704 static void
705 ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
707 TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
708 msgbuf->queued--;
709 ibuf_free(buf);