control.c revision 1.3
1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
5 * Copyright (c) 2012 George Nachman <tmux@georgester.com>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21
22#include <stdlib.h>
23#include <string.h>
24#include <time.h>
25#include <unistd.h>
26
27#include "tmux.h"
28
29/*
30 * Block of data to output. Each client has one "all" queue of blocks and
31 * another queue for each pane (in struct client_offset). %output blocks are
32 * added to both queues and other output lines (notifications) added only to
33 * the client queue.
34 *
35 * When a client becomes writeable, data from blocks on the pane queue are sent
36 * up to the maximum size (CLIENT_BUFFER_HIGH). If a block is entirely written,
37 * it is removed from both pane and client queues and if this means non-%output
38 * blocks are now at the head of the client queue, they are written.
39 *
40 * This means a %output block holds up any subsequent non-%output blocks until
41 * it is written which enforces ordering even if the client cannot accept the
42 * entire block in one go.
43 */
44struct control_block {
45	size_t				 size;
46	char				*line;
47	uint64_t			 t;
48
49	TAILQ_ENTRY(control_block)	 entry;
50	TAILQ_ENTRY(control_block)	 all_entry;
51};
52
53/* Control client pane. */
54struct control_pane {
55	u_int				 pane;
56
57	/*
58	 * Offsets into the pane data. The first (offset) is the data we have
59	 * written; the second (queued) the data we have queued (pointed to by
60	 * a block).
61	 */
62	struct window_pane_offset	 offset;
63	struct window_pane_offset	 queued;
64
65	int				 flags;
66#define CONTROL_PANE_OFF 0x1
67#define CONTROL_PANE_PAUSED 0x2
68
69	int				 pending_flag;
70	TAILQ_ENTRY(control_pane)	 pending_entry;
71
72	TAILQ_HEAD(, control_block)	 blocks;
73
74	RB_ENTRY(control_pane)		 entry;
75};
76RB_HEAD(control_panes, control_pane);
77
78/* Subscription pane. */
79struct control_sub_pane {
80	u_int				 pane;
81	u_int				 idx;
82	char				*last;
83
84	RB_ENTRY(control_sub_pane)	 entry;
85};
86RB_HEAD(control_sub_panes, control_sub_pane);
87
88/* Subscription window. */
89struct control_sub_window {
90	u_int				 window;
91	u_int				 idx;
92	char				*last;
93
94	RB_ENTRY(control_sub_window)	 entry;
95};
96RB_HEAD(control_sub_windows, control_sub_window);
97
98/* Control client subscription. */
99struct control_sub {
100	char				*name;
101	char				*format;
102
103	enum control_sub_type		 type;
104	u_int				 id;
105
106	char				*last;
107	struct control_sub_panes	 panes;
108	struct control_sub_windows	 windows;
109
110	RB_ENTRY(control_sub)		 entry;
111};
112RB_HEAD(control_subs, control_sub);
113
114/* Control client state. */
115struct control_state {
116	struct control_panes		 panes;
117
118	TAILQ_HEAD(, control_pane)	 pending_list;
119	u_int				 pending_count;
120
121	TAILQ_HEAD(, control_block)	 all_blocks;
122
123	struct bufferevent		*read_event;
124	struct bufferevent		*write_event;
125
126	struct control_subs		 subs;
127	struct event			 subs_timer;
128};
129
130/* Low and high watermarks. */
131#define CONTROL_BUFFER_LOW 512
132#define CONTROL_BUFFER_HIGH 8192
133
134/* Minimum to write to each client. */
135#define CONTROL_WRITE_MINIMUM 32
136
137/* Maximum age for clients that are not using pause mode. */
138#define CONTROL_MAXIMUM_AGE 300000
139
140/* Flags to ignore client. */
141#define CONTROL_IGNORE_FLAGS \
142	(CLIENT_CONTROL_NOOUTPUT| \
143	 CLIENT_UNATTACHEDFLAGS)
144
145/* Compare client panes. */
146static int
147control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
148{
149	if (cp1->pane < cp2->pane)
150		return (-1);
151	if (cp1->pane > cp2->pane)
152		return (1);
153	return (0);
154}
155RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
156
157/* Compare client subs. */
158static int
159control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2)
160{
161	return (strcmp(csub1->name, csub2->name));
162}
163RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp);
164
165/* Compare client subscription panes. */
166static int
167control_sub_pane_cmp(struct control_sub_pane *csp1,
168    struct control_sub_pane *csp2)
169{
170	if (csp1->pane < csp2->pane)
171		return (-1);
172	if (csp1->pane > csp2->pane)
173		return (1);
174	if (csp1->idx < csp2->idx)
175		return (-1);
176	if (csp1->idx > csp2->idx)
177		return (1);
178	return (0);
179}
180RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry,
181    control_sub_pane_cmp);
182
183/* Compare client subscription windows. */
184static int
185control_sub_window_cmp(struct control_sub_window *csw1,
186    struct control_sub_window *csw2)
187{
188	if (csw1->window < csw2->window)
189		return (-1);
190	if (csw1->window > csw2->window)
191		return (1);
192	if (csw1->idx < csw2->idx)
193		return (-1);
194	if (csw1->idx > csw2->idx)
195		return (1);
196	return (0);
197}
198RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry,
199    control_sub_window_cmp);
200
201/* Free a subscription. */
202static void
203control_free_sub(struct control_state *cs, struct control_sub *csub)
204{
205	struct control_sub_pane		*csp, *csp1;
206	struct control_sub_window	*csw, *csw1;
207
208	RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
209		RB_REMOVE(control_sub_panes, &csub->panes, csp);
210		free(csp);
211	}
212	RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
213		RB_REMOVE(control_sub_windows, &csub->windows, csw);
214		free(csw);
215	}
216	free(csub->last);
217
218	RB_REMOVE(control_subs, &cs->subs, csub);
219	free(csub->name);
220	free(csub->format);
221	free(csub);
222}
223
224/* Free a block. */
225static void
226control_free_block(struct control_state *cs, struct control_block *cb)
227{
228	free(cb->line);
229	TAILQ_REMOVE(&cs->all_blocks, cb, all_entry);
230	free(cb);
231}
232
233/* Get pane offsets for this client. */
234static struct control_pane *
235control_get_pane(struct client *c, struct window_pane *wp)
236{
237	struct control_state	*cs = c->control_state;
238	struct control_pane	 cp = { .pane = wp->id };
239
240	return (RB_FIND(control_panes, &cs->panes, &cp));
241}
242
243/* Add pane offsets for this client. */
244static struct control_pane *
245control_add_pane(struct client *c, struct window_pane *wp)
246{
247	struct control_state	*cs = c->control_state;
248	struct control_pane	*cp;
249
250	cp = control_get_pane(c, wp);
251	if (cp != NULL)
252		return (cp);
253
254	cp = xcalloc(1, sizeof *cp);
255	cp->pane = wp->id;
256	RB_INSERT(control_panes, &cs->panes, cp);
257
258	memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
259	memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
260	TAILQ_INIT(&cp->blocks);
261
262	return (cp);
263}
264
265/* Discard output for a pane. */
266static void
267control_discard_pane(struct client *c, struct control_pane *cp)
268{
269	struct control_state	*cs = c->control_state;
270	struct control_block	*cb, *cb1;
271
272	TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
273		TAILQ_REMOVE(&cp->blocks, cb, entry);
274		control_free_block(cs, cb);
275	}
276}
277
278/* Get actual pane for this client. */
279static struct window_pane *
280control_window_pane(struct client *c, u_int pane)
281{
282	struct window_pane	*wp;
283
284	if (c->session == NULL)
285		return (NULL);
286	if ((wp = window_pane_find_by_id(pane)) == NULL)
287		return (NULL);
288	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
289		return (NULL);
290	return (wp);
291}
292
293/* Reset control offsets. */
294void
295control_reset_offsets(struct client *c)
296{
297	struct control_state	*cs = c->control_state;
298	struct control_pane	*cp, *cp1;
299
300	RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
301		RB_REMOVE(control_panes, &cs->panes, cp);
302		free(cp);
303	}
304
305	TAILQ_INIT(&cs->pending_list);
306	cs->pending_count = 0;
307}
308
309/* Get offsets for client. */
310struct window_pane_offset *
311control_pane_offset(struct client *c, struct window_pane *wp, int *off)
312{
313	struct control_state	*cs = c->control_state;
314	struct control_pane	*cp;
315
316	if (c->flags & CLIENT_CONTROL_NOOUTPUT) {
317		*off = 0;
318		return (NULL);
319	}
320
321	cp = control_get_pane(c, wp);
322	if (cp == NULL || (cp->flags & CONTROL_PANE_PAUSED)) {
323		*off = 0;
324		return (NULL);
325	}
326	if (cp->flags & CONTROL_PANE_OFF) {
327		*off = 1;
328		return (NULL);
329	}
330	*off = (EVBUFFER_LENGTH(cs->write_event->output) >= CONTROL_BUFFER_LOW);
331	return (&cp->offset);
332}
333
334/* Set pane as on. */
335void
336control_set_pane_on(struct client *c, struct window_pane *wp)
337{
338	struct control_pane	*cp;
339
340	cp = control_get_pane(c, wp);
341	if (cp != NULL && (cp->flags & CONTROL_PANE_OFF)) {
342		cp->flags &= ~CONTROL_PANE_OFF;
343		memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
344		memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
345	}
346}
347
348/* Set pane as off. */
349void
350control_set_pane_off(struct client *c, struct window_pane *wp)
351{
352	struct control_pane	*cp;
353
354	cp = control_add_pane(c, wp);
355	cp->flags |= CONTROL_PANE_OFF;
356}
357
358/* Continue a paused pane. */
359void
360control_continue_pane(struct client *c, struct window_pane *wp)
361{
362	struct control_pane	*cp;
363
364	cp = control_get_pane(c, wp);
365	if (cp != NULL && (cp->flags & CONTROL_PANE_PAUSED)) {
366		cp->flags &= ~CONTROL_PANE_PAUSED;
367		memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
368		memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
369		control_write(c, "%%continue %%%u", wp->id);
370	}
371}
372
373/* Pause a pane. */
374void
375control_pause_pane(struct client *c, struct window_pane *wp)
376{
377	struct control_pane	*cp;
378
379	cp = control_add_pane(c, wp);
380	if (~cp->flags & CONTROL_PANE_PAUSED) {
381		cp->flags |= CONTROL_PANE_PAUSED;
382		control_discard_pane(c, cp);
383		control_write(c, "%%pause %%%u", wp->id);
384	}
385}
386
387/* Write a line. */
388static void __printflike(2, 0)
389control_vwrite(struct client *c, const char *fmt, va_list ap)
390{
391	struct control_state	*cs = c->control_state;
392	char			*s;
393
394	xvasprintf(&s, fmt, ap);
395	log_debug("%s: %s: writing line: %s", __func__, c->name, s);
396
397	bufferevent_write(cs->write_event, s, strlen(s));
398	bufferevent_write(cs->write_event, "\n", 1);
399
400	bufferevent_enable(cs->write_event, EV_WRITE);
401	free(s);
402}
403
404/* Write a line. */
405void
406control_write(struct client *c, const char *fmt, ...)
407{
408	struct control_state	*cs = c->control_state;
409	struct control_block	*cb;
410	va_list			 ap;
411
412	va_start(ap, fmt);
413
414	if (TAILQ_EMPTY(&cs->all_blocks)) {
415		control_vwrite(c, fmt, ap);
416		va_end(ap);
417		return;
418	}
419
420	cb = xcalloc(1, sizeof *cb);
421	xvasprintf(&cb->line, fmt, ap);
422	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
423	cb->t = get_timer();
424
425	log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
426	bufferevent_enable(cs->write_event, EV_WRITE);
427
428	va_end(ap);
429}
430
431/* Check age for this pane. */
432static int
433control_check_age(struct client *c, struct window_pane *wp,
434    struct control_pane *cp)
435{
436	struct control_block	*cb;
437	uint64_t		 t, age;
438
439	cb = TAILQ_FIRST(&cp->blocks);
440	if (cb == NULL)
441		return (0);
442	t = get_timer();
443	if (cb->t >= t)
444		return (0);
445
446	age = t - cb->t;
447	log_debug("%s: %s: %%%u is %llu behind", __func__, c->name, wp->id,
448	    (unsigned long long)age);
449
450	if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
451		if (age < c->pause_age)
452			return (0);
453		cp->flags |= CONTROL_PANE_PAUSED;
454		control_discard_pane(c, cp);
455		control_write(c, "%%pause %%%u", wp->id);
456	} else {
457		if (age < CONTROL_MAXIMUM_AGE)
458			return (0);
459		c->exit_message = xstrdup("too far behind");
460		c->flags |= CLIENT_EXIT;
461		control_discard(c);
462	}
463	return (1);
464}
465
466/* Write output from a pane. */
467void
468control_write_output(struct client *c, struct window_pane *wp)
469{
470	struct control_state	*cs = c->control_state;
471	struct control_pane	*cp;
472	struct control_block	*cb;
473	size_t			 new_size;
474
475	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
476		return;
477
478	if (c->flags & CONTROL_IGNORE_FLAGS) {
479		cp = control_get_pane(c, wp);
480		if (cp != NULL)
481			goto ignore;
482		return;
483	}
484	cp = control_add_pane(c, wp);
485	if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
486		goto ignore;
487	if (control_check_age(c, wp, cp))
488		return;
489
490	window_pane_get_new_data(wp, &cp->queued, &new_size);
491	if (new_size == 0)
492		return;
493	window_pane_update_used_data(wp, &cp->queued, new_size);
494
495	cb = xcalloc(1, sizeof *cb);
496	cb->size = new_size;
497	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
498	cb->t = get_timer();
499
500	TAILQ_INSERT_TAIL(&cp->blocks, cb, entry);
501	log_debug("%s: %s: new output block of %zu for %%%u", __func__, c->name,
502	    cb->size, wp->id);
503
504	if (!cp->pending_flag) {
505		log_debug("%s: %s: %%%u now pending", __func__, c->name,
506		    wp->id);
507		TAILQ_INSERT_TAIL(&cs->pending_list, cp, pending_entry);
508		cp->pending_flag = 1;
509		cs->pending_count++;
510	}
511	bufferevent_enable(cs->write_event, EV_WRITE);
512	return;
513
514ignore:
515	log_debug("%s: %s: ignoring pane %%%u", __func__, c->name, wp->id);
516	window_pane_update_used_data(wp, &cp->offset, SIZE_MAX);
517	window_pane_update_used_data(wp, &cp->queued, SIZE_MAX);
518}
519
520/* Control client error callback. */
521static enum cmd_retval
522control_error(struct cmdq_item *item, void *data)
523{
524	struct client	*c = cmdq_get_client(item);
525	char		*error = data;
526
527	cmdq_guard(item, "begin", 1);
528	control_write(c, "parse error: %s", error);
529	cmdq_guard(item, "error", 1);
530
531	free(error);
532	return (CMD_RETURN_NORMAL);
533}
534
535/* Control client error callback. */
536static void
537control_error_callback(__unused struct bufferevent *bufev,
538    __unused short what, void *data)
539{
540	struct client	*c = data;
541
542	c->flags |= CLIENT_EXIT;
543}
544
545/* Control client input callback. Read lines and fire commands. */
546static void
547control_read_callback(__unused struct bufferevent *bufev, void *data)
548{
549	struct client		*c = data;
550	struct control_state	*cs = c->control_state;
551	struct evbuffer		*buffer = cs->read_event->input;
552	char			*line, *error;
553	struct cmdq_state	*state;
554	enum cmd_parse_status	 status;
555
556	for (;;) {
557		line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
558		if (line == NULL)
559			break;
560		log_debug("%s: %s: %s", __func__, c->name, line);
561		if (*line == '\0') { /* empty line detach */
562			free(line);
563			c->flags |= CLIENT_EXIT;
564			break;
565		}
566
567		state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
568		status = cmd_parse_and_append(line, NULL, c, state, &error);
569		if (status == CMD_PARSE_ERROR)
570			cmdq_append(c, cmdq_get_callback(control_error, error));
571		cmdq_free_state(state);
572
573		free(line);
574	}
575}
576
577/* Does this control client have outstanding data to write? */
578int
579control_all_done(struct client *c)
580{
581	struct control_state	*cs = c->control_state;
582
583	if (!TAILQ_EMPTY(&cs->all_blocks))
584		return (0);
585	return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
586}
587
588/* Flush all blocks until output. */
589static void
590control_flush_all_blocks(struct client *c)
591{
592	struct control_state	*cs = c->control_state;
593	struct control_block	*cb, *cb1;
594
595	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) {
596		if (cb->size != 0)
597			break;
598		log_debug("%s: %s: flushing line: %s", __func__, c->name,
599		    cb->line);
600
601		bufferevent_write(cs->write_event, cb->line, strlen(cb->line));
602		bufferevent_write(cs->write_event, "\n", 1);
603		control_free_block(cs, cb);
604	}
605}
606
607/* Append data to buffer. */
608static struct evbuffer *
609control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
610    struct evbuffer *message, struct window_pane *wp, size_t size)
611{
612	u_char	*new_data;
613	size_t	 new_size;
614	u_int	 i;
615
616	if (message == NULL) {
617		message = evbuffer_new();
618		if (message == NULL)
619			fatalx("out of memory");
620		if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
621			evbuffer_add_printf(message,
622			    "%%extended-output %%%u %llu : ", wp->id,
623			    (unsigned long long)age);
624		} else
625			evbuffer_add_printf(message, "%%output %%%u ", wp->id);
626	}
627
628	new_data = window_pane_get_new_data(wp, &cp->offset, &new_size);
629	if (new_size < size)
630		fatalx("not enough data: %zu < %zu", new_size, size);
631	for (i = 0; i < size; i++) {
632		if (new_data[i] < ' ' || new_data[i] == '\\')
633			evbuffer_add_printf(message, "\\%03o", new_data[i]);
634		else
635			evbuffer_add_printf(message, "%c", new_data[i]);
636	}
637	window_pane_update_used_data(wp, &cp->offset, size);
638	return (message);
639}
640
641/* Write buffer. */
642static void
643control_write_data(struct client *c, struct evbuffer *message)
644{
645	struct control_state	*cs = c->control_state;
646
647	log_debug("%s: %s: %.*s", __func__, c->name,
648	    (int)EVBUFFER_LENGTH(message), EVBUFFER_DATA(message));
649
650	evbuffer_add(message, "\n", 1);
651	bufferevent_write_buffer(cs->write_event, message);
652	evbuffer_free(message);
653}
654
655/* Write output to client. */
656static int
657control_write_pending(struct client *c, struct control_pane *cp, size_t limit)
658{
659	struct control_state	*cs = c->control_state;
660	struct window_pane	*wp = NULL;
661	struct evbuffer		*message = NULL;
662	size_t			 used = 0, size;
663	struct control_block	*cb, *cb1;
664	uint64_t		 age, t = get_timer();
665
666	wp = control_window_pane(c, cp->pane);
667	if (wp == NULL) {
668		TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
669			TAILQ_REMOVE(&cp->blocks, cb, entry);
670			control_free_block(cs, cb);
671		}
672		control_flush_all_blocks(c);
673		return (0);
674	}
675
676	while (used != limit && !TAILQ_EMPTY(&cp->blocks)) {
677		if (control_check_age(c, wp, cp)) {
678			if (message != NULL)
679				evbuffer_free(message);
680			message = NULL;
681			break;
682		}
683
684		cb = TAILQ_FIRST(&cp->blocks);
685		if (cb->t < t)
686			age = t - cb->t;
687		else
688			age = 0;
689		log_debug("%s: %s: output block %zu (age %llu) for %%%u "
690		    "(used %zu/%zu)", __func__, c->name, cb->size,
691		    (unsigned long long)age, cp->pane, used, limit);
692
693		size = cb->size;
694		if (size > limit - used)
695			size = limit - used;
696		used += size;
697
698		message = control_append_data(c, cp, age, message, wp, size);
699
700		cb->size -= size;
701		if (cb->size == 0) {
702			TAILQ_REMOVE(&cp->blocks, cb, entry);
703			control_free_block(cs, cb);
704
705			cb = TAILQ_FIRST(&cs->all_blocks);
706			if (cb != NULL && cb->size == 0) {
707				if (wp != NULL && message != NULL) {
708					control_write_data(c, message);
709					message = NULL;
710				}
711				control_flush_all_blocks(c);
712			}
713		}
714	}
715	if (message != NULL)
716		control_write_data(c, message);
717	return (!TAILQ_EMPTY(&cp->blocks));
718}
719
720/* Control client write callback. */
721static void
722control_write_callback(__unused struct bufferevent *bufev, void *data)
723{
724	struct client		*c = data;
725	struct control_state	*cs = c->control_state;
726	struct control_pane	*cp, *cp1;
727	struct evbuffer		*evb = cs->write_event->output;
728	size_t			 space, limit;
729
730	control_flush_all_blocks(c);
731
732	while (EVBUFFER_LENGTH(evb) < CONTROL_BUFFER_HIGH) {
733		if (cs->pending_count == 0)
734			break;
735		space = CONTROL_BUFFER_HIGH - EVBUFFER_LENGTH(evb);
736		log_debug("%s: %s: %zu bytes available, %u panes", __func__,
737		    c->name, space, cs->pending_count);
738
739		limit = (space / cs->pending_count / 3); /* 3 bytes for \xxx */
740		if (limit < CONTROL_WRITE_MINIMUM)
741			limit = CONTROL_WRITE_MINIMUM;
742
743		TAILQ_FOREACH_SAFE(cp, &cs->pending_list, pending_entry, cp1) {
744			if (EVBUFFER_LENGTH(evb) >= CONTROL_BUFFER_HIGH)
745				break;
746			if (control_write_pending(c, cp, limit))
747				continue;
748			TAILQ_REMOVE(&cs->pending_list, cp, pending_entry);
749			cp->pending_flag = 0;
750			cs->pending_count--;
751		}
752	}
753	if (EVBUFFER_LENGTH(evb) == 0)
754		bufferevent_disable(cs->write_event, EV_WRITE);
755}
756
757/* Initialize for control mode. */
758void
759control_start(struct client *c)
760{
761	struct control_state	*cs;
762
763	if (c->flags & CLIENT_CONTROLCONTROL) {
764		close(c->out_fd);
765		c->out_fd = -1;
766	} else
767		setblocking(c->out_fd, 0);
768	setblocking(c->fd, 0);
769
770	cs = c->control_state = xcalloc(1, sizeof *cs);
771	RB_INIT(&cs->panes);
772	TAILQ_INIT(&cs->pending_list);
773	TAILQ_INIT(&cs->all_blocks);
774	RB_INIT(&cs->subs);
775
776	cs->read_event = bufferevent_new(c->fd, control_read_callback,
777	    control_write_callback, control_error_callback, c);
778	bufferevent_enable(cs->read_event, EV_READ);
779
780	if (c->flags & CLIENT_CONTROLCONTROL)
781		cs->write_event = cs->read_event;
782	else {
783		cs->write_event = bufferevent_new(c->out_fd, NULL,
784		    control_write_callback, control_error_callback, c);
785	}
786	bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW,
787	    0);
788
789	if (c->flags & CLIENT_CONTROLCONTROL) {
790		bufferevent_write(cs->write_event, "\033P1000p", 7);
791		bufferevent_enable(cs->write_event, EV_WRITE);
792	}
793}
794
795/* Discard all output for a client. */
796void
797control_discard(struct client *c)
798{
799	struct control_state	*cs = c->control_state;
800	struct control_pane	*cp;
801
802	RB_FOREACH(cp, control_panes, &cs->panes)
803		control_discard_pane(c, cp);
804	bufferevent_disable(cs->read_event, EV_READ);
805}
806
807/* Stop control mode. */
808void
809control_stop(struct client *c)
810{
811	struct control_state	*cs = c->control_state;
812	struct control_block	*cb, *cb1;
813	struct control_sub	*csub, *csub1;
814
815	if (~c->flags & CLIENT_CONTROLCONTROL)
816		bufferevent_free(cs->write_event);
817	bufferevent_free(cs->read_event);
818
819	RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1)
820		control_free_sub(cs, csub);
821	if (evtimer_initialized(&cs->subs_timer))
822		evtimer_del(&cs->subs_timer);
823
824	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
825		control_free_block(cs, cb);
826	control_reset_offsets(c);
827
828	free(cs);
829}
830
831/* Check session subscription. */
832static void
833control_check_subs_session(struct client *c, struct control_sub *csub)
834{
835	struct session		*s = c->session;
836	struct format_tree	*ft;
837	char			*value;
838
839	ft = format_create_defaults(NULL, c, s, NULL, NULL);
840	value = format_expand(ft, csub->format);
841	format_free(ft);
842
843	if (csub->last != NULL && strcmp(value, csub->last) == 0) {
844		free(value);
845		return;
846	}
847	control_write(c,
848	    "%%subscription-changed %s $%u - - - : %s",
849	    csub->name, s->id, value);
850	free(csub->last);
851	csub->last = value;
852}
853
854/* Check pane subscription. */
855static void
856control_check_subs_pane(struct client *c, struct control_sub *csub)
857{
858	struct session		*s = c->session;
859	struct window_pane	*wp;
860	struct window		*w;
861	struct winlink		*wl;
862	struct format_tree	*ft;
863	char			*value;
864	struct control_sub_pane	*csp, find;
865
866	wp = window_pane_find_by_id(csub->id);
867	if (wp == NULL)
868		return;
869	w = wp->window;
870
871	TAILQ_FOREACH(wl, &w->winlinks, wentry) {
872		if (wl->session != s)
873			continue;
874
875		ft = format_create_defaults(NULL, c, s, wl, wp);
876		value = format_expand(ft, csub->format);
877		format_free(ft);
878
879		find.pane = wp->id;
880		find.idx = wl->idx;
881
882		csp = RB_FIND(control_sub_panes, &csub->panes, &find);
883		if (csp == NULL) {
884			csp = xcalloc(1, sizeof *csp);
885			csp->pane = wp->id;
886			csp->idx = wl->idx;
887			RB_INSERT(control_sub_panes, &csub->panes, csp);
888		}
889
890		if (csp->last != NULL && strcmp(value, csp->last) == 0) {
891			free(value);
892			continue;
893		}
894		control_write(c,
895		    "%%subscription-changed %s $%u @%u %u %%%u : %s",
896		    csub->name, s->id, w->id, wl->idx, wp->id, value);
897		free(csp->last);
898		csp->last = value;
899	}
900}
901
902/* Check all panes subscription. */
903static void
904control_check_subs_all_panes(struct client *c, struct control_sub *csub)
905{
906	struct session		*s = c->session;
907	struct window_pane	*wp;
908	struct window		*w;
909	struct winlink		*wl;
910	struct format_tree	*ft;
911	char			*value;
912	struct control_sub_pane	*csp, find;
913
914	RB_FOREACH(wl, winlinks, &s->windows) {
915		w = wl->window;
916		TAILQ_FOREACH(wp, &w->panes, entry) {
917			ft = format_create_defaults(NULL, c, s, wl, wp);
918			value = format_expand(ft, csub->format);
919			format_free(ft);
920
921			find.pane = wp->id;
922			find.idx = wl->idx;
923
924			csp = RB_FIND(control_sub_panes, &csub->panes, &find);
925			if (csp == NULL) {
926				csp = xcalloc(1, sizeof *csp);
927				csp->pane = wp->id;
928				csp->idx = wl->idx;
929				RB_INSERT(control_sub_panes, &csub->panes, csp);
930			}
931
932			if (csp->last != NULL &&
933			    strcmp(value, csp->last) == 0) {
934				free(value);
935				continue;
936			}
937			control_write(c,
938			    "%%subscription-changed %s $%u @%u %u %%%u : %s",
939			    csub->name, s->id, w->id, wl->idx, wp->id, value);
940			free(csp->last);
941			csp->last = value;
942		}
943	}
944}
945
946/* Check window subscription. */
947static void
948control_check_subs_window(struct client *c, struct control_sub *csub)
949{
950	struct session			*s = c->session;
951	struct window			*w;
952	struct winlink			*wl;
953	struct format_tree		*ft;
954	char				*value;
955	struct control_sub_window	*csw, find;
956
957	w = window_find_by_id(csub->id);
958	if (w == NULL)
959		return;
960
961	TAILQ_FOREACH(wl, &w->winlinks, wentry) {
962		if (wl->session != s)
963			continue;
964
965		ft = format_create_defaults(NULL, c, s, wl, NULL);
966		value = format_expand(ft, csub->format);
967		format_free(ft);
968
969		find.window = w->id;
970		find.idx = wl->idx;
971
972		csw = RB_FIND(control_sub_windows, &csub->windows, &find);
973		if (csw == NULL) {
974			csw = xcalloc(1, sizeof *csw);
975			csw->window = w->id;
976			csw->idx = wl->idx;
977			RB_INSERT(control_sub_windows, &csub->windows, csw);
978		}
979
980		if (csw->last != NULL && strcmp(value, csw->last) == 0) {
981			free(value);
982			continue;
983		}
984		control_write(c,
985		    "%%subscription-changed %s $%u @%u %u - : %s",
986		    csub->name, s->id, w->id, wl->idx, value);
987		free(csw->last);
988		csw->last = value;
989	}
990}
991
992/* Check all windows subscription. */
993static void
994control_check_subs_all_windows(struct client *c, struct control_sub *csub)
995{
996	struct session			*s = c->session;
997	struct window			*w;
998	struct winlink			*wl;
999	struct format_tree		*ft;
1000	char				*value;
1001	struct control_sub_window	*csw, find;
1002
1003	RB_FOREACH(wl, winlinks, &s->windows) {
1004		w = wl->window;
1005
1006		ft = format_create_defaults(NULL, c, s, wl, NULL);
1007		value = format_expand(ft, csub->format);
1008		format_free(ft);
1009
1010		find.window = w->id;
1011		find.idx = wl->idx;
1012
1013		csw = RB_FIND(control_sub_windows, &csub->windows, &find);
1014		if (csw == NULL) {
1015			csw = xcalloc(1, sizeof *csw);
1016			csw->window = w->id;
1017			csw->idx = wl->idx;
1018			RB_INSERT(control_sub_windows, &csub->windows, csw);
1019		}
1020
1021		if (csw->last != NULL && strcmp(value, csw->last) == 0) {
1022			free(value);
1023			continue;
1024		}
1025		control_write(c,
1026		    "%%subscription-changed %s $%u @%u %u - : %s",
1027		    csub->name, s->id, w->id, wl->idx, value);
1028		free(csw->last);
1029		csw->last = value;
1030	}
1031}
1032
1033/* Check subscriptions timer. */
1034static void
1035control_check_subs_timer(__unused int fd, __unused short events, void *data)
1036{
1037	struct client		*c = data;
1038	struct control_state	*cs = c->control_state;
1039	struct control_sub	*csub, *csub1;
1040	struct timeval		 tv = { .tv_sec = 1 };
1041
1042	log_debug("%s: timer fired", __func__);
1043	evtimer_add(&cs->subs_timer, &tv);
1044
1045	RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
1046		switch (csub->type) {
1047		case CONTROL_SUB_SESSION:
1048			control_check_subs_session(c, csub);
1049			break;
1050		case CONTROL_SUB_PANE:
1051			control_check_subs_pane(c, csub);
1052			break;
1053		case CONTROL_SUB_ALL_PANES:
1054			control_check_subs_all_panes(c, csub);
1055			break;
1056		case CONTROL_SUB_WINDOW:
1057			control_check_subs_window(c, csub);
1058			break;
1059		case CONTROL_SUB_ALL_WINDOWS:
1060			control_check_subs_all_windows(c, csub);
1061			break;
1062		}
1063	}
1064}
1065
1066/* Add a subscription. */
1067void
1068control_add_sub(struct client *c, const char *name, enum control_sub_type type,
1069    int id, const char *format)
1070{
1071	struct control_state	*cs = c->control_state;
1072	struct control_sub	*csub, find;
1073	struct timeval		 tv = { .tv_sec = 1 };
1074
1075	find.name = __UNCONST(name);
1076	if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
1077		control_free_sub(cs, csub);
1078
1079	csub = xcalloc(1, sizeof *csub);
1080	csub->name = xstrdup(name);
1081	csub->type = type;
1082	csub->id = id;
1083	csub->format = xstrdup(format);
1084	RB_INSERT(control_subs, &cs->subs, csub);
1085
1086	RB_INIT(&csub->panes);
1087	RB_INIT(&csub->windows);
1088
1089	if (!evtimer_initialized(&cs->subs_timer))
1090		evtimer_set(&cs->subs_timer, control_check_subs_timer, c);
1091	if (!evtimer_pending(&cs->subs_timer, NULL))
1092		evtimer_add(&cs->subs_timer, &tv);
1093}
1094
1095/* Remove a subscription. */
1096void
1097control_remove_sub(struct client *c, const char *name)
1098{
1099	struct control_state	*cs = c->control_state;
1100	struct control_sub	*csub, find;
1101
1102	find.name = __UNCONST(name);
1103	if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
1104		control_free_sub(cs, csub);
1105	if (RB_EMPTY(&cs->subs))
1106		evtimer_del(&cs->subs_timer);
1107}
1108