commit
62cea02db3
@ -1,54 +0,0 @@
|
|||||||
From 486bb376218a37fe15318d7724d6eada36b81e6c Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Tue, 26 Mar 2013 17:58:04 +0100
|
|
||||||
Subject: [PATCH 1/3] sftp: seek: Don't flush buffers on same offset
|
|
||||||
|
|
||||||
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
|
|
||||||
---
|
|
||||||
src/sftp.c | 27 +++++++++++++++------------
|
|
||||||
1 file changed, 15 insertions(+), 12 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/sftp.c b/src/sftp.c
|
|
||||||
index d0536dd..3760025 100644
|
|
||||||
--- a/src/sftp.c
|
|
||||||
+++ b/src/sftp.c
|
|
||||||
@@ -2132,21 +2132,24 @@ libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *hnd,
|
|
||||||
LIBSSH2_API void
|
|
||||||
libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset)
|
|
||||||
{
|
|
||||||
- if(handle) {
|
|
||||||
- handle->u.file.offset = handle->u.file.offset_sent = offset;
|
|
||||||
- /* discard all pending requests and currently read data */
|
|
||||||
- sftp_packetlist_flush(handle);
|
|
||||||
+ if(!handle)
|
|
||||||
+ return;
|
|
||||||
+ if(handle->u.file.offset == offset && handle->u.file.offset_sent == offset)
|
|
||||||
+ return;
|
|
||||||
|
|
||||||
- /* free the left received buffered data */
|
|
||||||
- if (handle->u.file.data_left) {
|
|
||||||
- LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data);
|
|
||||||
- handle->u.file.data_left = handle->u.file.data_len = 0;
|
|
||||||
- handle->u.file.data = NULL;
|
|
||||||
- }
|
|
||||||
+ handle->u.file.offset = handle->u.file.offset_sent = offset;
|
|
||||||
+ /* discard all pending requests and currently read data */
|
|
||||||
+ sftp_packetlist_flush(handle);
|
|
||||||
|
|
||||||
- /* reset EOF to False */
|
|
||||||
- handle->u.file.eof = FALSE;
|
|
||||||
+ /* free the left received buffered data */
|
|
||||||
+ if (handle->u.file.data_left) {
|
|
||||||
+ LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data);
|
|
||||||
+ handle->u.file.data_left = handle->u.file.data_len = 0;
|
|
||||||
+ handle->u.file.data = NULL;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ /* reset EOF to False */
|
|
||||||
+ handle->u.file.eof = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* libssh2_sftp_seek
|
|
||||||
--
|
|
||||||
1.8.1.4
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
From a12f3ffab579b514eeb7fdfaca0ade271961cdb4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Mon, 8 Apr 2013 17:30:10 +0100
|
|
||||||
Subject: [PATCH 2/3] sftp: statvfs: Along error path, reset the correct
|
|
||||||
'state' variable.
|
|
||||||
|
|
||||||
---
|
|
||||||
src/sftp.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/src/sftp.c b/src/sftp.c
|
|
||||||
index 3760025..65fa77a 100644
|
|
||||||
--- a/src/sftp.c
|
|
||||||
+++ b/src/sftp.c
|
|
||||||
@@ -2752,7 +2752,7 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path,
|
|
||||||
"Error waiting for FXP EXTENDED REPLY");
|
|
||||||
} else if (data_len < 93) {
|
|
||||||
LIBSSH2_FREE(session, data);
|
|
||||||
- sftp->fstatvfs_state = libssh2_NB_state_idle;
|
|
||||||
+ sftp->statvfs_state = libssh2_NB_state_idle;
|
|
||||||
return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
|
|
||||||
"SFTP Protocol Error: short response");
|
|
||||||
}
|
|
||||||
--
|
|
||||||
1.8.1.4
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
|||||||
From 6e0d757f24a45252c4cae9ea09732eda2562c767 Mon Sep 17 00:00:00 2001
|
|
||||||
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
||||||
Date: Tue, 9 Apr 2013 11:42:09 +0200
|
|
||||||
Subject: [PATCH 3/3] sftp: Add support for fsync (OpenSSH extension).
|
|
||||||
|
|
||||||
The new libssh2_sftp_fsync API causes data and metadata in the
|
|
||||||
currently open file to be committed to disk at the server.
|
|
||||||
|
|
||||||
This is an OpenSSH extension to the SFTP protocol. See:
|
|
||||||
|
|
||||||
https://bugzilla.mindrot.org/show_bug.cgi?id=1798
|
|
||||||
---
|
|
||||||
docs/Makefile.am | 1 +
|
|
||||||
docs/libssh2_sftp_fsync.3 | 39 +++++++++++++++++++
|
|
||||||
include/libssh2_sftp.h | 1 +
|
|
||||||
src/sftp.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
src/sftp.h | 5 +++
|
|
||||||
5 files changed, 143 insertions(+)
|
|
||||||
create mode 100644 docs/libssh2_sftp_fsync.3
|
|
||||||
|
|
||||||
diff --git a/docs/Makefile.am b/docs/Makefile.am
|
|
||||||
index e4cf487..e6ab394 100644
|
|
||||||
--- a/docs/Makefile.am
|
|
||||||
+++ b/docs/Makefile.am
|
|
||||||
@@ -120,6 +120,7 @@ dist_man_MANS = \
|
|
||||||
libssh2_sftp_fstat.3 \
|
|
||||||
libssh2_sftp_fstat_ex.3 \
|
|
||||||
libssh2_sftp_fstatvfs.3 \
|
|
||||||
+ libssh2_sftp_fsync.3 \
|
|
||||||
libssh2_sftp_get_channel.3 \
|
|
||||||
libssh2_sftp_init.3 \
|
|
||||||
libssh2_sftp_last_error.3 \
|
|
||||||
diff --git a/docs/libssh2_sftp_fsync.3 b/docs/libssh2_sftp_fsync.3
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..646760a
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/docs/libssh2_sftp_fsync.3
|
|
||||||
@@ -0,0 +1,39 @@
|
|
||||||
+.TH libssh2_sftp_fsync 3 "8 Apr 2013" "libssh2 1.4.4" "libssh2 manual"
|
|
||||||
+.SH NAME
|
|
||||||
+libssh2_sftp_fsync - synchronize file to disk
|
|
||||||
+.SH SYNOPSIS
|
|
||||||
+.nf
|
|
||||||
+#include <libssh2.h>
|
|
||||||
+#include <libssh2_sftp.h>
|
|
||||||
+
|
|
||||||
+int
|
|
||||||
+libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
|
|
||||||
+.fi
|
|
||||||
+.SH DESCRIPTION
|
|
||||||
+This function causes the remote server to synchronize the file
|
|
||||||
+data and metadata to disk (like fsync(2)).
|
|
||||||
+
|
|
||||||
+For this to work requires fsync@openssh.com support on the server.
|
|
||||||
+
|
|
||||||
+\fIhandle\fP - SFTP File Handle as returned by
|
|
||||||
+.BR libssh2_sftp_open_ex(3)
|
|
||||||
+
|
|
||||||
+.SH RETURN VALUE
|
|
||||||
+Returns 0 on success or negative on failure. If used in non-blocking mode, it
|
|
||||||
+returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
|
||||||
+LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
|
||||||
+.SH ERRORS
|
|
||||||
+\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
|
||||||
+
|
|
||||||
+\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
|
||||||
+
|
|
||||||
+\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response
|
|
||||||
+was received on the socket, or an SFTP operation caused an errorcode
|
|
||||||
+to be returned by the server. In particular, this can be returned if
|
|
||||||
+the SSH server does not support the fsync operation: the SFTP subcode
|
|
||||||
+\fILIBSSH2_FX_OP_UNSUPPORTED\fP will be returned in this case.
|
|
||||||
+
|
|
||||||
+.SH AVAILABILITY
|
|
||||||
+Added in libssh2 1.4.4 and OpenSSH 6.3.
|
|
||||||
+.SH SEE ALSO
|
|
||||||
+.BR fsync(2)
|
|
||||||
diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h
|
|
||||||
index 74884fb..677faf2 100644
|
|
||||||
--- a/include/libssh2_sftp.h
|
|
||||||
+++ b/include/libssh2_sftp.h
|
|
||||||
@@ -247,6 +247,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
|
|
||||||
|
|
||||||
LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
|
|
||||||
const char *buffer, size_t count);
|
|
||||||
+LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
|
|
||||||
|
|
||||||
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
|
|
||||||
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
|
|
||||||
diff --git a/src/sftp.c b/src/sftp.c
|
|
||||||
index 65fa77a..01017fd 100644
|
|
||||||
--- a/src/sftp.c
|
|
||||||
+++ b/src/sftp.c
|
|
||||||
@@ -986,6 +986,10 @@ sftp_shutdown(LIBSSH2_SFTP *sftp)
|
|
||||||
LIBSSH2_FREE(session, sftp->symlink_packet);
|
|
||||||
sftp->symlink_packet = NULL;
|
|
||||||
}
|
|
||||||
+ if (sftp->fsync_packet) {
|
|
||||||
+ LIBSSH2_FREE(session, sftp->fsync_packet);
|
|
||||||
+ sftp->fsync_packet = NULL;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
sftp_packet_flush(sftp);
|
|
||||||
|
|
||||||
@@ -2014,6 +2018,99 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
|
|
||||||
+{
|
|
||||||
+ LIBSSH2_SFTP *sftp = handle->sftp;
|
|
||||||
+ LIBSSH2_CHANNEL *channel = sftp->channel;
|
|
||||||
+ LIBSSH2_SESSION *session = channel->session;
|
|
||||||
+ /* 34 = packet_len(4) + packet_type(1) + request_id(4) +
|
|
||||||
+ string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */
|
|
||||||
+ uint32_t packet_len = handle->handle_len + 34;
|
|
||||||
+ size_t data_len;
|
|
||||||
+ unsigned char *packet, *s, *data;
|
|
||||||
+ ssize_t rc;
|
|
||||||
+ uint32_t retcode;
|
|
||||||
+
|
|
||||||
+ if (sftp->fsync_state == libssh2_NB_state_idle) {
|
|
||||||
+ _libssh2_debug(session, LIBSSH2_TRACE_SFTP,
|
|
||||||
+ "Issuing fsync command");
|
|
||||||
+ s = packet = LIBSSH2_ALLOC(session, packet_len);
|
|
||||||
+ if (!packet) {
|
|
||||||
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
||||||
+ "Unable to allocate memory for FXP_EXTENDED "
|
|
||||||
+ "packet");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ _libssh2_store_u32(&s, packet_len - 4);
|
|
||||||
+ *(s++) = SSH_FXP_EXTENDED;
|
|
||||||
+ sftp->fsync_request_id = sftp->request_id++;
|
|
||||||
+ _libssh2_store_u32(&s, sftp->fsync_request_id);
|
|
||||||
+ _libssh2_store_str(&s, "fsync@openssh.com", 17);
|
|
||||||
+ _libssh2_store_str(&s, handle->handle, handle->handle_len);
|
|
||||||
+
|
|
||||||
+ sftp->fsync_state = libssh2_NB_state_created;
|
|
||||||
+ } else {
|
|
||||||
+ packet = sftp->fsync_packet;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (sftp->fsync_state == libssh2_NB_state_created) {
|
|
||||||
+ rc = _libssh2_channel_write(channel, 0, packet, packet_len);
|
|
||||||
+ if (rc == LIBSSH2_ERROR_EAGAIN ||
|
|
||||||
+ (0 <= rc && rc < (ssize_t)packet_len)) {
|
|
||||||
+ sftp->fsync_packet = packet;
|
|
||||||
+ return LIBSSH2_ERROR_EAGAIN;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ LIBSSH2_FREE(session, packet);
|
|
||||||
+ sftp->fsync_packet = NULL;
|
|
||||||
+
|
|
||||||
+ if (rc < 0) {
|
|
||||||
+ sftp->fsync_state = libssh2_NB_state_idle;
|
|
||||||
+ return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
|
||||||
+ "_libssh2_channel_write() failed");
|
|
||||||
+ }
|
|
||||||
+ sftp->fsync_state = libssh2_NB_state_sent;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
|
|
||||||
+ sftp->fsync_request_id, &data, &data_len);
|
|
||||||
+ if (rc == LIBSSH2_ERROR_EAGAIN) {
|
|
||||||
+ return rc;
|
|
||||||
+ } else if (rc) {
|
|
||||||
+ sftp->fsync_state = libssh2_NB_state_idle;
|
|
||||||
+ return _libssh2_error(session, rc,
|
|
||||||
+ "Error waiting for FXP EXTENDED REPLY");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ sftp->fsync_state = libssh2_NB_state_idle;
|
|
||||||
+
|
|
||||||
+ retcode = _libssh2_ntohu32(data + 5);
|
|
||||||
+ LIBSSH2_FREE(session, data);
|
|
||||||
+
|
|
||||||
+ if (retcode != LIBSSH2_FX_OK) {
|
|
||||||
+ sftp->last_errno = retcode;
|
|
||||||
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
|
|
||||||
+ "fsync failed");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* libssh2_sftp_fsync
|
|
||||||
+ * Commit data on the handle to disk.
|
|
||||||
+ */
|
|
||||||
+LIBSSH2_API int
|
|
||||||
+libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd)
|
|
||||||
+{
|
|
||||||
+ int rc;
|
|
||||||
+ if(!hnd)
|
|
||||||
+ return LIBSSH2_ERROR_BAD_USE;
|
|
||||||
+ BLOCK_ADJUST(rc, hnd->sftp->channel->session,
|
|
||||||
+ sftp_fsync(hnd));
|
|
||||||
+ return rc;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* sftp_fstat
|
|
||||||
*
|
|
||||||
diff --git a/src/sftp.h b/src/sftp.h
|
|
||||||
index 55bdb46..63e8139 100644
|
|
||||||
--- a/src/sftp.h
|
|
||||||
+++ b/src/sftp.h
|
|
||||||
@@ -175,6 +175,11 @@ struct _LIBSSH2_SFTP
|
|
||||||
/* State variable used in sftp_write() */
|
|
||||||
libssh2_nonblocking_states write_state;
|
|
||||||
|
|
||||||
+ /* State variables used in sftp_fsync() */
|
|
||||||
+ libssh2_nonblocking_states fsync_state;
|
|
||||||
+ unsigned char *fsync_packet;
|
|
||||||
+ uint32_t fsync_request_id;
|
|
||||||
+
|
|
||||||
/* State variables used in libssh2_sftp_readdir() */
|
|
||||||
libssh2_nonblocking_states readdir_state;
|
|
||||||
unsigned char *readdir_packet;
|
|
||||||
--
|
|
||||||
1.8.1.4
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
|||||||
From 9e56b84c41efcaf3349f82a93c3dc854e172e5c4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
Date: Fri, 9 Aug 2013 16:22:08 +0200
|
|
||||||
Subject: [PATCH 4/5] partially revert "window_size: explicit adjustments only"
|
|
||||||
|
|
||||||
This partially reverts commit 03ca9020756a4e16f0294e5b35e9826ee6af2364
|
|
||||||
in order to fix extreme slowdown when uploading to localhost via SFTP.
|
|
||||||
|
|
||||||
I was able to repeat the issue on RHEL-7 on localhost only. It did not
|
|
||||||
occur when uploading via network and it did not occur on a RHEL-6 box
|
|
||||||
with the same version of libssh2.
|
|
||||||
|
|
||||||
The problem was that sftp_read() used a read-ahead logic to figure out
|
|
||||||
the window_size, but sftp_packet_read() called indirectly from
|
|
||||||
sftp_write() did not use any read-ahead logic.
|
|
||||||
---
|
|
||||||
src/channel.c | 29 +++++++++++++++++++++++++++++
|
|
||||||
1 files changed, 29 insertions(+), 0 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 4f41e1f..d4ffdce 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -1759,6 +1759,15 @@ 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
|
|
||||||
@@ -1867,6 +1876,26 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
From 96e1078fced70e39e4163857ad8345ae9d24573f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
Date: Wed, 14 Aug 2013 17:37:00 +0200
|
|
||||||
Subject: [PATCH 5/5] channel.c: fix a use after free
|
|
||||||
|
|
||||||
Bug: https://trac.libssh2.org/ticket/268
|
|
||||||
---
|
|
||||||
src/channel.c | 2 --
|
|
||||||
1 files changed, 0 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index d4ffdce..9f2c241 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -670,8 +670,6 @@ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
|
|
||||||
|
|
||||||
LIBSSH2_FREE(session, listener);
|
|
||||||
|
|
||||||
- listener->chanFwdCncl_state = libssh2_NB_state_idle;
|
|
||||||
-
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
From d0a263ef805244245afd9b709bdd3dc733113a6c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Daniel Stenberg <daniel@haxx.se>
|
|
||||||
Date: Sat, 7 Sep 2013 13:41:14 +0200
|
|
||||||
Subject: [PATCH 06/11] _libssh2_channel_write: client spins on write when window full
|
|
||||||
|
|
||||||
When there's no window to "write to", there's no point in waiting for
|
|
||||||
the socket to become writable since it most likely just will continue to
|
|
||||||
be.
|
|
||||||
|
|
||||||
Patch-by: ncm
|
|
||||||
Fixes #258
|
|
||||||
|
|
||||||
[upstream commit e6c46cc249227de7b7cd136d72eded5dcb3f9381]
|
|
||||||
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
src/channel.c | 10 +++++++++-
|
|
||||||
1 files changed, 9 insertions(+), 1 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 9f2c241..74262d8 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -2039,9 +2039,17 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN))
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
- if(channel->local.window_size <= 0)
|
|
||||||
+ if(channel->local.window_size <= 0) {
|
|
||||||
/* there's no room for data so we stop */
|
|
||||||
+
|
|
||||||
+ /* Waiting on the socket to be writable would be wrong because we
|
|
||||||
+ * would be back here immediately, but a readable socket might
|
|
||||||
+ * herald an incoming window adjustment.
|
|
||||||
+ */
|
|
||||||
+ session->socket_block_directions = LIBSSH2_SESSION_BLOCK_INBOUND;
|
|
||||||
+
|
|
||||||
return (rc==LIBSSH2_ERROR_EAGAIN?rc:0);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
channel->write_bufwrite = buflen;
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
|||||||
From 8af6637d86b6a85e8889c286f7ff3d841fc5621c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Salvador Fandino <sfandino@yahoo.com>
|
|
||||||
Date: Sat, 12 Oct 2013 02:51:46 +0200
|
|
||||||
Subject: [PATCH 07/11] window_size: redid window handling for flow control reasons
|
|
||||||
|
|
||||||
Until now, the window size (channel->remote.window_size) was being
|
|
||||||
updated just after receiving the packet from the transport layer.
|
|
||||||
|
|
||||||
That behaviour is wrong because the channel queue may grow uncontrolled
|
|
||||||
when data arrives from the network faster that the upper layer consumes
|
|
||||||
it.
|
|
||||||
|
|
||||||
This patch adds a new counter, read_avail, which keeps a count of the
|
|
||||||
bytes available from the packet queue for reading. Also, now the window
|
|
||||||
size is adjusted when the data is actually read by an upper layer.
|
|
||||||
|
|
||||||
That way, if the upper layer stops reading data, the window will
|
|
||||||
eventually fill and the remote host will stop sending data. When the
|
|
||||||
upper layers reads enough data, a window adjust packet is delivered and
|
|
||||||
the transfer resumes.
|
|
||||||
|
|
||||||
The read_avail counter is used to detect the situation when the remote
|
|
||||||
server tries to send data surpassing the window size. In that case, the
|
|
||||||
extra data is discarded.
|
|
||||||
|
|
||||||
Signed-off-by: Salvador <sfandino@yahoo.com>
|
|
||||||
|
|
||||||
[upstream commit cdeef54967ed5b7d5bd8fa6da5851aa3d173faa0]
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
src/channel.c | 8 +++++++-
|
|
||||||
src/libssh2_priv.h | 2 ++
|
|
||||||
src/packet.c | 35 ++++++++++++++++++++++++++++-------
|
|
||||||
3 files changed, 37 insertions(+), 8 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 74262d8..499d815 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -1411,6 +1411,9 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
|
|
||||||
channel->flush_state = libssh2_NB_state_created;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ channel->read_avail -= channel->flush_flush_bytes;
|
|
||||||
+ channel->remote.window_size -= channel->flush_flush_bytes;
|
|
||||||
+
|
|
||||||
if (channel->flush_refund_bytes) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
@@ -1868,11 +1871,14 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
/* if the transport layer said EAGAIN then we say so as well */
|
|
||||||
return _libssh2_error(session, rc, "would block");
|
|
||||||
}
|
|
||||||
- else
|
|
||||||
+ else {
|
|
||||||
+ channel->read_avail -= bytes_read;
|
|
||||||
+ channel->remote.window_size -= bytes_read;
|
|
||||||
/* make sure we remain in the created state to focus on emptying the
|
|
||||||
data we already have in the packet brigade before we try to read
|
|
||||||
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! */
|
|
||||||
diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
|
|
||||||
index 4ec9f73..fcf4370 100644
|
|
||||||
--- a/src/libssh2_priv.h
|
|
||||||
+++ b/src/libssh2_priv.h
|
|
||||||
@@ -357,6 +357,8 @@ struct _LIBSSH2_CHANNEL
|
|
||||||
libssh2_channel_data local, remote;
|
|
||||||
/* Amount of bytes to be refunded to receive window (but not yet sent) */
|
|
||||||
uint32_t adjust_queue;
|
|
||||||
+ /* Data immediately available for reading */
|
|
||||||
+ uint32_t read_avail;
|
|
||||||
|
|
||||||
LIBSSH2_SESSION *session;
|
|
||||||
|
|
||||||
diff --git a/src/packet.c b/src/packet.c
|
|
||||||
index bfbd56a..d2e758c 100644
|
|
||||||
--- a/src/packet.c
|
|
||||||
+++ b/src/packet.c
|
|
||||||
@@ -653,6 +653,18 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
||||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
||||||
"Ignoring extended data and refunding %d bytes",
|
|
||||||
(int) (datalen - 13));
|
|
||||||
+ if (channelp->read_avail + datalen - data_head >=
|
|
||||||
+ channelp->remote.window_size)
|
|
||||||
+ datalen = channelp->remote.window_size -
|
|
||||||
+ channelp->read_avail + data_head;
|
|
||||||
+
|
|
||||||
+ channelp->remote.window_size -= datalen - data_head;
|
|
||||||
+ _libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
||||||
+ "shrinking window size by %lu bytes to %lu, read_avail %lu",
|
|
||||||
+ datalen - data_head,
|
|
||||||
+ channelp->remote.window_size,
|
|
||||||
+ channelp->read_avail);
|
|
||||||
+
|
|
||||||
session->packAdd_channelp = channelp;
|
|
||||||
|
|
||||||
/* Adjust the window based on the block we just freed */
|
|
||||||
@@ -684,7 +696,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
||||||
" to receive, truncating");
|
|
||||||
datalen = channelp->remote.packet_size + data_head;
|
|
||||||
}
|
|
||||||
- if (channelp->remote.window_size <= 0) {
|
|
||||||
+ if (channelp->remote.window_size <= channelp->read_avail) {
|
|
||||||
/*
|
|
||||||
* Spec says we MAY ignore bytes sent beyond
|
|
||||||
* window_size
|
|
||||||
@@ -700,17 +712,26 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
||||||
/* Reset EOF status */
|
|
||||||
channelp->remote.eof = 0;
|
|
||||||
|
|
||||||
- if ((datalen - data_head) > channelp->remote.window_size) {
|
|
||||||
+ if (channelp->read_avail + datalen - data_head >
|
|
||||||
+ channelp->remote.window_size) {
|
|
||||||
_libssh2_error(session,
|
|
||||||
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
|
|
||||||
"Remote sent more data than current "
|
|
||||||
"window allows, truncating");
|
|
||||||
- datalen = channelp->remote.window_size + data_head;
|
|
||||||
- channelp->remote.window_size = 0;
|
|
||||||
+ datalen = channelp->remote.window_size -
|
|
||||||
+ channelp->read_avail + data_head;
|
|
||||||
}
|
|
||||||
- else
|
|
||||||
- /* Now that we've received it, shrink our window */
|
|
||||||
- channelp->remote.window_size -= datalen - data_head;
|
|
||||||
+
|
|
||||||
+ /* Update the read_avail counter. The window size will be
|
|
||||||
+ * updated once the data is actually read from the queue
|
|
||||||
+ * from an upper layer */
|
|
||||||
+ channelp->read_avail += datalen - data_head;
|
|
||||||
+
|
|
||||||
+ _libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
||||||
+ "increasing read_avail by %lu bytes to %lu/%lu",
|
|
||||||
+ (long)(datalen - data_head),
|
|
||||||
+ (long)channelp->read_avail,
|
|
||||||
+ (long)channelp->remote.window_size);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
|||||||
From cae2385ba898f71038ed4dd00ddae02f85e588e7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Salvador <sfandino@yahoo.com>
|
|
||||||
Date: Tue, 15 Oct 2013 11:45:10 +0200
|
|
||||||
Subject: [PATCH 08/11] _libssh2_channel_read: fix data drop when out of window
|
|
||||||
|
|
||||||
After filling the read buffer with data from the read queue, when the
|
|
||||||
window size was too small, "libssh2_channel_receive_window_adjust" was
|
|
||||||
called to increase it. In non-blocking mode that function could return
|
|
||||||
EAGAIN and, in that case, the EAGAIN was propagated upwards and the data
|
|
||||||
already read on the buffer lost.
|
|
||||||
|
|
||||||
The function was also moving between the two read states
|
|
||||||
"libssh2_NB_state_idle" and "libssh2_NB_state_created" both of which
|
|
||||||
behave in the same way (excepting a debug statment).
|
|
||||||
|
|
||||||
This commit modifies "_libssh2_channel_read" so that the
|
|
||||||
"libssh2_channel_receive_window_adjust" call is performed first (when
|
|
||||||
required) and if everything goes well, then it reads the data from the
|
|
||||||
queued packets into the read buffer.
|
|
||||||
|
|
||||||
It also removes the useless "libssh2_NB_state_created" read state.
|
|
||||||
|
|
||||||
Some rotted comments have also been updated.
|
|
||||||
|
|
||||||
Signed-off-by: Salvador <sfandino@yahoo.com>
|
|
||||||
|
|
||||||
[upstream commit 27f9ac2549b7721cf9d857022c0e7a311830b367]
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
src/channel.c | 75 +++++++++++++++++++--------------------------------------
|
|
||||||
1 files changed, 25 insertions(+), 50 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 499d815..82f6980 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -1751,31 +1751,33 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
LIBSSH2_PACKET *read_packet;
|
|
||||||
LIBSSH2_PACKET *read_next;
|
|
||||||
|
|
||||||
- if (channel->read_state == libssh2_NB_state_idle) {
|
|
||||||
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
||||||
- "channel_read() wants %d bytes from channel %lu/%lu "
|
|
||||||
- "stream #%d",
|
|
||||||
- (int) buflen, channel->local.id, channel->remote.id,
|
|
||||||
- stream_id);
|
|
||||||
- channel->read_state = libssh2_NB_state_created;
|
|
||||||
- }
|
|
||||||
+ _libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
||||||
+ "channel_read() wants %d bytes from channel %lu/%lu "
|
|
||||||
+ "stream #%d",
|
|
||||||
+ (int) buflen, channel->local.id, channel->remote.id,
|
|
||||||
+ stream_id);
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * =============================== 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;
|
|
||||||
- }
|
|
||||||
+ /* expand the receiving window first if it has become too narrow */
|
|
||||||
+ if((channel->read_state == libssh2_NB_state_jump1) ||
|
|
||||||
+ (channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30))) {
|
|
||||||
+
|
|
||||||
+ /* the actual window adjusting may not finish so we need to deal with
|
|
||||||
+ this special state here */
|
|
||||||
+ channel->read_state = libssh2_NB_state_jump1;
|
|
||||||
+ rc = _libssh2_channel_receive_window_adjust(channel,
|
|
||||||
+ (LIBSSH2_CHANNEL_WINDOW_DEFAULT*60),
|
|
||||||
+ 0, NULL);
|
|
||||||
+ if (rc)
|
|
||||||
+ return rc;
|
|
||||||
|
|
||||||
- rc = 1; /* set to >0 to let the while loop start */
|
|
||||||
+ channel->read_state = libssh2_NB_state_idle;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- /* Process all pending incoming packets in all states in order to "even
|
|
||||||
- out" the network readings. Tests prove that this way produces faster
|
|
||||||
- transfers. */
|
|
||||||
- while (rc > 0)
|
|
||||||
+ /* Process all pending incoming packets. Tests prove that this way
|
|
||||||
+ produces faster transfers. */
|
|
||||||
+ do {
|
|
||||||
rc = _libssh2_transport_read(session);
|
|
||||||
+ } while (rc > 0);
|
|
||||||
|
|
||||||
if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN))
|
|
||||||
return _libssh2_error(session, rc, "transport read");
|
|
||||||
@@ -1857,8 +1859,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bytes_read) {
|
|
||||||
- channel->read_state = libssh2_NB_state_idle;
|
|
||||||
-
|
|
||||||
/* If the channel is already at EOF or even closed, we need to signal
|
|
||||||
that back. We may have gotten that info while draining the incoming
|
|
||||||
transport layer until EAGAIN so we must not be fooled by that
|
|
||||||
@@ -1871,34 +1871,9 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
/* if the transport layer said EAGAIN then we say so as well */
|
|
||||||
return _libssh2_error(session, rc, "would block");
|
|
||||||
}
|
|
||||||
- else {
|
|
||||||
- channel->read_avail -= bytes_read;
|
|
||||||
- channel->remote.window_size -= bytes_read;
|
|
||||||
- /* make sure we remain in the created state to focus on emptying the
|
|
||||||
- data we already have in the packet brigade before we try to read
|
|
||||||
- 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;
|
|
||||||
- }
|
|
||||||
+ channel->read_avail -= bytes_read;
|
|
||||||
+ channel->remote.window_size -= bytes_read;
|
|
||||||
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
From 5c14f0e6ecfe73da86d3ad20edd60c4756037935 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Salvador <sfandino-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>
|
|
||||||
Date: Wed, 16 Oct 2013 13:31:31 +0200
|
|
||||||
Subject: [PATCH 09/11] _libssh2_channel_read: Honour window_size_initial
|
|
||||||
|
|
||||||
_libssh2_channel_read was using an arbitrary hard-coded limit to trigger
|
|
||||||
the window adjusting code. The adjustment used was also hard-coded and
|
|
||||||
arbitrary, 15MB actually, which would limit the usability of libssh2 on
|
|
||||||
systems with little RAM.
|
|
||||||
|
|
||||||
This patch, uses the window_size parameter passed to
|
|
||||||
libssh2_channel_open_ex (stored as remote.window_size_initial) plus the
|
|
||||||
buflen as the base for the trigger and the adjustment calculation.
|
|
||||||
|
|
||||||
The memory usage when using the default window size is reduced from 22MB
|
|
||||||
to 256KB per channel (actually, if compression is used, these numbers
|
|
||||||
should be incremented by ~50% to account for the errors between the
|
|
||||||
decompressed packet sizes and the predicted sizes).
|
|
||||||
|
|
||||||
My tests indicate that this change does not impact the performance of
|
|
||||||
transfers across localhost or a LAN, being it on par with that of
|
|
||||||
OpenSSH. On the other hand, it will probably slow down transfers on
|
|
||||||
networks with high bandwidth*delay when the default window size
|
|
||||||
(LIBSSH2_CHANNEL_WINDOW_DEFAULT=256KB) is used.
|
|
||||||
|
|
||||||
Signed-off-by: Salvador Fandino <sfandino@yahoo.com>
|
|
||||||
|
|
||||||
[upstream commit 1b3307dda0c58d9023a657747592ac86703b1ff4]
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
src/channel.c | 11 +++++++----
|
|
||||||
1 files changed, 7 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 82f6980..36c75d2 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -1758,14 +1758,17 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
|
||||||
stream_id);
|
|
||||||
|
|
||||||
/* expand the receiving window first if it has become too narrow */
|
|
||||||
- if((channel->read_state == libssh2_NB_state_jump1) ||
|
|
||||||
- (channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30))) {
|
|
||||||
+ if( (channel->read_state == libssh2_NB_state_jump1) ||
|
|
||||||
+ (channel->remote.window_size < channel->remote.window_size_initial / 4 * 3 + buflen) ) {
|
|
||||||
+
|
|
||||||
+ uint32_t adjustment = channel->remote.window_size_initial + buflen - channel->remote.window_size;
|
|
||||||
+ if (adjustment < LIBSSH2_CHANNEL_MINADJUST)
|
|
||||||
+ adjustment = LIBSSH2_CHANNEL_MINADJUST;
|
|
||||||
|
|
||||||
/* the actual window adjusting may not finish so we need to deal with
|
|
||||||
this special state here */
|
|
||||||
channel->read_state = libssh2_NB_state_jump1;
|
|
||||||
- rc = _libssh2_channel_receive_window_adjust(channel,
|
|
||||||
- (LIBSSH2_CHANNEL_WINDOW_DEFAULT*60),
|
|
||||||
+ rc = _libssh2_channel_receive_window_adjust(channel, adjustment,
|
|
||||||
0, NULL);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
|||||||
From 0a758095c40ae1b32dc5052a706a16c2d9ac5742 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Salvador Fandino <sfandino@yahoo.com>
|
|
||||||
Date: Mon, 21 Oct 2013 11:58:55 +0200
|
|
||||||
Subject: [PATCH 10/11] Set default window size to 2MB
|
|
||||||
|
|
||||||
The default channel window size used until now was 256KB. This value is
|
|
||||||
too small and results on a bottleneck on real-life networks where
|
|
||||||
round-trip delays can easily reach 300ms.
|
|
||||||
|
|
||||||
The issue was not visible because the configured channel window size
|
|
||||||
was being ignored and a hard-coded value of ~22MB being used instead,
|
|
||||||
but that was fixed on a previous commit.
|
|
||||||
|
|
||||||
This patch just changes the default window size
|
|
||||||
(LIBSSH2_CHANNEL_WINDOW_DEFAULT) to 2MB. It is the same value used by
|
|
||||||
OpenSSH and in our opinion represents a good compromise between memory
|
|
||||||
used and transfer speed.
|
|
||||||
|
|
||||||
Performance tests were run to determine the optimum value. The details
|
|
||||||
and related discussion are available from the following thread on the
|
|
||||||
libssh2 mailing-list:
|
|
||||||
|
|
||||||
http://www.libssh2.org/mail/libssh2-devel-archive-2013-10/0018.shtml
|
|
||||||
http://article.gmane.org/gmane.network.ssh.libssh2.devel/6543
|
|
||||||
|
|
||||||
An excerpt follows:
|
|
||||||
|
|
||||||
"I have been running some transfer test and measuring their speed.
|
|
||||||
|
|
||||||
My setup was composed of a quad-core Linux machine running Ubuntu 13.10
|
|
||||||
x86_64 with a LXC container inside. The data transfers were performed
|
|
||||||
from the container to the host (never crossing through a physical
|
|
||||||
network device).
|
|
||||||
|
|
||||||
Network delays were simulated using the tc tool. And ping was used to
|
|
||||||
verify that they worked as intended during the tests.
|
|
||||||
|
|
||||||
The operation performed was the equivalent to the following ssh command:
|
|
||||||
|
|
||||||
$ ssh container "dd bs=16K count=8K if=/dev/zero" >/dev/null
|
|
||||||
|
|
||||||
Though, establishment and closing of the SSH connection was excluded
|
|
||||||
from the timings.
|
|
||||||
|
|
||||||
I run the tests several times transferring files of sizes up to 128MB
|
|
||||||
and the results were consistent between runs.
|
|
||||||
|
|
||||||
The results corresponding to the 128MB transfer are available here:
|
|
||||||
|
|
||||||
https://docs.google.com/spreadsheet/ccc?key=0Ao1yRmX6PQQzdG5wSFlrZl9HRWNET3ZyN0hnaGo5ZFE&usp=sharing
|
|
||||||
|
|
||||||
It clearly shows that 256KB is too small as the default window size.
|
|
||||||
Moving to a 512MB generates a great improvement and after the 1MB mark
|
|
||||||
the returns rapidly diminish. Other factors (TCP window size, probably)
|
|
||||||
become more limiting than the channel window size
|
|
||||||
|
|
||||||
For comparison I also performed the same transfers using OpenSSH. Its
|
|
||||||
speed is usually on par with that of libssh2 using a window size of 1MB
|
|
||||||
(even if it uses a 2MB window, maybe it is less aggressive sending the
|
|
||||||
window adjust msgs)."
|
|
||||||
|
|
||||||
Signed-off-by: Salvador Fandino <sfandino@yahoo.com>
|
|
||||||
|
|
||||||
[upstream commit 85a827d1bceb9abd4442f225dd7c65ef5cefdc32]
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
include/libssh2.h | 2 +-
|
|
||||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/include/libssh2.h b/include/libssh2.h
|
|
||||||
index 9b1a6e1..df873fc 100644
|
|
||||||
--- a/include/libssh2.h
|
|
||||||
+++ b/include/libssh2.h
|
|
||||||
@@ -587,7 +587,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
|
|
||||||
long timeout);
|
|
||||||
|
|
||||||
/* Channel API */
|
|
||||||
-#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (256*1024)
|
|
||||||
+#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (2*1024*1024)
|
|
||||||
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768
|
|
||||||
#define LIBSSH2_CHANNEL_MINADJUST 1024
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
From baadc811a703b9a6dec655c7afb3218d8cff51fa Mon Sep 17 00:00:00 2001
|
|
||||||
From: Daniel Stenberg <daniel@haxx.se>
|
|
||||||
Date: Sun, 16 Mar 2014 20:02:37 +0100
|
|
||||||
Subject: [PATCH 11/11] channel_receive_window_adjust: store windows size always
|
|
||||||
|
|
||||||
Avoid it sometimes returning without storing it, leaving calling
|
|
||||||
functions with unknown content!
|
|
||||||
|
|
||||||
Detected by clang-analyzer
|
|
||||||
|
|
||||||
[upstream commit fcb601da7b37c6e9bbcd264199597e2ddb7bc347]
|
|
||||||
|
|
||||||
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
||||||
---
|
|
||||||
src/channel.c | 11 ++++-------
|
|
||||||
1 files changed, 4 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/channel.c b/src/channel.c
|
|
||||||
index 36c75d2..1d074df 100644
|
|
||||||
--- a/src/channel.c
|
|
||||||
+++ b/src/channel.c
|
|
||||||
@@ -1,6 +1,6 @@
|
|
||||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
|
||||||
* Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
|
|
||||||
- * Copyright (c) 2008-2011 by Daniel Stenberg
|
|
||||||
+ * Copyright (c) 2008-2014 by Daniel Stenberg
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
@@ -1544,6 +1544,9 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
+ if(store)
|
|
||||||
+ *store = channel->remote.window_size;
|
|
||||||
+
|
|
||||||
if (channel->adjust_state == libssh2_NB_state_idle) {
|
|
||||||
if (!force
|
|
||||||
&& (adjustment + channel->adjust_queue <
|
|
||||||
@@ -1553,14 +1556,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
|
||||||
"for channel %lu/%lu",
|
|
||||||
adjustment, channel->local.id, channel->remote.id);
|
|
||||||
channel->adjust_queue += adjustment;
|
|
||||||
- if(store)
|
|
||||||
- *store = channel->remote.window_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!adjustment && !channel->adjust_queue) {
|
|
||||||
- if(store)
|
|
||||||
- *store = channel->remote.window_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1598,8 +1597,6 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
|
||||||
|
|
||||||
channel->adjust_state = libssh2_NB_state_idle;
|
|
||||||
|
|
||||||
- if(store)
|
|
||||||
- *store = channel->remote.window_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
1.7.1
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
|||||||
From a958624be229315ab57017040ef15c5ae072d1ac Mon Sep 17 00:00:00 2001
|
|
||||||
From: Matthias Kerestesch <mail@kerestesch.de>
|
|
||||||
Date: Sat, 18 May 2013 23:01:35 +0200
|
|
||||||
Subject: [PATCH] libssh2_agent_init: init ->fd to LIBSSH2_INVALID_SOCKET
|
|
||||||
|
|
||||||
... previously it was left at 0 which is a valid file descriptor!
|
|
||||||
|
|
||||||
Bug: https://trac.libssh2.org/ticket/265
|
|
||||||
|
|
||||||
Fixes #265
|
|
||||||
|
|
||||||
Upstream-commit: 1ad20ac7d3e21d091e7cfec58fda0afdc359360a
|
|
||||||
---
|
|
||||||
src/agent.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/src/agent.c b/src/agent.c
|
|
||||||
index 1c65149..a8a5025 100644
|
|
||||||
--- a/src/agent.c
|
|
||||||
+++ b/src/agent.c
|
|
||||||
@@ -652,6 +652,7 @@ libssh2_agent_init(LIBSSH2_SESSION *session)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(agent, 0, sizeof *agent);
|
|
||||||
+ agent->fd = LIBSSH2_INVALID_SOCKET;
|
|
||||||
agent->session = session;
|
|
||||||
_libssh2_list_init(&agent->head);
|
|
||||||
|
|
||||||
--
|
|
||||||
2.1.0
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
Version: GnuPG v1.4.11 (GNU/Linux)
|
|
||||||
|
|
||||||
iEYEABECAAYFAk5miSYACgkQeOEcayedXJH3swCg6URaVPa2VvmUISM7KrLAbyfw
|
|
||||||
aqYAoJxpmM0XY9HYqrMqmtH2uYNbpJyL
|
|
||||||
=yCYe
|
|
||||||
-----END PGP SIGNATURE-----
|
|
Loading…
Reference in new issue