control.c revision 1.42
1/* $OpenBSD: control.c,v 1.42 2020/06/12 08:35:01 nicm Exp $ */
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 <event.h>
23#include <stdlib.h>
24#include <string.h>
25#include <time.h>
26#include <unistd.h>
27
28#include "tmux.h"
29
30/*
31 * Block of data to output. Each client has one "all" queue of blocks and
32 * another queue for each pane (in struct client_offset). %output blocks are
33 * added to both queues and other output lines (notifications) added only to
34 * the client queue.
35 *
36 * When a client becomes writeable, data from blocks on the pane queue are sent
37 * up to the maximum size (CLIENT_BUFFER_HIGH). If a block is entirely written,
38 * it is removed from both pane and client queues and if this means non-%output
39 * blocks are now at the head of the client queue, they are written.
40 *
41 * This means a %output block holds up any subsequent non-%output blocks until
42 * it is written which enforces ordering even if the client cannot accept the
43 * entire block in one go.
44 */
45struct control_block {
46	size_t				 size;
47	char				*line;
48	uint64_t			 t;
49
50	TAILQ_ENTRY(control_block)	 entry;
51	TAILQ_ENTRY(control_block)	 all_entry;
52};
53
54/* Control client pane. */
55struct control_pane {
56	u_int				 pane;
57
58	/*
59	 * Offsets into the pane data. The first (offset) is the data we have
60	 * written; the second (queued) the data we have queued (pointed to by
61	 * a block).
62	 */
63	struct window_pane_offset	 offset;
64	struct window_pane_offset	 queued;
65
66	int				 flags;
67#define CONTROL_PANE_OFF 0x1
68#define CONTROL_PANE_PAUSED 0x2
69
70	int				 pending_flag;
71	TAILQ_ENTRY(control_pane)	 pending_entry;
72
73	TAILQ_HEAD(, control_block)	 blocks;
74
75	RB_ENTRY(control_pane)		 entry;
76};
77RB_HEAD(control_panes, control_pane);
78
79/* Control client state. */
80struct control_state {
81	struct control_panes		 panes;
82
83	TAILQ_HEAD(, control_pane)	 pending_list;
84	u_int				 pending_count;
85
86	TAILQ_HEAD(, control_block)	 all_blocks;
87
88	struct bufferevent		*read_event;
89	struct bufferevent		*write_event;
90};
91
92/* Low and high watermarks. */
93#define CONTROL_BUFFER_LOW 512
94#define CONTROL_BUFFER_HIGH 8192
95
96/* Minimum to write to each client. */
97#define CONTROL_WRITE_MINIMUM 32
98
99/* Maximum age for clients that are not using pause mode. */
100#define CONTROL_MAXIMUM_AGE 300000
101
102/* Flags to ignore client. */
103#define CONTROL_IGNORE_FLAGS \
104	(CLIENT_CONTROL_NOOUTPUT| \
105	 CLIENT_UNATTACHEDFLAGS)
106
107/* Compare client panes. */
108static int
109control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
110{
111	if (cp1->pane < cp2->pane)
112		return (-1);
113	if (cp1->pane > cp2->pane)
114		return (1);
115	return (0);
116}
117RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
118
119/* Free a block. */
120static void
121control_free_block(struct control_state *cs, struct control_block *cb)
122{
123	free(cb->line);
124	TAILQ_REMOVE(&cs->all_blocks, cb, all_entry);
125	free(cb);
126}
127
128/* Get pane offsets for this client. */
129static struct control_pane *
130control_get_pane(struct client *c, struct window_pane *wp)
131{
132	struct control_state	*cs = c->control_state;
133	struct control_pane	 cp = { .pane = wp->id };
134
135	return (RB_FIND(control_panes, &cs->panes, &cp));
136}
137
138/* Add pane offsets for this client. */
139static struct control_pane *
140control_add_pane(struct client *c, struct window_pane *wp)
141{
142	struct control_state	*cs = c->control_state;
143	struct control_pane	*cp;
144
145	cp = control_get_pane(c, wp);
146	if (cp != NULL)
147		return (cp);
148
149	cp = xcalloc(1, sizeof *cp);
150	cp->pane = wp->id;
151	RB_INSERT(control_panes, &cs->panes, cp);
152
153	memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
154	memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
155	TAILQ_INIT(&cp->blocks);
156
157	return (cp);
158}
159
160/* Discard output for a pane. */
161static void
162control_discard_pane(struct client *c, struct control_pane *cp)
163{
164	struct control_state	*cs = c->control_state;
165	struct control_block	*cb, *cb1;
166
167	TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
168		TAILQ_REMOVE(&cp->blocks, cb, entry);
169		control_free_block(cs, cb);
170	}
171}
172
173/* Get actual pane for this client. */
174static struct window_pane *
175control_window_pane(struct client *c, u_int pane)
176{
177	struct window_pane	*wp;
178
179	if (c->session == NULL)
180		return (NULL);
181	if ((wp = window_pane_find_by_id(pane)) == NULL)
182		return (NULL);
183	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
184		return (NULL);
185	return (wp);
186}
187
188/* Reset control offsets. */
189void
190control_reset_offsets(struct client *c)
191{
192	struct control_state	*cs = c->control_state;
193	struct control_pane	*cp, *cp1;
194
195	RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
196		RB_REMOVE(control_panes, &cs->panes, cp);
197		free(cp);
198	}
199
200	TAILQ_INIT(&cs->pending_list);
201	cs->pending_count = 0;
202}
203
204/* Get offsets for client. */
205struct window_pane_offset *
206control_pane_offset(struct client *c, struct window_pane *wp, int *off)
207{
208	struct control_state	*cs = c->control_state;
209	struct control_pane	*cp;
210
211	if (c->flags & CLIENT_CONTROL_NOOUTPUT) {
212		*off = 0;
213		return (NULL);
214	}
215
216	cp = control_get_pane(c, wp);
217	if (cp == NULL || (cp->flags & CONTROL_PANE_PAUSED)) {
218		*off = 0;
219		return (NULL);
220	}
221	if (cp->flags & CONTROL_PANE_OFF) {
222		*off = 1;
223		return (NULL);
224	}
225	*off = (EVBUFFER_LENGTH(cs->write_event->output) >= CONTROL_BUFFER_LOW);
226	return (&cp->offset);
227}
228
229/* Set pane as on. */
230void
231control_set_pane_on(struct client *c, struct window_pane *wp)
232{
233	struct control_pane	*cp;
234
235	cp = control_get_pane(c, wp);
236	if (cp != NULL && (cp->flags & CONTROL_PANE_OFF)) {
237		cp->flags &= ~CONTROL_PANE_OFF;
238		memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
239		memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
240	}
241}
242
243/* Set pane as off. */
244void
245control_set_pane_off(struct client *c, struct window_pane *wp)
246{
247	struct control_pane	*cp;
248
249	cp = control_add_pane(c, wp);
250	cp->flags |= CONTROL_PANE_OFF;
251}
252
253/* Continue a paused pane. */
254void
255control_continue_pane(struct client *c, struct window_pane *wp)
256{
257	struct control_pane	*cp;
258
259	cp = control_get_pane(c, wp);
260	if (cp != NULL && (cp->flags & CONTROL_PANE_PAUSED)) {
261		cp->flags &= ~CONTROL_PANE_PAUSED;
262		memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
263		memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
264		control_write(c, "%%continue %%%u", wp->id);
265	}
266}
267
268/* Pause a pane. */
269void
270control_pause_pane(struct client *c, struct window_pane *wp)
271{
272	struct control_pane	*cp;
273
274	cp = control_add_pane(c, wp);
275	if (~cp->flags & CONTROL_PANE_PAUSED) {
276		cp->flags |= CONTROL_PANE_PAUSED;
277		control_discard_pane(c, cp);
278		control_write(c, "%%pause %%%u", wp->id);
279	}
280}
281
282/* Write a line. */
283static void
284control_vwrite(struct client *c, const char *fmt, va_list ap)
285{
286	struct control_state	*cs = c->control_state;
287	char			*s;
288
289	xvasprintf(&s, fmt, ap);
290	log_debug("%s: %s: writing line: %s", __func__, c->name, s);
291
292	bufferevent_write(cs->write_event, s, strlen(s));
293	bufferevent_write(cs->write_event, "\n", 1);
294
295	bufferevent_enable(cs->write_event, EV_WRITE);
296	free(s);
297}
298
299/* Write a line. */
300void
301control_write(struct client *c, const char *fmt, ...)
302{
303	struct control_state	*cs = c->control_state;
304	struct control_block	*cb;
305	va_list			 ap;
306
307	va_start(ap, fmt);
308
309	if (TAILQ_EMPTY(&cs->all_blocks)) {
310		control_vwrite(c, fmt, ap);
311		va_end(ap);
312		return;
313	}
314
315	cb = xcalloc(1, sizeof *cb);
316	xvasprintf(&cb->line, fmt, ap);
317	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
318	cb->t = get_timer();
319
320	log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
321	bufferevent_enable(cs->write_event, EV_WRITE);
322
323	va_end(ap);
324}
325
326/* Check age for this pane. */
327static int
328control_check_age(struct client *c, struct window_pane *wp,
329    struct control_pane *cp)
330{
331	struct control_block	*cb;
332	uint64_t		 t, age;
333
334	cb = TAILQ_FIRST(&cp->blocks);
335	if (cb == NULL)
336		return (0);
337	t = get_timer();
338	if (cb->t >= t)
339		return (0);
340
341	age = t - cb->t;
342	log_debug("%s: %s: %%%u is %llu behind", __func__, c->name, wp->id,
343	    (unsigned long long)age);
344
345	if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
346		if (age < c->pause_age)
347			return (0);
348		cp->flags |= CONTROL_PANE_PAUSED;
349		control_discard_pane(c, cp);
350		control_write(c, "%%pause %%%u", wp->id);
351	} else {
352		if (age < CONTROL_MAXIMUM_AGE)
353			return (0);
354		c->exit_message = xstrdup("too far behind");
355		c->flags |= CLIENT_EXIT;
356		control_discard(c);
357	}
358	return (1);
359}
360
361/* Write output from a pane. */
362void
363control_write_output(struct client *c, struct window_pane *wp)
364{
365	struct control_state	*cs = c->control_state;
366	struct control_pane	*cp;
367	struct control_block	*cb;
368	size_t			 new_size;
369
370	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
371		return;
372
373	if (c->flags & CONTROL_IGNORE_FLAGS) {
374		cp = control_get_pane(c, wp);
375		if (cp != NULL)
376			goto ignore;
377		return;
378	}
379	cp = control_add_pane(c, wp);
380	if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
381		goto ignore;
382	if (control_check_age(c, wp, cp))
383		return;
384
385	window_pane_get_new_data(wp, &cp->queued, &new_size);
386	if (new_size == 0)
387		return;
388	window_pane_update_used_data(wp, &cp->queued, new_size);
389
390	cb = xcalloc(1, sizeof *cb);
391	cb->size = new_size;
392	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
393	cb->t = get_timer();
394
395	TAILQ_INSERT_TAIL(&cp->blocks, cb, entry);
396	log_debug("%s: %s: new output block of %zu for %%%u", __func__, c->name,
397	    cb->size, wp->id);
398
399	if (!cp->pending_flag) {
400		log_debug("%s: %s: %%%u now pending", __func__, c->name,
401		    wp->id);
402		TAILQ_INSERT_TAIL(&cs->pending_list, cp, pending_entry);
403		cp->pending_flag = 1;
404		cs->pending_count++;
405	}
406	bufferevent_enable(cs->write_event, EV_WRITE);
407	return;
408
409ignore:
410	log_debug("%s: %s: ignoring pane %%%u", __func__, c->name, wp->id);
411	window_pane_update_used_data(wp, &cp->offset, SIZE_MAX);
412	window_pane_update_used_data(wp, &cp->queued, SIZE_MAX);
413}
414
415/* Control client error callback. */
416static enum cmd_retval
417control_error(struct cmdq_item *item, void *data)
418{
419	struct client	*c = cmdq_get_client(item);
420	char		*error = data;
421
422	cmdq_guard(item, "begin", 1);
423	control_write(c, "parse error: %s", error);
424	cmdq_guard(item, "error", 1);
425
426	free(error);
427	return (CMD_RETURN_NORMAL);
428}
429
430/* Control client error callback. */
431static void
432control_error_callback(__unused struct bufferevent *bufev,
433    __unused short what, void *data)
434{
435	struct client	*c = data;
436
437	c->flags |= CLIENT_EXIT;
438}
439
440/* Control client input callback. Read lines and fire commands. */
441static void
442control_read_callback(__unused struct bufferevent *bufev, void *data)
443{
444	struct client		*c = data;
445	struct control_state	*cs = c->control_state;
446	struct evbuffer		*buffer = cs->read_event->input;
447	char			*line, *error;
448	struct cmdq_state	*state;
449	enum cmd_parse_status	 status;
450
451	for (;;) {
452		line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
453		if (line == NULL)
454			break;
455		log_debug("%s: %s: %s", __func__, c->name, line);
456		if (*line == '\0') { /* empty line detach */
457			free(line);
458			c->flags |= CLIENT_EXIT;
459			break;
460		}
461
462		state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
463		status = cmd_parse_and_append(line, NULL, c, state, &error);
464		if (status == CMD_PARSE_ERROR)
465			cmdq_append(c, cmdq_get_callback(control_error, error));
466		cmdq_free_state(state);
467
468		free(line);
469	}
470}
471
472/* Does this control client have outstanding data to write? */
473int
474control_all_done(struct client *c)
475{
476	struct control_state	*cs = c->control_state;
477
478	if (!TAILQ_EMPTY(&cs->all_blocks))
479		return (0);
480	return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
481}
482
483/* Flush all blocks until output. */
484static void
485control_flush_all_blocks(struct client *c)
486{
487	struct control_state	*cs = c->control_state;
488	struct control_block	*cb, *cb1;
489
490	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) {
491		if (cb->size != 0)
492			break;
493		log_debug("%s: %s: flushing line: %s", __func__, c->name,
494		    cb->line);
495
496		bufferevent_write(cs->write_event, cb->line, strlen(cb->line));
497		bufferevent_write(cs->write_event, "\n", 1);
498		control_free_block(cs, cb);
499	}
500}
501
502/* Append data to buffer. */
503static struct evbuffer *
504control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
505    struct evbuffer *message, struct window_pane *wp, size_t size)
506{
507	u_char	*new_data;
508	size_t	 new_size;
509	u_int	 i;
510
511	if (message == NULL) {
512		message = evbuffer_new();
513		if (message == NULL)
514			fatalx("out of memory");
515		if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
516			evbuffer_add_printf(message,
517			    "%%extended-output %%%u %llu : ", wp->id,
518			    (unsigned long long)age);
519		} else
520			evbuffer_add_printf(message, "%%output %%%u ", wp->id);
521	}
522
523	new_data = window_pane_get_new_data(wp, &cp->offset, &new_size);
524	if (new_size < size)
525		fatalx("not enough data: %zu < %zu", new_size, size);
526	for (i = 0; i < size; i++) {
527		if (new_data[i] < ' ' || new_data[i] == '\\')
528			evbuffer_add_printf(message, "\\%03o", new_data[i]);
529		else
530			evbuffer_add_printf(message, "%c", new_data[i]);
531	}
532	window_pane_update_used_data(wp, &cp->offset, size);
533	return (message);
534}
535
536/* Write buffer. */
537static void
538control_write_data(struct client *c, struct evbuffer *message)
539{
540	struct control_state	*cs = c->control_state;
541
542	log_debug("%s: %s: %.*s", __func__, c->name,
543	    (int)EVBUFFER_LENGTH(message), EVBUFFER_DATA(message));
544
545	evbuffer_add(message, "\n", 1);
546	bufferevent_write_buffer(cs->write_event, message);
547	evbuffer_free(message);
548}
549
550/* Write output to client. */
551static int
552control_write_pending(struct client *c, struct control_pane *cp, size_t limit)
553{
554	struct control_state	*cs = c->control_state;
555	struct window_pane	*wp = NULL;
556	struct evbuffer		*message = NULL;
557	size_t			 used = 0, size;
558	struct control_block	*cb, *cb1;
559	uint64_t		 age, t = get_timer();
560
561	wp = control_window_pane(c, cp->pane);
562	if (wp == NULL) {
563		TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
564			TAILQ_REMOVE(&cp->blocks, cb, entry);
565			control_free_block(cs, cb);
566		}
567		control_flush_all_blocks(c);
568		return (0);
569	}
570
571	while (used != limit && !TAILQ_EMPTY(&cp->blocks)) {
572		if (control_check_age(c, wp, cp)) {
573			if (message != NULL)
574				evbuffer_free(message);
575			message = NULL;
576			break;
577		}
578
579		cb = TAILQ_FIRST(&cp->blocks);
580		if (cb->t < t)
581			age = t - cb->t;
582		else
583			age = 0;
584		log_debug("%s: %s: output block %zu (age %llu) for %%%u "
585		    "(used %zu/%zu)", __func__, c->name, cb->size, age,
586		    cp->pane, used, limit);
587
588		size = cb->size;
589		if (size > limit - used)
590			size = limit - used;
591		used += size;
592
593		message = control_append_data(c, cp, age, message, wp, size);
594
595		cb->size -= size;
596		if (cb->size == 0) {
597			TAILQ_REMOVE(&cp->blocks, cb, entry);
598			control_free_block(cs, cb);
599
600			cb = TAILQ_FIRST(&cs->all_blocks);
601			if (cb != NULL && cb->size == 0) {
602				if (wp != NULL && message != NULL) {
603					control_write_data(c, message);
604					message = NULL;
605				}
606				control_flush_all_blocks(c);
607			}
608		}
609	}
610	if (message != NULL)
611		control_write_data(c, message);
612	return (!TAILQ_EMPTY(&cp->blocks));
613}
614
615/* Control client write callback. */
616static void
617control_write_callback(__unused struct bufferevent *bufev, void *data)
618{
619	struct client		*c = data;
620	struct control_state	*cs = c->control_state;
621	struct control_pane	*cp, *cp1;
622	struct evbuffer		*evb = cs->write_event->output;
623	size_t			 space, limit;
624
625	control_flush_all_blocks(c);
626
627	while (EVBUFFER_LENGTH(evb) < CONTROL_BUFFER_HIGH) {
628		if (cs->pending_count == 0)
629			break;
630		space = CONTROL_BUFFER_HIGH - EVBUFFER_LENGTH(evb);
631		log_debug("%s: %s: %zu bytes available, %u panes", __func__,
632		    c->name, space, cs->pending_count);
633
634		limit = (space / cs->pending_count / 3); /* 3 bytes for \xxx */
635		if (limit < CONTROL_WRITE_MINIMUM)
636			limit = CONTROL_WRITE_MINIMUM;
637
638		TAILQ_FOREACH_SAFE(cp, &cs->pending_list, pending_entry, cp1) {
639			if (EVBUFFER_LENGTH(evb) >= CONTROL_BUFFER_HIGH)
640				break;
641			if (control_write_pending(c, cp, limit))
642				continue;
643			TAILQ_REMOVE(&cs->pending_list, cp, pending_entry);
644			cp->pending_flag = 0;
645			cs->pending_count--;
646		}
647	}
648	if (EVBUFFER_LENGTH(evb) == 0)
649		bufferevent_disable(cs->write_event, EV_WRITE);
650}
651
652/* Initialize for control mode. */
653void
654control_start(struct client *c)
655{
656	struct control_state	*cs;
657
658	if (c->flags & CLIENT_CONTROLCONTROL) {
659		close(c->out_fd);
660		c->out_fd = -1;
661	} else
662		setblocking(c->out_fd, 0);
663	setblocking(c->fd, 0);
664
665	cs = c->control_state = xcalloc(1, sizeof *cs);
666	RB_INIT(&cs->panes);
667	TAILQ_INIT(&cs->pending_list);
668	TAILQ_INIT(&cs->all_blocks);
669
670	cs->read_event = bufferevent_new(c->fd, control_read_callback,
671	    control_write_callback, control_error_callback, c);
672	bufferevent_enable(cs->read_event, EV_READ);
673
674	if (c->flags & CLIENT_CONTROLCONTROL)
675		cs->write_event = cs->read_event;
676	else {
677		cs->write_event = bufferevent_new(c->out_fd, NULL,
678		    control_write_callback, control_error_callback, c);
679	}
680	bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW,
681	    0);
682
683	if (c->flags & CLIENT_CONTROLCONTROL) {
684		bufferevent_write(cs->write_event, "\033P1000p", 7);
685		bufferevent_enable(cs->write_event, EV_WRITE);
686	}
687}
688
689/* Discard all output for a client. */
690void
691control_discard(struct client *c)
692{
693	struct control_state	*cs = c->control_state;
694	struct control_pane	*cp;
695
696	RB_FOREACH(cp, control_panes, &cs->panes)
697		control_discard_pane(c, cp);
698}
699
700/* Stop control mode. */
701void
702control_stop(struct client *c)
703{
704	struct control_state	*cs = c->control_state;
705	struct control_block	*cb, *cb1;
706
707	if (~c->flags & CLIENT_CONTROLCONTROL)
708		bufferevent_free(cs->write_event);
709	bufferevent_free(cs->read_event);
710
711	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
712		control_free_block(cs, cb);
713	control_reset_offsets(c);
714
715	free(cs);
716}
717