diff options
author | Matt Johnston <matt@ucc.asn.au> | 2015-05-02 22:47:25 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2015-05-02 22:47:25 +0800 |
commit | 19e1afbd1ca6d306166ce74bcd6c6889f8d196f3 (patch) | |
tree | 682e347d7cd5cee4c388743781cd723fce0598a2 | |
parent | fee32054e68324f8c2e13858f21e2ac406190734 (diff) |
Fix no-writev fallback
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | circbuffer.c | 31 | ||||
-rw-r--r-- | circbuffer.h | 3 | ||||
-rw-r--r-- | common-channel.c | 68 | ||||
-rw-r--r-- | common-session.c | 6 | ||||
-rw-r--r-- | packet.c | 6 |
6 files changed, 55 insertions, 61 deletions
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below. Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the same license: -Copyright (c) 2002-2014 Matt Johnston +Copyright (c) 2002-2015 Matt Johnston Portions copyright (c) 2004 Mihnea Stoenescu All rights reserved. diff --git a/circbuffer.c b/circbuffer.c index 949fa84..c0c8641 100644 --- a/circbuffer.c +++ b/circbuffer.c @@ -67,23 +67,6 @@ unsigned int cbuf_getavail(circbuffer * cbuf) { } -unsigned int cbuf_readlen(circbuffer *cbuf) { - - dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size); - dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size); - - if (cbuf->used == 0) { - TRACE(("cbuf_readlen: unused buffer")) - return 0; - } - - if (cbuf->readpos < cbuf->writepos) { - return cbuf->writepos - cbuf->readpos; - } - - return cbuf->size - cbuf->readpos; -} - unsigned int cbuf_writelen(circbuffer *cbuf) { dropbear_assert(cbuf->used <= cbuf->size); @@ -102,14 +85,6 @@ unsigned int cbuf_writelen(circbuffer *cbuf) { return cbuf->size - cbuf->writepos; } -unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) { - if (len > cbuf_readlen(cbuf)) { - dropbear_exit("Bad cbuf read"); - } - - return &cbuf->data[cbuf->readpos]; -} - void cbuf_readptrs(circbuffer *cbuf, unsigned char **p1, unsigned int *len1, unsigned char **p2, unsigned int *len2) { @@ -146,12 +121,6 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) { void cbuf_incrread(circbuffer *cbuf, unsigned int len) { -#if 0 - if (len > cbuf_readlen(cbuf)) { - dropbear_exit("Bad cbuf read"); - } -#endif - dropbear_assert(cbuf->used >= len); cbuf->used -= len; cbuf->readpos = (cbuf->readpos + len) % cbuf->size; diff --git a/circbuffer.h b/circbuffer.h index 81bb91d..744a2c1 100644 --- a/circbuffer.h +++ b/circbuffer.h @@ -40,10 +40,9 @@ void cbuf_free(circbuffer * cbuf); unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */ unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */ -unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */ unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */ -unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len); +/* returns pointers to the two portions of the circular buffer that can be read */ void cbuf_readptrs(circbuffer *cbuf, unsigned char **p1, unsigned int *len1, unsigned char **p2, unsigned int *len2); diff --git a/common-channel.c b/common-channel.c index 6dce497..5f4051e 100644 --- a/common-channel.c +++ b/common-channel.c @@ -434,10 +434,36 @@ static void send_msg_channel_eof(struct Channel *channel) { TRACE(("leave send_msg_channel_eof")) } -/* Called to write data out to the local side of the channel. - Writes the circular buffer contents and also the "moredata" buffer - if not null. Will ignore EAGAIN */ -static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, +#ifndef HAVE_WRITEV +static void writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf, + const unsigned char *UNUSED(moredata), unsigned int *morelen) { + + unsigned char *circ_p1, *circ_p2; + unsigned int circ_len1, circ_len2; + ssize_t written; + + if (morelen) { + /* fallback doesn't consume moredata */ + *morelen = 0; + } + + /* Write the first portion of the circular buffer */ + cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); + written = write(fd, circ_p1, circ_len1); + if (written < 0) { + if (errno != EINTR && errno != EAGAIN) { + TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) + close_chan_fd(channel, fd, SHUT_WR); + } + } else { + cbuf_incrread(cbuf, written); + channel->recvdonelen += written; + } +} +#endif /* !HAVE_WRITEV */ + +#ifdef HAVE_WRITEV +static void writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf, const unsigned char *moredata, unsigned int *morelen) { struct iovec iov[3]; @@ -445,9 +471,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, unsigned int circ_len1, circ_len2; int io_count = 0; - int written; - - TRACE(("enter writechannel fd %d", fd)) + ssize_t written; cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); @@ -502,24 +526,19 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, channel->recvdonelen += written; } -#if 0 - - maxlen = cbuf_readlen(cbuf); - - /* Write the data out */ - len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); - if (len <= 0) { - TRACE(("errno %d len %d", errno, len)) - if (len < 0 && errno != EINTR) { - close_chan_fd(channel, fd, SHUT_WR); - } - TRACE(("leave writechannel: len <= 0")) - return; - } - TRACE(("writechannel wrote %d", len)) +} +#endif /* HAVE_WRITEV */ - cbuf_incrread(cbuf, len); - channel->recvdonelen += len; +/* Called to write data out to the local side of the channel. + Writes the circular buffer contents and also the "moredata" buffer + if not null. Will ignore EAGAIN */ +static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, + const unsigned char *moredata, unsigned int *morelen) { + TRACE(("enter writechannel fd %d", fd)) +#ifdef HAVE_WRITEV + writechannel_writev(channel, fd, cbuf, moredata, morelen); +#else + writechannel_fallback(channel, fd, cbuf, moredata, morelen); #endif /* Window adjust handling */ @@ -537,6 +556,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, TRACE(("leave writechannel")) } + /* Set the file descriptors for the main select in session.c * This avoid channels which don't have any window available, are closed, etc*/ void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) { diff --git a/common-session.c b/common-session.c index 44e7030..083b5c5 100644 --- a/common-session.c +++ b/common-session.c @@ -1,7 +1,7 @@ /* * Dropbear - a SSH2 server * - * Copyright (c) 2002,2003 Matt Johnston + * Copyright (c) Matt Johnston * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -280,7 +280,7 @@ void session_cleanup() { return; } - /* Beware of changing order of functions here. */ + /* BEWARE of changing order of functions here. */ /* Must be before extra_session_cleanup() */ chancleanup(); @@ -289,7 +289,7 @@ void session_cleanup() { ses.extra_session_cleanup(); } - /* After these are freed most functions will exit */ + /* After these are freed most functions will fail */ #ifdef DROPBEAR_CLEANUP /* listeners call cleanup functions, this should occur before other session state is freed. */ @@ -61,6 +61,10 @@ void write_packet() { /* 50 is somewhat arbitrary */ unsigned int iov_count = 50; struct iovec iov[50]; +#else + int len; + buffer* writebuf; + int packet_type; #endif TRACE2(("enter write_packet")) @@ -97,6 +101,8 @@ void write_packet() { * a cleartext packet_type indicator */ packet_type = writebuf->data[writebuf->len-1]; len = writebuf->len - 1 - writebuf->pos; + TRACE2(("write_packet type %d len %d/%d", packet_type, + len, writebuf->len-1)) dropbear_assert(len > 0); /* Try to write as much as possible */ written = write(ses.sock_out, buf_getptr(writebuf, len), len); |