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 printflike(2, 0)
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 || wp->fd == -1) {
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           if (cs->read_event == NULL)
779                     fatalx("out of memory");
780 
781           if (c->flags & CLIENT_CONTROLCONTROL)
782                     cs->write_event = cs->read_event;
783           else {
784                     cs->write_event = bufferevent_new(c->out_fd, NULL,
785                         control_write_callback, control_error_callback, c);
786                     if (cs->write_event == NULL)
787                               fatalx("out of memory");
788           }
789           bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW,
790               0);
791 
792           if (c->flags & CLIENT_CONTROLCONTROL) {
793                     bufferevent_write(cs->write_event, "\033P1000p", 7);
794                     bufferevent_enable(cs->write_event, EV_WRITE);
795           }
796 }
797 
798 /* Control client ready. */
799 void
control_ready(struct client * c)800 control_ready(struct client *c)
801 {
802           bufferevent_enable(c->control_state->read_event, EV_READ);
803 }
804 
805 /* Discard all output for a client. */
806 void
control_discard(struct client * c)807 control_discard(struct client *c)
808 {
809           struct control_state          *cs = c->control_state;
810           struct control_pane *cp;
811 
812           RB_FOREACH(cp, control_panes, &cs->panes)
813                     control_discard_pane(c, cp);
814           bufferevent_disable(cs->read_event, EV_READ);
815 }
816 
817 /* Stop control mode. */
818 void
control_stop(struct client * c)819 control_stop(struct client *c)
820 {
821           struct control_state          *cs = c->control_state;
822           struct control_block          *cb, *cb1;
823           struct control_sub  *csub, *csub1;
824 
825           if (~c->flags & CLIENT_CONTROLCONTROL)
826                     bufferevent_free(cs->write_event);
827           bufferevent_free(cs->read_event);
828 
829           RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1)
830                     control_free_sub(cs, csub);
831           if (evtimer_initialized(&cs->subs_timer))
832                     evtimer_del(&cs->subs_timer);
833 
834           TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
835                     control_free_block(cs, cb);
836           control_reset_offsets(c);
837 
838           free(cs);
839 }
840 
841 /* Check session subscription. */
842 static void
control_check_subs_session(struct client * c,struct control_sub * csub)843 control_check_subs_session(struct client *c, struct control_sub *csub)
844 {
845           struct session                *s = c->session;
846           struct format_tree  *ft;
847           char                          *value;
848 
849           ft = format_create_defaults(NULL, c, s, NULL, NULL);
850           value = format_expand(ft, csub->format);
851           format_free(ft);
852 
853           if (csub->last != NULL && strcmp(value, csub->last) == 0) {
854                     free(value);
855                     return;
856           }
857           control_write(c,
858               "%%subscription-changed %s $%u - - - : %s",
859               csub->name, s->id, value);
860           free(csub->last);
861           csub->last = value;
862 }
863 
864 /* Check pane subscription. */
865 static void
control_check_subs_pane(struct client * c,struct control_sub * csub)866 control_check_subs_pane(struct client *c, struct control_sub *csub)
867 {
868           struct session                *s = c->session;
869           struct window_pane  *wp;
870           struct window                 *w;
871           struct winlink                *wl;
872           struct format_tree  *ft;
873           char                          *value;
874           struct control_sub_pane       *csp, find;
875 
876           wp = window_pane_find_by_id(csub->id);
877           if (wp == NULL || wp->fd == -1)
878                     return;
879           w = wp->window;
880 
881           TAILQ_FOREACH(wl, &w->winlinks, wentry) {
882                     if (wl->session != s)
883                               continue;
884 
885                     ft = format_create_defaults(NULL, c, s, wl, wp);
886                     value = format_expand(ft, csub->format);
887                     format_free(ft);
888 
889                     find.pane = wp->id;
890                     find.idx = wl->idx;
891 
892                     csp = RB_FIND(control_sub_panes, &csub->panes, &find);
893                     if (csp == NULL) {
894                               csp = xcalloc(1, sizeof *csp);
895                               csp->pane = wp->id;
896                               csp->idx = wl->idx;
897                               RB_INSERT(control_sub_panes, &csub->panes, csp);
898                     }
899 
900                     if (csp->last != NULL && strcmp(value, csp->last) == 0) {
901                               free(value);
902                               continue;
903                     }
904                     control_write(c,
905                         "%%subscription-changed %s $%u @%u %u %%%u : %s",
906                         csub->name, s->id, w->id, wl->idx, wp->id, value);
907                     free(csp->last);
908                     csp->last = value;
909           }
910 }
911 
912 /* Check all panes subscription. */
913 static void
control_check_subs_all_panes(struct client * c,struct control_sub * csub)914 control_check_subs_all_panes(struct client *c, struct control_sub *csub)
915 {
916           struct session                *s = c->session;
917           struct window_pane  *wp;
918           struct window                 *w;
919           struct winlink                *wl;
920           struct format_tree  *ft;
921           char                          *value;
922           struct control_sub_pane       *csp, find;
923 
924           RB_FOREACH(wl, winlinks, &s->windows) {
925                     w = wl->window;
926                     TAILQ_FOREACH(wp, &w->panes, entry) {
927                               ft = format_create_defaults(NULL, c, s, wl, wp);
928                               value = format_expand(ft, csub->format);
929                               format_free(ft);
930 
931                               find.pane = wp->id;
932                               find.idx = wl->idx;
933 
934                               csp = RB_FIND(control_sub_panes, &csub->panes, &find);
935                               if (csp == NULL) {
936                                         csp = xcalloc(1, sizeof *csp);
937                                         csp->pane = wp->id;
938                                         csp->idx = wl->idx;
939                                         RB_INSERT(control_sub_panes, &csub->panes, csp);
940                               }
941 
942                               if (csp->last != NULL &&
943                                   strcmp(value, csp->last) == 0) {
944                                         free(value);
945                                         continue;
946                               }
947                               control_write(c,
948                                   "%%subscription-changed %s $%u @%u %u %%%u : %s",
949                                   csub->name, s->id, w->id, wl->idx, wp->id, value);
950                               free(csp->last);
951                               csp->last = value;
952                     }
953           }
954 }
955 
956 /* Check window subscription. */
957 static void
control_check_subs_window(struct client * c,struct control_sub * csub)958 control_check_subs_window(struct client *c, struct control_sub *csub)
959 {
960           struct session                          *s = c->session;
961           struct window                           *w;
962           struct winlink                          *wl;
963           struct format_tree            *ft;
964           char                                    *value;
965           struct control_sub_window     *csw, find;
966 
967           w = window_find_by_id(csub->id);
968           if (w == NULL)
969                     return;
970 
971           TAILQ_FOREACH(wl, &w->winlinks, wentry) {
972                     if (wl->session != s)
973                               continue;
974 
975                     ft = format_create_defaults(NULL, c, s, wl, NULL);
976                     value = format_expand(ft, csub->format);
977                     format_free(ft);
978 
979                     find.window = w->id;
980                     find.idx = wl->idx;
981 
982                     csw = RB_FIND(control_sub_windows, &csub->windows, &find);
983                     if (csw == NULL) {
984                               csw = xcalloc(1, sizeof *csw);
985                               csw->window = w->id;
986                               csw->idx = wl->idx;
987                               RB_INSERT(control_sub_windows, &csub->windows, csw);
988                     }
989 
990                     if (csw->last != NULL && strcmp(value, csw->last) == 0) {
991                               free(value);
992                               continue;
993                     }
994                     control_write(c,
995                         "%%subscription-changed %s $%u @%u %u - : %s",
996                         csub->name, s->id, w->id, wl->idx, value);
997                     free(csw->last);
998                     csw->last = value;
999           }
1000 }
1001 
1002 /* Check all windows subscription. */
1003 static void
control_check_subs_all_windows(struct client * c,struct control_sub * csub)1004 control_check_subs_all_windows(struct client *c, struct control_sub *csub)
1005 {
1006           struct session                          *s = c->session;
1007           struct window                           *w;
1008           struct winlink                          *wl;
1009           struct format_tree            *ft;
1010           char                                    *value;
1011           struct control_sub_window     *csw, find;
1012 
1013           RB_FOREACH(wl, winlinks, &s->windows) {
1014                     w = wl->window;
1015 
1016                     ft = format_create_defaults(NULL, c, s, wl, NULL);
1017                     value = format_expand(ft, csub->format);
1018                     format_free(ft);
1019 
1020                     find.window = w->id;
1021                     find.idx = wl->idx;
1022 
1023                     csw = RB_FIND(control_sub_windows, &csub->windows, &find);
1024                     if (csw == NULL) {
1025                               csw = xcalloc(1, sizeof *csw);
1026                               csw->window = w->id;
1027                               csw->idx = wl->idx;
1028                               RB_INSERT(control_sub_windows, &csub->windows, csw);
1029                     }
1030 
1031                     if (csw->last != NULL && strcmp(value, csw->last) == 0) {
1032                               free(value);
1033                               continue;
1034                     }
1035                     control_write(c,
1036                         "%%subscription-changed %s $%u @%u %u - : %s",
1037                         csub->name, s->id, w->id, wl->idx, value);
1038                     free(csw->last);
1039                     csw->last = value;
1040           }
1041 }
1042 
1043 /* Check subscriptions timer. */
1044 static void
control_check_subs_timer(__unused int fd,__unused short events,void * data)1045 control_check_subs_timer(__unused int fd, __unused short events, void *data)
1046 {
1047           struct client                 *c = data;
1048           struct control_state          *cs = c->control_state;
1049           struct control_sub  *csub, *csub1;
1050           struct timeval                 tv = { .tv_sec = 1 };
1051 
1052           log_debug("%s: timer fired", __func__);
1053           evtimer_add(&cs->subs_timer, &tv);
1054 
1055           RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
1056                     switch (csub->type) {
1057                     case CONTROL_SUB_SESSION:
1058                               control_check_subs_session(c, csub);
1059                               break;
1060                     case CONTROL_SUB_PANE:
1061                               control_check_subs_pane(c, csub);
1062                               break;
1063                     case CONTROL_SUB_ALL_PANES:
1064                               control_check_subs_all_panes(c, csub);
1065                               break;
1066                     case CONTROL_SUB_WINDOW:
1067                               control_check_subs_window(c, csub);
1068                               break;
1069                     case CONTROL_SUB_ALL_WINDOWS:
1070                               control_check_subs_all_windows(c, csub);
1071                               break;
1072                     }
1073           }
1074 }
1075 
1076 /* Add a subscription. */
1077 void
control_add_sub(struct client * c,const char * name,enum control_sub_type type,int id,const char * format)1078 control_add_sub(struct client *c, const char *name, enum control_sub_type type,
1079     int id, const char *format)
1080 {
1081           struct control_state          *cs = c->control_state;
1082           struct control_sub  *csub, find;
1083           struct timeval                 tv = { .tv_sec = 1 };
1084 
1085           find.name = __UNCONST(name);
1086           if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
1087                     control_free_sub(cs, csub);
1088 
1089           csub = xcalloc(1, sizeof *csub);
1090           csub->name = xstrdup(name);
1091           csub->type = type;
1092           csub->id = id;
1093           csub->format = xstrdup(format);
1094           RB_INSERT(control_subs, &cs->subs, csub);
1095 
1096           RB_INIT(&csub->panes);
1097           RB_INIT(&csub->windows);
1098 
1099           if (!evtimer_initialized(&cs->subs_timer))
1100                     evtimer_set(&cs->subs_timer, control_check_subs_timer, c);
1101           if (!evtimer_pending(&cs->subs_timer, NULL))
1102                     evtimer_add(&cs->subs_timer, &tv);
1103 }
1104 
1105 /* Remove a subscription. */
1106 void
control_remove_sub(struct client * c,const char * name)1107 control_remove_sub(struct client *c, const char *name)
1108 {
1109           struct control_state          *cs = c->control_state;
1110           struct control_sub  *csub, find;
1111 
1112           find.name = __UNCONST(name);
1113           if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL)
1114                     control_free_sub(cs, csub);
1115           if (RB_EMPTY(&cs->subs))
1116                     evtimer_del(&cs->subs_timer);
1117 }
1118