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