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 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 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 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 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 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 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 * 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 * 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 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 * 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 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 * 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 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 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 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 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) 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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