Annotation of embedaddon/tmux/proc.c, revision 1.1
1.1 ! misho 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
! 15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
! 16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include <sys/types.h>
! 20: #include <sys/uio.h>
! 21: #include <sys/utsname.h>
! 22:
! 23: #include <errno.h>
! 24: #include <event.h>
! 25: #include <stdlib.h>
! 26: #include <string.h>
! 27: #include <unistd.h>
! 28:
! 29: #include "tmux.h"
! 30:
! 31: struct tmuxproc {
! 32: const char *name;
! 33: int exit;
! 34:
! 35: void (*signalcb)(int);
! 36: };
! 37:
! 38: struct tmuxpeer {
! 39: struct tmuxproc *parent;
! 40:
! 41: struct imsgbuf ibuf;
! 42: struct event event;
! 43:
! 44: int flags;
! 45: #define PEER_BAD 0x1
! 46:
! 47: void (*dispatchcb)(struct imsg *, void *);
! 48: void *arg;
! 49: };
! 50:
! 51: static int peer_check_version(struct tmuxpeer *, struct imsg *);
! 52: static void proc_update_event(struct tmuxpeer *);
! 53:
! 54: static void
! 55: proc_event_cb(__unused int fd, short events, void *arg)
! 56: {
! 57: struct tmuxpeer *peer = arg;
! 58: ssize_t n;
! 59: struct imsg imsg;
! 60:
! 61: if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
! 62: if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
! 63: n == 0) {
! 64: peer->dispatchcb(NULL, peer->arg);
! 65: return;
! 66: }
! 67: for (;;) {
! 68: if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
! 69: peer->dispatchcb(NULL, peer->arg);
! 70: return;
! 71: }
! 72: if (n == 0)
! 73: break;
! 74: log_debug("peer %p message %d", peer, imsg.hdr.type);
! 75:
! 76: if (peer_check_version(peer, &imsg) != 0) {
! 77: if (imsg.fd != -1)
! 78: close(imsg.fd);
! 79: imsg_free(&imsg);
! 80: break;
! 81: }
! 82:
! 83: peer->dispatchcb(&imsg, peer->arg);
! 84: imsg_free(&imsg);
! 85: }
! 86: }
! 87:
! 88: if (events & EV_WRITE) {
! 89: if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
! 90: peer->dispatchcb(NULL, peer->arg);
! 91: return;
! 92: }
! 93: }
! 94:
! 95: if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
! 96: peer->dispatchcb(NULL, peer->arg);
! 97: return;
! 98: }
! 99:
! 100: proc_update_event(peer);
! 101: }
! 102:
! 103: static void
! 104: proc_signal_cb(int signo, __unused short events, void *arg)
! 105: {
! 106: struct tmuxproc *tp = arg;
! 107:
! 108: tp->signalcb(signo);
! 109: }
! 110:
! 111: static int
! 112: peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
! 113: {
! 114: int version;
! 115:
! 116: version = imsg->hdr.peerid & 0xff;
! 117: if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
! 118: log_debug("peer %p bad version %d", peer, version);
! 119:
! 120: proc_send(peer, MSG_VERSION, -1, NULL, 0);
! 121: peer->flags |= PEER_BAD;
! 122:
! 123: return (-1);
! 124: }
! 125: return (0);
! 126: }
! 127:
! 128: static void
! 129: proc_update_event(struct tmuxpeer *peer)
! 130: {
! 131: short events;
! 132:
! 133: event_del(&peer->event);
! 134:
! 135: events = EV_READ;
! 136: if (peer->ibuf.w.queued > 0)
! 137: events |= EV_WRITE;
! 138: event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
! 139:
! 140: event_add(&peer->event, NULL);
! 141: }
! 142:
! 143: int
! 144: proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
! 145: size_t len)
! 146: {
! 147: struct imsgbuf *ibuf = &peer->ibuf;
! 148: void *vp = (void *)buf;
! 149: int retval;
! 150:
! 151: if (peer->flags & PEER_BAD)
! 152: return (-1);
! 153: log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
! 154:
! 155: retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
! 156: if (retval != 1)
! 157: return (-1);
! 158: proc_update_event(peer);
! 159: return (0);
! 160: }
! 161:
! 162: int
! 163: proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
! 164: {
! 165: return (proc_send(peer, type, -1, s, strlen(s) + 1));
! 166: }
! 167:
! 168: struct tmuxproc *
! 169: proc_start(const char *name, struct event_base *base, int forkflag,
! 170: void (*signalcb)(int))
! 171: {
! 172: struct tmuxproc *tp;
! 173: struct utsname u;
! 174:
! 175: if (forkflag) {
! 176: switch (fork()) {
! 177: case -1:
! 178: fatal("fork failed");
! 179: case 0:
! 180: break;
! 181: default:
! 182: return (NULL);
! 183: }
! 184: if (daemon(1, 0) != 0)
! 185: fatal("daemon failed");
! 186:
! 187: clear_signals(0);
! 188: if (event_reinit(base) != 0)
! 189: fatalx("event_reinit failed");
! 190: }
! 191:
! 192: log_open(name);
! 193: setproctitle("%s (%s)", name, socket_path);
! 194:
! 195: if (uname(&u) < 0)
! 196: memset(&u, 0, sizeof u);
! 197:
! 198: log_debug("%s started (%ld): version %s, socket %s, protocol %d", name,
! 199: (long)getpid(), VERSION, socket_path, PROTOCOL_VERSION);
! 200: log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
! 201: u.version, event_get_version(), event_get_method());
! 202:
! 203: tp = xcalloc(1, sizeof *tp);
! 204: tp->name = xstrdup(name);
! 205:
! 206: tp->signalcb = signalcb;
! 207: set_signals(proc_signal_cb, tp);
! 208:
! 209: return (tp);
! 210: }
! 211:
! 212: void
! 213: proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
! 214: {
! 215: log_debug("%s loop enter", tp->name);
! 216: do
! 217: event_loop(EVLOOP_ONCE);
! 218: while (!tp->exit && (loopcb == NULL || !loopcb ()));
! 219: log_debug("%s loop exit", tp->name);
! 220: }
! 221:
! 222: void
! 223: proc_exit(struct tmuxproc *tp)
! 224: {
! 225: tp->exit = 1;
! 226: }
! 227:
! 228: struct tmuxpeer *
! 229: proc_add_peer(struct tmuxproc *tp, int fd,
! 230: void (*dispatchcb)(struct imsg *, void *), void *arg)
! 231: {
! 232: struct tmuxpeer *peer;
! 233:
! 234: peer = xcalloc(1, sizeof *peer);
! 235: peer->parent = tp;
! 236:
! 237: peer->dispatchcb = dispatchcb;
! 238: peer->arg = arg;
! 239:
! 240: imsg_init(&peer->ibuf, fd);
! 241: event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
! 242:
! 243: log_debug("add peer %p: %d (%p)", peer, fd, arg);
! 244:
! 245: proc_update_event(peer);
! 246: return (peer);
! 247: }
! 248:
! 249: void
! 250: proc_remove_peer(struct tmuxpeer *peer)
! 251: {
! 252: log_debug("remove peer %p", peer);
! 253:
! 254: event_del(&peer->event);
! 255: imsg_clear(&peer->ibuf);
! 256:
! 257: close(peer->ibuf.fd);
! 258: free(peer);
! 259: }
! 260:
! 261: void
! 262: proc_kill_peer(struct tmuxpeer *peer)
! 263: {
! 264: peer->flags |= PEER_BAD;
! 265: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>