Annotation of embedaddon/tmux/proc.c, revision 1.1.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>