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