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

Reply via email to