Annotation of src/usr.bin/tmux/proc.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: proc.c,v 1.1 2015/10/27 13:23:24 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
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/queue.h>
21: #include <sys/uio.h>
22:
23: #include <errno.h>
24: #include <event.h>
25: #include <imsg.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29:
30: #include "tmux.h"
31:
32: struct tmuxproc {
33: const char *name;
34: int exit;
35:
36: void (*signalcb)(int);
37: };
38:
39: struct tmuxpeer {
40: struct tmuxproc *parent;
41:
42: struct imsgbuf ibuf;
43: struct event event;
44:
45: int flags;
46: #define PEER_BAD 0x1
47:
48: void (*dispatchcb)(struct imsg *, void *);
49: void *arg;
50: };
51:
1.2 ! nicm 52: static int peer_check_version(struct tmuxpeer *, struct imsg *);
! 53: static void proc_update_event(struct tmuxpeer *);
1.1 nicm 54:
55: static void
56: proc_event_cb(unused int fd, short events, void *arg)
57: {
58: struct tmuxpeer *peer = arg;
59: ssize_t n;
60: struct imsg imsg;
61:
62: if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
63: if ((n = imsg_read(&peer->ibuf)) == -1 || 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:
1.2 ! nicm 76: if (peer_check_version(peer, &imsg) != 0) {
1.1 nicm 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);
1.2 ! nicm 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: imsg->hdr.peerid >>= 8;
! 126: return (0);
1.1 nicm 127: }
128:
129: static void
130: proc_update_event(struct tmuxpeer *peer)
131: {
132: short events;
133:
134: event_del(&peer->event);
135:
136: events = EV_READ;
137: if (peer->ibuf.w.queued > 0)
138: events |= EV_WRITE;
139: event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
140:
141: event_add(&peer->event, NULL);
142: }
143:
144: int
145: proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
146: size_t len)
147: {
148: struct imsgbuf *ibuf = &peer->ibuf;
149: void *vp = (void *)buf;
150: int retval;
151:
152: if (peer->flags & PEER_BAD)
153: return (-1);
154: log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
155:
156: retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
157: if (retval != 1)
158: return (-1);
159: proc_update_event(peer);
160: return (0);
161: }
162:
163: int
164: proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
165: {
166: return (proc_send(peer, type, -1, s, strlen(s) + 1));
167: }
168:
169: struct tmuxproc *
170: proc_start(const char *name, struct event_base *base, int forkflag,
171: void (*signalcb)(int))
172: {
173: struct tmuxproc *tp;
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: logfile(name);
193: setproctitle("%s (%s)", name, socket_path);
194:
195: log_debug("%s started (%ld): socket %s, protocol %d", name,
196: (long)getpid(), socket_path, PROTOCOL_VERSION);
197:
198: tp = xcalloc(1, sizeof *tp);
199: tp->name = xstrdup(name);
200:
201: tp->signalcb = signalcb;
202: set_signals(proc_signal_cb, tp);
203:
204: return (tp);
205: }
206:
207: void
208: proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
209: {
210: log_debug("%s loop enter", tp->name);
211: do
212: event_loop(EVLOOP_ONCE);
213: while (!tp->exit && (loopcb == NULL || !loopcb ()));
214: log_debug("%s loop exit", tp->name);
215: }
216:
217: void
218: proc_exit(struct tmuxproc *tp)
219: {
220: tp->exit = 1;
221: }
222:
223: struct tmuxpeer *
224: proc_add_peer(struct tmuxproc *tp, int fd,
225: void (*dispatchcb)(struct imsg *, void *), void *arg)
226: {
227: struct tmuxpeer *peer;
228:
229: peer = xcalloc(1, sizeof *peer);
230: peer->parent = tp;
231:
232: peer->dispatchcb = dispatchcb;
233: peer->arg = arg;
234:
235: imsg_init(&peer->ibuf, fd);
236: event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
237:
238: log_debug("add peer %p: %d (%p)", peer, fd, arg);
239:
240: proc_update_event(peer);
241: return (peer);
242: }
243:
244: void
245: proc_remove_peer(struct tmuxpeer *peer)
246: {
247: log_debug("remove peer %p", peer);
248:
249: event_del(&peer->event);
250: imsg_clear(&peer->ibuf);
251:
252: close(peer->ibuf.fd);
253: free(peer);
254: }
255:
256: void
257: proc_kill_peer(struct tmuxpeer *peer)
258: {
259: peer->flags |= PEER_BAD;
260: }