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 */
44 struct 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. */
54 struct 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 };
76 RB_HEAD(control_panes, control_pane);
77
78 /* Subscription pane. */
79 struct control_sub_pane {
80 u_int pane;
81 u_int idx;
82 char *last;
83
84 RB_ENTRY(control_sub_pane) entry;
85 };
86 RB_HEAD(control_sub_panes, control_sub_pane);
87
88 /* Subscription window. */
89 struct control_sub_window {
90 u_int window;
91 u_int idx;
92 char *last;
93
94 RB_ENTRY(control_sub_window) entry;
95 };
96 RB_HEAD(control_sub_windows, control_sub_window);
97
98 /* Control client subscription. */
99 struct 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 };
112 RB_HEAD(control_subs, control_sub);
113
114 /* Control client state. */
115 struct 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. */
146 static int
control_pane_cmp(struct control_pane * cp1,struct control_pane * cp2)147 control_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 }
155 RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp);
156
157 /* Compare client subs. */
158 static int
control_sub_cmp(struct control_sub * csub1,struct control_sub * csub2)159 control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2)
160 {
161 return (strcmp(csub1->name, csub2->name));
162 }
163 RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp);
164
165 /* Compare client subscription panes. */
166 static int
control_sub_pane_cmp(struct control_sub_pane * csp1,struct control_sub_pane * csp2)167 control_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 }
180 RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry,
181 control_sub_pane_cmp);
182
183 /* Compare client subscription windows. */
184 static int
control_sub_window_cmp(struct control_sub_window * csw1,struct control_sub_window * csw2)185 control_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 }
198 RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry,
199 control_sub_window_cmp);
200
201 /* Free a subscription. */
202 static void
control_free_sub(struct control_state * cs,struct control_sub * csub)203 control_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. */
225 static void
control_free_block(struct control_state * cs,struct control_block * cb)226 control_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. */
234 static struct control_pane *
control_get_pane(struct client * c,struct window_pane * wp)235 control_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. */
244 static struct control_pane *
control_add_pane(struct client * c,struct window_pane * wp)245 control_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. */
266 static void
control_discard_pane(struct client * c,struct control_pane * cp)267 control_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. */
279 static struct window_pane *
control_window_pane(struct client * c,u_int pane)280 control_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. */
294 void
control_reset_offsets(struct client * c)295 control_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. */
310 struct window_pane_offset *
control_pane_offset(struct client * c,struct window_pane * wp,int * off)311 control_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. */
335 void
control_set_pane_on(struct client * c,struct window_pane * wp)336 control_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. */
349 void
control_set_pane_off(struct client * c,struct window_pane * wp)350 control_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. */
359 void
control_continue_pane(struct client * c,struct window_pane * wp)360 control_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. */
374 void
control_pause_pane(struct client * c,struct window_pane * wp)375 control_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. */
388 static void
control_vwrite(struct client * c,const char * fmt,va_list ap)389 control_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. */
405 void
control_write(struct client * c,const char * fmt,...)406 control_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. */
432 static int
control_check_age(struct client * c,struct window_pane * wp,struct control_pane * cp)433 control_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. */
467 void
control_write_output(struct client * c,struct window_pane * wp)468 control_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
514 ignore:
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. */
521 static enum cmd_retval
control_error(struct cmdq_item * item,void * data)522 control_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. */
536 static void
control_error_callback(__unused struct bufferevent * bufev,__unused short what,void * data)537 control_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. */
546 static void
control_read_callback(__unused struct bufferevent * bufev,void * data)547 control_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? */
578 int
control_all_done(struct client * c)579 control_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. */
589 static void
control_flush_all_blocks(struct client * c)590 control_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. */
608 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)609 control_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. */
642 static void
control_write_data(struct client * c,struct evbuffer * message)643 control_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. */
656 static int
control_write_pending(struct client * c,struct control_pane * cp,size_t limit)657 control_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. */
721 static void
control_write_callback(__unused struct bufferevent * bufev,void * data)722 control_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. */
758 void
control_start(struct client * c)759 control_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. */
796 void
control_discard(struct client * c)797 control_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. */
808 void
control_stop(struct client * c)809 control_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. */
832 static void
control_check_subs_session(struct client * c,struct control_sub * csub)833 control_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. */
855 static void
control_check_subs_pane(struct client * c,struct control_sub * csub)856 control_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. */
903 static void
control_check_subs_all_panes(struct client * c,struct control_sub * csub)904 control_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. */
947 static void
control_check_subs_window(struct client * c,struct control_sub * csub)948 control_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. */
993 static void
control_check_subs_all_windows(struct client * c,struct control_sub * csub)994 control_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. */
1034 static void
control_check_subs_timer(__unused int fd,__unused short events,void * data)1035 control_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. */
1067 void
control_add_sub(struct client * c,const char * name,enum control_sub_type type,int id,const char * format)1068 control_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 = (char *)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. */
1096 void
control_remove_sub(struct client * c,const char * name)1097 control_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 = (char *)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