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 */ 45struct control_block { 46 size_t size; 47 char *line; 48 uint64_t t; 49 50 TAILQ_ENTRY(control_block) entry; 51 TAILQ_ENTRY(control_block) all_entry; 52}; 53 54/* Control client pane. */ 55struct control_pane { 56 u_int pane; 57 58 /* 59 * Offsets into the pane data. The first (offset) is the data we have 60 * written; the second (queued) the data we have queued (pointed to by 61 * a block). 62 */ 63 struct window_pane_offset offset; 64 struct window_pane_offset queued; 65 66 int flags; 67#define CONTROL_PANE_OFF 0x1 68#define CONTROL_PANE_PAUSED 0x2 69 70 int pending_flag; 71 TAILQ_ENTRY(control_pane) pending_entry; 72 73 TAILQ_HEAD(, control_block) blocks; 74 75 RB_ENTRY(control_pane) entry; 76}; 77RB_HEAD(control_panes, control_pane); 78 79/* Subscription pane. */ 80struct control_sub_pane { 81 u_int pane; 82 u_int idx; 83 char *last; 84 85 RB_ENTRY(control_sub_pane) entry; 86}; 87RB_HEAD(control_sub_panes, control_sub_pane); 88 89/* Subscription window. */ 90struct control_sub_window { 91 u_int window; 92 u_int idx; 93 char *last; 94 95 RB_ENTRY(control_sub_window) entry; 96}; 97RB_HEAD(control_sub_windows, control_sub_window); 98 99/* Control client subscription. */ 100struct 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}; 113RB_HEAD(control_subs, control_sub); 114 115/* Control client state. */ 116struct 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. */ 147static int 148control_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} 156RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp); 157 158/* Compare client subs. */ 159static int 160control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2) 161{ 162 return (strcmp(csub1->name, csub2->name)); 163} 164RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp); 165 166/* Compare client subscription panes. */ 167static int 168control_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} 181RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry, 182 control_sub_pane_cmp); 183 184/* Compare client subscription windows. */ 185static int 186control_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} 199RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry, 200 control_sub_window_cmp); 201 202/* Free a subscription. */ 203static void 204control_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. */ 226static void 227control_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. */ 235static struct control_pane * 236control_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. */ 245static struct control_pane * 246control_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. */ 267static void 268control_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. */ 280static struct window_pane * 281control_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. */ 295void 296control_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. */ 311struct window_pane_offset * 312control_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. */ 336void 337control_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. */ 350void 351control_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. */ 360void 361control_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. */ 375void 376control_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. */ 389static void printflike(2, 0) 390control_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. */ 406void 407control_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. */ 433static int 434control_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. */ 468void 469control_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 515ignore: 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. */ 522static enum cmd_retval 523control_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. */ 537static void 538control_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. */ 547static void 548control_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? */ 579int 580control_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. */ 590static void 591control_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. */ 609static struct evbuffer * 610control_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. */ 643static void 644control_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. */ 657static int 658control_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. */ 722static void 723control_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. */ 759void 760control_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. */ 800void 801control_ready(struct client *c) 802{ 803 bufferevent_enable(c->control_state->read_event, EV_READ); 804} 805 806/* Discard all output for a client. */ 807void 808control_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. */ 819void 820control_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. */ 843static void 844control_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. */ 866static void 867control_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. */ 914static void 915control_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. */ 958static void 959control_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. */ 1004static void 1005control_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. */ 1045static void 1046control_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. */ 1078void 1079control_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. */ 1107void 1108control_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