imsg-buffer.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /* $OpenBSD: imsg-buffer.c,v 1.7 2015/07/12 18:40:49 nicm Exp $ */
  2. /*
  3. * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <sys/uio.h>
  20. #include <limits.h>
  21. #include <errno.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include "tmux.h"
  26. #include "imsg.h"
  27. int ibuf_realloc(struct ibuf *, size_t);
  28. void ibuf_enqueue(struct msgbuf *, struct ibuf *);
  29. void ibuf_dequeue(struct msgbuf *, struct ibuf *);
  30. struct ibuf *
  31. ibuf_open(size_t len)
  32. {
  33. struct ibuf *buf;
  34. if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
  35. return (NULL);
  36. if ((buf->buf = malloc(len)) == NULL) {
  37. free(buf);
  38. return (NULL);
  39. }
  40. buf->size = buf->max = len;
  41. buf->fd = -1;
  42. return (buf);
  43. }
  44. struct ibuf *
  45. ibuf_dynamic(size_t len, size_t max)
  46. {
  47. struct ibuf *buf;
  48. if (max < len)
  49. return (NULL);
  50. if ((buf = ibuf_open(len)) == NULL)
  51. return (NULL);
  52. if (max > 0)
  53. buf->max = max;
  54. return (buf);
  55. }
  56. int
  57. ibuf_realloc(struct ibuf *buf, size_t len)
  58. {
  59. u_char *b;
  60. /* on static buffers max is eq size and so the following fails */
  61. if (buf->wpos + len > buf->max) {
  62. errno = ERANGE;
  63. return (-1);
  64. }
  65. b = realloc(buf->buf, buf->wpos + len);
  66. if (b == NULL)
  67. return (-1);
  68. buf->buf = b;
  69. buf->size = buf->wpos + len;
  70. return (0);
  71. }
  72. int
  73. ibuf_add(struct ibuf *buf, const void *data, size_t len)
  74. {
  75. if (buf->wpos + len > buf->size)
  76. if (ibuf_realloc(buf, len) == -1)
  77. return (-1);
  78. memcpy(buf->buf + buf->wpos, data, len);
  79. buf->wpos += len;
  80. return (0);
  81. }
  82. void *
  83. ibuf_reserve(struct ibuf *buf, size_t len)
  84. {
  85. void *b;
  86. if (buf->wpos + len > buf->size)
  87. if (ibuf_realloc(buf, len) == -1)
  88. return (NULL);
  89. b = buf->buf + buf->wpos;
  90. buf->wpos += len;
  91. return (b);
  92. }
  93. void *
  94. ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
  95. {
  96. /* only allowed to seek in already written parts */
  97. if (pos + len > buf->wpos)
  98. return (NULL);
  99. return (buf->buf + pos);
  100. }
  101. size_t
  102. ibuf_size(struct ibuf *buf)
  103. {
  104. return (buf->wpos);
  105. }
  106. size_t
  107. ibuf_left(struct ibuf *buf)
  108. {
  109. return (buf->max - buf->wpos);
  110. }
  111. void
  112. ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
  113. {
  114. ibuf_enqueue(msgbuf, buf);
  115. }
  116. int
  117. ibuf_write(struct msgbuf *msgbuf)
  118. {
  119. struct iovec iov[IOV_MAX];
  120. struct ibuf *buf;
  121. unsigned int i = 0;
  122. ssize_t n;
  123. memset(&iov, 0, sizeof(iov));
  124. TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
  125. if (i >= IOV_MAX)
  126. break;
  127. iov[i].iov_base = buf->buf + buf->rpos;
  128. iov[i].iov_len = buf->wpos - buf->rpos;
  129. i++;
  130. }
  131. again:
  132. if ((n = writev(msgbuf->fd, iov, i)) == -1) {
  133. if (errno == EINTR)
  134. goto again;
  135. if (errno == ENOBUFS)
  136. errno = EAGAIN;
  137. return (-1);
  138. }
  139. if (n == 0) { /* connection closed */
  140. errno = 0;
  141. return (0);
  142. }
  143. msgbuf_drain(msgbuf, n);
  144. return (1);
  145. }
  146. void
  147. ibuf_free(struct ibuf *buf)
  148. {
  149. free(buf->buf);
  150. free(buf);
  151. }
  152. void
  153. msgbuf_init(struct msgbuf *msgbuf)
  154. {
  155. msgbuf->queued = 0;
  156. msgbuf->fd = -1;
  157. TAILQ_INIT(&msgbuf->bufs);
  158. }
  159. void
  160. msgbuf_drain(struct msgbuf *msgbuf, size_t n)
  161. {
  162. struct ibuf *buf, *next;
  163. for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
  164. buf = next) {
  165. next = TAILQ_NEXT(buf, entry);
  166. if (buf->rpos + n >= buf->wpos) {
  167. n -= buf->wpos - buf->rpos;
  168. ibuf_dequeue(msgbuf, buf);
  169. } else {
  170. buf->rpos += n;
  171. n = 0;
  172. }
  173. }
  174. }
  175. void
  176. msgbuf_clear(struct msgbuf *msgbuf)
  177. {
  178. struct ibuf *buf;
  179. while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
  180. ibuf_dequeue(msgbuf, buf);
  181. }
  182. int
  183. msgbuf_write(struct msgbuf *msgbuf)
  184. {
  185. struct iovec iov[IOV_MAX];
  186. struct ibuf *buf;
  187. unsigned int i = 0;
  188. ssize_t n;
  189. struct msghdr msg;
  190. struct cmsghdr *cmsg;
  191. union {
  192. struct cmsghdr hdr;
  193. char buf[CMSG_SPACE(sizeof(int))];
  194. } cmsgbuf;
  195. memset(&iov, 0, sizeof(iov));
  196. memset(&msg, 0, sizeof(msg));
  197. memset(&cmsgbuf, 0, sizeof(cmsgbuf));
  198. TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
  199. if (i >= IOV_MAX)
  200. break;
  201. iov[i].iov_base = buf->buf + buf->rpos;
  202. iov[i].iov_len = buf->wpos - buf->rpos;
  203. i++;
  204. if (buf->fd != -1)
  205. break;
  206. }
  207. msg.msg_iov = iov;
  208. msg.msg_iovlen = i;
  209. if (buf != NULL && buf->fd != -1) {
  210. msg.msg_control = (caddr_t)&cmsgbuf.buf;
  211. msg.msg_controllen = sizeof(cmsgbuf.buf);
  212. cmsg = CMSG_FIRSTHDR(&msg);
  213. cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  214. cmsg->cmsg_level = SOL_SOCKET;
  215. cmsg->cmsg_type = SCM_RIGHTS;
  216. *(int *)CMSG_DATA(cmsg) = buf->fd;
  217. }
  218. again:
  219. if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
  220. if (errno == EINTR)
  221. goto again;
  222. if (errno == ENOBUFS)
  223. errno = EAGAIN;
  224. return (-1);
  225. }
  226. if (n == 0) { /* connection closed */
  227. errno = 0;
  228. return (0);
  229. }
  230. /*
  231. * assumption: fd got sent if sendmsg sent anything
  232. * this works because fds are passed one at a time
  233. */
  234. if (buf != NULL && buf->fd != -1) {
  235. close(buf->fd);
  236. buf->fd = -1;
  237. }
  238. msgbuf_drain(msgbuf, n);
  239. return (1);
  240. }
  241. void
  242. ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
  243. {
  244. TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
  245. msgbuf->queued++;
  246. }
  247. void
  248. ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
  249. {
  250. TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
  251. if (buf->fd != -1)
  252. close(buf->fd);
  253. msgbuf->queued--;
  254. ibuf_free(buf);
  255. }