control.c revision 1.36
1/* $OpenBSD: control.c,v 1.36 2020/06/01 21:08:05 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 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 68 int pending_flag; 69 TAILQ_ENTRY(control_pane) pending_entry; 70 71 TAILQ_HEAD(, control_block) blocks; 72 73 RB_ENTRY(control_pane) entry; 74}; 75RB_HEAD(control_panes, control_pane); 76 77/* Control client state. */ 78struct control_state { 79 struct control_panes panes; 80 81 TAILQ_HEAD(, control_pane) pending_list; 82 u_int pending_count; 83 84 TAILQ_HEAD(, control_block) all_blocks; 85 86 struct bufferevent *read_event; 87 struct bufferevent *write_event; 88}; 89 90/* Low watermark. */ 91#define CONTROL_BUFFER_LOW 512 92#define CONTROL_BUFFER_HIGH 8192 93 94/* Minimum to write to each client. */ 95#define CONTROL_WRITE_MINIMUM 32 96 97/* Flags to ignore client. */ 98#define CONTROL_IGNORE_FLAGS \ 99 (CLIENT_CONTROL_NOOUTPUT| \ 100 CLIENT_UNATTACHEDFLAGS) 101 102/* Compare client panes. */ 103static int 104control_pane_cmp(struct control_pane *cp1, struct control_pane *cp2) 105{ 106 if (cp1->pane < cp2->pane) 107 return (-1); 108 if (cp1->pane > cp2->pane) 109 return (1); 110 return (0); 111} 112RB_GENERATE_STATIC(control_panes, control_pane, entry, control_pane_cmp); 113 114/* Free a block. */ 115static void 116control_free_block(struct control_state *cs, struct control_block *cb) 117{ 118 free(cb->line); 119 TAILQ_REMOVE(&cs->all_blocks, cb, all_entry); 120 free(cb); 121} 122 123/* Get pane offsets for this client. */ 124static struct control_pane * 125control_get_pane(struct client *c, struct window_pane *wp) 126{ 127 struct control_state *cs = c->control_state; 128 struct control_pane cp = { .pane = wp->id }; 129 130 return (RB_FIND(control_panes, &cs->panes, &cp)); 131} 132 133/* Add pane offsets for this client. */ 134static struct control_pane * 135control_add_pane(struct client *c, struct window_pane *wp) 136{ 137 struct control_state *cs = c->control_state; 138 struct control_pane *cp; 139 140 cp = control_get_pane(c, wp); 141 if (cp != NULL) 142 return (cp); 143 144 cp = xcalloc(1, sizeof *cp); 145 cp->pane = wp->id; 146 RB_INSERT(control_panes, &cs->panes, cp); 147 148 memcpy(&cp->offset, &wp->offset, sizeof cp->offset); 149 memcpy(&cp->queued, &wp->offset, sizeof cp->queued); 150 TAILQ_INIT(&cp->blocks); 151 152 return (cp); 153} 154 155/* Reset control offsets. */ 156void 157control_reset_offsets(struct client *c) 158{ 159 struct control_state *cs = c->control_state; 160 struct control_pane *cp, *cp1; 161 162 RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) { 163 RB_REMOVE(control_panes, &cs->panes, cp); 164 free(cp); 165 } 166 167 TAILQ_INIT(&cs->pending_list); 168 cs->pending_count = 0; 169} 170 171/* Get offsets for client. */ 172struct window_pane_offset * 173control_pane_offset(struct client *c, struct window_pane *wp, int *off) 174{ 175 struct control_state *cs = c->control_state; 176 struct control_pane *cp; 177 178 if (c->flags & CLIENT_CONTROL_NOOUTPUT) { 179 *off = 0; 180 return (NULL); 181 } 182 183 cp = control_get_pane(c, wp); 184 if (cp == NULL) { 185 *off = 0; 186 return (NULL); 187 } 188 if (cp->flags & CONTROL_PANE_OFF) { 189 *off = 1; 190 return (NULL); 191 } 192 *off = (EVBUFFER_LENGTH(cs->write_event->output) >= CONTROL_BUFFER_LOW); 193 return (&cp->offset); 194} 195 196/* Set pane as on. */ 197void 198control_set_pane_on(struct client *c, struct window_pane *wp) 199{ 200 struct control_pane *cp; 201 202 cp = control_get_pane(c, wp); 203 if (cp != NULL) { 204 cp->flags &= ~CONTROL_PANE_OFF; 205 memcpy(&cp->offset, &wp->offset, sizeof cp->offset); 206 memcpy(&cp->queued, &wp->offset, sizeof cp->queued); 207 } 208} 209 210/* Set pane as off. */ 211void 212control_set_pane_off(struct client *c, struct window_pane *wp) 213{ 214 struct control_pane *cp; 215 216 cp = control_add_pane(c, wp); 217 cp->flags |= CONTROL_PANE_OFF; 218} 219 220/* Write a line. */ 221static void 222control_vwrite(struct client *c, const char *fmt, va_list ap) 223{ 224 struct control_state *cs = c->control_state; 225 char *s; 226 227 xvasprintf(&s, fmt, ap); 228 log_debug("%s: %s: writing line: %s", __func__, c->name, s); 229 230 bufferevent_write(cs->write_event, s, strlen(s)); 231 bufferevent_write(cs->write_event, "\n", 1); 232 233 bufferevent_enable(cs->write_event, EV_WRITE); 234 free(s); 235} 236 237/* Write a line. */ 238void 239control_write(struct client *c, const char *fmt, ...) 240{ 241 struct control_state *cs = c->control_state; 242 struct control_block *cb; 243 va_list ap; 244 245 va_start(ap, fmt); 246 247 if (TAILQ_EMPTY(&cs->all_blocks)) { 248 control_vwrite(c, fmt, ap); 249 va_end(ap); 250 return; 251 } 252 253 cb = xcalloc(1, sizeof *cb); 254 xvasprintf(&cb->line, fmt, ap); 255 TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry); 256 257 log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line); 258 bufferevent_enable(cs->write_event, EV_WRITE); 259 260 va_end(ap); 261} 262 263/* Write output from a pane. */ 264void 265control_write_output(struct client *c, struct window_pane *wp) 266{ 267 struct control_state *cs = c->control_state; 268 struct control_pane *cp; 269 struct control_block *cb; 270 size_t new_size; 271 272 if (winlink_find_by_window(&c->session->windows, wp->window) == NULL) 273 return; 274 275 if (c->flags & CONTROL_IGNORE_FLAGS) { 276 cp = control_get_pane(c, wp); 277 if (cp != NULL) 278 goto ignore; 279 return; 280 } 281 cp = control_add_pane(c, wp); 282 if (cp->flags & CONTROL_PANE_OFF) 283 goto ignore; 284 285 window_pane_get_new_data(wp, &cp->queued, &new_size); 286 if (new_size == 0) 287 return; 288 window_pane_update_used_data(wp, &cp->queued, new_size); 289 290 cb = xcalloc(1, sizeof *cb); 291 cb->size = new_size; 292 TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry); 293 294 TAILQ_INSERT_TAIL(&cp->blocks, cb, entry); 295 log_debug("%s: %s: new output block of %zu for %%%u", __func__, c->name, 296 cb->size, wp->id); 297 298 if (!cp->pending_flag) { 299 log_debug("%s: %s: %%%u now pending", __func__, c->name, 300 wp->id); 301 TAILQ_INSERT_TAIL(&cs->pending_list, cp, pending_entry); 302 cp->pending_flag = 1; 303 cs->pending_count++; 304 } 305 bufferevent_enable(cs->write_event, EV_WRITE); 306 return; 307 308ignore: 309 log_debug("%s: %s: ignoring pane %%%u", __func__, c->name, wp->id); 310 window_pane_update_used_data(wp, &cp->offset, SIZE_MAX); 311 window_pane_update_used_data(wp, &cp->queued, SIZE_MAX); 312} 313 314/* Control client error callback. */ 315static enum cmd_retval 316control_error(struct cmdq_item *item, void *data) 317{ 318 struct client *c = cmdq_get_client(item); 319 char *error = data; 320 321 cmdq_guard(item, "begin", 1); 322 control_write(c, "parse error: %s", error); 323 cmdq_guard(item, "error", 1); 324 325 free(error); 326 return (CMD_RETURN_NORMAL); 327} 328 329/* Control client error callback. */ 330static void 331control_error_callback(__unused struct bufferevent *bufev, 332 __unused short what, void *data) 333{ 334 struct client *c = data; 335 336 c->flags |= CLIENT_EXIT; 337} 338 339/* Control client input callback. Read lines and fire commands. */ 340static void 341control_read_callback(__unused struct bufferevent *bufev, void *data) 342{ 343 struct client *c = data; 344 struct control_state *cs = c->control_state; 345 struct evbuffer *buffer = cs->read_event->input; 346 char *line, *error; 347 struct cmdq_state *state; 348 enum cmd_parse_status status; 349 350 for (;;) { 351 line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF); 352 if (line == NULL) 353 break; 354 log_debug("%s: %s: %s", __func__, c->name, line); 355 if (*line == '\0') { /* empty line detach */ 356 free(line); 357 c->flags |= CLIENT_EXIT; 358 break; 359 } 360 361 state = cmdq_new_state(NULL, NULL, CMDQ_STATE_CONTROL); 362 status = cmd_parse_and_append(line, NULL, c, state, &error); 363 if (status == CMD_PARSE_ERROR) 364 cmdq_append(c, cmdq_get_callback(control_error, error)); 365 cmdq_free_state(state); 366 367 free(line); 368 } 369} 370 371/* Does this control client have outstanding data to write? */ 372int 373control_all_done(struct client *c) 374{ 375 struct control_state *cs = c->control_state; 376 377 if (!TAILQ_EMPTY(&cs->all_blocks)) 378 return (0); 379 return (EVBUFFER_LENGTH(cs->write_event->output) == 0); 380} 381 382/* Flush all blocks until output. */ 383static void 384control_flush_all_blocks(struct client *c) 385{ 386 struct control_state *cs = c->control_state; 387 struct control_block *cb, *cb1; 388 389 TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) { 390 if (cb->size != 0) 391 break; 392 log_debug("%s: %s: flushing line: %s", __func__, c->name, 393 cb->line); 394 395 bufferevent_write(cs->write_event, cb->line, strlen(cb->line)); 396 bufferevent_write(cs->write_event, "\n", 1); 397 control_free_block(cs, cb); 398 } 399} 400 401/* Append data to buffer. */ 402static struct evbuffer * 403control_append_data(struct control_pane *cp, struct evbuffer *message, 404 struct window_pane *wp, size_t size) 405{ 406 u_char *new_data; 407 size_t new_size; 408 u_int i; 409 410 if (message == NULL) { 411 message = evbuffer_new(); 412 if (message == NULL) 413 fatalx("out of memory"); 414 evbuffer_add_printf(message, "%%output %%%u ", wp->id); 415 } 416 417 new_data = window_pane_get_new_data(wp, &cp->offset, &new_size); 418 if (new_size < size) 419 fatalx("not enough data: %zu < %zu", new_size, size); 420 for (i = 0; i < size; i++) { 421 if (new_data[i] < ' ' || new_data[i] == '\\') 422 evbuffer_add_printf(message, "\\%03o", new_data[i]); 423 else 424 evbuffer_add_printf(message, "%c", new_data[i]); 425 } 426 window_pane_update_used_data(wp, &cp->offset, size); 427 return (message); 428} 429 430/* Write buffer. */ 431static void 432control_write_data(struct client *c, struct evbuffer *message) 433{ 434 struct control_state *cs = c->control_state; 435 436 log_debug("%s: %s: %.*s", __func__, c->name, 437 (int)EVBUFFER_LENGTH(message), EVBUFFER_DATA(message)); 438 439 evbuffer_add(message, "\n", 1); 440 bufferevent_write_buffer(cs->write_event, message); 441 evbuffer_free(message); 442} 443 444/* Write output to client. */ 445static int 446control_write_pending(struct client *c, struct control_pane *cp, size_t limit) 447{ 448 struct control_state *cs = c->control_state; 449 struct session *s = c->session; 450 struct window_pane *wp = NULL; 451 struct evbuffer *message = NULL; 452 size_t used = 0, size; 453 struct control_block *cb, *cb1; 454 455 if (s == NULL || 456 (wp = window_pane_find_by_id(cp->pane)) == NULL || 457 winlink_find_by_window(&s->windows, wp->window) == NULL) { 458 TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) { 459 TAILQ_REMOVE(&cp->blocks, cb, entry); 460 control_free_block(cs, cb); 461 } 462 control_flush_all_blocks(c); 463 return (0); 464 } 465 466 while (used != limit && !TAILQ_EMPTY(&cp->blocks)) { 467 cb = TAILQ_FIRST(&cp->blocks); 468 log_debug("%s: %s: output block %zu for %%%u (used %zu/%zu)", 469 __func__, c->name, cb->size, cp->pane, used, limit); 470 471 size = cb->size; 472 if (size > limit - used) 473 size = limit - used; 474 used += size; 475 476 message = control_append_data(cp, message, wp, size); 477 478 cb->size -= size; 479 if (cb->size == 0) { 480 TAILQ_REMOVE(&cp->blocks, cb, entry); 481 control_free_block(cs, cb); 482 483 cb = TAILQ_FIRST(&cs->all_blocks); 484 if (cb != NULL && cb->size == 0) { 485 if (wp != NULL && message != NULL) { 486 control_write_data(c, message); 487 message = NULL; 488 } 489 control_flush_all_blocks(c); 490 } 491 } 492 } 493 if (message != NULL) 494 control_write_data(c, message); 495 return (!TAILQ_EMPTY(&cp->blocks)); 496} 497 498/* Control client write callback. */ 499static void 500control_write_callback(__unused struct bufferevent *bufev, void *data) 501{ 502 struct client *c = data; 503 struct control_state *cs = c->control_state; 504 struct control_pane *cp, *cp1; 505 struct evbuffer *evb = cs->write_event->output; 506 size_t space, limit; 507 508 control_flush_all_blocks(c); 509 510 while (EVBUFFER_LENGTH(evb) < CONTROL_BUFFER_HIGH) { 511 if (cs->pending_count == 0) 512 break; 513 space = CONTROL_BUFFER_HIGH - EVBUFFER_LENGTH(evb); 514 log_debug("%s: %s: %zu bytes available, %u panes", __func__, 515 c->name, space, cs->pending_count); 516 517 limit = (space / cs->pending_count / 3); /* 3 bytes for \xxx */ 518 if (limit < CONTROL_WRITE_MINIMUM) 519 limit = CONTROL_WRITE_MINIMUM; 520 521 TAILQ_FOREACH_SAFE(cp, &cs->pending_list, pending_entry, cp1) { 522 if (EVBUFFER_LENGTH(evb) >= CONTROL_BUFFER_HIGH) 523 break; 524 if (control_write_pending(c, cp, limit)) 525 continue; 526 TAILQ_REMOVE(&cs->pending_list, cp, pending_entry); 527 cp->pending_flag = 0; 528 cs->pending_count--; 529 } 530 } 531 if (EVBUFFER_LENGTH(evb) == 0) 532 bufferevent_disable(cs->write_event, EV_WRITE); 533} 534 535/* Initialize for control mode. */ 536void 537control_start(struct client *c) 538{ 539 struct control_state *cs; 540 541 if (c->flags & CLIENT_CONTROLCONTROL) { 542 close(c->out_fd); 543 c->out_fd = -1; 544 } else 545 setblocking(c->out_fd, 0); 546 setblocking(c->fd, 0); 547 548 cs = c->control_state = xcalloc(1, sizeof *cs); 549 RB_INIT(&cs->panes); 550 TAILQ_INIT(&cs->pending_list); 551 TAILQ_INIT(&cs->all_blocks); 552 553 cs->read_event = bufferevent_new(c->fd, control_read_callback, 554 control_write_callback, control_error_callback, c); 555 bufferevent_enable(cs->read_event, EV_READ); 556 557 if (c->flags & CLIENT_CONTROLCONTROL) 558 cs->write_event = cs->read_event; 559 else { 560 cs->write_event = bufferevent_new(c->out_fd, NULL, 561 control_write_callback, control_error_callback, c); 562 } 563 bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW, 564 0); 565 566 if (c->flags & CLIENT_CONTROLCONTROL) { 567 bufferevent_write(cs->write_event, "\033P1000p", 7); 568 bufferevent_enable(cs->write_event, EV_WRITE); 569 } 570} 571 572/* Flush all output for a client that is detaching. */ 573void 574control_flush(struct client *c) 575{ 576 struct control_state *cs = c->control_state; 577 struct control_pane *cp; 578 struct control_block *cb, *cb1; 579 580 RB_FOREACH(cp, control_panes, &cs->panes) { 581 TAILQ_FOREACH_SAFE(cb, &cp->blocks, entry, cb1) { 582 TAILQ_REMOVE(&cp->blocks, cb, entry); 583 control_free_block(cs, cb); 584 } 585 } 586} 587 588/* Stop control mode. */ 589void 590control_stop(struct client *c) 591{ 592 struct control_state *cs = c->control_state; 593 struct control_block *cb, *cb1; 594 595 if (~c->flags & CLIENT_CONTROLCONTROL) 596 bufferevent_free(cs->write_event); 597 bufferevent_free(cs->read_event); 598 599 TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1) 600 control_free_block(cs, cb); 601 control_reset_offsets(c); 602 603 free(cs); 604} 605