control.c revision 1.3
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 */ 44struct 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. */ 54struct 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}; 76RB_HEAD(control_panes, control_pane); 77 78/* Subscription pane. */ 79struct control_sub_pane { 80 u_int pane; 81 u_int idx; 82 char *last; 83 84 RB_ENTRY(control_sub_pane) entry; 85}; 86RB_HEAD(control_sub_panes, control_sub_pane); 87 88/* Subscription window. */ 89struct control_sub_window { 90 u_int window; 91 u_int idx; 92 char *last; 93 94 RB_ENTRY(control_sub_window) entry; 95}; 96RB_HEAD(control_sub_windows, control_sub_window); 97 98/* Control client subscription. */ 99struct 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}; 112RB_HEAD(control_subs, control_sub); 113 114/* Control client state. */ 115struct 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. */ 146static int 147control_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} 155RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp); 156 157/* Compare client subs. */ 158static int 159control_sub_cmp(struct control_sub *csub1, struct control_sub *csub2) 160{ 161 return (strcmp(csub1->name, csub2->name)); 162} 163RB_GENERATE_STATIC(control_subs, control_sub, entry, control_sub_cmp); 164 165/* Compare client subscription panes. */ 166static int 167control_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} 180RB_GENERATE_STATIC(control_sub_panes, control_sub_pane, entry, 181 control_sub_pane_cmp); 182 183/* Compare client subscription windows. */ 184static int 185control_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} 198RB_GENERATE_STATIC(control_sub_windows, control_sub_window, entry, 199 control_sub_window_cmp); 200 201/* Free a subscription. */ 202static void 203control_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. */ 225static void 226control_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. */ 234static struct control_pane * 235control_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. */ 244static struct control_pane * 245control_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. */ 266static void 267control_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. */ 279static struct window_pane * 280control_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. */ 294void 295control_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. */ 310struct window_pane_offset * 311control_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. */ 335void 336control_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. */ 349void 350control_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. */ 359void 360control_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. */ 374void 375control_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. */ 388static void __printflike(2, 0) 389control_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. */ 405void 406control_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. */ 432static int 433control_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. */ 467void 468control_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 514ignore: 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. */ 521static enum cmd_retval 522control_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. */ 536static void 537control_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. */ 546static void 547control_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? */ 578int 579control_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. */ 589static void 590control_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. */ 608static struct evbuffer * 609control_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. */ 642static void 643control_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. */ 656static int 657control_write_pending(struct client *c, struct control_pane *cp, size_t limit) 658{ 659 struct control_state *cs = c->control_state; 660 struct window_pane *wp = NULL; 661 struct evbuffer *message = NULL; 662 size_t used = 0, size; 663 struct control_block *cb, *cb1; 664 uint64_t age, t = get_timer(); 665 666 wp = control_window_pane(c, cp->pane); 667 if (wp == NULL) { 668 TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) { 669 TAILQ_REMOVE(&cp->blocks, cb, entry); 670 control_free_block(cs, cb); 671 } 672 control_flush_all_blocks(c); 673 return (0); 674 } 675 676 while (used != limit && !TAILQ_EMPTY(&cp->blocks)) { 677 if (control_check_age(c, wp, cp)) { 678 if (message != NULL) 679 evbuffer_free(message); 680 message = NULL; 681 break; 682 } 683 684 cb = TAILQ_FIRST(&cp->blocks); 685 if (cb->t < t) 686 age = t - cb->t; 687 else 688 age = 0; 689 log_debug("%s: %s: output block %zu (age %llu) for %%%u " 690 "(used %zu/%zu)", __func__, c->name, cb->size, 691 (unsigned long long)age, cp->pane, used, limit); 692 693 size = cb->size; 694 if (size > limit - used) 695 size = limit - used; 696 used += size; 697 698 message = control_append_data(c, cp, age, message, wp, size); 699 700 cb->size -= size; 701 if (cb->size == 0) { 702 TAILQ_REMOVE(&cp->blocks, cb, entry); 703 control_free_block(cs, cb); 704 705 cb = TAILQ_FIRST(&cs->all_blocks); 706 if (cb != NULL && cb->size == 0) { 707 if (wp != NULL && message != NULL) { 708 control_write_data(c, message); 709 message = NULL; 710 } 711 control_flush_all_blocks(c); 712 } 713 } 714 } 715 if (message != NULL) 716 control_write_data(c, message); 717 return (!TAILQ_EMPTY(&cp->blocks)); 718} 719 720/* Control client write callback. */ 721static void 722control_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. */ 758void 759control_start(struct client *c) 760{ 761 struct control_state *cs; 762 763 if (c->flags & CLIENT_CONTROLCONTROL) { 764 close(c->out_fd); 765 c->out_fd = -1; 766 } else 767 setblocking(c->out_fd, 0); 768 setblocking(c->fd, 0); 769 770 cs = c->control_state = xcalloc(1, sizeof *cs); 771 RB_INIT(&cs->panes); 772 TAILQ_INIT(&cs->pending_list); 773 TAILQ_INIT(&cs->all_blocks); 774 RB_INIT(&cs->subs); 775 776 cs->read_event = bufferevent_new(c->fd, control_read_callback, 777 control_write_callback, control_error_callback, c); 778 bufferevent_enable(cs->read_event, EV_READ); 779 780 if (c->flags & CLIENT_CONTROLCONTROL) 781 cs->write_event = cs->read_event; 782 else { 783 cs->write_event = bufferevent_new(c->out_fd, NULL, 784 control_write_callback, control_error_callback, c); 785 } 786 bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW, 787 0); 788 789 if (c->flags & CLIENT_CONTROLCONTROL) { 790 bufferevent_write(cs->write_event, "\033P1000p", 7); 791 bufferevent_enable(cs->write_event, EV_WRITE); 792 } 793} 794 795/* Discard all output for a client. */ 796void 797control_discard(struct client *c) 798{ 799 struct control_state *cs = c->control_state; 800 struct control_pane *cp; 801 802 RB_FOREACH(cp, control_panes, &cs->panes) 803 control_discard_pane(c, cp); 804 bufferevent_disable(cs->read_event, EV_READ); 805} 806 807/* Stop control mode. */ 808void 809control_stop(struct client *c) 810{ 811 struct control_state *cs = c->control_state; 812 struct control_block *cb, *cb1; 813 struct control_sub *csub, *csub1; 814 815 if (~c->flags & CLIENT_CONTROLCONTROL) 816 bufferevent_free(cs->write_event); 817 bufferevent_free(cs->read_event); 818 819 RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) 820 control_free_sub(cs, csub); 821 if (evtimer_initialized(&cs->subs_timer)) 822 evtimer_del(&cs->subs_timer); 823 824 TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) 825 control_free_block(cs, cb); 826 control_reset_offsets(c); 827 828 free(cs); 829} 830 831/* Check session subscription. */ 832static void 833control_check_subs_session(struct client *c, struct control_sub *csub) 834{ 835 struct session *s = c->session; 836 struct format_tree *ft; 837 char *value; 838 839 ft = format_create_defaults(NULL, c, s, NULL, NULL); 840 value = format_expand(ft, csub->format); 841 format_free(ft); 842 843 if (csub->last != NULL && strcmp(value, csub->last) == 0) { 844 free(value); 845 return; 846 } 847 control_write(c, 848 "%%subscription-changed %s $%u - - - : %s", 849 csub->name, s->id, value); 850 free(csub->last); 851 csub->last = value; 852} 853 854/* Check pane subscription. */ 855static void 856control_check_subs_pane(struct client *c, struct control_sub *csub) 857{ 858 struct session *s = c->session; 859 struct window_pane *wp; 860 struct window *w; 861 struct winlink *wl; 862 struct format_tree *ft; 863 char *value; 864 struct control_sub_pane *csp, find; 865 866 wp = window_pane_find_by_id(csub->id); 867 if (wp == NULL) 868 return; 869 w = wp->window; 870 871 TAILQ_FOREACH(wl, &w->winlinks, wentry) { 872 if (wl->session != s) 873 continue; 874 875 ft = format_create_defaults(NULL, c, s, wl, wp); 876 value = format_expand(ft, csub->format); 877 format_free(ft); 878 879 find.pane = wp->id; 880 find.idx = wl->idx; 881 882 csp = RB_FIND(control_sub_panes, &csub->panes, &find); 883 if (csp == NULL) { 884 csp = xcalloc(1, sizeof *csp); 885 csp->pane = wp->id; 886 csp->idx = wl->idx; 887 RB_INSERT(control_sub_panes, &csub->panes, csp); 888 } 889 890 if (csp->last != NULL && strcmp(value, csp->last) == 0) { 891 free(value); 892 continue; 893 } 894 control_write(c, 895 "%%subscription-changed %s $%u @%u %u %%%u : %s", 896 csub->name, s->id, w->id, wl->idx, wp->id, value); 897 free(csp->last); 898 csp->last = value; 899 } 900} 901 902/* Check all panes subscription. */ 903static void 904control_check_subs_all_panes(struct client *c, struct control_sub *csub) 905{ 906 struct session *s = c->session; 907 struct window_pane *wp; 908 struct window *w; 909 struct winlink *wl; 910 struct format_tree *ft; 911 char *value; 912 struct control_sub_pane *csp, find; 913 914 RB_FOREACH(wl, winlinks, &s->windows) { 915 w = wl->window; 916 TAILQ_FOREACH(wp, &w->panes, entry) { 917 ft = format_create_defaults(NULL, c, s, wl, wp); 918 value = format_expand(ft, csub->format); 919 format_free(ft); 920 921 find.pane = wp->id; 922 find.idx = wl->idx; 923 924 csp = RB_FIND(control_sub_panes, &csub->panes, &find); 925 if (csp == NULL) { 926 csp = xcalloc(1, sizeof *csp); 927 csp->pane = wp->id; 928 csp->idx = wl->idx; 929 RB_INSERT(control_sub_panes, &csub->panes, csp); 930 } 931 932 if (csp->last != NULL && 933 strcmp(value, csp->last) == 0) { 934 free(value); 935 continue; 936 } 937 control_write(c, 938 "%%subscription-changed %s $%u @%u %u %%%u : %s", 939 csub->name, s->id, w->id, wl->idx, wp->id, value); 940 free(csp->last); 941 csp->last = value; 942 } 943 } 944} 945 946/* Check window subscription. */ 947static void 948control_check_subs_window(struct client *c, struct control_sub *csub) 949{ 950 struct session *s = c->session; 951 struct window *w; 952 struct winlink *wl; 953 struct format_tree *ft; 954 char *value; 955 struct control_sub_window *csw, find; 956 957 w = window_find_by_id(csub->id); 958 if (w == NULL) 959 return; 960 961 TAILQ_FOREACH(wl, &w->winlinks, wentry) { 962 if (wl->session != s) 963 continue; 964 965 ft = format_create_defaults(NULL, c, s, wl, NULL); 966 value = format_expand(ft, csub->format); 967 format_free(ft); 968 969 find.window = w->id; 970 find.idx = wl->idx; 971 972 csw = RB_FIND(control_sub_windows, &csub->windows, &find); 973 if (csw == NULL) { 974 csw = xcalloc(1, sizeof *csw); 975 csw->window = w->id; 976 csw->idx = wl->idx; 977 RB_INSERT(control_sub_windows, &csub->windows, csw); 978 } 979 980 if (csw->last != NULL && strcmp(value, csw->last) == 0) { 981 free(value); 982 continue; 983 } 984 control_write(c, 985 "%%subscription-changed %s $%u @%u %u - : %s", 986 csub->name, s->id, w->id, wl->idx, value); 987 free(csw->last); 988 csw->last = value; 989 } 990} 991 992/* Check all windows subscription. */ 993static void 994control_check_subs_all_windows(struct client *c, struct control_sub *csub) 995{ 996 struct session *s = c->session; 997 struct window *w; 998 struct winlink *wl; 999 struct format_tree *ft; 1000 char *value; 1001 struct control_sub_window *csw, find; 1002 1003 RB_FOREACH(wl, winlinks, &s->windows) { 1004 w = wl->window; 1005 1006 ft = format_create_defaults(NULL, c, s, wl, NULL); 1007 value = format_expand(ft, csub->format); 1008 format_free(ft); 1009 1010 find.window = w->id; 1011 find.idx = wl->idx; 1012 1013 csw = RB_FIND(control_sub_windows, &csub->windows, &find); 1014 if (csw == NULL) { 1015 csw = xcalloc(1, sizeof *csw); 1016 csw->window = w->id; 1017 csw->idx = wl->idx; 1018 RB_INSERT(control_sub_windows, &csub->windows, csw); 1019 } 1020 1021 if (csw->last != NULL && strcmp(value, csw->last) == 0) { 1022 free(value); 1023 continue; 1024 } 1025 control_write(c, 1026 "%%subscription-changed %s $%u @%u %u - : %s", 1027 csub->name, s->id, w->id, wl->idx, value); 1028 free(csw->last); 1029 csw->last = value; 1030 } 1031} 1032 1033/* Check subscriptions timer. */ 1034static void 1035control_check_subs_timer(__unused int fd, __unused short events, void *data) 1036{ 1037 struct client *c = data; 1038 struct control_state *cs = c->control_state; 1039 struct control_sub *csub, *csub1; 1040 struct timeval tv = { .tv_sec = 1 }; 1041 1042 log_debug("%s: timer fired", __func__); 1043 evtimer_add(&cs->subs_timer, &tv); 1044 1045 RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) { 1046 switch (csub->type) { 1047 case CONTROL_SUB_SESSION: 1048 control_check_subs_session(c, csub); 1049 break; 1050 case CONTROL_SUB_PANE: 1051 control_check_subs_pane(c, csub); 1052 break; 1053 case CONTROL_SUB_ALL_PANES: 1054 control_check_subs_all_panes(c, csub); 1055 break; 1056 case CONTROL_SUB_WINDOW: 1057 control_check_subs_window(c, csub); 1058 break; 1059 case CONTROL_SUB_ALL_WINDOWS: 1060 control_check_subs_all_windows(c, csub); 1061 break; 1062 } 1063 } 1064} 1065 1066/* Add a subscription. */ 1067void 1068control_add_sub(struct client *c, const char *name, enum control_sub_type type, 1069 int id, const char *format) 1070{ 1071 struct control_state *cs = c->control_state; 1072 struct control_sub *csub, find; 1073 struct timeval tv = { .tv_sec = 1 }; 1074 1075 find.name = __UNCONST(name); 1076 if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL) 1077 control_free_sub(cs, csub); 1078 1079 csub = xcalloc(1, sizeof *csub); 1080 csub->name = xstrdup(name); 1081 csub->type = type; 1082 csub->id = id; 1083 csub->format = xstrdup(format); 1084 RB_INSERT(control_subs, &cs->subs, csub); 1085 1086 RB_INIT(&csub->panes); 1087 RB_INIT(&csub->windows); 1088 1089 if (!evtimer_initialized(&cs->subs_timer)) 1090 evtimer_set(&cs->subs_timer, control_check_subs_timer, c); 1091 if (!evtimer_pending(&cs->subs_timer, NULL)) 1092 evtimer_add(&cs->subs_timer, &tv); 1093} 1094 1095/* Remove a subscription. */ 1096void 1097control_remove_sub(struct client *c, const char *name) 1098{ 1099 struct control_state *cs = c->control_state; 1100 struct control_sub *csub, find; 1101 1102 find.name = __UNCONST(name); 1103 if ((csub = RB_FIND(control_subs, &cs->subs, &find)) != NULL) 1104 control_free_sub(cs, csub); 1105 if (RB_EMPTY(&cs->subs)) 1106 evtimer_del(&cs->subs_timer); 1107} 1108