Mercurial > dropbear
comparison common-channel.c @ 1054:c71df09bc610 nocircbuffer
Avoid copying data into circular buffer
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 01 Mar 2015 00:44:45 +0800 |
parents | 01eea88963f3 |
children | 696205e3dc99 |
comparison
equal
deleted
inserted
replaced
1053:fd3712d1ff7f | 1054:c71df09bc610 |
---|---|
40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, | 40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, |
41 const unsigned char *text, const unsigned char *lang); | 41 const unsigned char *text, const unsigned char *lang); |
42 static void send_msg_channel_open_confirmation(struct Channel* channel, | 42 static void send_msg_channel_open_confirmation(struct Channel* channel, |
43 unsigned int recvwindow, | 43 unsigned int recvwindow, |
44 unsigned int recvmaxpacket); | 44 unsigned int recvmaxpacket); |
45 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); | 45 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, |
46 const unsigned char *moredata, unsigned int *morelen); | |
46 static void send_msg_channel_window_adjust(struct Channel *channel, | 47 static void send_msg_channel_window_adjust(struct Channel *channel, |
47 unsigned int incr); | 48 unsigned int incr); |
48 static void send_msg_channel_data(struct Channel *channel, int isextended); | 49 static void send_msg_channel_data(struct Channel *channel, int isextended); |
49 static void send_msg_channel_eof(struct Channel *channel); | 50 static void send_msg_channel_eof(struct Channel *channel); |
50 static void send_msg_channel_close(struct Channel *channel); | 51 static void send_msg_channel_close(struct Channel *channel); |
239 do_check_close = 1; | 240 do_check_close = 1; |
240 } | 241 } |
241 | 242 |
242 /* write to program/pipe stdin */ | 243 /* write to program/pipe stdin */ |
243 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { | 244 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { |
244 writechannel(channel, channel->writefd, channel->writebuf); | 245 writechannel(channel, channel->writefd, channel->writebuf, NULL, NULL); |
245 do_check_close = 1; | 246 do_check_close = 1; |
246 } | 247 } |
247 | 248 |
248 /* stderr for client mode */ | 249 /* stderr for client mode */ |
249 if (ERRFD_IS_WRITE(channel) | 250 if (ERRFD_IS_WRITE(channel) |
250 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { | 251 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { |
251 writechannel(channel, channel->errfd, channel->extrabuf); | 252 writechannel(channel, channel->errfd, channel->extrabuf, NULL, NULL); |
252 do_check_close = 1; | 253 do_check_close = 1; |
253 } | 254 } |
254 | 255 |
255 if (ses.channel_signal_pending) { | 256 if (ses.channel_signal_pending) { |
256 /* SIGCHLD can change channel state for server sessions */ | 257 /* SIGCHLD can change channel state for server sessions */ |
432 | 433 |
433 TRACE(("leave send_msg_channel_eof")) | 434 TRACE(("leave send_msg_channel_eof")) |
434 } | 435 } |
435 | 436 |
436 /* Called to write data out to the local side of the channel. | 437 /* Called to write data out to the local side of the channel. |
437 * Only called when we know we can write to a channel, writes as much as | 438 Writes the circular buffer contents and also the "moredata" buffer |
438 * possible */ | 439 if not null. Will ignore EAGAIN */ |
439 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { | 440 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, |
440 | 441 const unsigned char *moredata, unsigned int *morelen) { |
441 int len, maxlen; | 442 |
443 struct iovec iov[3]; | |
444 unsigned char *circ_p1, *circ_p2; | |
445 unsigned int circ_len1, circ_len2; | |
446 int io_count = 0; | |
447 | |
448 int written; | |
442 | 449 |
443 TRACE(("enter writechannel fd %d", fd)) | 450 TRACE(("enter writechannel fd %d", fd)) |
451 | |
452 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); | |
453 | |
454 if (circ_len1 > 0) { | |
455 TRACE(("circ1 %d", circ_len1)) | |
456 iov[io_count].iov_base = circ_p1; | |
457 iov[io_count].iov_len = circ_len1; | |
458 io_count++; | |
459 } | |
460 | |
461 if (circ_len2 > 0) { | |
462 TRACE(("circ2 %d", circ_len2)) | |
463 iov[io_count].iov_base = circ_p2; | |
464 iov[io_count].iov_len = circ_len2; | |
465 io_count++; | |
466 } | |
467 | |
468 if (morelen) { | |
469 assert(moredata); | |
470 TRACE(("more %d", *morelen)) | |
471 iov[io_count].iov_base = (void*)moredata; | |
472 iov[io_count].iov_len = *morelen; | |
473 io_count++; | |
474 } | |
475 | |
476 if (morelen) { | |
477 /* Default return value, none consumed */ | |
478 *morelen = 0; | |
479 } | |
480 | |
481 written = writev(fd, iov, io_count); | |
482 | |
483 if (written < 0) { | |
484 if (errno != EINTR && errno != EAGAIN) { | |
485 TRACE(("errno %d len %d", errno, len)) | |
486 close_chan_fd(channel, fd, SHUT_WR); | |
487 } | |
488 } else { | |
489 int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written); | |
490 cbuf_incrread(cbuf, cbuf_written); | |
491 if (morelen) { | |
492 *morelen = written - cbuf_written; | |
493 } | |
494 channel->recvdonelen += written; | |
495 } | |
496 | |
497 #if 0 | |
444 | 498 |
445 maxlen = cbuf_readlen(cbuf); | 499 maxlen = cbuf_readlen(cbuf); |
446 | 500 |
447 /* Write the data out */ | 501 /* Write the data out */ |
448 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); | 502 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); |
456 } | 510 } |
457 TRACE(("writechannel wrote %d", len)) | 511 TRACE(("writechannel wrote %d", len)) |
458 | 512 |
459 cbuf_incrread(cbuf, len); | 513 cbuf_incrread(cbuf, len); |
460 channel->recvdonelen += len; | 514 channel->recvdonelen += len; |
515 #endif | |
461 | 516 |
462 /* Window adjust handling */ | 517 /* Window adjust handling */ |
463 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { | 518 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { |
464 /* Set it back to max window */ | |
465 send_msg_channel_window_adjust(channel, channel->recvdonelen); | 519 send_msg_channel_window_adjust(channel, channel->recvdonelen); |
466 channel->recvwindow += channel->recvdonelen; | 520 channel->recvwindow += channel->recvdonelen; |
467 channel->recvdonelen = 0; | 521 channel->recvdonelen = 0; |
468 } | 522 } |
469 | 523 |
743 | 797 |
744 unsigned int datalen; | 798 unsigned int datalen; |
745 unsigned int maxdata; | 799 unsigned int maxdata; |
746 unsigned int buflen; | 800 unsigned int buflen; |
747 unsigned int len; | 801 unsigned int len; |
802 unsigned int consumed; | |
748 | 803 |
749 TRACE(("enter recv_msg_channel_data")) | 804 TRACE(("enter recv_msg_channel_data")) |
750 | 805 |
751 if (channel->recv_eof) { | 806 if (channel->recv_eof) { |
752 dropbear_exit("Received data after eof"); | 807 dropbear_exit("Received data after eof"); |
768 * lead to corrupted file transfers etc (chunks missed etc). It's better to | 823 * lead to corrupted file transfers etc (chunks missed etc). It's better to |
769 * just die horribly */ | 824 * just die horribly */ |
770 if (datalen > maxdata) { | 825 if (datalen > maxdata) { |
771 dropbear_exit("Oversized packet"); | 826 dropbear_exit("Oversized packet"); |
772 } | 827 } |
828 | |
829 dropbear_assert(channel->recvwindow >= datalen); | |
830 channel->recvwindow -= datalen; | |
831 dropbear_assert(channel->recvwindow <= opts.recv_window); | |
832 | |
833 consumed = datalen; | |
834 writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed); | |
835 | |
836 datalen -= consumed; | |
837 buf_incrpos(ses.payload, consumed); | |
838 | |
773 | 839 |
774 /* We may have to run throught twice, if the buffer wraps around. Can't | 840 /* We may have to run throught twice, if the buffer wraps around. Can't |
775 * just "leave it for next time" like with writechannel, since this | 841 * just "leave it for next time" like with writechannel, since this |
776 * is payload data */ | 842 * is payload data */ |
777 len = datalen; | 843 len = datalen; |
783 buf_getptr(ses.payload, buflen), buflen); | 849 buf_getptr(ses.payload, buflen), buflen); |
784 cbuf_incrwrite(cbuf, buflen); | 850 cbuf_incrwrite(cbuf, buflen); |
785 buf_incrpos(ses.payload, buflen); | 851 buf_incrpos(ses.payload, buflen); |
786 len -= buflen; | 852 len -= buflen; |
787 } | 853 } |
788 | |
789 dropbear_assert(channel->recvwindow >= datalen); | |
790 channel->recvwindow -= datalen; | |
791 dropbear_assert(channel->recvwindow <= opts.recv_window); | |
792 | 854 |
793 TRACE(("leave recv_msg_channel_data")) | 855 TRACE(("leave recv_msg_channel_data")) |
794 } | 856 } |
795 | 857 |
796 /* Increment the outgoing data window for a channel - the remote end limits | 858 /* Increment the outgoing data window for a channel - the remote end limits |