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:
40
src/sftp.c
40
src/sftp.c
@@ -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");
|
||||
|
@@ -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
|
||||
{
|
||||
|
Reference in New Issue
Block a user