diff --git a/src/channel.c b/src/channel.c index d2453322..8d6fb0ab 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1734,6 +1734,9 @@ libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, * It is important to not return 0 until the currently read channel is * complete. If we read stuff from the wire but it was no payload data to fill * in the buffer with, we MUST make sure to return LIBSSH2_ERROR_EAGAIN. + * + * The receive window must be maintained (enlarged) by the user of this + * function. */ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen) @@ -1755,15 +1758,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, channel->read_state = libssh2_NB_state_created; } - /* - * =============================== NOTE =============================== - * I know this is very ugly and not a really good use of "goto", but - * this case statement would be even uglier to do it any other way - */ - if (channel->read_state == libssh2_NB_state_jump1) { - goto channel_read_window_adjust; - } - rc = 1; /* set to >0 to let the while loop start */ /* Process all pending incoming packets in all states in order to "even @@ -1872,26 +1866,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, more off the network again */ channel->read_state = libssh2_NB_state_created; - if(channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30)) { - /* the window is getting too narrow, expand it! */ - - channel_read_window_adjust: - channel->read_state = libssh2_NB_state_jump1; - /* the actual window adjusting may not finish so we need to deal with - this special state here */ - rc = _libssh2_channel_receive_window_adjust(channel, - (LIBSSH2_CHANNEL_WINDOW_DEFAULT*60), 0, NULL); - if (rc) - return rc; - - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() filled %d adjusted %d", - bytes_read, buflen); - /* continue in 'created' state to drain the already read packages - first before starting to empty the socket further */ - channel->read_state = libssh2_NB_state_created; - } - return bytes_read; } @@ -1904,16 +1878,29 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, * currently read channel is complete. If we read stuff from the wire but it * was no payload data to fill in the buffer with, we MUST make sure to return * LIBSSH2_ERROR_EAGAIN. + * + * This function will first make sure there's a receive window enough to + * receive a full buffer's wort of contents. An application may choose to + * adjust the receive window more to increase transfer performance. */ LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen) { int rc; + unsigned long recv_window; if(!channel) return LIBSSH2_ERROR_BAD_USE; + recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); + + if(buflen > recv_window) { + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_receive_window_adjust(channel, buflen, + 0, NULL)); + } + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_read(channel, stream_id, buf, buflen)); return rc; diff --git a/src/sftp.c b/src/sftp.c index 4f846c59..45e04399 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -1111,8 +1111,10 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, having been acked - until we reach EOF. */ if(!filep->eof) { size_t max_read_ahead = buffer_size*4; - if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*30) - max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*30; + unsigned long recv_window; + + if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*4) + max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*4; /* if the buffer_size passed in now is smaller than what has already been sent, we risk getting count become a very large number */ @@ -1137,6 +1139,26 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, buffer_size*4 amount of data so that we can return them very fast in subsequent calls. */ + + recv_window = libssh2_channel_window_read_ex(sftp->channel, + NULL, NULL); + if(max_read_ahead > recv_window) { + /* more data will be asked for than what the window currently + allows, expand it! */ + + if(total_read) + /* since we risk getting EAGAIN below, we return here if + there is data available */ + return total_read; + + rc = _libssh2_channel_receive_window_adjust(sftp->channel, + max_read_ahead*8, + 0, NULL); + /* if this returns EAGAIN, we will get back to this function + at next call */ + if (rc) + return rc; + } } while(count > 0) {