1
1

sftp_packet_read: adjust window size as necessary

Commit 03ca9020756 tried to simplify the window sizing logic but broke
SFTP readdir as there was no window sizing code left there so large
directory listings no longer worked.

This change introduces window sizing logic to the sftp_packet_read()
function so that it now tells the remote about the local size having a
window size that suffice when it is about to ask for directory data.

Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2012-03/0069.shtml
Reported by: Eric
Этот коммит содержится в:
Daniel Stenberg 2012-03-12 22:49:25 +01:00
родитель 7e53949e66
Коммит 7194a9bd7b
2 изменённых файлов: 106 добавлений и 72 удалений

Просмотреть файл

@ -1,6 +1,6 @@
/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2007 Eli Fant <elifantu@mail.ru>
* Copyright (c) 2009-2011 by Daniel Stenberg
* Copyright (c) 2009-2012 by Daniel Stenberg
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@ -175,9 +175,18 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
size_t packet_received;
ssize_t rc;
uint32_t packet_len; /* 32bits on the wire */
uint32_t adjust;
unsigned long recv_window;
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet");
switch(sftp->packet_state) {
case libssh2_NB_state_sent:
sftp->packet_state = libssh2_NB_state_idle;
goto window_adjust;
default:
/* If there was a previous partial, start using it */
if (sftp->partial_packet) {
@ -222,6 +231,29 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
"Unable to allocate SFTP packet");
sftp->partial_size_len = 0;
packet_received = 0;
sftp->partial_len = packet_len;
sftp->partial_received = packet_received;
window_adjust:
recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL);
/* how much data to ask for */
adjust = sftp->partial_len - sftp->partial_received;
if(adjust > recv_window) {
/* ask for twice the data amount we need at once */
rc = _libssh2_channel_receive_window_adjust(channel, adjust*2,
0, NULL);
/* store the state so that we continue with the correct
operation at next invoke */
sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN)?
libssh2_NB_state_sent:
libssh2_NB_state_idle;
if(rc == LIBSSH2_ERROR_EAGAIN)
return rc;
}
}
/* Read as much of the packet as we can */
@ -232,12 +264,11 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
if (rc == LIBSSH2_ERROR_EAGAIN) {
/*
* We received EAGAIN, save what we have and return EAGAIN to the
* caller
* We received EAGAIN, save what we have and return EAGAIN to
* the caller. Set 'partial_packet' so that this function
* knows how to continue on the next invoke.
*/
sftp->partial_packet = packet;
sftp->partial_len = packet_len;
sftp->partial_received = packet_received;
return rc;
}
else if (rc < 0) {
@ -257,6 +288,8 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
}
return packet[0];
}
}
/*
* sftp_packetlist_flush
@ -676,12 +709,10 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION,
0, &data, &data_len);
if (rc == LIBSSH2_ERROR_EAGAIN) {
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for response from SFTP subsystem");
if (rc == LIBSSH2_ERROR_EAGAIN)
return NULL;
} else if (rc) {
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
else if (rc) {
_libssh2_error(session, rc,
"Timeout waiting for response from SFTP subsystem");
goto sftp_init_error;
}

Просмотреть файл

@ -161,6 +161,9 @@ struct _LIBSSH2_SFTP
/* State variable used in sftp_read() */
libssh2_nonblocking_states read_state;
/* State variable used in sftp_packet_read() */
libssh2_nonblocking_states packet_state;
/* State variable used in sftp_write() */
libssh2_nonblocking_states write_state;