control.c revision 1.36
1/* $OpenBSD: control.c,v 1.36 2020/06/01 21:08:05 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
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
68	int				 pending_flag;
69	TAILQ_ENTRY(control_pane)	 pending_entry;
70
71	TAILQ_HEAD(, control_block)	 blocks;
72
73	RB_ENTRY(control_pane)		 entry;
74};
75RB_HEAD(control_panes, control_pane);
76
77/* Control client state. */
78struct control_state {
79	struct control_panes		 panes;
80
81	TAILQ_HEAD(, control_pane)	 pending_list;
82	u_int				 pending_count;
83
84	TAILQ_HEAD(, control_block)	 all_blocks;
85
86	struct bufferevent		*read_event;
87	struct bufferevent		*write_event;
88};
89
90/* Low watermark. */
91#define CONTROL_BUFFER_LOW 512
92#define CONTROL_BUFFER_HIGH 8192
93
94/* Minimum to write to each client. */
95#define CONTROL_WRITE_MINIMUM 32
96
97/* Flags to ignore client. */
98#define CONTROL_IGNORE_FLAGS \
99	(CLIENT_CONTROL_NOOUTPUT| \
100	 CLIENT_UNATTACHEDFLAGS)
101
102/* Compare client panes. */
103static int
104control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2)
105{
106	if (cp1->pane < cp2->pane)
107		return (-1);
108	if (cp1->pane > cp2->pane)
109		return (1);
110	return (0);
111}
112RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
113
114/* Free a block. */
115static void
116control_free_block(struct control_state *cs, struct control_block *cb)
117{
118	free(cb->line);
119	TAILQ_REMOVE(&cs->all_blocks, cb, all_entry);
120	free(cb);
121}
122
123/* Get pane offsets for this client. */
124static struct control_pane *
125control_get_pane(struct client *c, struct window_pane *wp)
126{
127	struct control_state	*cs = c->control_state;
128	struct control_pane	 cp = { .pane = wp->id };
129
130	return (RB_FIND(control_panes, &cs->panes, &cp));
131}
132
133/* Add pane offsets for this client. */
134static struct control_pane *
135control_add_pane(struct client *c, struct window_pane *wp)
136{
137	struct control_state	*cs = c->control_state;
138	struct control_pane	*cp;
139
140	cp = control_get_pane(c, wp);
141	if (cp != NULL)
142		return (cp);
143
144	cp = xcalloc(1, sizeof *cp);
145	cp->pane = wp->id;
146	RB_INSERT(control_panes, &cs->panes, cp);
147
148	memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
149	memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
150	TAILQ_INIT(&cp->blocks);
151
152	return (cp);
153}
154
155/* Reset control offsets. */
156void
157control_reset_offsets(struct client *c)
158{
159	struct control_state	*cs = c->control_state;
160	struct control_pane	*cp, *cp1;
161
162	RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
163		RB_REMOVE(control_panes, &cs->panes, cp);
164		free(cp);
165	}
166
167	TAILQ_INIT(&cs->pending_list);
168	cs->pending_count = 0;
169}
170
171/* Get offsets for client. */
172struct window_pane_offset *
173control_pane_offset(struct client *c, struct window_pane *wp, int *off)
174{
175	struct control_state	*cs = c->control_state;
176	struct control_pane	*cp;
177
178	if (c->flags & CLIENT_CONTROL_NOOUTPUT) {
179		*off = 0;
180		return (NULL);
181	}
182
183	cp = control_get_pane(c, wp);
184	if (cp == NULL) {
185		*off = 0;
186		return (NULL);
187	}
188	if (cp->flags & CONTROL_PANE_OFF) {
189		*off = 1;
190		return (NULL);
191	}
192	*off = (EVBUFFER_LENGTH(cs->write_event->output) >= CONTROL_BUFFER_LOW);
193	return (&cp->offset);
194}
195
196/* Set pane as on. */
197void
198control_set_pane_on(struct client *c, struct window_pane *wp)
199{
200	struct control_pane	*cp;
201
202	cp = control_get_pane(c, wp);
203	if (cp != NULL) {
204		cp->flags &= ~CONTROL_PANE_OFF;
205		memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
206		memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
207	}
208}
209
210/* Set pane as off. */
211void
212control_set_pane_off(struct client *c, struct window_pane *wp)
213{
214	struct control_pane	*cp;
215
216	cp = control_add_pane(c, wp);
217	cp->flags |= CONTROL_PANE_OFF;
218}
219
220/* Write a line. */
221static void
222control_vwrite(struct client *c, const char *fmt, va_list ap)
223{
224	struct control_state	*cs = c->control_state;
225	char			*s;
226
227	xvasprintf(&s, fmt, ap);
228	log_debug("%s: %s: writing line: %s", __func__, c->name, s);
229
230	bufferevent_write(cs->write_event, s, strlen(s));
231	bufferevent_write(cs->write_event, "\n", 1);
232
233	bufferevent_enable(cs->write_event, EV_WRITE);
234	free(s);
235}
236
237/* Write a line. */
238void
239control_write(struct client *c, const char *fmt, ...)
240{
241	struct control_state	*cs = c->control_state;
242	struct control_block	*cb;
243	va_list			 ap;
244
245	va_start(ap, fmt);
246
247	if (TAILQ_EMPTY(&cs->all_blocks)) {
248		control_vwrite(c, fmt, ap);
249		va_end(ap);
250		return;
251	}
252
253	cb = xcalloc(1, sizeof *cb);
254	xvasprintf(&cb->line, fmt, ap);
255	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
256
257	log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
258	bufferevent_enable(cs->write_event, EV_WRITE);
259
260	va_end(ap);
261}
262
263/* Write output from a pane. */
264void
265control_write_output(struct client *c, struct window_pane *wp)
266{
267	struct control_state	*cs = c->control_state;
268	struct control_pane	*cp;
269	struct control_block	*cb;
270	size_t			 new_size;
271
272	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
273		return;
274
275	if (c->flags & CONTROL_IGNORE_FLAGS) {
276		cp = control_get_pane(c, wp);
277		if (cp != NULL)
278			goto ignore;
279		return;
280	}
281	cp = control_add_pane(c, wp);
282	if (cp->flags & CONTROL_PANE_OFF)
283		goto ignore;
284
285	window_pane_get_new_data(wp, &cp->queued, &new_size);
286	if (new_size == 0)
287		return;
288	window_pane_update_used_data(wp, &cp->queued, new_size);
289
290	cb = xcalloc(1, sizeof *cb);
291	cb->size = new_size;
292	TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
293
294	TAILQ_INSERT_TAIL(&cp->blocks, cb, entry);
295	log_debug("%s: %s: new output block of %zu for %%%u", __func__, c->name,
296	    cb->size, wp->id);
297
298	if (!cp->pending_flag) {
299		log_debug("%s: %s: %%%u now pending", __func__, c->name,
300		    wp->id);
301		TAILQ_INSERT_TAIL(&cs->pending_list, cp, pending_entry);
302		cp->pending_flag = 1;
303		cs->pending_count++;
304	}
305	bufferevent_enable(cs->write_event, EV_WRITE);
306	return;
307
308ignore:
309	log_debug("%s: %s: ignoring pane %%%u", __func__, c->name, wp->id);
310	window_pane_update_used_data(wp, &cp->offset, SIZE_MAX);
311	window_pane_update_used_data(wp, &cp->queued, SIZE_MAX);
312}
313
314/* Control client error callback. */
315static enum cmd_retval
316control_error(struct cmdq_item *item, void *data)
317{
318	struct client	*c = cmdq_get_client(item);
319	char		*error = data;
320
321	cmdq_guard(item, "begin", 1);
322	control_write(c, "parse error: %s", error);
323	cmdq_guard(item, "error", 1);
324
325	free(error);
326	return (CMD_RETURN_NORMAL);
327}
328
329/* Control client error callback. */
330static void
331control_error_callback(__unused struct bufferevent *bufev,
332    __unused short what, void *data)
333{
334	struct client	*c = data;
335
336	c->flags |= CLIENT_EXIT;
337}
338
339/* Control client input callback. Read lines and fire commands. */
340static void
341control_read_callback(__unused struct bufferevent *bufev, void *data)
342{
343	struct client		*c = data;
344	struct control_state	*cs = c->control_state;
345	struct evbuffer		*buffer = cs->read_event->input;
346	char			*line, *error;
347	struct cmdq_state	*state;
348	enum cmd_parse_status	 status;
349
350	for (;;) {
351		line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
352		if (line == NULL)
353			break;
354		log_debug("%s: %s: %s", __func__, c->name, line);
355		if (*line == '\0') { /* empty line detach */
356			free(line);
357			c->flags |= CLIENT_EXIT;
358			break;
359		}
360
361		state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL);
362		status = cmd_parse_and_append(line, NULL, c, state, &error);
363		if (status == CMD_PARSE_ERROR)
364			cmdq_append(c, cmdq_get_callback(control_error, error));
365		cmdq_free_state(state);
366
367		free(line);
368	}
369}
370
371/* Does this control client have outstanding data to write? */
372int
373control_all_done(struct client *c)
374{
375	struct control_state	*cs = c->control_state;
376
377	if (!TAILQ_EMPTY(&cs->all_blocks))
378		return (0);
379	return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
380}
381
382/* Flush all blocks until output. */
383static void
384control_flush_all_blocks(struct client *c)
385{
386	struct control_state	*cs = c->control_state;
387	struct control_block	*cb, *cb1;
388
389	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) {
390		if (cb->size != 0)
391			break;
392		log_debug("%s: %s: flushing line: %s", __func__, c->name,
393		    cb->line);
394
395		bufferevent_write(cs->write_event, cb->line, strlen(cb->line));
396		bufferevent_write(cs->write_event, "\n", 1);
397		control_free_block(cs, cb);
398	}
399}
400
401/* Append data to buffer. */
402static struct evbuffer *
403control_append_data(struct control_pane *cp, struct evbuffer *message,
404    struct window_pane *wp, size_t size)
405{
406	u_char	*new_data;
407	size_t	 new_size;
408	u_int	 i;
409
410	if (message == NULL) {
411		message = evbuffer_new();
412		if (message == NULL)
413			fatalx("out of memory");
414		evbuffer_add_printf(message, "%%output %%%u ", wp->id);
415	}
416
417	new_data = window_pane_get_new_data(wp, &cp->offset, &new_size);
418	if (new_size < size)
419		fatalx("not enough data: %zu < %zu", new_size, size);
420	for (i = 0; i < size; i++) {
421		if (new_data[i] < ' ' || new_data[i] == '\\')
422			evbuffer_add_printf(message, "\\%03o", new_data[i]);
423		else
424			evbuffer_add_printf(message, "%c", new_data[i]);
425	}
426	window_pane_update_used_data(wp, &cp->offset, size);
427	return (message);
428}
429
430/* Write buffer. */
431static void
432control_write_data(struct client *c, struct evbuffer *message)
433{
434	struct control_state	*cs = c->control_state;
435
436	log_debug("%s: %s: %.*s", __func__, c->name,
437	    (int)EVBUFFER_LENGTH(message), EVBUFFER_DATA(message));
438
439	evbuffer_add(message, "\n", 1);
440	bufferevent_write_buffer(cs->write_event, message);
441	evbuffer_free(message);
442}
443
444/* Write output to client. */
445static int
446control_write_pending(struct client *c, struct control_pane *cp, size_t limit)
447{
448	struct control_state	*cs = c->control_state;
449	struct session		*s = c->session;
450	struct window_pane	*wp = NULL;
451	struct evbuffer		*message = NULL;
452	size_t			 used = 0, size;
453	struct control_block	*cb, *cb1;
454
455	if (s == NULL ||
456	    (wp = window_pane_find_by_id(cp->pane)) == NULL ||
457	    winlink_find_by_window(&s->windows, wp->window) == NULL) {
458		TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
459			TAILQ_REMOVE(&cp->blocks, cb, entry);
460			control_free_block(cs, cb);
461		}
462		control_flush_all_blocks(c);
463		return (0);
464	}
465
466	while (used != limit && !TAILQ_EMPTY(&cp->blocks)) {
467		cb = TAILQ_FIRST(&cp->blocks);
468		log_debug("%s: %s: output block %zu for %%%u (used %zu/%zu)",
469		    __func__, c->name, cb->size, cp->pane, used, limit);
470
471		size = cb->size;
472		if (size > limit - used)
473			size = limit - used;
474		used += size;
475
476		message = control_append_data(cp, message, wp, size);
477
478		cb->size -= size;
479		if (cb->size == 0) {
480			TAILQ_REMOVE(&cp->blocks, cb, entry);
481			control_free_block(cs, cb);
482
483			cb = TAILQ_FIRST(&cs->all_blocks);
484			if (cb != NULL && cb->size == 0) {
485				if (wp != NULL && message != NULL) {
486					control_write_data(c, message);
487					message = NULL;
488				}
489				control_flush_all_blocks(c);
490			}
491		}
492	}
493	if (message != NULL)
494		control_write_data(c, message);
495	return (!TAILQ_EMPTY(&cp->blocks));
496}
497
498/* Control client write callback. */
499static void
500control_write_callback(__unused struct bufferevent *bufev, void *data)
501{
502	struct client		*c = data;
503	struct control_state	*cs = c->control_state;
504	struct control_pane	*cp, *cp1;
505	struct evbuffer		*evb = cs->write_event->output;
506	size_t			 space, limit;
507
508	control_flush_all_blocks(c);
509
510	while (EVBUFFER_LENGTH(evb) < CONTROL_BUFFER_HIGH) {
511		if (cs->pending_count == 0)
512			break;
513		space = CONTROL_BUFFER_HIGH - EVBUFFER_LENGTH(evb);
514		log_debug("%s: %s: %zu bytes available, %u panes", __func__,
515		    c->name, space, cs->pending_count);
516
517		limit = (space / cs->pending_count / 3); /* 3 bytes for \xxx */
518		if (limit < CONTROL_WRITE_MINIMUM)
519			limit = CONTROL_WRITE_MINIMUM;
520
521		TAILQ_FOREACH_SAFE(cp, &cs->pending_list, pending_entry, cp1) {
522			if (EVBUFFER_LENGTH(evb) >= CONTROL_BUFFER_HIGH)
523				break;
524			if (control_write_pending(c, cp, limit))
525				continue;
526			TAILQ_REMOVE(&cs->pending_list, cp, pending_entry);
527			cp->pending_flag = 0;
528			cs->pending_count--;
529		}
530	}
531	if (EVBUFFER_LENGTH(evb) == 0)
532		bufferevent_disable(cs->write_event, EV_WRITE);
533}
534
535/* Initialize for control mode. */
536void
537control_start(struct client *c)
538{
539	struct control_state	*cs;
540
541	if (c->flags & CLIENT_CONTROLCONTROL) {
542		close(c->out_fd);
543		c->out_fd = -1;
544	} else
545		setblocking(c->out_fd, 0);
546	setblocking(c->fd, 0);
547
548	cs = c->control_state = xcalloc(1, sizeof *cs);
549	RB_INIT(&cs->panes);
550	TAILQ_INIT(&cs->pending_list);
551	TAILQ_INIT(&cs->all_blocks);
552
553	cs->read_event = bufferevent_new(c->fd, control_read_callback,
554	    control_write_callback, control_error_callback, c);
555	bufferevent_enable(cs->read_event, EV_READ);
556
557	if (c->flags & CLIENT_CONTROLCONTROL)
558		cs->write_event = cs->read_event;
559	else {
560		cs->write_event = bufferevent_new(c->out_fd, NULL,
561		    control_write_callback, control_error_callback, c);
562	}
563	bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW,
564	    0);
565
566	if (c->flags & CLIENT_CONTROLCONTROL) {
567		bufferevent_write(cs->write_event, "\033P1000p", 7);
568		bufferevent_enable(cs->write_event, EV_WRITE);
569	}
570}
571
572/* Flush all output for a client that is detaching. */
573void
574control_flush(struct client *c)
575{
576	struct control_state	*cs = c->control_state;
577	struct control_pane	*cp;
578	struct control_block	*cb, *cb1;
579
580	RB_FOREACH(cp, control_panes, &cs->panes) {
581		TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) {
582			TAILQ_REMOVE(&cp->blocks, cb, entry);
583			control_free_block(cs, cb);
584		}
585	}
586}
587
588/* Stop control mode. */
589void
590control_stop(struct client *c)
591{
592	struct control_state	*cs = c->control_state;
593	struct control_block	*cb, *cb1;
594
595	if (~c->flags & CLIENT_CONTROLCONTROL)
596		bufferevent_free(cs->write_event);
597	bufferevent_free(cs->read_event);
598
599	TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
600		control_free_block(cs, cb);
601	control_reset_offsets(c);
602
603	free(cs);
604}
605