proc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
  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 MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/uio.h>
  19. #include <sys/utsname.h>
  20. #include <errno.h>
  21. #include <event.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include "tmux.h"
  26. struct tmuxproc {
  27. const char *name;
  28. int exit;
  29. void (*signalcb)(int);
  30. };
  31. struct tmuxpeer {
  32. struct tmuxproc *parent;
  33. struct imsgbuf ibuf;
  34. struct event event;
  35. int flags;
  36. #define PEER_BAD 0x1
  37. void (*dispatchcb)(struct imsg *, void *);
  38. void *arg;
  39. };
  40. static int peer_check_version(struct tmuxpeer *, struct imsg *);
  41. static void proc_update_event(struct tmuxpeer *);
  42. static void
  43. proc_event_cb(__unused int fd, short events, void *arg)
  44. {
  45. struct tmuxpeer *peer = arg;
  46. ssize_t n;
  47. struct imsg imsg;
  48. if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
  49. if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
  50. n == 0) {
  51. peer->dispatchcb(NULL, peer->arg);
  52. return;
  53. }
  54. for (;;) {
  55. if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
  56. peer->dispatchcb(NULL, peer->arg);
  57. return;
  58. }
  59. if (n == 0)
  60. break;
  61. log_debug("peer %p message %d", peer, imsg.hdr.type);
  62. if (peer_check_version(peer, &imsg) != 0) {
  63. if (imsg.fd != -1)
  64. close(imsg.fd);
  65. imsg_free(&imsg);
  66. break;
  67. }
  68. peer->dispatchcb(&imsg, peer->arg);
  69. imsg_free(&imsg);
  70. }
  71. }
  72. if (events & EV_WRITE) {
  73. if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
  74. peer->dispatchcb(NULL, peer->arg);
  75. return;
  76. }
  77. }
  78. if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
  79. peer->dispatchcb(NULL, peer->arg);
  80. return;
  81. }
  82. proc_update_event(peer);
  83. }
  84. static void
  85. proc_signal_cb(int signo, __unused short events, void *arg)
  86. {
  87. struct tmuxproc *tp = arg;
  88. tp->signalcb(signo);
  89. }
  90. static int
  91. peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
  92. {
  93. int version;
  94. version = imsg->hdr.peerid & 0xff;
  95. if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
  96. log_debug("peer %p bad version %d", peer, version);
  97. proc_send(peer, MSG_VERSION, -1, NULL, 0);
  98. peer->flags |= PEER_BAD;
  99. return (-1);
  100. }
  101. return (0);
  102. }
  103. static void
  104. proc_update_event(struct tmuxpeer *peer)
  105. {
  106. short events;
  107. event_del(&peer->event);
  108. events = EV_READ;
  109. if (peer->ibuf.w.queued > 0)
  110. events |= EV_WRITE;
  111. event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
  112. event_add(&peer->event, NULL);
  113. }
  114. int
  115. proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
  116. size_t len)
  117. {
  118. struct imsgbuf *ibuf = &peer->ibuf;
  119. void *vp = (void *)buf;
  120. int retval;
  121. if (peer->flags & PEER_BAD)
  122. return (-1);
  123. log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
  124. retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
  125. if (retval != 1)
  126. return (-1);
  127. proc_update_event(peer);
  128. return (0);
  129. }
  130. int
  131. proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
  132. {
  133. return (proc_send(peer, type, -1, s, strlen(s) + 1));
  134. }
  135. struct tmuxproc *
  136. proc_start(const char *name, struct event_base *base, int forkflag,
  137. void (*signalcb)(int))
  138. {
  139. struct tmuxproc *tp;
  140. struct utsname u;
  141. if (forkflag) {
  142. switch (fork()) {
  143. case -1:
  144. fatal("fork failed");
  145. case 0:
  146. break;
  147. default:
  148. return (NULL);
  149. }
  150. if (daemon(1, 0) != 0)
  151. fatal("daemon failed");
  152. clear_signals(0);
  153. if (event_reinit(base) != 0)
  154. fatalx("event_reinit failed");
  155. }
  156. log_open(name);
  157. #ifdef HAVE_SETPROCTITLE
  158. setproctitle("%s (%s)", name, socket_path);
  159. #endif
  160. if (uname(&u) < 0)
  161. memset(&u, 0, sizeof u);
  162. log_debug("%s started (%ld): socket %s, protocol %d", name,
  163. (long)getpid(), socket_path, PROTOCOL_VERSION);
  164. log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
  165. u.version, event_get_version(), event_get_method());
  166. tp = xcalloc(1, sizeof *tp);
  167. tp->name = xstrdup(name);
  168. tp->signalcb = signalcb;
  169. set_signals(proc_signal_cb, tp);
  170. return (tp);
  171. }
  172. void
  173. proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
  174. {
  175. log_debug("%s loop enter", tp->name);
  176. do
  177. event_loop(EVLOOP_ONCE);
  178. while (!tp->exit && (loopcb == NULL || !loopcb ()));
  179. log_debug("%s loop exit", tp->name);
  180. }
  181. void
  182. proc_exit(struct tmuxproc *tp)
  183. {
  184. tp->exit = 1;
  185. }
  186. struct tmuxpeer *
  187. proc_add_peer(struct tmuxproc *tp, int fd,
  188. void (*dispatchcb)(struct imsg *, void *), void *arg)
  189. {
  190. struct tmuxpeer *peer;
  191. peer = xcalloc(1, sizeof *peer);
  192. peer->parent = tp;
  193. peer->dispatchcb = dispatchcb;
  194. peer->arg = arg;
  195. imsg_init(&peer->ibuf, fd);
  196. event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
  197. log_debug("add peer %p: %d (%p)", peer, fd, arg);
  198. proc_update_event(peer);
  199. return (peer);
  200. }
  201. void
  202. proc_remove_peer(struct tmuxpeer *peer)
  203. {
  204. log_debug("remove peer %p", peer);
  205. event_del(&peer->event);
  206. imsg_clear(&peer->ibuf);
  207. close(peer->ibuf.fd);
  208. free(peer);
  209. }
  210. void
  211. proc_kill_peer(struct tmuxpeer *peer)
  212. {
  213. peer->flags |= PEER_BAD;
  214. }