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