sftp_write: handle "left over" acked data

The SFTP handle struct now buffers number of acked bytes that haven't
yet been returned. The way this is used is as following:

1. sftp_write() gets called with a buffer of let say size 32000. We
split 32000 into 8 smaller packets and send them off one by one. One of
them gets acked before the function returns so 4000 is returned.

2. sftp_write() gets called again a short while after the previous one,
now with a much smaller size passed in to the function. Lets say 8000.
In the mean-time, all of the remaining packets from the previous call
have been acked (7*4000 = 28000). This function then returns 8000 as all
data passed in are already sent and it can't return any more than what
it got passed in. But we have 28000 bytes acked. We now store the
remaining 20000 in the handle->u.file.acked struct field to add up in
the next call.

3. sftp_write() gets called again, and now there's a backlogged 20000
bytes to return as fine and that will get skipped from the beginning
of the buffer that is passed in.
This commit is contained in:
Daniel Stenberg
2010-11-11 11:43:30 +01:00
parent 2f5a2ff8e6
commit 7899d28ecb
2 changed files with 34 additions and 8 deletions

View File

@@ -1435,13 +1435,24 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
size_t org_count = count;
size_t eagain = 0;
/* number of bytes sent off that haven't been acked and therefor
we will get passed in here again */
size_t unacked = handle->u.file.offset_sent - handle->u.file.offset;
/* Number of bytes sent off that haven't been acked and therefor we will
get passed in here again.
/* skip the part already made into packets */
buffer += unacked;
count -= unacked;
Also, add up the number of bytes that actually already have been acked
but we haven't been able to return as such yet, so we will get that
data as well passed in here again.
*/
size_t already = (handle->u.file.offset_sent - handle->u.file.offset)+
handle->u.file.acked;
if(count >= already) {
/* skip the part already made into packets */
buffer += already;
count -= already;
}
else
/* there is more data already fine than what we got in this call */
count = 0;
while(count) {
/* TODO: Possibly this should have some logic to prevent a very very
@@ -1558,10 +1569,23 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
}
}
if(acked)
/* if there were acked data in a previous call that wasn't returned then,
add that up and try to return it all now. This can happen if the app
first sends a huge buffer of data, and then in a second call it sends a
smaller one. */
acked += handle->u.file.acked;
if(acked) {
ssize_t ret = MIN(acked, org_count);
/* we got data acked so return that amount, but no more than what
was asked to get sent! */
return MIN(acked, org_count);
/* store the remainder. 'ret' is always equal to or less than 'acked'
here */
handle->u.file.acked = acked - ret;
return ret;
}
else if(eagain)
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block sftp_write");

View File

@@ -81,6 +81,8 @@ struct _LIBSSH2_SFTP_HANDLE
{
libssh2_uint64_t offset;
libssh2_uint64_t offset_sent;
size_t acked; /* container for acked data that hasn't been
returned yet */
} file;
struct _libssh2_sftp_handle_dir_data
{