I have code calling libssh2_channel_read_ex()
<http://www.libssh2.org//libssh2_channel_read_ex.html>, requesting small
reads,
typically < 100 bytes. I notice that the receive window size collapses
very quickly, resulting in timeouts when on a high-latency/high-loss
connection, and otherwise running much more slowly than expected.
The attached patch to examples/ssh2_exec.c illustrates the problem.
Manually updating the window, as shown in the #if 0 block, seems
to stabilize the window size, providing a larger window for worse
connections.
Am I using it right? This code in libssh2_channel_read_ex (src/channel.c)
seems to be at fault:
if(buflen > recv_window) {
BLOCK_ADJUST(rc, channel->session,
_libssh2_channel_receive_window_adjust(channel,
buflen,
1, NULL));
}
When buflen is small, recv_window can never get large enough to be useful,
even when libssh2's (256K) input buffer is empty. Is there a recommended
way to keep the window from collapsing, or should clients not be doing
small reads?
This failure did not occur using libssh2-1.2.5. Running the attached code
(altered just enough to be) linked with 1.2.5 does not exhibit the problem.
Nathan Myers
n...@cantrip.org
--- ../../imports/libssh2/example/ssh2_exec.c 2012-07-04 17:20:19.310258000 -0700
+++ slow.c 2013-01-16 16:57:32.591994303 -0800
@@ -10,7 +10,15 @@
*
*/
+#if 0
#include "libssh2_config.h"
+#else
+#define HAVE_SYS_SOCKET_H
+#define HAVE_NETINET_IN_H
+#define HAVE_SYS_SELECT_H
+#define HAVE_UNISTD_H
+#define HAVE_ARPA_INET_H
+#endif
#include <libssh2.h>
#ifdef HAVE_WINSOCK2_H
@@ -73,7 +81,7 @@
int main(int argc, char *argv[])
{
const char *hostname = "127.0.0.1";
- const char *commandline = "uptime";
+ const char *commandline = "cat /dev/zero";
const char *username = "user";
const char *password = "password";
unsigned long hostaddr;
@@ -90,6 +98,13 @@
LIBSSH2_KNOWNHOSTS *nh;
int type;
+ unsigned long long windowsum = 0;
+ unsigned long calls = 0, windowsize = 0, windowlo = ~0ul, windowhi = 0;
+ unsigned long long then, now;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL); then = tv.tv_sec * 1000000 + tv.tv_usec;
+
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0), &wsadata);
@@ -252,16 +267,32 @@
int rc;
do
{
- char buffer[0x4000];
+ char buffer[10];
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
- int i;
bytecount += rc;
- fprintf(stderr, "We read:\n");
- for( i=0; i < rc; ++i )
- fputc( buffer[i], stderr);
- fprintf(stderr, "\n");
+
+ ++calls;
+ windowsize = libssh2_channel_window_read_ex(channel, 0,0);
+ if (windowlo > windowsize) windowlo = windowsize;
+ if (windowhi < windowsize) windowhi = windowsize;
+ windowsum += windowsize;
+#if 0 /* a hack: stabilizes window size */
+ libssh2_channel_receive_window_adjust2(channel, rc, 0,0);
+#endif
+ gettimeofday(&tv, NULL);
+ now = tv.tv_sec * 1000000 + tv.tv_usec;
+ if (now - then >= 1000000) {
+ printf("n=%-6lu wlo=%-6lu whi=%-6lu wav=%-6llu got=%-6d\n",
+ calls, windowlo, windowhi, windowsum/calls, bytecount);
+ if (calls > 10 && windowsum == 0)
+ break; // busted
+
+ bytecount = windowhi = windowsum = calls = 0;
+ windowlo = ~0ul;
+ then = now;
+ }
}
else {
if( rc != LIBSSH2_ERROR_EAGAIN )
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel