File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / proc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>