1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott (at) gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "tmux.h" 29 30 /* 31 * IPC file handling. Both client and server use the same data structures 32 * (client_file and client_files) to store list of active files. Most functions 33 * are for use either in client or server but not both. 34 */ 35 36 static int file_next_stream = 3; 37 38 RB_GENERATE(client_files, client_file, entry, file_cmp); 39 40 /* Get path for file, either as given or from working directory. */ 41 static char * 42 file_get_path(struct client *c, const char *file) 43 { 44 const char *home; 45 char *path, *full_path; 46 47 if (strncmp(file, "~/", 2) != 0) 48 path = xstrdup(file); 49 else { 50 home = find_home(); 51 if (home == NULL) 52 home = ""; 53 xasprintf(&path, "%s%s", home, file + 1); 54 } 55 if (*path == '/') 56 return (path); 57 xasprintf(&full_path, "%s/%s", server_client_get_cwd(c, NULL), path); 58 return (full_path); 59 } 60 61 /* Tree comparison function. */ 62 int 63 file_cmp(struct client_file *cf1, struct client_file *cf2) 64 { 65 if (cf1->stream < cf2->stream) 66 return (-1); 67 if (cf1->stream > cf2->stream) 68 return (1); 69 return (0); 70 } 71 72 /* 73 * Create a file object in the client process - the peer is the server to send 74 * messages to. Check callback is fired when the file is finished with so the 75 * process can decide if it needs to exit (if it is waiting for files to 76 * flush). 77 */ 78 struct client_file * 79 file_create_with_peer(struct tmuxpeer *peer, struct client_files *files, 80 int stream, client_file_cb cb, void *cbdata) 81 { 82 struct client_file *cf; 83 84 cf = xcalloc(1, sizeof *cf); 85 cf->c = NULL; 86 cf->references = 1; 87 cf->stream = stream; 88 89 cf->buffer = evbuffer_new(); 90 if (cf->buffer == NULL) 91 fatalx("out of memory"); 92 93 cf->cb = cb; 94 cf->data = cbdata; 95 96 cf->peer = peer; 97 cf->tree = files; 98 RB_INSERT(client_files, files, cf); 99 100 return (cf); 101 } 102 103 /* Create a file object in the server, communicating with the given client. */ 104 struct client_file * 105 file_create_with_client(struct client *c, int stream, client_file_cb cb, 106 void *cbdata) 107 { 108 struct client_file *cf; 109 110 if (c != NULL && (c->flags & CLIENT_ATTACHED)) 111 c = NULL; 112 113 cf = xcalloc(1, sizeof *cf); 114 cf->c = c; 115 cf->references = 1; 116 cf->stream = stream; 117 118 cf->buffer = evbuffer_new(); 119 if (cf->buffer == NULL) 120 fatalx("out of memory"); 121 122 cf->cb = cb; 123 cf->data = cbdata; 124 125 if (cf->c != NULL) { 126 cf->peer = cf->c->peer; 127 cf->tree = &cf->c->files; 128 RB_INSERT(client_files, &cf->c->files, cf); 129 cf->c->references++; 130 } 131 132 return (cf); 133 } 134 135 /* Free a file. */ 136 void 137 file_free(struct client_file *cf) 138 { 139 if (--cf->references != 0) 140 return; 141 142 evbuffer_free(cf->buffer); 143 free(cf->path); 144 145 if (cf->tree != NULL) 146 RB_REMOVE(client_files, cf->tree, cf); 147 if (cf->c != NULL) 148 server_client_unref(cf->c); 149 150 free(cf); 151 } 152 153 /* Event to fire the done callback. */ 154 static void 155 file_fire_done_cb(__unused int fd, __unused short events, void *arg) 156 { 157 struct client_file *cf = arg; 158 struct client *c = cf->c; 159 160 if (cf->cb != NULL && 161 (cf->closed || c == NULL || (~c->flags & CLIENT_DEAD))) 162 cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data); 163 file_free(cf); 164 } 165 166 /* Add an event to fire the done callback (used by the server). */ 167 void 168 file_fire_done(struct client_file *cf) 169 { 170 event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL); 171 } 172 173 /* Fire the read callback. */ 174 void 175 file_fire_read(struct client_file *cf) 176 { 177 if (cf->cb != NULL) 178 cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data); 179 } 180 181 /* Can this file be printed to? */ 182 int 183 file_can_print(struct client *c) 184 { 185 if (c == NULL || 186 (c->flags & CLIENT_ATTACHED) || 187 (c->flags & CLIENT_CONTROL)) 188 return (0); 189 return (1); 190 } 191 192 /* Print a message to a file. */ 193 void 194 file_print(struct client *c, const char *fmt, ...) 195 { 196 va_list ap; 197 198 va_start(ap, fmt); 199 file_vprint(c, fmt, ap); 200 va_end(ap); 201 } 202 203 /* Print a message to a file. */ 204 void 205 file_vprint(struct client *c, const char *fmt, va_list ap) 206 { 207 struct client_file find, *cf; 208 struct msg_write_open msg; 209 210 if (!file_can_print(c)) 211 return; 212 213 find.stream = 1; 214 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 215 cf = file_create_with_client(c, 1, NULL, NULL); 216 cf->path = xstrdup("-"); 217 218 evbuffer_add_vprintf(cf->buffer, fmt, ap); 219 220 msg.stream = 1; 221 msg.fd = STDOUT_FILENO; 222 msg.flags = 0; 223 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 224 } else { 225 evbuffer_add_vprintf(cf->buffer, fmt, ap); 226 file_push(cf); 227 } 228 } 229 230 /* Print a buffer to a file. */ 231 void 232 file_print_buffer(struct client *c, void *data, size_t size) 233 { 234 struct client_file find, *cf; 235 struct msg_write_open msg; 236 237 if (!file_can_print(c)) 238 return; 239 240 find.stream = 1; 241 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 242 cf = file_create_with_client(c, 1, NULL, NULL); 243 cf->path = xstrdup("-"); 244 245 evbuffer_add(cf->buffer, data, size); 246 247 msg.stream = 1; 248 msg.fd = STDOUT_FILENO; 249 msg.flags = 0; 250 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 251 } else { 252 evbuffer_add(cf->buffer, data, size); 253 file_push(cf); 254 } 255 } 256 257 /* Report an error to a file. */ 258 void 259 file_error(struct client *c, const char *fmt, ...) 260 { 261 struct client_file find, *cf; 262 struct msg_write_open msg; 263 va_list ap; 264 265 if (!file_can_print(c)) 266 return; 267 268 va_start(ap, fmt); 269 270 find.stream = 2; 271 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 272 cf = file_create_with_client(c, 2, NULL, NULL); 273 cf->path = xstrdup("-"); 274 275 evbuffer_add_vprintf(cf->buffer, fmt, ap); 276 277 msg.stream = 2; 278 msg.fd = STDERR_FILENO; 279 msg.flags = 0; 280 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 281 } else { 282 evbuffer_add_vprintf(cf->buffer, fmt, ap); 283 file_push(cf); 284 } 285 286 va_end(ap); 287 } 288 289 /* Write data to a file. */ 290 void 291 file_write(struct client *c, const char *path, int flags, const void *bdata, 292 size_t bsize, client_file_cb cb, void *cbdata) 293 { 294 struct client_file *cf; 295 struct msg_write_open *msg; 296 size_t msglen; 297 int fd = -1; 298 u_int stream = file_next_stream++; 299 FILE *f; 300 const char *mode; 301 302 if (strcmp(path, "-") == 0) { 303 cf = file_create_with_client(c, stream, cb, cbdata); 304 cf->path = xstrdup("-"); 305 306 fd = STDOUT_FILENO; 307 if (c == NULL || 308 (c->flags & CLIENT_ATTACHED) || 309 (c->flags & CLIENT_CONTROL)) { 310 cf->error = EBADF; 311 goto done; 312 } 313 goto skip; 314 } 315 316 cf = file_create_with_client(c, stream, cb, cbdata); 317 cf->path = file_get_path(c, path); 318 319 if (c == NULL || c->flags & CLIENT_ATTACHED) { 320 if (flags & O_APPEND) 321 mode = "ab"; 322 else 323 mode = "wb"; 324 f = fopen(cf->path, mode); 325 if (f == NULL) { 326 cf->error = errno; 327 goto done; 328 } 329 if (fwrite(bdata, 1, bsize, f) != bsize) { 330 fclose(f); 331 cf->error = EIO; 332 goto done; 333 } 334 fclose(f); 335 goto done; 336 } 337 338 skip: 339 evbuffer_add(cf->buffer, bdata, bsize); 340 341 msglen = strlen(cf->path) + 1 + sizeof *msg; 342 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 343 cf->error = E2BIG; 344 goto done; 345 } 346 msg = xmalloc(msglen); 347 msg->stream = cf->stream; 348 msg->fd = fd; 349 msg->flags = flags; 350 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 351 if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { 352 free(msg); 353 cf->error = EINVAL; 354 goto done; 355 } 356 free(msg); 357 return; 358 359 done: 360 file_fire_done(cf); 361 } 362 363 /* Read a file. */ 364 struct client_file * 365 file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) 366 { 367 struct client_file *cf; 368 struct msg_read_open *msg; 369 size_t msglen; 370 int fd = -1; 371 u_int stream = file_next_stream++; 372 FILE *f = NULL; 373 size_t size; 374 char buffer[BUFSIZ]; 375 376 if (strcmp(path, "-") == 0) { 377 cf = file_create_with_client(c, stream, cb, cbdata); 378 cf->path = xstrdup("-"); 379 380 fd = STDIN_FILENO; 381 if (c == NULL || 382 (c->flags & CLIENT_ATTACHED) || 383 (c->flags & CLIENT_CONTROL)) { 384 cf->error = EBADF; 385 goto done; 386 } 387 goto skip; 388 } 389 390 cf = file_create_with_client(c, stream, cb, cbdata); 391 cf->path = file_get_path(c, path); 392 393 if (c == NULL || c->flags & CLIENT_ATTACHED) { 394 f = fopen(cf->path, "rb"); 395 if (f == NULL) { 396 cf->error = errno; 397 goto done; 398 } 399 for (;;) { 400 size = fread(buffer, 1, sizeof buffer, f); 401 if (evbuffer_add(cf->buffer, buffer, size) != 0) { 402 cf->error = ENOMEM; 403 goto done; 404 } 405 if (size != sizeof buffer) 406 break; 407 } 408 if (ferror(f)) { 409 cf->error = EIO; 410 goto done; 411 } 412 goto done; 413 } 414 415 skip: 416 msglen = strlen(cf->path) + 1 + sizeof *msg; 417 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 418 cf->error = E2BIG; 419 goto done; 420 } 421 msg = xmalloc(msglen); 422 msg->stream = cf->stream; 423 msg->fd = fd; 424 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 425 if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { 426 free(msg); 427 cf->error = EINVAL; 428 goto done; 429 } 430 free(msg); 431 return cf; 432 433 done: 434 if (f != NULL) 435 fclose(f); 436 file_fire_done(cf); 437 return NULL; 438 } 439 440 /* Cancel a file read. */ 441 void 442 file_cancel(struct client_file *cf) 443 { 444 struct msg_read_cancel msg; 445 446 log_debug("read cancel file %d", cf->stream); 447 448 if (cf->closed) 449 return; 450 cf->closed = 1; 451 452 msg.stream = cf->stream; 453 proc_send(cf->peer, MSG_READ_CANCEL, -1, &msg, sizeof msg); 454 } 455 456 /* Push event, fired if there is more writing to be done. */ 457 static void 458 file_push_cb(__unused int fd, __unused short events, void *arg) 459 { 460 struct client_file *cf = arg; 461 462 if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD) 463 file_push(cf); 464 file_free(cf); 465 } 466 467 /* Push uwritten data to the client for a file, if it will accept it. */ 468 void 469 file_push(struct client_file *cf) 470 { 471 struct msg_write_data *msg; 472 size_t msglen, sent, left; 473 struct msg_write_close close; 474 475 msg = xmalloc(sizeof *msg); 476 left = EVBUFFER_LENGTH(cf->buffer); 477 while (left != 0) { 478 sent = left; 479 if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 480 sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 481 482 msglen = (sizeof *msg) + sent; 483 msg = xrealloc(msg, msglen); 484 msg->stream = cf->stream; 485 memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent); 486 if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0) 487 break; 488 evbuffer_drain(cf->buffer, sent); 489 490 left = EVBUFFER_LENGTH(cf->buffer); 491 log_debug("file %d sent %zu, left %zu", cf->stream, sent, left); 492 } 493 if (left != 0) { 494 cf->references++; 495 event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL); 496 } else if (cf->stream > 2) { 497 close.stream = cf->stream; 498 proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); 499 file_fire_done(cf); 500 } 501 free(msg); 502 } 503 504 /* Check if any files have data left to write. */ 505 int 506 file_write_left(struct client_files *files) 507 { 508 struct client_file *cf; 509 size_t left; 510 int waiting = 0; 511 512 RB_FOREACH(cf, client_files, files) { 513 if (cf->event == NULL) 514 continue; 515 left = EVBUFFER_LENGTH(cf->event->output); 516 if (left != 0) { 517 waiting++; 518 log_debug("file %u %zu bytes left", cf->stream, left); 519 } 520 } 521 return (waiting != 0); 522 } 523 524 /* Client file write error callback. */ 525 static void 526 file_write_error_callback(__unused struct bufferevent *bev, __unused short what, 527 void *arg) 528 { 529 struct client_file *cf = arg; 530 531 log_debug("write error file %d", cf->stream); 532 533 bufferevent_free(cf->event); 534 cf->event = NULL; 535 536 close(cf->fd); 537 cf->fd = -1; 538 539 if (cf->cb != NULL) 540 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 541 } 542 543 /* Client file write callback. */ 544 static void 545 file_write_callback(__unused struct bufferevent *bev, void *arg) 546 { 547 struct client_file *cf = arg; 548 549 log_debug("write check file %d", cf->stream); 550 551 if (cf->cb != NULL) 552 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 553 554 if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { 555 bufferevent_free(cf->event); 556 close(cf->fd); 557 RB_REMOVE(client_files, cf->tree, cf); 558 file_free(cf); 559 } 560 } 561 562 /* Handle a file write open message (client). */ 563 void 564 file_write_open(struct client_files *files, struct tmuxpeer *peer, 565 struct imsg *imsg, int allow_streams, int close_received, 566 client_file_cb cb, void *cbdata) 567 { 568 struct msg_write_open *msg = imsg->data; 569 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 570 const char *path; 571 struct msg_write_ready reply; 572 struct client_file find, *cf; 573 const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; 574 int error = 0; 575 576 if (msglen < sizeof *msg) 577 fatalx("bad MSG_WRITE_OPEN size"); 578 if (msglen == sizeof *msg) 579 path = "-"; 580 else 581 path = (const char *)(msg + 1); 582 log_debug("open write file %d %s", msg->stream, path); 583 584 find.stream = msg->stream; 585 if (RB_FIND(client_files, files, &find) != NULL) { 586 error = EBADF; 587 goto reply; 588 } 589 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 590 if (cf->closed) { 591 error = EBADF; 592 goto reply; 593 } 594 595 cf->fd = -1; 596 if (msg->fd == -1) 597 cf->fd = open(path, msg->flags|flags, 0644); 598 else if (allow_streams) { 599 if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) 600 errno = EBADF; 601 else { 602 cf->fd = dup(msg->fd); 603 if (close_received) 604 close(msg->fd); /* can only be used once */ 605 } 606 } else 607 errno = EBADF; 608 if (cf->fd == -1) { 609 error = errno; 610 goto reply; 611 } 612 613 cf->event = bufferevent_new(cf->fd, NULL, file_write_callback, 614 file_write_error_callback, cf); 615 if (cf->event == NULL) 616 fatalx("out of memory"); 617 bufferevent_enable(cf->event, EV_WRITE); 618 goto reply; 619 620 reply: 621 reply.stream = msg->stream; 622 reply.error = error; 623 proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply); 624 } 625 626 /* Handle a file write data message (client). */ 627 void 628 file_write_data(struct client_files *files, struct imsg *imsg) 629 { 630 struct msg_write_data *msg = imsg->data; 631 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 632 struct client_file find, *cf; 633 size_t size = msglen - sizeof *msg; 634 635 if (msglen < sizeof *msg) 636 fatalx("bad MSG_WRITE size"); 637 find.stream = msg->stream; 638 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 639 fatalx("unknown stream number"); 640 log_debug("write %zu to file %d", size, cf->stream); 641 642 if (cf->event != NULL) 643 bufferevent_write(cf->event, msg + 1, size); 644 } 645 646 /* Handle a file write close message (client). */ 647 void 648 file_write_close(struct client_files *files, struct imsg *imsg) 649 { 650 struct msg_write_close *msg = imsg->data; 651 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 652 struct client_file find, *cf; 653 654 if (msglen != sizeof *msg) 655 fatalx("bad MSG_WRITE_CLOSE size"); 656 find.stream = msg->stream; 657 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 658 fatalx("unknown stream number"); 659 log_debug("close file %d", cf->stream); 660 661 if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { 662 if (cf->event != NULL) 663 bufferevent_free(cf->event); 664 if (cf->fd != -1) 665 close(cf->fd); 666 RB_REMOVE(client_files, files, cf); 667 file_free(cf); 668 } 669 } 670 671 /* Client file read error callback. */ 672 static void 673 file_read_error_callback(__unused struct bufferevent *bev, __unused short what, 674 void *arg) 675 { 676 struct client_file *cf = arg; 677 struct msg_read_done msg; 678 679 log_debug("read error file %d", cf->stream); 680 681 msg.stream = cf->stream; 682 msg.error = 0; 683 proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg); 684 685 bufferevent_free(cf->event); 686 close(cf->fd); 687 RB_REMOVE(client_files, cf->tree, cf); 688 file_free(cf); 689 } 690 691 /* Client file read callback. */ 692 static void 693 file_read_callback(__unused struct bufferevent *bev, void *arg) 694 { 695 struct client_file *cf = arg; 696 void *bdata; 697 size_t bsize; 698 struct msg_read_data *msg; 699 size_t msglen; 700 701 msg = xmalloc(sizeof *msg); 702 for (;;) { 703 bdata = EVBUFFER_DATA(cf->event->input); 704 bsize = EVBUFFER_LENGTH(cf->event->input); 705 706 if (bsize == 0) 707 break; 708 if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 709 bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 710 log_debug("read %zu from file %d", bsize, cf->stream); 711 712 msglen = (sizeof *msg) + bsize; 713 msg = xrealloc(msg, msglen); 714 msg->stream = cf->stream; 715 memcpy(msg + 1, bdata, bsize); 716 proc_send(cf->peer, MSG_READ, -1, msg, msglen); 717 718 evbuffer_drain(cf->event->input, bsize); 719 } 720 free(msg); 721 } 722 723 /* Handle a file read open message (client). */ 724 void 725 file_read_open(struct client_files *files, struct tmuxpeer *peer, 726 struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, 727 void *cbdata) 728 { 729 struct msg_read_open *msg = imsg->data; 730 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 731 const char *path; 732 struct msg_read_done reply; 733 struct client_file find, *cf; 734 const int flags = O_NONBLOCK|O_RDONLY; 735 int error; 736 737 if (msglen < sizeof *msg) 738 fatalx("bad MSG_READ_OPEN size"); 739 if (msglen == sizeof *msg) 740 path = "-"; 741 else 742 path = (const char *)(msg + 1); 743 log_debug("open read file %d %s", msg->stream, path); 744 745 find.stream = msg->stream; 746 if (RB_FIND(client_files, files, &find) != NULL) { 747 error = EBADF; 748 goto reply; 749 } 750 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 751 if (cf->closed) { 752 error = EBADF; 753 goto reply; 754 } 755 756 cf->fd = -1; 757 if (msg->fd == -1) 758 cf->fd = open(path, flags); 759 else if (allow_streams) { 760 if (msg->fd != STDIN_FILENO) 761 errno = EBADF; 762 else { 763 cf->fd = dup(msg->fd); 764 if (close_received) 765 close(msg->fd); /* can only be used once */ 766 } 767 } else 768 errno = EBADF; 769 if (cf->fd == -1) { 770 error = errno; 771 goto reply; 772 } 773 774 cf->event = bufferevent_new(cf->fd, file_read_callback, NULL, 775 file_read_error_callback, cf); 776 if (cf->event == NULL) 777 fatalx("out of memory"); 778 bufferevent_enable(cf->event, EV_READ); 779 return; 780 781 reply: 782 reply.stream = msg->stream; 783 reply.error = error; 784 proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply); 785 } 786 787 /* Handle a read cancel message (client). */ 788 void 789 file_read_cancel(struct client_files *files, struct imsg *imsg) 790 { 791 struct msg_read_cancel *msg = imsg->data; 792 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 793 struct client_file find, *cf; 794 795 if (msglen != sizeof *msg) 796 fatalx("bad MSG_READ_CANCEL size"); 797 find.stream = msg->stream; 798 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 799 fatalx("unknown stream number"); 800 log_debug("cancel file %d", cf->stream); 801 802 file_read_error_callback(NULL, 0, cf); 803 } 804 805 /* Handle a write ready message (server). */ 806 void 807 file_write_ready(struct client_files *files, struct imsg *imsg) 808 { 809 struct msg_write_ready *msg = imsg->data; 810 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 811 struct client_file find, *cf; 812 813 if (msglen != sizeof *msg) 814 fatalx("bad MSG_WRITE_READY size"); 815 find.stream = msg->stream; 816 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 817 return; 818 if (msg->error != 0) { 819 cf->error = msg->error; 820 file_fire_done(cf); 821 } else 822 file_push(cf); 823 } 824 825 /* Handle read data message (server). */ 826 void 827 file_read_data(struct client_files *files, struct imsg *imsg) 828 { 829 struct msg_read_data *msg = imsg->data; 830 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 831 struct client_file find, *cf; 832 void *bdata = msg + 1; 833 size_t bsize = msglen - sizeof *msg; 834 835 if (msglen < sizeof *msg) 836 fatalx("bad MSG_READ_DATA size"); 837 find.stream = msg->stream; 838 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 839 return; 840 841 log_debug("file %d read %zu bytes", cf->stream, bsize); 842 if (cf->error == 0 && !cf->closed) { 843 if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { 844 cf->error = ENOMEM; 845 file_fire_done(cf); 846 } else 847 file_fire_read(cf); 848 } 849 } 850 851 /* Handle a read done message (server). */ 852 void 853 file_read_done(struct client_files *files, struct imsg *imsg) 854 { 855 struct msg_read_done *msg = imsg->data; 856 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 857 struct client_file find, *cf; 858 859 if (msglen != sizeof *msg) 860 fatalx("bad MSG_READ_DONE size"); 861 find.stream = msg->stream; 862 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 863 return; 864 865 log_debug("file %d read done", cf->stream); 866 cf->error = msg->error; 867 file_fire_done(cf); 868 } 869